-
Notifications
You must be signed in to change notification settings - Fork 2.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
Use 'raise from' in initialization #2112
Conversation
When y'all are reviewing things, I'd love some initial feedback on this idea. |
We'll get to things in due time. Give us some time, please. |
80bd01f
to
2d1ad8e
Compare
Can you rebase on master, to see what is failing? |
Fails on Python 2.7, but as noted in the original description:
|
I changed my mind about this implementation, I think it makes more sense to have a |
91d80ee
to
f07809c
Compare
Looks like all the tests will pass now except for the NVIDIA thing which failed because of a download issue. |
cd0eeff
to
89c04e7
Compare
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.
Awesome, thanks!
/// Replaces the current Python error indicator with the chosen error, performing a | ||
/// 'raise from' to indicate that the chosen error was caused by the original error | ||
inline void raise_from(PyObject *type, const char *message) { | ||
// from cpython/errors.c _PyErr_FormatVFromCause |
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.
For future reference it would be ideal to have a full link, even if it's long, e.g. (the code looks the same at first glance):
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.
I looked a bit a the history of errors.c, I think @virtuald's copy is most similar to the oldest version (467ab19 on Oct 21, 2016) that still has any blamed lines today:
The diff is:
--- commit_a_467ab194fc6 2021-08-23 16:31:10.128182694 -0700
+++ copy_pr2112 2021-08-23 16:32:52.148562421 -0700
@@ -1,26 +1,20 @@
-static PyObject *
-_PyErr_FormatVFromCause(PyObject *exception, const char *format, va_list vargs)
-{
- PyObject *exc, *val, *val2, *tb;
-
- assert(PyErr_Occurred());
+inline void raise_from(PyObject *type, const char *message) {
+ // from cpython/errors.c _PyErr_FormatVFromCause
+ PyObject *exc = nullptr, *val = nullptr, *val2 = nullptr, *tb = nullptr;
PyErr_Fetch(&exc, &val, &tb);
+
PyErr_NormalizeException(&exc, &val, &tb);
- if (tb != NULL) {
+ if (tb != nullptr) {
PyException_SetTraceback(val, tb);
Py_DECREF(tb);
}
Py_DECREF(exc);
- assert(!PyErr_Occurred());
-
- PyErr_FormatV(exception, format, vargs);
+ PyErr_SetString(type, message);
PyErr_Fetch(&exc, &val2, &tb);
PyErr_NormalizeException(&exc, &val2, &tb);
Py_INCREF(val);
PyException_SetCause(val2, val);
PyException_SetContext(val2, val);
PyErr_Restore(exc, val2, tb);
-
- return NULL;
}
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.
For completeness, the 3 commits I looked at are:
- https://github.com/python/cpython/commits/467ab194fc6/Python/errors.c
- https://github.com/python/cpython/commits/b4bdecd0fc9/Python/errors.c
- https://github.com/python/cpython/commits/438a12dd9d8/Python/errors.c
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 602) static PyObject *
b4bdecd0fc9 (Victor Stinner 2019-05-24 13:44:24 +0200 603) _PyErr_FormatVFromCause(PyThreadState *tstate, PyObject *exception,
b4bdecd0fc9 (Victor Stinner 2019-05-24 13:44:24 +0200 604) const char *format, va_list vargs)
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 605) {
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 606) PyObject *exc, *val, *val2, *tb;
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 607)
b4bdecd0fc9 (Victor Stinner 2019-05-24 13:44:24 +0200 608) assert(_PyErr_Occurred(tstate));
b4bdecd0fc9 (Victor Stinner 2019-05-24 13:44:24 +0200 609) _PyErr_Fetch(tstate, &exc, &val, &tb);
b4bdecd0fc9 (Victor Stinner 2019-05-24 13:44:24 +0200 610) _PyErr_NormalizeException(tstate, &exc, &val, &tb);
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 611) if (tb != NULL) {
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 612) PyException_SetTraceback(val, tb);
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 613) Py_DECREF(tb);
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 614) }
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 615) Py_DECREF(exc);
b4bdecd0fc9 (Victor Stinner 2019-05-24 13:44:24 +0200 616) assert(!_PyErr_Occurred(tstate));
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 617)
438a12dd9d8 (Victor Stinner 2019-05-24 17:01:38 +0200 618) _PyErr_FormatV(tstate, exception, format, vargs);
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 619)
b4bdecd0fc9 (Victor Stinner 2019-05-24 13:44:24 +0200 620) _PyErr_Fetch(tstate, &exc, &val2, &tb);
b4bdecd0fc9 (Victor Stinner 2019-05-24 13:44:24 +0200 621) _PyErr_NormalizeException(tstate, &exc, &val2, &tb);
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 622) Py_INCREF(val);
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 623) PyException_SetCause(val2, val);
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 624) PyException_SetContext(val2, val);
b4bdecd0fc9 (Victor Stinner 2019-05-24 13:44:24 +0200 625) _PyErr_Restore(tstate, exc, val2, tb);
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 626)
467ab194fc6 (Serhiy Storchaka 2016-10-21 17:09:17 +0300 627) return NULL;
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.
For easy future reference, this is the merged PR #3215 diff relative to the base version:
--- commit_a_467ab194fc6 2021-08-23 16:31:10.128182694 -0700
+++ copy_final 2021-08-23 17:33:04.173103658 -0700
@@ -1,19 +1,20 @@
-static PyObject *
-_PyErr_FormatVFromCause(PyObject *exception, const char *format, va_list vargs)
-{
- PyObject *exc, *val, *val2, *tb;
+inline void raise_from(PyObject *type, const char *message) {
+ // Based on _PyErr_FormatVFromCause:
+ // https://github.com/python/cpython/blob/467ab194fc6189d9f7310c89937c51abeac56839/Python/errors.c#L405
+ // See https://github.com/pybind/pybind11/pull/2112 for details.
+ PyObject *exc = nullptr, *val = nullptr, *val2 = nullptr, *tb = nullptr;
assert(PyErr_Occurred());
PyErr_Fetch(&exc, &val, &tb);
PyErr_NormalizeException(&exc, &val, &tb);
- if (tb != NULL) {
+ if (tb != nullptr) {
PyException_SetTraceback(val, tb);
Py_DECREF(tb);
}
Py_DECREF(exc);
assert(!PyErr_Occurred());
- PyErr_FormatV(exception, format, vargs);
+ PyErr_SetString(type, message);
PyErr_Fetch(&exc, &val2, &tb);
PyErr_NormalizeException(&exc, &val2, &tb);
@@ -21,6 +22,4 @@
PyException_SetCause(val2, val);
PyException_SetContext(val2, val);
PyErr_Restore(exc, val2, tb);
-
- return NULL;
}
Hi all, I'll try to fix up the comment now as per my own suggestion as of a couple weeks ago. Hang on ... |
Unfortunately I cannot push to this branch, therefore I created a helper PR #3215. |
* Add py::raise_from to enable chaining exceptions on Python 3.3+ * Use 'raise from' in initialization * Documenting the exact base version of _PyErr_FormatVFromCause, adding back `assert`s. Co-authored-by: Dustin Spicuzza <dustin@virtualroadside.com>
Merged via #3215. |
We ran into an issue where a unicode decode exception occurred during initialization, and it was difficult to figure out what was causing the exception without looking directly at the object. Unfortunately, pybind11 currently swallows all exceptions by only retaining the text. This would change it to use the equivalent of
raise ImportError('something') from e
.There are several things to be considered here:
Suggested changelog entry:
* Added ``py::raise_from`` to enable chaining exceptions