If any exception is raised during the body of a with statement, the __exit__ method is immediately called with that exception as an argument. It is up to __exit__ to then decide whether the exception has been properly handled (by returning a truthy value) or whether it should be re-raised after __exit__ completes (by returning a non-truthy value).
SessionTransaction.__exit__ only returns None, which indicates that any exception that may have been raised in the body of the with statement will be raised again.
Note that since the "default" return value of any function is None,
the default behavior of __exit__ is to propagate any exceptions. No user-level code is expected to call __exit__ explicitly or look at its return value, so you really have to do out of your way to return a truthy value and suppress an expression.
Also note the description of the with statement's semantics:
The following code:
with EXPRESSION as TARGET:
SUITE
is semantically equivalent to:
manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False
try:
TARGET = value
SUITE
except:
hit_except = True
if not exit(manager, *sys.exc_info()):
raise
finally:
if not hit_except:
exit(manager, None, None, None)
The __exit__ method is called under one of two mutually exclusive conditions:
- An exception was raised, in which case it was called in the
except clause. If it returns false, the caught exception is re-raised.
- An exception was not raised, in which case it is called in the
finally block. hit_except is ensures that exit is not called twice
if exit itself raises an exception in the except block.
sessionhas anexceptclause to determine whether it should commit or rollback. You're depending on it to re-raise the exception. Or maybe not, now that I think about it a bit more I'm not sure how the mechanics of that would work.finally:for the cleanup actions, notexcept:__exit__function never raises in the Mock.