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 Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python