-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Use PyErr_WriteUnraisable when an error occurs in a destructor #2358
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -329,3 +329,21 @@ class PyNonFinalFinalChild(m.IsNonFinalFinal): | |
def test_exception_rvalue_abort(): | ||
with pytest.raises(RuntimeError): | ||
m.PyPrintDestructor().throw_something() | ||
|
||
|
||
def test_pyexception_destructor(): | ||
import sys | ||
|
||
if hasattr(sys, "unraisablehook"): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only Python 3.8+ have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's why I made it conditional. If the logic works on one version of python since this is so esoteric I didn't think it was worth testing on the older versions too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pybind11 has some way of capturing the stderr. It would definitely be good to test on all Python versions, if possible (especially Python 2, which tends to act up/do things differently!). |
||
old_hook = sys.unraisablehook | ||
try: | ||
ctxt = [None] | ||
|
||
def new_hook(*args): | ||
ctxt[0] = True | ||
|
||
sys.unraisablehook = new_hook | ||
m.PyRaiseDestructor() | ||
assert ctxt[0] is not None | ||
finally: | ||
sys.unraisablehook = old_hook |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for passing the
type
rather than the value here? According to the docs:As written it would print
Exception ignored in: ValueError
(sincerepr(v_h.type->type)
is ValueError). It would be better if we could find a way to get better information to the user, e.g. the name of the destructor.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
v_h.type->type
is the class, not the exception.I assumed that if I hit an error here, then the value no longer existed so a
__repr__
wouldn't be sensible? I'm not sure if the name is still around, though I guess it must be?Though, you're right, it would be good to do something more sensible. Python does this:
As mentioned above, here's what I currently have:
I suppose we could add a name and a pointer value?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it's probably good as is, since printing the name of the offending class gives a good idea as to where the occurred.
We definitely don't want to call any extra functions in this type of code, using what is available is best.