SavinaRoja/PyUserInput — pull request #47 by casebeer (2014-06-22 05:10:16+00:00)
Title: Fix for extremely slow pyobjc import

I've been seeing the very long import time bug on Mac documented in Issue #5.

Specifically,

import pymouse

hangs for in excess of 15 seconds on Mac OS X 10.9.3/Python 2.7.5 with pyobjc v2.5.1.

I've traced the issue back to the pyobjc project, which has a bug discussion containing this message:

> If you are only using framework wrappers: make sure you do not use "from Foundation import ", use "import Foundation" or "from Foundation import NSObject" instead. Someone recently noticed that the "from ... import " form is currently much slower than it used to be, due to the way the PyObjC lazy loader is implemented. I'm working on a fix for that, but even with the fix explicit imports will be better because they perform less form (because explicit imports don't have to resolve the symbols you don't use).

https://bitbucket.org/ronaldoussoren/pyobjc/issue/2/faster-metadata-support#comment-5204985

The pymouse/mac.py and pykeyboard/mac.py modules use exactly this `from Quartz import *` import style.

Changing this to `import Quartz` and fixing the references to Quartz objects solves the import time issues.

I've also added a unit test that checks the import times for pymouse and pykeyboard. Since this is an import bug, only the first of these tests can ever fail (since subsequent `from Quartz import *` calls won't reimport Quartz). Even so, the test does catch the bug described above.

### Reproducing the bug

#### Environment

- Mac OS X 10.9.3 Mavericks
- 1.6 GHz Core 2 Duo, 8 GB RAM, SSD
- Python 2.7.5
- pyobjc-core 2.5.1
- PyUserInput 0.1.9 (both from PyPi and git bbf8c41)

#### Steps

1. import the pymouse module.

You should observe at least a 15 second hang with no output or other response. For example:

print "About to import pymouse"
import pymouse
print "This will print at least 15 seconds later"

### Results

Before the patch, at version 0.1.9/bbf8c41:

$ time python -m pymouse
...

real 0m14.961s
user 0m14.275s
sys 0m0.164s

After changing to `import Quartz`:

$ time python -m pymouse
...

real 0m0.495s
user 0m0.381s
sys 0m0.092s

### Caveats/risks

Three unit tests fail for me when I run `nosetests` both before and after this PR's commits, so I don't have a clean baseline to evaluate whether I've broken anything, for example by missing adding the Quartz.* reference to any Quartz package objects in pymouse/mac.py or pykeyboard/mac.py.

I can successfully run the examples/filetranscriber.py demo and the tests/basic.py program.