muffel
muffel

Reputation: 7360

Detect whether an Exceptions was already handled in nested with statements in Python 2.7

Consider the following piece of code:

class Test(object):
    def __enter__(self):
        pass
    def __exit__(self,type,value,trace):
        if type:
            print "Error occured: " + str(value.args)
            #if I changed the next line to 'return True', the
            #'print "should not happen"' statements are executed, but the
            #error information would be only printed once (what I want)
            return False
        return True

with Test():
    with Test():
        with Test():
            raise Exception('Foo','Bar')
        print "should not happen"
    print "should not happen"

Output of example:

Error occured: ('Foo', 'Bar')

Error occured: ('Foo', 'Bar')

Error occured: ('Foo', 'Bar')

I have several nested with Statements, and want to handle the case where an Exception is raised somewhere in the code. What I want to achieve is that the execution is stopped (no "should not happen" output in the example above), but the error information is only printed once. I therefore need to somehow know whether the same error was already handled.

Do you have any idea how this could be achieved?

Upvotes: 1

Views: 53

Answers (2)

Daniel
Daniel

Reputation: 42748

You can add a error_handled attribute to the exception and test for it:

class Test(object):
    def __enter__(self):
        pass
    def __exit__(self,type,value,trace):
        if type:
            if not getattr(value,'error_handled', False):
                value.error_handled = True
                print "Error occured: " + str(value.args)

with Test():
    with Test():
        with Test():
            raise Exception('Foo','Bar')
        print "should not happen"
    print "should not happen"

Upvotes: 1

mgilson
mgilson

Reputation: 309891

You can't really do this cleanly -- Either the context manager swallows the exception or it doesn't.

If you're OK with the exception propagating out of the manager (which you should be if you're handling arbitrary exceptions here), you can monkey-patch the exception instance:

def __exit__(self, type, value, trace):
    if type:
        if not getattr(value, '_printed_it_already', False):
           print "error occured: " + str(value.args)
           value._printed_it_already = True
           return False
    return True

Note that this sort of monkey-patching is frowned upon in Python ... I think it's worth asking what you're actually trying to do. Usually when an unhandled exception prints it's stack-trace, you get a pretty good idea what the exception's args were to begin with...

Upvotes: 4

Related Questions