[Twisted-Python] Giving inlineCallbacks-wrapped functions access to the deferred their wrapper will return

Terry Jones terry at jon.es
Sat Apr 11 18:55:27 EDT 2009


This will probably fall into the too-weird or too-infrequent to be worth
implementing category, but I think it's worth mentioning. (BTW, none of the
following code has been run.)

When you write a normal function that returns a deferred, it (of course)
has access to the deferred it's going to return:

    def func():
        d = defer.Deferred()
        d.addCallback(...).addErrback(...)
        callSomethingElse(d)
        return d

Apart from operating on the deferred itself, func can pass the deferred to
some other function that might add more callbacks (as in the call to
callSomethingElse). That's all very nice and convenient.

But if I write this:

    @defer.inlineCallbacks
    def func():
        # do some stuff to calculate a result.
        defer.returnValue(result)

func never has its hands on the deferred that will be returned (by
_inlineCallbacks) to the caller of its wrapper.

I can get around this in ways that are less elegant:

    @defer.inlineCallbacks
    def func():
        # do some stuff
        d = defer.Deferred()
        callSomethingElse(d)
        d.callback(result)
        newResult = yield d
        defer.returnValue(newResult)

But I don't really like doing it that way: it's a slightly different coding
style, it's much more manual, the above is just one simple example - actual
usage could be more involved, and it doesn't feel as natural as the kind of
code I can write when I'm not using inlineCallbacks.

A way around this (which maybe will generate howls of protest) would be to
have _inlineCallbacks do something this:

    def unwindGenerator(*args, **kwargs):
        assert '_inlineCallbacksDeferred' not in kwargs
        d = Deferred()
        return _inlineCallbacks(None, f(*args, **kwargs, _inlineCallbacksDeferred=d), d)
    return mergeFunctionMetadata(f, unwindGenerator)

While I don't like this implementation much, it does manage to simply put
the deferred that _inlineCallbacks will eventually return, into the hands
of f (i.e., func above).  func can then pass the deferred around, add
callbacks to it etc. exactly as a normal (non-inlineCallbacks) function would.

Maybe there's a cleaner way to implement this?

I ran into this asymmetry today, when I wanted a function to pass its
deferred off to another function but realized that because mine was an
inlineCallbacks-decorated function I couldn't do it in the same way I would
otherwise.

Comments?

Terry




More information about the Twisted-Python mailing list