[Twisted-Python] how to write a safe catch-all

exarkun at twistedmatrix.com exarkun at twistedmatrix.com
Thu Sep 30 10:33:24 EDT 2010


On 02:13 pm, chris at simplistix.co.uk wrote:
>On 30/09/2010 14:39, Jonathan Lange wrote:
>>On Thu, Sep 30, 2010 at 2:36 PM, Chris Withers<chris at simplistix.co.uk> 
>>wrote:
>>...
>>>
>>>Is there any way I can get both errbacks *and* exceptions handled 
>>>nicely in
>>>my `loop` call?
>>
>>You know about defer.maybeDeferred, right?
>
>Yep, the problem is with `loop` implemented like so:
>
>def loop():
>     d = maybeDeferred(doStuff)
>     d.addErrback(partial(log.err,_why='Unhandled scheduled exception'))

Names that begin with an underscore are private.  Also, partial is a 
pointless complexification here.

    def loop():
        d = maybeDeferred(doStuff)
        d.addErrback(log.err, 'Unhandled scheduled exception')
>...the logging is odd:
>
>2010-09-30 15:07:03,161 ERROR   : log         (22194|7f41910b26e0):
>Unhandled Error
>Traceback (most recent call last):
>   File "test_looping.py", line 47, in <module>
>     reactor.run()
>   File "/twisted/internet/base.py", line 1166, in run
>     self.mainLoop()
>   File "/twisted/internet/base.py", line 1175, in mainLoop
>     self.runUntilCurrent()
>--- <exception caught here> ---
>   File "/twisted/internet/base.py", line 779, in runUntilCurrent
>     call.func(*call.args, **call.kw)
>   File "test_looping.py", line 30, in __call__
>     del self.connector
>exceptions.AttributeError: Break instance has no attribute 'connector'


This is not logged by your code.  Do you recognize that?
>
>called  4
>called  5
>/twisted/internet/defer.py:262: DeprecationWarning: Don't pass strings
>(like 'Break!') to failure.Failure (replacing with a DefaultException).
>   fail = failure.Failure(fail)
>2010-09-30 15:07:05,167 ERROR   : log         (22194|7f41910b26e0):
>Unhandled scheduled exception
>Traceback (most recent call last):
>Failure: twisted.python.failure.DefaultException: Break!

This comes from some code not included in the code you posted.  It looks 
like you're using Failure wrong though.  Quoting from above:

    Don't pass strings (like 'Break!') to failure.Failure.
>
>So, how come my log.err doesn't get used for the AttributeError on
>connector?

I'm sure it doesn't help for me to simply repeat myself, since if it 
didn't make sense the first time probably won't make sense the third or 
fourth time.  I don't know what else to say though.

log.err is an errback on the Deferred you created in loop.

An errback is called (roughly) when a Deferred fires with a Failure.

Your Deferred *never* fires with a Failure corresponding to that 
AttributeError.  This is the most important thing.  If you don't 
understand this, say so and we can talk about it some more.  Everything 
else is just confusing particulars.

Unfortunately maybeDeferred cannot help here.  It solves a slightly 
related problem and does nothing about this one.  You may well want to 
use it, but it's not going to address your `AttributeError` issue in any 
way, because of what I said above, and will repeat here for emphasis:

The AttributeError never becomes an error result on any Deferred.  It is 
caught inside the reactor implementation, logged there by Twisted 
itself, and then thrown away forever.

Jean-Paul



More information about the Twisted-Python mailing list