[Twisted-Python] Oddity(?) with zero-length Deferred lists

Good afternoon! I notice an oddity with zero-length DeferredLists. The example script (http://dpaste.com/49099/) should just return the contents of a bunch of URLs given at the command line, or some errors like so: $ python test.py a b c [(False, <twisted.python.failure.Failure twisted.web.error.Error>), (False, <twisted.python.failure.Failure twisted.web.error.Error>), (False, <twisted.python.failure.Failure twisted.web.error.Error>)] *but* $ python test.py # no arguments [] # then hangs, never reaching "quit" Is this odd behaviour? In defer.py 's DeferredList.__init__ there is: self.resultList = [None] * len(deferredList) Deferred.__init__(self) if len(deferredList) == 0 and not fireOnOneCallback: self.callback(self.resultList) Thanks in advance! Gregg ------------------------ #!/usr/bin/env python ## example script1 from twisted.web.client import getPage from twisted.internet import reactor, defer def getUrls(L): dL = defer.DeferredList( [getPage(x) for x in L] , consumeErrors=True) return dL def results(data): print data return def quit(data): reactor.stop() return if __name__ == "__main__": import sys L = sys.argv[1:] d = getUrls(L) d.addCallback(results) d.addCallback(quit ) reactor.run()

On Fri, 09 May 2008 14:33:19 -0500, Gregg Lind <gregg@renesys.com> wrote:
Good afternoon!
I notice an oddity with zero-length DeferredLists.
The example script (http://dpaste.com/49099/) should just return the contents of a bunch of URLs given at the command line, or some errors like so:
$ python test.py a b c [(False, <twisted.python.failure.Failure twisted.web.error.Error>), (False, <twisted.python.failure.Failure twisted.web.error.Error>), (False, <twisted.python.failure.Failure twisted.web.error.Error>)]
*but*
$ python test.py # no arguments [] # then hangs, never reaching "quit"
You can do this in a simpler way without involving DeferredList: >>> from twisted.internet.defer import succeed >>> from twisted.internet import reactor >>> d = succeed(None) >>> d.addCallback(lambda ign: reactor.stop()) <Deferred at 0xB7D1F12CL current result: <twisted.python.failure.Failure twisted.internet.error.ReactorNotRunning>> >>> reactor.run() <hang> As you can see from this example, the Deferred already has a result (a Failure) by the time reactor.run() is called. Adding a callback to a Deferred which already has a result (such as succeed(None) or DeferredList([])) calls the callback immediately. So your sample program is trying to stop the reactor before it starts. Then nothing tries to stop the reactor after you actually do start it. If you add an errback to your Deferred, you'll see the problem reported. One solution to this is to use reactor.callWhenRunning(reactor.stop) instead of reactor.stop(). Jean-Paul

Jean-Paul! Thank you for the quick and informative answer! Gregg Jean-Paul Calderone wrote:
On Fri, 09 May 2008 14:33:19 -0500, Gregg Lind <gregg@renesys.com> wrote:
Good afternoon!
I notice an oddity with zero-length DeferredLists.
The example script (http://dpaste.com/49099/) should just return the contents of a bunch of URLs given at the command line, or some errors like so:
$ python test.py a b c [(False, <twisted.python.failure.Failure twisted.web.error.Error>), (False, <twisted.python.failure.Failure twisted.web.error.Error>), (False, <twisted.python.failure.Failure twisted.web.error.Error>)]
*but*
$ python test.py # no arguments [] # then hangs, never reaching "quit"
You can do this in a simpler way without involving DeferredList:
from twisted.internet.defer import succeed from twisted.internet import reactor d = succeed(None) d.addCallback(lambda ign: reactor.stop()) <Deferred at 0xB7D1F12CL current result: <twisted.python.failure.Failure twisted.internet.error.ReactorNotRunning>> reactor.run() <hang>
As you can see from this example, the Deferred already has a result (a Failure) by the time reactor.run() is called. Adding a callback to a Deferred which already has a result (such as succeed(None) or DeferredList([])) calls the callback immediately. So your sample program is trying to stop the reactor before it starts. Then nothing tries to stop the reactor after you actually do start it. If you add an errback to your Deferred, you'll see the problem reported. One solution to this is to use reactor.callWhenRunning(reactor.stop) instead of reactor.stop().
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
participants (2)
-
Gregg Lind
-
Jean-Paul Calderone