[Twisted-Python] Tracebacks being dropped from exceptions when using inlineCallbacks

Terry Jones terry at jon.es
Sat Jan 17 12:11:09 EST 2009


Hi Glyph

>>>>> "glyph" == glyph  <glyph at divmod.com> writes:
glyph> It sounds like the real issue here is that we don't have a channel
glyph> to communicate a "cleaned traceback" (i.e., failure with stringified
glyph> frames, but no traceback) from one bit of code to another?

Yes, now that I better understand what's going on with cleaning failures, I
think that's completely accurate.

glyph> 1. More of this discussion should be on a ticket.  The mailing list
glyph> is good for getting discussions started and figuring out what needs
glyph> to be done, but now we're talking about the technical specifics of
glyph> resolving a specific problem.  Someone (terry?) should take the
glyph> specifics in the email that started this thread and file an
glyph> appropriate ticket.

OK, I will do that, because I do still think there is a problem. Code below.

glyph> 2. When filing that ticket, I'd really like a full working example
glyph> of inlineCallbacks not showing a traceback to play with, not just
glyph> examples of portions of the problem.  The obvious example I tried,

glyph> from twisted.internet.defer import inlineCallbacks

glyph> def buggy2():
glyph>     raise RuntimeError("Whoops!")

glyph> @inlineCallbacks
glyph> def buggy():
glyph>     yield buggy2()

glyph> buggy()

glyph> actually prints a nice descriptive traceback.

That's because buggy2 is raising an exception, there's no failure coming
back via a deferred into buggy (where its traceback would ultimately be
replaced with None in cleanFailure).

Here's a example:

    from twisted.internet import reactor, defer

    def ok(r): print 'OK', r
    def nok(r): print 'FAILED', r

    def two():
        try:
            1 / 0
        except Exception:
            return defer.fail()

    @defer.inlineCallbacks
    def one():
        yield two()

    def zero():
        one().addCallbacks(ok, nok).addBoth(lambda _: reactor.stop())

    reactor.callLater(0, zero)
    reactor.run()


Because two returns a deferred whose errback has been called, one gets a
result that's a failure and that failure gets cleaned.  The output of
running this example is:

    FAILED [Failure instance: Traceback: <type 'exceptions.ZeroDivisionError'>: integer division or modulo by zero
    /usr/lib/python2.5/site-packages/twisted/internet/posixbase.py:228:mainLoop
    /usr/lib/python2.5/site-packages/twisted/internet/base.py:561:runUntilCurrent
    five.py:17:zero
    /usr/lib/python2.5/site-packages/twisted/internet/defer.py:813:unwindGenerator
    --- <exception caught here> ---
    /usr/lib/python2.5/site-packages/twisted/internet/defer.py:724:_inlineCallbacks
    five.py:14:one
    ]

Showing the exception caught on line 14 (in one) not line 8. If you look at
the deferred that comes back from calling two, its failure result has None
as its tb attribute (via the process described in my original mail).


However if we replace one with a version that doesn't use inlineCallbacks:

    def one():
        return two()

Then the failure has the original traceback:

    FAILED [Failure instance: Traceback: <type 'exceptions.ZeroDivisionError'>: integer division or modulo by zero
    /usr/lib/python2.5/site-packages/twisted/internet/posixbase.py:228:mainLoop
    /usr/lib/python2.5/site-packages/twisted/internet/base.py:561:runUntilCurrent
    five.py:17:zero
    five.py:14:one
    --- <exception caught here> ---
    five.py:8:two
    ]


I'll file a ticket and we can take discussion about what to do into the
tracker.

Thanks!

Terry




More information about the Twisted-Python mailing list