[Twisted-Python] inlineCallbacksDecorator
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. 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@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
[Twisted-Python] Weekly Bug Summary
Bug summary __ Summary for 2009-05-31 through 2009-06-07 Bugs opened: 10Bugs closed: 2 Total open bugs: 1121 (+8) |== Type Changes |== Priority Changes |== Component Changes |Defect: +4 |Highest: +1 |Conch:+3 |Enhancement: +3 |Normal: +5 |Core: +4 |Regression: +1 |Low: +2 |Mail: -1 |Web2: +1 |Website: +1 Total Tickets Open Tickets New / Reopened Bugs __ = Highest = [#3871] `twistd conch´ always fails due to an unhandled AttributeError; conch server cannot be started. (opened by exarkun) regression conch http://twistedmatrix.com/trac/ticket/3871 = Normal = [#3862] Chapters in the twisted documentation should have one-line summaries that are included in the table of contents (opened by radix) enhancement core http://twistedmatrix.com/trac/ticket/3862 [#3863] twisted.conch.avatar.ConchUser incompletely implements IConchUser (opened by exarkun) defect conch http://twistedmatrix.com/trac/ticket/3863 [#3864] twisted.conch.manhole_ssh.TerminalSessionTransport requires `session` and `write` attributes on an object only documented as being a ProcessProtocol instance (opened by exarkun) defect conch http://twistedmatrix.com/trac/ticket/3864 [#3865] Provide method for debugging twistd plugin scanning (opened by powdahound) enhancement core http://twistedmatrix.com/trac/ticket/3865 [#3868] twisted\python\lockfile.py problem on portable Python install (opened by JamesB) defect core http://twistedmatrix.com/trac/ticket/3868 [#3869] API reference not available for download (opened by JamesB) enhancement websitehttp://twistedmatrix.com/trac/ticket/3869 [#3870] SERVER_SOFTWARE identifier for twisted.web2 is incorrectly formatted (opened by thijs) defect web2 http://twistedmatrix.com/trac/ticket/3870 = Low = [#3866] ClientCreator should not use reactor.callLater to fire its Deferred (opened by exarkun) defect core http://twistedmatrix.com/trac/ticket/3866 [#3867] Document trac-post-commit-hook functionality in svn-dev policy (opened by thijs) enhancement core http://twistedmatrix.com/trac/ticket/3867 Closed Bugs __ = Normal = [#3846] t.mail.test.test_imap.PreauthIMAP4ClientMixin._result conflicts with Python 2.7 unittest (opened by ivank, closed by exarkun, fixed) defect mail http://twistedmatrix.com/trac/ticket/3846 [#3791] DelayedCall should use unsignedID in str method (opened by therve, closed by exarkun, fixed) enhancement core http://twistedmatrix.com/trac/ticket/3791 Ticket Lifetime Stats __ Oldest open ticket - [#50] conch command-line client doesn't work in win32 (since 2003-07-12 16:41:06). Newest open ticket - [#3871] `twistd conch´ always fails due to an unhandled AttributeError; conch server cannot be started. (since 2009-06-06 08:51:05). Mean open ticket age: 792 days, 21:43:50.307043. Median: 764 days, 20:17:55.238355. Standard deviation: 553 days, 10:53:17.283842. Interquartile range: 732 days, 18:46:18. Mean time between ticket creation and ticket resolution: 201 days, 1:10:33.199041. Median: 25 days, 18:17:40. Standard deviation is 342 days, 16:46:19.793774. The interquartile range is 232 days, 5:56:02. Mean time spent in review: 72 days, 19:26:24.407228. Median: 4 days, 0:03:10. Standard deviation: 238 days, 20:07:26.658173. Interquartile range: 16 days, 11:11:56. Mean number of times a ticket is reviewed: 2.02462121212. Median: 1 Standard deviation: 1.6802551688. Interquartile range: 1. Contributor Stats __ In the last 4 weeks, 20 unique ticket reporters 8 unique ticket reviewers 2 unique ticket resolvers In the last 24 weeks, 94 unique ticket reporters 18 unique ticket reviewers 14 unique ticket resolvers In the last 48 weeks, 159 unique ticket reporters 22 unique ticket reviewers 18 unique ticket resolvers ___ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
Re: [Twisted-Python] inlineCallbacksDecorator
On Sunday 07 June 2009, Terry Jones wrote: > 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) As far as I can see, this decorator could be applied to any function that returns a Deferred, not just to inlineCallbacks. Bye, Maarten ___ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python