[Twisted-Python] Global reactor unit tests in the Twisted test suite
glyph at twistedmatrix.com
Tue Nov 1 23:18:12 EDT 2011
On Nov 1, 2011, at 10:20 PM, Tim Allen wrote:
> On Tue, Nov 01, 2011 at 02:48:02PM -0400, Glyph wrote:
>> If you can think of a better solution that addresses all of these
>> concerns simultaneously somehow, please share, I'd love to hear it
> I'm not sure if it addresses all your concerns, but
> twisted.python.context will let you set a particular value for things
> you call and all their descendants (unless one of them sets a new value
> in the context). I can imagine interleaving code that passes a reactor
> parameter explicitly and code that grabs a reactor from the current
> context without much hassle.
I invented twisted.python.context for this very reason!
But... I find the idea of encouraging its widespread use disconcerting.
There are a couple of issues (and if you search the web for "emacs lisp dynamic scope" you will find a whole bunch of them) but the main problem is this:
When you do context.get(something) and something isn't there... what do you do? Whose fault is it?
As a parallel example, when a function gets called with the wrong argument, it's quite easy to figure out where the problem is: you just look at the caller, and the caller almost certainly knows who they are. The caller somehow has to know about the signature of the callee and if they get it wrong it's an immediate and obvious runtime error.
But when code has a relationship to its caller's caller's caller's caller's caller, and there may be any amount of indirection in there (callbacks registered on Deferreds, for example) how do you find the place that really should have been the one to pass the result? How do you know at the time you invoke something, all the context that it may require?
The immediate place I can think of where this would cause issues is with GUI callbacks. Right now Twisted goes out of its way to make sure that you can '.connect("clicked", ...)' on a GTK widget and use any old python callback you want. If we made the reactor context-driven, then that would work... mostly. If Twisted's callbacks were run with the reactor present, then the GUI's callbacks might not have the reactor available to them because they lack some setup.
Of course you can probably fix that problem, but there are other places where it will crop up again; the standard idiom is to call a bunch of functions to set up event handlers, then call reactor.run(). But what if the reactor isn't available to those functions before it's run?
Et cetera, et cetera.
If you can think of a solid, robust way to specify contracts that describe what context is expected, by whom, and how it can be filled at the right time without surprising consequences, I'd love to hear it, but I won't hold my breath :).
More information about the Twisted-Python