Stackless Python and Sockets
I've been intrigued by Stackless Python for a while, and
finally got around to installing it one one of my machines. FreeBSD doesn't have a port available, so after creating an ezjail
to isolate the installation, it was just a matter of fetching and extracting stackless-251-export.tar.bz2 and doing a standard ./configure && make && make install
The installation looks pretty much like a normal Python installation on FreeBSD, with a /usr/local/bin/python binary and libraries in /usr/local/lib/python2.5
Networking is something I especially wanted to check out with Stackless, and the examples on the Stackless website mostly make use of a stacklesssocket.py module which is a separate download. That module has unittests built in as the module's main function, but when running it on my FreeBSD 7.0-CURRENT box, it died with an exception ending in:
File "stacklesssocket.py.ok", line 286, in handle_connect
self.connectChannel.send(None)
AttributeError: 'NoneType' object has no attribute 'send'
after doing some digging, I found that stacklesssocket.py has a dispatcher class which is a subclass of a class by the same name in Python's asyncore.py module. stacklesssocket.dispatcher.connect() calls asyncore.dispatcher.connect() which may directly call the object's handle_connect() method before returning back to stacklesssocket.dispatcher.connect(). However stacklesssocket.dispatcher.connect() doesn't setup that channel until after the call to asyncore.dispatcher.connect() returns. So when handle_connect() tries to send a message over a channel that doesn't exist yet, an exception is raised.
This trivial patch seems to fix the problem - only sending a message over the channel if it exists (which should only happen if there's another tasklet waiting on it back in a stacklesssocket.dispatcher.connect() method).
--- stacklesssocket.py.orig 2007-09-18 20:58:02.000835000 -0500 +++ stacklesssocket.py 2007-09-18 22:03:13.370709131 -0500 @@ -282,7 +282,7 @@ # Inform the blocked connect call that the connection has been made. def handle_connect(self): - if self.socket.type != SOCK_DGRAM: + if (self.socket.type != SOCK_DGRAM) and self.connectChannel: self.connectChannel.send(None) # Asyncore says its done but self.readBuffer may be non-empty
With that patch, the unittests run successfully - at least on my box.