PEP 343: A messy contextmanager corner case
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?
participants (1)
-
Phillip J. Eby