The special method __exit__
should only raise an
exception when it fails. It should never raise the provided exception, it is the caller’s responsibility.
Raising this exception will make the stack trace difficult to understand.
The __exit__
method can filter passed-in exceptions by simply returning True or False.
This rule raises an issue when:
- an
__exit__
method has a bare raise
outside of an except
block.
- an
__exit__
method raises the exception provided as parameter.
Noncompliant Code Example
class MyContextManager:
def __enter__(self):
return self
def __exit__(self, *args):
raise # Noncompliant
raise args[2] # Noncompliant
class MyContextManager:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
raise exc_value # Noncompliant
Compliant Solution
class MyContextManager:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
# by default the function will return None, which is always False, and the exc_value will naturally raise.
pass
class MyContextManager:
def __enter__(self, stop_exceptions):
return self
def __exit__(self, *args):
try:
print("42")
except:
print("exception")
raise # No issue when raising another exception. The __exit__ method can fail and raise an exception
raise MemoryError("No more memory") # This is ok too.
See