[Twisted-Python] Flow: better synchronous exceptions [patch]
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 try: result = d.next() except ParticularError, e: traceback.print_exc() 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/
Thank you for applying this patch, it is a big improvement. Also, to summarize our IRC chat: 1. You think it is about time to move flow into twisted and Glyph/Itamar support this move; great. 2. You like the idea of adding it as a top level, twisted.flow.* module; this means breaking flow.py into several chunks. 3. For the public stages and controllers, flow.py could be broken down into the facility that they use: twisted.flow.thread, twisted.flow.defer 4. The core of flow, 'wrap' function and its private stages, could be put into flow/flow.py; it is a bit redundant, but we could not think of another option. 5. We didn't discuss where the abstract interfaces, "Stage", and "Callback" should go. Perhaps flow.interface? 6. We didn't discuss other public stages that are not directly associated with a facility, such as Zip. Perhaps these could be put into flow.misc or flow.tools? 7. Most importantly (for me), due to the redundancy of flow/flow.py I'd like to ask glyph if a limited form of __init__.py import could be used in the case of a module/module.py mechansim so that the public objects in module.py could be imported into the module itself. ie, in flow/__init__.py having: "from flow import wrap, Cooperate" Thank you so much. Clark On Mon, Jun 23, 2003 at 10:46:21PM -0400, Christopher Armstrong wrote: | 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 | try: | result = d.next() | except ParticularError, e: | traceback.print_exc()
On Tue, Jun 24, 2003 at 05:42:39AM +0000, Clark C. Evans wrote:
7. Most importantly (for me), due to the redundancy of flow/flow.py I'd like to ask glyph if a limited form of __init__.py import could be used in the case of a module/module.py mechansim so that the public objects in module.py could be imported into the module itself. ie, in flow/__init__.py having:
"from flow import wrap, Cooperate"
I think I mentioned this on IRC, but: aarragghgah no! That path leads to Zope 2. It's painful. I'd far prefer to have to type: from twisted.flow import flow # or from twisted.flow.flow import wrap, Cooperate in my code than deal with magical __init__.py in packages. I recognise the desire to make using the package more convenient, but I think the trade-off isn't worth it. The rest of Twisted manages very nicely without this, and it would be nice if we could keep it like that. No exceptions, please. -Andrew.
On Tuesday, June 24, 2003, at 12:42 AM, Clark C. Evans wrote:
7. Most importantly (for me), due to the redundancy of flow/flow.py I'd like to ask glyph if a limited form of __init__.py import could be used in the case of a module/module.py mechansim so that the public objects in module.py could be imported into the module itself. ie, in flow/__init__.py having:
This is a general problem that needs to be solved within Twisted. Packages should be able to specify public interfaces which you can import directly, such as from twisted.internet import Application from twisted.web import Resource from twisted.cred import IRealm These interfaces are generally much smaller than the total of the classes in all the modules, and specifying things this way would make documentation simpler and allow us to change implementations and provide backwards compatibility in a much nicer way. The problem is that the Python import system does not give us the right kind of hooks to provide this without importing things in advance or giving a performance hit to objects imported this way (making them getattr wrappers), as far as I can tell; while you can patch __import__, you can't catch the *first* import mid-way, so if someone starts a program with from twisted.internet import Application you could not patch __import__ in twisted/__init__.py because it is not called recursively. I am not opposed to evil in order to make this work, but I am very opposed to _fragile_ evil; something as basic as the import system should not be prone to surprising behavior and subtle misconfiguration. So, I am opposed to flow implementing its own ad-hoc name promotion until we can come up with a standardizeable way to promote names to the package level, but I would very much like to figure out how to promote names in a generic way.
participants (4)
-
Andrew Bennetts
-
Christopher Armstrong
-
Clark C. Evans
-
Glyph Lefkowitz