[Python-Dev] PEP 343: A messy contextmanager corner case
Phillip J. Eby
pje at telecommunity.com
Fri Mar 24 22:48:17 CET 2006
I was just updating an experimental context library for the latest PEP 343
protocol, and I ran into a rather messy situation with the recently added
error-suppression feature, when used in combination with @contextmanager,
that caused some of my tests to fail.
Basically, the problem is this. The way contextmanager is implemented in
the PEP, __exit__ will always either throw an exception or return True in
the exception case. It will never return a false value to reraise the
The problem with this is that it requires chained __exit__ handlers to trap
errors in any other __exit__ methods they call, unless contextmanager can
somehow detect that the reraised exception is the same one, and suppress it.
This case doesn't affect nominal use of a single contextmanager in a 'with'
statement. It only affects contexts that need to call other contexts'
But it seems to me that it might be a good idea to make
GeneratorContextManager.__exit__() simply return False if the generator
reraises an exception. That way, an __exit__() that raises an error can
always be considered broken, which simplifies context chaining quite a bit.
This would basically consist of adding another "except:" clause to the
__exit__() method, to check if the raised value is the same value as the
one that was passed in to throw(). The test_contextlib tests all pass with
this change, but of course I would add a test to ensure that __exit__()
returns False if the same value is reraised.
I would also update the PEP to reflect the updated implementation, and to
explain that __exit__() methods should not propagate exceptions unless they
are unable to fulfill their contract.
More information about the Python-Dev