<div style="font-family:Calibri,sans-serif">Hi,</div><div style="font-family:Calibri,sans-serif"> </div><div style="font-family:Calibri,sans-serif">I am hitting an issue with inlineCallbacks-decorated functions. It seems that from within an inlineCallbacks-decorated func, if you yield on another deferred-returning func, and that deferred-returning func returns a deferred which will errback with a Failure wrapping a user defined exception type, then the user defined exception gets repackaged as a common Exception by the time you are in the inlineCallbacks-decorated function. It seems to be related to the fact that inside an inlineCallbacks-decorated func, if you yield on a func, and that func returns a deferred which errs back, twisted will convert the errback into a synchronous exception that it raises for you. That’s all a bit wordy, so maybe some code will help clarify:</div>
<div style="font-family:Calibri,sans-serif"> </div><div style="font-family:Calibri,sans-serif">$ cat inlinecallbacks-loses-exception-types.py</div><div style="font-family:Calibri,sans-serif">#!/usr/bin/env python</div><div style="font-family:Calibri,sans-serif">
</div><div style="font-family:Calibri,sans-serif">import sys, traceback</div><div style="font-family:Calibri,sans-serif">from twisted.internet import defer, reactor</div><div style="font-family:Calibri,sans-serif">
</div><div style="font-family:Calibri,sans-serif">class MyException(Exception):</div><div style="font-family:Calibri,sans-serif"> pass</div><div style="font-family:Calibri,sans-serif"> </div><div style="font-family:Calibri,sans-serif">
def go2():</div><div style="font-family:Calibri,sans-serif"> "An ordinary deferred-returning function that will return a deferred which is ready to errback()"</div><div style="font-family:Calibri,sans-serif">
try:</div><div style="font-family:Calibri,sans-serif"> raise MyException('xyz')</div><div style="font-family:Calibri,sans-serif"> except Exception as e:</div><div style="font-family:Calibri,sans-serif">
return defer.fail() # errs back with current exception context</div><div style="font-family:Calibri,sans-serif"> </div><div style="font-family:Calibri,sans-serif"> return defer.succeed(1) # unreachable code</div>
<div style="font-family:Calibri,sans-serif"> </div><div style="font-family:Calibri,sans-serif">@defer.inlineCallbacks</div><div style="font-family:Calibri,sans-serif">def go_inlinecb():</div><div style="font-family:Calibri,sans-serif">
try:</div><div style="font-family:Calibri,sans-serif"> x = yield go2()</div><div style="font-family:Calibri,sans-serif"> print 'no exception raised'</div><div style="font-family:Calibri,sans-serif">
except MyException as e:</div><div style="font-family:Calibri,sans-serif"> print 'got my custom exception'</div><div style="font-family:Calibri,sans-serif"> traceback.print_exc()</div><div style="font-family:Calibri,sans-serif">
except Exception as e:</div><div style="font-family:Calibri,sans-serif"> print 'got a garden variety exception'</div><div style="font-family:Calibri,sans-serif"> traceback.print_exc()</div><div style="font-family:Calibri,sans-serif">
</div><div style="font-family:Calibri,sans-serif">def go_noinlinecb():</div><div style="font-family:Calibri,sans-serif"> d = go2()</div><div style="font-family:Calibri,sans-serif"> def cb(data):</div><div style="font-family:Calibri,sans-serif">
print 'got data in cb: %s' % (data)</div><div style="font-family:Calibri,sans-serif"> def eb(failure):</div><div style="font-family:Calibri,sans-serif"> try:</div><div style="font-family:Calibri,sans-serif">
failure.raiseException()</div><div style="font-family:Calibri,sans-serif"> except MyException as e:</div><div style="font-family:Calibri,sans-serif"> print 'got my custom exception'</div>
<div style="font-family:Calibri,sans-serif"> traceback.print_exc()</div><div style="font-family:Calibri,sans-serif"> except Exception as e:</div><div style="font-family:Calibri,sans-serif"> print 'got a garden variety exception'</div>
<div style="font-family:Calibri,sans-serif"> traceback.print_exc()</div><div style="font-family:Calibri,sans-serif"> d.addCallbacks(cb, eb)</div><div style="font-family:Calibri,sans-serif"> </div><div style="font-family:Calibri,sans-serif">
if sys.argv[1] == 'inline':</div><div style="font-family:Calibri,sans-serif"> reactor.callWhenRunning(go_inlinecb)</div><div style="font-family:Calibri,sans-serif">elif sys.argv[1] == 'noinline':</div><div style="font-family:Calibri,sans-serif">
reactor.callWhenRunning(go_noinlinecb)</div><div style="font-family:Calibri,sans-serif">reactor.callLater(2, reactor.stop)</div><div style="font-family:Calibri,sans-serif">reactor.run()</div><div style="font-family:Calibri,sans-serif">
</div><div style="font-family:Calibri,sans-serif">$ ./inlinecallbacks-loses-exception-types.py inline </div><div style="font-family:Calibri,sans-serif">got a garden variety exception</div><div style="font-family:Calibri,sans-serif">
Traceback (most recent call last):</div><div style="font-family:Calibri,sans-serif"> File "./inlinecallbacks-loses-exception-types.py", line 21, in go_inlinecb</div><div style="font-family:Calibri,sans-serif"> x = yield go2()</div>
<div style="font-family:Calibri,sans-serif">Exception: xyz</div><div style="font-family:Calibri,sans-serif"> </div><div style="font-family:Calibri,sans-serif">$ ./inlinecallbacks-loses-exception-types.py noinline</div><div style="font-family:Calibri,sans-serif">
got my custom exception</div><div style="font-family:Calibri,sans-serif">Traceback (most recent call last):</div><div style="font-family:Calibri,sans-serif"> File "./inlinecallbacks-loses-exception-types.py", line 36, in eb</div>
<div style="font-family:Calibri,sans-serif"> failure.raiseException()</div><div style="font-family:Calibri,sans-serif"> File "/sw/external/twisted-py27-11.0.0/lib/python/twisted/python/failure.py", line 338, in raiseException</div>
<div style="font-family:Calibri,sans-serif"> raise self.type, self.value, self.tb</div><div style="font-family:Calibri,sans-serif">MyException: xyz</div><div style="font-family:Calibri,sans-serif"> </div><div style="font-family:Calibri,sans-serif">
So as you can see, it seems that if you use inlineCallbacks, you cannot ‘except MyException’ and catch your own custom exceptions. Somehow a generic Exception is constructed. Is there any workaround or is this a known issue?</div>
<div><br></div><div>Thanks,<br clear="all"><div><br></div>-- <br>Benjamin Rutt<br>
<br>
</div>