-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
Handling exceptions within a @contextmanager
function doesn't clear sys.exception()
#111375
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
Comments
CC @ncoghlan |
This is a nice bug - everything is working as designed but the result is indeed unexpected. I don't think it can be fixed in contextlib without changes to the interpreter, and if I'm right it's unlikely that this will use case will justify such changes. Either way, for now at least we should mention this as a quirk of contextlib. @pR0Ps would you like to propose a doc patch? |
I was messing around with this and after I wired up a C API call to Before: Lines 161 to 163 in 230e8e9
After: try:
__clear_current_exc() # defined in C as: { PyErr_SetHandledException(Py_None); return Py_None; }
self.gen.throw(value)
except StopIteration as exc: This essentially amounts to running Python 2's With this change, the result of running the test case from above matches my expected result:
At the moment, my implementation is just a proof of concept that I quickly hacked together, but I'd be willing to clean it up, fix the edge cases, write tests, etc. if this is something that would be considered acceptable to add in some fashion and not too hacky. |
Ah yes, that might work. You'd need to restore the exception after throw() returns. Make sure you have a test for when this whole thing is nested in another except block (and check the value of sys.exception() after the nested one). |
…dicate that an exception was handled (#113302)
… to indicate that an exception was handled (python#113302)
… to indicate that an exception was handled (python#113302)
… to indicate that an exception was handled (python#113302)
… to indicate that an exception was handled (python#113302)
Bug report
Bug description:
The issue
I would expect that handling exceptions within a
contextlib.contextmanager
-created function would work in the same way as other functions and clear thesys.exception()
after an error is handled.The above example prints:
Whereas since the error was handled by the
except:
block, my expectation was:Just working as designed?
From doing some digging, it seems like this is happening because the exception is still being handled by the
_GeneratorContextManager.__exit__
function (added by the@contextlib.contextmanager
decorator) that's driving thectx_gen
generator, even after thectg_gen
has handled it.The following is a very rough approximation of how
@contextlib.contextmanager
drivesctx_gen
:Running the above (including the definitions from the first code block) also prints:
In the above code, it's more clear that the exception is still being handled by the
except Exception as e:
block untilc.throw()
returns/raises, which only happens after the generator exits. Therefore the exception is still being handled the entire timectx_gen
is running all the code after the firstyield
.The fix?
Even though this behavior looks to be technically correct, it still seems unexpected and a bit of an abstraction leak.
Is this something that can be/should be fixed? Or should the behavior just be documented?
CPython versions tested on:
3.8, 3.9, 3.10, 3.11, CPython main branch
Operating systems tested on:
macOS
Linked PRs
@contextmanager
-decorated functions #111676NULL
in the exception stack to indicate an exception was handled #113302The text was updated successfully, but these errors were encountered: