-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
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
PEP 678: Make it possible to enrich an exception's error message #89770
Comments
The requirement comes from Hypothesis, see It is necessary there to add a note to an exception describing which test case it comes from. The note should be printed by __str__ of this exception. class Explanation(Exception):
__module__ = "builtins"
def __str__(self) -> str:
return f"\n{self.args[0]}" try: # Ideally something more like:
e.__note__ = msg
raise |
This code shows my current best workaround based on a wrapper exception, with the traceback below annotating the additional details that I'd prefer to omit for clarity: $ python example.py
Traceback (most recent call last):
File "example.py", line 8, in <module>
raise AssertionError(why)
AssertionError: Failed!
# These lines are
The above exception was the direct cause of the following exception: # confusing for new
# users, and they
Traceback (most recent call last): # only exist due
File "example.py", line 10, in <module> # to implementation
raise Explanation(msg) from e # via the Explanation
Explanation: # wrapper type :-(
You can reproduce this error by ...
... The motivation for this is that we'd like to use ExceptionGroup to indicate that |
bpo-28953 is another use case for this feature. |
Reopening to implement PEP 678. |
The implementation is complete, I am leaving this open for one more documentation PR (but that should not block the release). |
Was it a deliberate choice to not add a C API for exception notes? It seems to not be trivial to safely and correctly call PyObject *type, *exc, *tb;
PyErr_Fetch(&type, &exc, &tb);
PyErr_NormalizeException(&type, &exc, &tb);
PyObject* ret = PyObject_CallMethod(exc, "add_note", "s", "Some message");
Py_XDECREF(ret);
if (ret) {
// Note successfully added, restore the modified exception.
PyErr_Restore(type, exc, tb);
} else {
// Failed to add the note, set `__context__` on the new exception.
Py_XDECREF(type);
Py_XDECREF(tb);
PyObject *context = exc;
PyErr_Fetch(&type, &exc, &tb);
PyErr_NormalizeException(&type, &exc, &tb);
PyException_SetContext(exc, context);
PyErr_Restore(type, exc, tb);
} |
If we added a dedicated C API, you'd still need to do error checking, and such an API wouldn't be taking care of fetching/restoring the exception (you'd just be passing it an exception object), so the only line that would be simpler would be
|
Hm. I was hoping for a PyObject *type, *exc, *tb;
PyErr_Fetch(&type, &exc, &tb);
PyErr_NormalizeException(&type, &exc, &tb);
PyException_AddNote(exc, "Some message");
PyErr_Restore(type, exc, tb); but perhaps I'm being too focused on my own use case, and that wouldn't be sufficiently generic. I'm picturing |
Setting |
Yes, you're right OK, I see your point. I still think this is quite hard to use, but maybe the complexity is irreducible. |
Thanks for leaving a complete snippet showing how to do this. If in the future we find that many people are trying to do this from C (currently we only have a few use cases, all of which are Python code) we may consider adding a C API to reduce the complexity for those people, and your snippet will be helpful in designing the right API then. |
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: