开发者

Fatal Errors and Deferreds in Twisted, stop a deferred

I have a problem, with normal try except blocks in python you can just return if there is a fatal error, ex...

try:
    logon()
except 404_Error:
    retry_logon(try = 2)

except AuthenticationProblem:
    error_label.SetText( "You password or username was wrong. Make sure that CAPS LOCK key is not on." )
    return#nothing more we can do here
else:
    #display user information or whatever

So how do this with deferreds, if I just return it goes onto execute the callbacks thinking the error is handled but how do I inform the user something went wrong and destroy the down river chain.

==== Update ===

mg thanks for the help but it didn't work, even with a fatal error the defer still returns to the callbacks afterwords

from twisted.internet import reactor
from twisted.internet.defer import Deferred as D

class NonFatalError(Exception):
    'non fatal error'
class FatalError(Exception):
    'fatal error'
def c(s):
    print "Callback called"
    print "Data Received: %s" % s
def e(f):
    print "Errorback Called"
    print "Error Type: %s" % type(f)
    print "Traceback"
    f.printTraceback()
    print "======================================="
    f.trap(NonFatalError)
    return "Error Handled"
def e_fatal(f, d):
    print "Errorback Called"
    print "Error Type: %s" % type(f)
    print "Traceback"
    f.printTraceback()
    print "============开发者_开发百科==========================="
    print "Fatal Error"
    f.trap(FatalError)
    return "Fatal Error... Crash and die. No more callbacks should be called."

def trigger():
    d.errback(FatalError("This error is fatal to the defer"))

if __name__ == "__main__":
    d = D()
    d.addErrback(e)
    d.addErrback(e_fatal, d)
    d.addCallback(c)
    d.addCallback(c)
    d.addCallback(c)
    d.addCallback(c)
    reactor.callLater(3, trigger)
    reactor.callLater(10, reactor.stop)
    reactor.run()

    raw_input("Done.")


Ok, a whole new answer to explain better how deferreds work. You should think, at least I do, the flow of the program as a state machine. A success or a failure is like an input of that machine that, potentially, change the state. In your case you have two states, logged and non logged, and three inputs: successfully logged in, wrong authentication and could not logged for server problems. Only one of this inputs is recoverable, the case the server could not login the user for same strange problem and in this case you can recover the problem retrying the login. Here the new code:

import sys
from twisted.internet import reactor, defer


class FourOhFourError(Exception):
    pass


class AuthenticationError(Exception):
    pass


def logon(retry=3, success=2, wrong_auth=0):
    # do stuff
    d = defer.Deferred()
    # not_found is the only error recoverable
    d.addErrback(not_found, retry, success)
    if wrong_auth:
        reactor.callLater(0, d.errback, AuthenticationError("wrong auth"))
    else:
        if success == 0:
            reactor.callLater(0, d.callback, "Mario")
        else:
            reactor.callLater(0, d.errback, FourOhFourError("Not found"))
    return d


def not_found(failure, retry, success):
    failure.trap(FourOhFourError) # this is superfluous here
    print failure.getErrorMessage()
    if retry == 0:
        raise AuthenticationError("Max retries")
    # do stuff
    print "retring..."
    d = defer.Deferred()
    d.addCallback(logon, success-1)
    reactor.callLater(1, d.callback, retry-1) # not really clean here
    return d


def wrong_auth(failure):
    failure.trap(AuthenticationError) # this is superfluous here
    # do stuff
    print "something goes wrong"
    print failure.getErrorMessage()


def loggedIn(user):
    print "hello %s" % user


def stop(_):
    reactor.stop()


d = logon(*map(int, sys.argv[1:]))
d.addCallbacks(loggedIn, wrong_auth)
d.addBoth(stop)
reactor.run()

Invoke the code with three parameters: the maximum number of retries, at which retry the system should login the user and the third is a boolean indicating the correctness of the user credentials. Try the following invocations: 0 0 1, 3 2 0, 3 4 0.

I hope this example is more explicative.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜