[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 
original exception.

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' 
__exit__ methods.

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.

Any objections?

More information about the Python-Dev mailing list