[Twisted-Python] Flow: better synchronous exceptions [patch]

Christopher Armstrong radix at twistedmatrix.com
Mon Jun 23 22:46:21 EDT 2003

Here's a patch that changes semantics of Stage.next. Currently,
if a Deferred errbacks with an exception that you haven't 
explicitly trapped, Stage.next will raise the Failure object
(via the failure's trap method). I've changed this so it rather
does `raise type(failure.value), failure.value, failure.tb'.

What this means is that you can write code like this:

    d = flow.wrap(getDeferred())
    yield d
        result = d.next()
    except ParticularError, e:

Two benefits here. One, I can actually say 
"except ParticularError" -- before, the type of the exception
raised would be Failure. Two, the traceback printed by 
traceback.print_exc() will actually be useful and show you the
stack trace of the original code that raised the error, rather
than the traceback starting from the Failure.trap call. 

Of course, the traceback is cleaned once Deferred.runCallbacks
finishes, but this only matters when the Deferred is resolved
synchronously, as far as I can tell. In that case, you will
get a pretty useless traceback, but it won't  be any more 
useless than the tracebacks that used to be reported.

The only drawback I see is that it breaks a flow test. :-)

  FailTest: exceptions.ZeroDivisionError raised instead of Failure

Because the test is expecting a Failure to be raised, not 
the original, and more useful, exception.

  self.assertRaises(flow.Failure, list, flow.Block(badgen()))

Clark, I'll be waiting for confirmation from you to commit this or
trash it.

 Twisted | Christopher Armstrong: International Man of Twistery
  Radix  |          Release Manager,  Twisted Project
---------+     http://twistedmatrix.com/users/radix.twistd/
-------------- next part --------------
? better-synchronous-exceptions.diff
? flow.xhtml
Index: flow.py
RCS file: /cvs/Twisted/sandbox/flow.py,v
retrieving revision 1.107
diff -u -r1.107 flow.py
--- flow.py	22 Jun 2003 06:45:12 -0000	1.107
+++ flow.py	24 Jun 2003 02:35:46 -0000
@@ -297,9 +297,19 @@
                 return self.results.pop(0)
         if self.stop:
             raise StopIteration()
         if self.failure:
             self.stop = True
-            return self.failure.trap(*self._trap)
+            cr = self.failure.check(*self._trap)
+            if cr:
+                return cr
+            if self.failure.tb:
+                raise self.failure.value.__class__, self.failure.value, self.failure.tb
+            raise self.failure.value
         raise NotReadyError("Must 'yield' this object before calling next()")
     def _yield(self):
@@ -492,11 +502,13 @@
         obj = obj()
     typ = type(obj)
     if typ is type([]) or typ is type(tuple()):
         return _List(obj)
     if typ is type(''):
         return _String(obj)
     if isinstance(obj, defer.Deferred):
         return _Deferred(obj, *trap)

More information about the Twisted-Python mailing list