[Twisted-Python] deferredGenerator or inlineCallbacks

Justin Warren daedalus at eigenmagic.com
Tue Jan 15 02:18:59 MST 2008


On Tue, 2008-01-15 at 07:34 +0100, Vincent Bernat wrote:
> OoO En ce  milieu de nuit étoilée du mardi 15  janvier 2008, vers 03:53,
> 
> Can we use exceptions?

Yes, it appears so.

You do something like this:

@defer.inlineCallbacks
def my_inline_function():
    try:

        # call a function that returns a Deferred, but that might
        # raise an Exception somewhere, which will trigger the
        # .errback() of the deferred that gets returned
        value = yield function_to_get_value_that_raises_exception()

    except Exception, e:    # poor form, but useful for an example
        print "Caught an exception:", e

The Exception that gets caught will be whatever Exception was wrapped up
in the Failure that gets passed to the .errback(). Some neat magic is
happening under the covers to unwrap the Exception from the Failure, so
you can use normal logic like this.

Beware in your own code: make sure that you don't just raise an
Exception where you should be calling an .errback(), or you'll see
'Unhandled error in Deferred' messages.

Executable demo code follows.

As an aside, thanks to the Twisted Matrix folks for this sweet
enhancement to twisted. Glyph gets the main blame, because he's listed
as the maintainer in twisted.internet.defer. Kudos!

#
# inlineDeferred try/except demo
#
def later_processing(d):
    # This must be an .errback(), not just a bare 'raise'
    # or I'm actually raising the error outside of the
    # Deferred chain.
    if True:  # simulate a test for an error condition
        # simulate triggering an errback on error
        d.errback( ValueError("My error!") )
    else:
        # Simulating normal behaviour
        d.callback("success!")

def deferred_fetch_value():
    """
    Simulate waiting for a deferred thing to fetch a value
    """
    d = defer.Deferred()
    reactor.callLater(1, later_processing, d)
    return d

@defer.inlineCallbacks
def get_value():
    """
    Sample function to get a value, which will asyncronously block
waiting
    for a deferred.
    """
    try:
        value = yield deferred_fetch_value()
        defer.returnValue( value )
    except ValueError, e:
        print "caught exception:", e
        #defer.returnValue( None )
        pass

@defer.inlineCallbacks
def get_value2():
    """
    Sample function to get a value, which will asyncronously block
waiting
    for a deferred.
    """
    value = yield deferred_fetch_value()
    defer.returnValue( value )

def my_error(failure):
    print "an error occurred: %s", failure
    reactor.stop()

def mystop(ignored):
    reactor.stop()

@defer.inlineCallbacks
def call_get_value():
    print "fetching value..."
    value = yield get_value()
    print "got value:", value

def go():
    d = call_get_value()
    d.addCallback(mystop)
    d.addErrback(my_error)

reactor.callLater(0, go)
reactor.run()

-- 
Justin Warren <daedalus at eigenmagic.com>




More information about the Twisted-Python mailing list