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.