[Twisted-Python] inlineCallbacks + raise exception behavior is different than deferred.errback

Hello: Please refer to the following script: import sys import twisted.internet.defer import twisted.internet.reactor import twisted.python.log print "Twisted version", twisted.version print "Python version", sys.version class ExceptionToRaise(Exception): pass exception_to_raise = ExceptionToRaise() @twisted.internet.defer.inlineCallbacks def icb_error_maker(): """ Raises an exception implemented as an inline inlineCallbacks """ raise exception_to_raise def pod_error_maker(): """ Raises an exception implemented as a plain old deferred """ deferred = twisted.internet.defer.Deferred() deferred.errback(exception_to_raise) return deferred #ERROR_MAKER_TO_USE = icb_error_maker ERROR_MAKER_TO_USE = pod_error_maker @twisted.internet.defer.inlineCallbacks def intermediate_function3(): print 'intermediate_function3 1' try: yield ERROR_MAKER_TO_USE() except BaseException as exception: print 'intermediate_function3 exception', repr(exception) raise print 'intermediate_function3 2' @twisted.internet.defer.inlineCallbacks def intermediate_function2(): print 'intermediate_function2 1' try: yield intermediate_function3() except BaseException as exception: print 'intermediate_function2 exception', repr(exception) raise print 'intermediate_function2 2' @twisted.internet.defer.inlineCallbacks def intermediate_function1(): print 'intermediate_function1 1' try: yield intermediate_function2() except BaseException as exception: print 'intermediate_function1 exception', repr(exception) raise print 'intermediate_function1 2' def run(): d = intermediate_function1() d.addErrback(twisted.python.log.err) d.addBoth(lambda n: twisted.internet.reactor.stop()) twisted.internet.reactor.callWhenRunning(run) twisted.internet.reactor.run() When ERROR_MAKER_TO_USE = icb_error_maker The output is as follows: Twisted version [twisted, version 13.2.0] Python version 2.7.3 (default, Feb 27 2014, 20:00:17) [GCC 4.6.3] intermediate_function1 1 intermediate_function2 1 intermediate_function3 1 intermediate_function3 exception ExceptionToRaise() intermediate_function2 exception ExceptionToRaise() intermediate_function1 exception ExceptionToRaise() Unhandled Error Traceback (most recent call last): File "/home/daveb/bzr_repo/player_rm2/test2/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1237, in unwindGenerator return _inlineCallbacks(None, gen, Deferred()) File "/home/daveb/bzr_repo/player_rm2/test2/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1099, in _inlineCallbacks result = g.send(result) File "icb_error_test1.py", line 52, in intermediate_function2 yield intermediate_function3() File "/home/daveb/bzr_repo/player_rm2/test2/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1237, in unwindGenerator return _inlineCallbacks(None, gen, Deferred()) --- <exception caught here> --- File "/home/daveb/bzr_repo/player_rm2/test2/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1099, in _inlineCallbacks result = g.send(result) File "icb_error_test1.py", line 37, in intermediate_function3 yield ERROR_MAKER_TO_USE() File "/home/daveb/bzr_repo/player_rm2/test2/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1228, in unwindGenerator gen = f(*args, **kwargs) File "icb_error_test1.py", line 19, in icb_error_maker raise exception_to_raise __main__.ExceptionToRaise: However when ERROR_MAKER_TO_USE = pod_error_maker The output is as follows: Twisted version [twisted, version 13.2.0] Python version 2.7.3 (default, Feb 27 2014, 20:00:17) [GCC 4.6.3] intermediate_function1 1 intermediate_function2 1 intermediate_function3 1 intermediate_function3 exception ExceptionToRaise() intermediate_function2 exception ExceptionToRaise() intermediate_function1 exception ExceptionToRaise() Unhandled Error Traceback (most recent call last): Failure: __main__.ExceptionToRaise: Questions: 1. Why is it that icb_error_maker raises an exception that retains its traceback while pod_error_maker does not? 2. How might one retain the inlineCallback trace when handling Exceptions/Failures from deferreds? (I would prefer a universal method, ie not doing a Try/Reraise at every yield point) ? 3. I have taken a look at the code in twisted/internet/defer.py and I am not sure where the distinction between inlineCallback exceptions and deferred errors are being made. Would someone please elaborate on this process. Thanks

On 04:36 pm, croepha@gmail.com wrote:
Hello:
Hi, I don't know about anyone else but in my email client all of the indentation in this example has been destroyed making it impractical to try to understand the specifics of your question. I can at least say that yes, traceback mangling by inlineCallbacks is a known issue. Jean-Paul

Apologies, here is the example, pasted on pound-python http://paste.pound-python.org/show/t4MsnEHFYAQrJ0pv6gsY/ On Thu, Apr 3, 2014 at 11:54 AM, <exarkun@twistedmatrix.com> wrote:

On 04:36 pm, croepha@gmail.com wrote:
Hello:
Hi, I don't know about anyone else but in my email client all of the indentation in this example has been destroyed making it impractical to try to understand the specifics of your question. I can at least say that yes, traceback mangling by inlineCallbacks is a known issue. Jean-Paul

Apologies, here is the example, pasted on pound-python http://paste.pound-python.org/show/t4MsnEHFYAQrJ0pv6gsY/ On Thu, Apr 3, 2014 at 11:54 AM, <exarkun@twistedmatrix.com> wrote:
participants (2)
-
Croepha
-
exarkun@twistedmatrix.com