pepijndevos/PyMouse — pull request #20 by casebeer (2014-06-22 05:35:53+00:00)
Title: Avoid Quartz lazyloader `from Quartz import *` bug

I've been having a problem with very long import times/hanging on import.

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 module uses 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 time for pymouse.

### 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
- PyMouse 1.0 (from PyPi or git b0cc56c)

#### 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 1.0/b0cc56c:

$ time python -m pymouse
...
real	0m16.040s
user	0m14.322s
sys	0m0.194s

After changing to `import Quartz`:

$ time python -m pymouse
...
real	0m0.558s
user	0m0.390s
sys	0m0.087s

**n.b. I've issued substantially this same Pull Request to the PyUserinput project as well.**