The challenge/goal that I was working with was this:
allow for asynchronous python callback on system event from inside  
pure python code (and the corollary became: without adverse memory  
impact of multiple Cocoa loading python processes)
The core of crankd's functionality revolves around the use of an  
NSRunloop
Ideally the runloop blocks till an event occurs, but that makes crankd  
unresponsive to signals etc - hence the timer
The same runloop behavior makes it impossible to keep things truly  
asynchronous if the runloop is being run anywhere in the main thread  
of your code (your code meaning - the calling code / user code), and  
so no form of standard import and function calling would work.
also to have this all happening in the main thread means that one has  
to mix Cocoa and python in the same program
To allow segregation of the Cocoa and Python, the Cocoa runloop has to  
occur is a separate thread of execution.  Problems with that are:
python threading, and multiprocessing modules use os.fork and fork()  
is not compatible with Cocoa:
http://lists.apple.com/archives/cocoa-dev/2005/Jan/msg00676.html
The next approach attempted was to use NSThread so that Cocoa was  
always running in a non-forked process and that the threading was  
handled by Cocoa directly.  However, only a subset of Cocoa frameworks  
are thread safe and those do not include critical ones like  
NSWorkplace etc.
http://www.mail-archive.com/coco...@lists.apple.com/msg26099.html
As a side note, I was able to get a NSThread spawned with its own  
runloop and callbacks working in python - but only for a simple timer.
So what I've come up with is a method whereby the runloop code runs  
inside its own process - and communicates with standard python code  
through named pipes.
This results then in three layers:
1) end user code - read as simple python code (no pyobjc), uses  
EventListener class
2) EventListener class - provides interface to associate callable  
functions with system events.  This class handles communication with  
the runloop watcher through named pipes, adding events to be watched  
and receiving event occurrences and running the callbacks
3) eventwatcher tool - a program that is run and watches for events -  
communicates with one or more EventListener instances via named  
pipes.  A single process would handle all EventListener instances in  
any user code - events can be added or removed while running (not  
avail in crankd currently).
I've have outlined the design of 2 and 3 pretty thoroughly with some  
aspects spot tested with experiments.
So now the question is whether to proceed.
I know this group is rightfully averse to complexity - but the outline  
I have for dispatching events through named pipes is pretty efficient  
and I haven't been able to think of any other way to factor out the  
runloop dependent parts of crankd.
Do others feel that the functionality of listening for various system  
events and executing python code in response is a feature that would  
be useful to have as a general API abstracted from the context of the  
crankd utility?  Note that such a refactor I'm proposing is largely  
compatible and independent from the work Nigel is doing - as his  
improvements would just be split into those that are runloop-code  
related and those that are crankd related.
Please weigh in with your opinion
-Preston
As far as a general purpose API goes, I can see where it could be
valuable in the future but I'd recommend starting with a major crankd
upgrade and breaking out the API the first time we come up with a
solid use for it - otherwise I'm afraid it might end up being a large
amount of work with limited utility.
Chris