[Twisted-Python] If the errbacks of a canceled Deferred are called with error other than CancelledError, is this acceptable?

Terry Jones terry at jon.es
Thu Jun 20 16:26:37 MDT 2013


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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20130620/2e62c911/attachment-0002.html>


More information about the Twisted-Python mailing list