Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The correct way to handle Exceptions in a Python2.7 context manager class

I have several context managers for a project I'm working on. It is about to ship and I've run into something I'm starting to panic about.

I was under the impression that you should not reraise the exceptions passed as arguments to the __exit__ method of the context manager class. However, I was preforming some testing and it seemed like a context manager was suppressing an exception that was being thrown inside it. When I changed my __exit__ methods to look like this:

def __exit__(self, type_, value, trace):
    if trace is not None:
        print('ERROR IN TRACEBACK: ' + str(value))
        # PYTHON 2.7 RAISE SYNTAX:
        raise type_, value, trace

the errors seemed to pass through correctly.

My question is: What is the correct way to deal with exceptions in the __exit__ method if type_, value, and trace are not None? Is it bad to raise (reraise?) the exception like this? Is this how I'm supposed to do it?

The error I encountered might have been caused by something else. Normally I would go through and test this all thoroughly, but my time seems to be very limited at the moment. I'm hoping somebody can explain the proper implementation of this function and

Ultimately: Can I safely leave the raise type_, value, trace in my context manager __exit__ methods?

like image 378
Erotemic Avatar asked Mar 19 '23 02:03

Erotemic


1 Answers

The __exit__ method's return value should indicate whether or any exception that was passed to it should be re-raised (per the docs):

contextmanager.__exit__(exc_type, exc_val, exc_tb)

Exit the runtime context and return a Boolean flag indicating if any exception that occurred should be suppressed. If an exception occurred while executing the body of the with statement, the arguments contain the exception type, value and traceback information. Otherwise, all three arguments are None.

So as long as your __exit__ method is returning something False-y, the exception should get re-raised without you explicitly doing anything.

Furthermore, the docs explicilty state not to re-raise the exception yourself:

The exception passed in should never be reraised explicitly - instead, this method should return a false value to indicate that the method completed successfully and does not want to suppress the raised exception. This allows context management code (such as contextlib.nested) to easily detect whether or not an __exit__() method has actually failed.

like image 97
dano Avatar answered Apr 26 '23 12:04

dano