[Twisted-Python] inlineCallbacksDecorator

Drew Smathers drew.smathers at gmail.com
Mon Jun 8 14:31:16 EDT 2009

On Sat, Jun 6, 2009 at 9:41 PM, Terry Jones<terry at jon.es> wrote:
> I try to avoid using inlineCallbacks. There are two cases where I will
> happily use it though: when I write a method that would need more than a
> few callback functions, and, more importantly, when the logical flow of a
> method is non-trivial (i.e., it depends on the returned values or errors of
> several deferreds).
> One inconvenience with inlineCallbacks is that you might have some kind of
> processing you want done no matter how the function returns, or wherever an
> error occurs. Two solutions here are 1) to put try/except calls around your
> various yields, and/or to perhaps do something else with various callbacks
> that might call defer.returnValue, or 2) expect each caller of your method
> to deal with the result. I don't like the first of those much (depending on
> the code), and don't like the second at all.

How does inlineCallbacks preclude you from adding "processing you want
done no matter how the function returns" or currying callbacks?  From
my understanding of the problem, this is already solved by attaching
callbacks/errbacks in the regular way:

def foo(a, b, c):
foo(a, b, c).addBoth(cb, a, b, c)

> So I wrote a decorator specifically for inlineCallbacks decorated functions:
>    from twisted.internet import defer
>    def inlineCallbacksDecorator(callback, errback=defer.passthru):
>        def wrap(f):
>            def wrapper(*args, **kw):
>                d = f(*args, **kw)
>                if isinstance(d, defer.Deferred):
>                    return d.addCallbacks(callback, errback,
>                                          callbackArgs=args, callbackKeywords=kw,
>                                          errbackArgs=args, errbackKeywords=kw)
>                # We were used to decorate a non-inlineCallbacks function.
>                raise Exception(
>                    'Function %r was decorated with inlineCallbacksDecorator but '
>                    'did not return a deferred (did you forget to also decorate '
>                    'with inlineCallbacks?)' % f.__name__)
>            return mergeFunctionMetadata(f, wrapper)
>        return wrap
> You can use it like this:
>    def _cbok(result, a, b=None):
>        print 'In _cbok: a=%r b=%r' % (a, b)
>        return result
>    def _cberr(failure, *args, **kw):
>        pass
>        # Do something....  and maybe also return the failure.
>    @inlineCallbacksDecorator(_cbok, _cberr)
>    @defer.inlineCallbacks
>    def frog(a, b=None):
>        print 'a = %r, b = %r' % (a, b)
>        result = yield produceDeferred()
>        # yield produceErr()
>        defer.returnValue(a)
> The nice/interesting thing about this is that the callback and errback
> functions get called with the deferred result of calling frog (as decorated
> by inlineCallbacks) *and* the original arguments passed to frog.  You can
> of course ignore the original args if you're not interested in them.
> You can argue that this doesn't really buy you anything. That's of course
> true.  It's only a decorator that makes it neater to do certain things.
> Logging, accounting and error processing come immediately to mind. Just
> keeping code looking simpler/cleaner is enough of a reason for me.
> After writing this, I realized it deals with what I was clumsily trying to
> achieve here
> http://twistedmatrix.com/pipermail/twisted-python/2009-April/019492.html
> back in April.
> Terry
> _______________________________________________
> Twisted-Python mailing list
> Twisted-Python at twistedmatrix.com
> http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

More information about the Twisted-Python mailing list