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.
| 810 | /// Replaces the current Python error indicator with the chosen error, performing a |
| 811 | /// 'raise from' to indicate that the chosen error was caused by the original error. |
| 812 | inline void raise_from(PyObject *type, const char *message) { |
| 813 | // Based on _PyErr_FormatVFromCause: |
| 814 | // https://github.com/python/cpython/blob/467ab194fc6189d9f7310c89937c51abeac56839/Python/errors.c#L405 |
| 815 | // See https://github.com/pybind/pybind11/pull/2112 for details. |
| 816 | PyObject *exc = nullptr, *val = nullptr, *val2 = nullptr, *tb = nullptr; |
| 817 | |
| 818 | assert(PyErr_Occurred()); |
| 819 | PyErr_Fetch(&exc, &val, &tb); |
| 820 | PyErr_NormalizeException(&exc, &val, &tb); |
| 821 | if (tb != nullptr) { |
| 822 | PyException_SetTraceback(val, tb); |
| 823 | Py_DECREF(tb); |
| 824 | } |
| 825 | Py_DECREF(exc); |
| 826 | assert(!PyErr_Occurred()); |
| 827 | |
| 828 | PyErr_SetString(type, message); |
| 829 | |
| 830 | PyErr_Fetch(&exc, &val2, &tb); |
| 831 | PyErr_NormalizeException(&exc, &val2, &tb); |
| 832 | Py_INCREF(val); |
| 833 | PyException_SetCause(val2, val); |
| 834 | PyException_SetContext(val2, val); |
| 835 | PyErr_Restore(exc, val2, tb); |
| 836 | } |
| 837 | |
| 838 | /// Sets the current Python error indicator with the chosen error, performing a 'raise from' |
| 839 | /// from the error contained in error_already_set to indicate that the chosen error was |