By the way, I don't need any of this to make its way into Twisted. I can
still write my own class that does what I want (well, wanted). Below is a
2013 version of the CancelableDeferred. It's untested. The basic idea is
that if you get a regular deferred from somewhere, you can use the class
below to make a new deferred that you can callback, errback, or cancel at
will. You can give a value to 'cancel' and it will be in args[0] of the
CancelledError that your errback will receive.
I still find this approach attractive because it maintains the
power/elegance of coding with Twisted deferreds but also gives the caller
of deferred-producing code more flexibility. That's got to be a good thing,
right?
I hope the code makes the intention more clear, not less.
Terry
from twisted.internet.defer import CancelledError, Deferred
from twisted.python.failure import Failure
class ControllableDeferred2013(object):
'''A Deferred-like class that takes a regular Twisted Deferred and
provides a deferred that can be fired at will. If you have a regular
Twisted Deferred, you can produce a deferred you have more control over
by using your Deferred instance to make an instance of this class.
Any time you need to fire a ControllableDeferred2013 instance for any
reason, call its callback, errback or cancel method. It will fire
immediately with the value you provide and the original Deferred will
be cancelled.'''
def __init__(self, originalDeferred):
self._fired = False
self._originalDeferred = originalDeferred
self._newDeferred = Deferred()
for method in ('addBoth', 'addCallback', 'addCallbacks',
'addErrback',
'chainDeferred'):
setattr(self, method, getattr(self._newDeferred, method))
originalDeferred.addBoth(self._originalFired)
def _originalFired(self, result):
if not self._fired:
self._fired = True
self._originalDeferred.chainDeferred(self._newDeferred)
def cancel(self, value=None):
if not self._fired:
self._fired = True
self._newDeferred.errback(Failure(CancelledError(value)))
self._originalDeferred.cancel()
def callback(self, result=None):
if not self._fired:
self._fired = True
self._newDeferred.callback(result)
self._originalDeferred.cancel()
def errback(self, fail=None):
if not self._fired:
self._fired = True
self._newDeferred.errback(fail)
self._originalDeferred.cancel()
def pause(self):
self._newDeferred.pause()
self._originalDeferred.pause()
def unpause(self):
self._newDeferred.unpause()
self._originalDeferred.unpause()
# BTW, I posted the above code to
http://blogs.fluidinfo.com/terry/2013/06/20/yet-another-cancelable-twisted-deferred-class/as
well.
_______________________________________________
Twisted-Python mailing list
[email protected]
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python