Patch by Stefan Behnel.
exception state.
+.. c:function:: void PyErr_GetExcInfo(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback)
+
+ Retrieve the exception info, as known from ``sys.exc_info()``. This refers
+ to an exception that was already caught, not to an exception that was
+ freshly raised. Returns new references for the three objects, any of which
+ may be *NULL*. Does not modify the exception info state.
+
+ .. note::
+
+ This function is not normally used by code that wants to handle exceptions.
+ Rather, it can be used when code needs to save and restore the exception
+ state temporarily. Use :c:func:`PyErr_SetExcInfo` to restore or clear the
+ exception state.
+
+.. versionadded:: 3.3
+
+
+.. c:function:: void PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback)
+
+ Set the exception info, as known from ``sys.exc_info()``. This refers
+ to an exception that was already caught, not to an exception that was
+ freshly raised. This function steals the references of the arguments.
+ To clear the exception state, pass *NULL* for all three arguments.
+ For general rules about the three arguments, see :c:func:`PyErr_Restore`.
+
+ .. note::
+
+ This function is not normally used by code that wants to handle exceptions.
+ Rather, it can be used when code needs to save and restore the exception
+ state temporarily. Use :c:func:`PyErr_GetExcInfo` to read the exception
+ state.
+
+.. versionadded:: 3.3
+
+
.. c:function:: void PyErr_SetString(PyObject *type, const char *message)
This is the most common way to set the error indicator. The first argument
PyAPI_FUNC(void) PyErr_Clear(void);
PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **);
PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *);
+PyAPI_FUNC(void) PyErr_GetExcInfo(PyObject **, PyObject **, PyObject **);
+PyAPI_FUNC(void) PyErr_SetExcInfo(PyObject *, PyObject *, PyObject *);
#if defined(__clang__) || \
(defined(__GNUC__) && \
def test_memoryview_from_NULL_pointer(self):
self.assertRaises(ValueError, _testcapi.make_memoryview_from_NULL_pointer)
+ def test_exc_info(self):
+ raised_exception = ValueError("5")
+ new_exc = TypeError("TEST")
+ try:
+ raise raised_exception
+ except ValueError as e:
+ tb = e.__traceback__
+ orig_sys_exc_info = sys.exc_info()
+ orig_exc_info = _testcapi.set_exc_info(new_exc.__class__, new_exc, None)
+ new_sys_exc_info = sys.exc_info()
+ new_exc_info = _testcapi.set_exc_info(*orig_exc_info)
+ reset_sys_exc_info = sys.exc_info()
+
+ self.assertEqual(orig_exc_info[1], e)
+
+ self.assertSequenceEqual(orig_exc_info, (raised_exception.__class__, raised_exception, tb))
+ self.assertSequenceEqual(orig_sys_exc_info, orig_exc_info)
+ self.assertSequenceEqual(reset_sys_exc_info, orig_exc_info)
+ self.assertSequenceEqual(new_exc_info, (new_exc.__class__, new_exc, None))
+ self.assertSequenceEqual(new_sys_exc_info, new_exc_info)
+ else:
+ self.assertTrue(False)
+
@unittest.skipUnless(threading, 'Threading required for this test.')
class TestPendingCalls(unittest.TestCase):
Core and Builtins
-----------------
+- Issue #14098: New functions PyErr_GetExcInfo and PyErr_SetExcInfo.
+ Patch by Stefan Behnel.
+
- Issue #14385: It is now possible to use a custom type for the __builtins__
namespace, instead of a dict. It can be used for sandboxing for example.
Raise also a NameError instead of ImportError if __build_class__ name if not
return NULL;
}
+static PyObject *
+test_set_exc_info(PyObject *self, PyObject *args)
+{
+ PyObject *orig_exc;
+ PyObject *new_type, *new_value, *new_tb;
+ PyObject *type, *value, *tb;
+ if (!PyArg_ParseTuple(args, "OOO:test_set_exc_info",
+ &new_type, &new_value, &new_tb))
+ return NULL;
+
+ PyErr_GetExcInfo(&type, &value, &tb);
+
+ Py_INCREF(new_type);
+ Py_INCREF(new_value);
+ Py_INCREF(new_tb);
+ PyErr_SetExcInfo(new_type, new_value, new_tb);
+
+ orig_exc = PyTuple_Pack(3, type ? type : Py_None, value ? value : Py_None, tb ? tb : Py_None);
+ Py_XDECREF(type);
+ Py_XDECREF(value);
+ Py_XDECREF(tb);
+ return orig_exc;
+}
static int test_run_counter = 0;
#endif
{"traceback_print", traceback_print, METH_VARARGS},
{"exception_print", exception_print, METH_VARARGS},
+ {"set_exc_info", test_set_exc_info, METH_VARARGS},
{"argparsing", argparsing, METH_VARARGS},
{"code_newempty", code_newempty, METH_VARARGS},
{"make_exception_with_doc", (PyCFunction)make_exception_with_doc,
PyErr_Restore(NULL, NULL, NULL);
}
+void
+PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+
+ *p_type = tstate->exc_type;
+ *p_value = tstate->exc_value;
+ *p_traceback = tstate->exc_traceback;
+
+ Py_XINCREF(*p_type);
+ Py_XINCREF(*p_value);
+ Py_XINCREF(*p_traceback);
+}
+
+void
+PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback)
+{
+ PyObject *oldtype, *oldvalue, *oldtraceback;
+ PyThreadState *tstate = PyThreadState_GET();
+
+ oldtype = tstate->exc_type;
+ oldvalue = tstate->exc_value;
+ oldtraceback = tstate->exc_traceback;
+
+ tstate->exc_type = p_type;
+ tstate->exc_value = p_value;
+ tstate->exc_traceback = p_traceback;
+
+ Py_XDECREF(oldtype);
+ Py_XDECREF(oldvalue);
+ Py_XDECREF(oldtraceback);
+}
+
/* Convenience functions to set a type error exception and return 0 */
int