-
-
Notifications
You must be signed in to change notification settings - Fork 29.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exception context is not suppressed correctly in contextlib.ExitStack.__exit__ #59174
Comments
When adding the test case for bpo-14963, I discovered that contextlib.ExitStack can't *quite* reproduce the exception handling of nested with statements. The problem arises when the original exception gets suppressed by one of the handlers, but an outer handler raises a *new* exception, then nested with statements will correctly indicate that there was no exception context active when the new exception was raised (since the inner with statement will fully clear the exception state). By contrast, when using ExitStack, the interpreter will add the original exception from inside the body of the with statement as the context for the *new* exception, even though the inner exception had been suppressed before the outer one was encountered. Restoring sys.exc_clear() *might* allow this discrepancy to be resolved by explicitly clearing the exception state when one of the callbacks indicates that the current exception has been handled (although it might be trickier than that, if the problem is actually due to caching the exception state inside the with cleanup code in the eval loop) |
Another possible solution is to explicitly set an exception's __supress_context__ attribute to False (right now impossible because it's the default value). Feels a bit like solving our hack with another hack (: And about the PSF contrib agreement, I'll do it as soon as I'm near a printer. too bad we're using pens and not RSA private keys for signatures (-: thanks, Alon |
Electronic contributor forms are actually on the PSF wishlist. We'll get there some day (maybe after the website update). Getting back to the problem at hand, I think you might be on to something with the idea of exploiting PEP-409 to handle this. Specifically, where we reraise a caught exception when there are no exception details active, we should be able to replace the bare raise with something like: # A containing with statement will automatically add the exception
# context back in after it gets suppressed. Avoid displaying it.
if suppressed_exc and exc_details == (None, None, None):
raise exc from None
raise That way, the exception *display* of escaping exceptions will still match that of nested with statements, even though the attributes are subtly different (suppress_context being set to True, rather than __context__ being None) |
Ok, so turns out this was just a stupid bug: we set the __context__ attr only if an exception is raised, but not when an exception has been previously 'cleared'. so the context is filled (by python) with the last exception raised which is the outer one. This is how I understood it: |
Ah, you're absolutely right. Interestingly though, the old recursive implementation appeared to have the same bug, and I'd deliberately used the recursive approach precisely so that suppressed exceptions *would* get cleared correctly. I must have managed to leave a loophole somewhere :( I also realised simply overwriting the context isn't correct in all cases, and have adjusted the test cases accordingly. |
New changeset c108bc96aec6 by Nick Coghlan in branch 'default': |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: