Skip to content

Commit cfbe30d

Browse files
committed
Adds function to error_already_set that performs 'raise from'
1 parent e248869 commit cfbe30d

File tree

1 file changed

+27
-0
lines changed

1 file changed

+27
-0
lines changed

include/pybind11/pytypes.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,33 @@ class error_already_set : public std::runtime_error {
346346
/// the given tuple.
347347
bool matches(handle exc) const { return PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()); }
348348

349+
/// Replaces the currently held error with the chosen error, performing a 'raise from' to make
350+
/// the new error caused by the original error
351+
void caused(PyObject *type, const char *message) {
352+
// from cpython/errors.c _PyErr_FormatVFromCause
353+
PyObject *exc, *val, *val2, *tb;
354+
exc = m_type.release().ptr();
355+
val = m_value.release().ptr();
356+
tb = m_trace.release().ptr();
357+
358+
PyErr_NormalizeException(&exc, &val, &tb);
359+
if (tb != nullptr) {
360+
PyException_SetTraceback(val, tb);
361+
Py_DECREF(tb);
362+
}
363+
Py_DECREF(exc);
364+
365+
PyErr_SetString(type, message);
366+
PyErr_Fetch(&exc, &val2, &tb);
367+
PyErr_NormalizeException(&exc, &val2, &tb);
368+
Py_INCREF(val);
369+
PyException_SetCause(val2, val);
370+
PyException_SetContext(val2, val);
371+
m_type = reinterpret_steal<object>(exc);
372+
if (val2) { m_value = reinterpret_steal<object>(val2); }
373+
if (tb) { m_trace = reinterpret_steal<object>(tb); }
374+
}
375+
349376
const object& type() const { return m_type; }
350377
const object& value() const { return m_value; }
351378
const object& trace() const { return m_trace; }

0 commit comments

Comments
 (0)