Commit aa2efcb0 authored by Martin v. Löwis's avatar Martin v. Löwis

Issue #14098: New functions PyErr_GetExcInfo and PyErr_SetExcInfo.

Patch by Stefan Behnel.
parent e27b3608
...@@ -129,6 +129,41 @@ in various ways. There is a separate error indicator for each thread. ...@@ -129,6 +129,41 @@ in various ways. There is a separate error indicator for each thread.
exception state. 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) .. c:function:: void PyErr_SetString(PyObject *type, const char *message)
This is the most common way to set the error indicator. The first argument This is the most common way to set the error indicator. The first argument
......
...@@ -82,6 +82,8 @@ PyAPI_FUNC(PyObject *) PyErr_Occurred(void); ...@@ -82,6 +82,8 @@ PyAPI_FUNC(PyObject *) PyErr_Occurred(void);
PyAPI_FUNC(void) PyErr_Clear(void); PyAPI_FUNC(void) PyErr_Clear(void);
PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **);
PyAPI_FUNC(void) PyErr_Restore(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__) || \ #if defined(__clang__) || \
(defined(__GNUC__) && \ (defined(__GNUC__) && \
......
...@@ -55,6 +55,29 @@ class CAPITest(unittest.TestCase): ...@@ -55,6 +55,29 @@ class CAPITest(unittest.TestCase):
def test_memoryview_from_NULL_pointer(self): def test_memoryview_from_NULL_pointer(self):
self.assertRaises(ValueError, _testcapi.make_memoryview_from_NULL_pointer) 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.') @unittest.skipUnless(threading, 'Threading required for this test.')
class TestPendingCalls(unittest.TestCase): class TestPendingCalls(unittest.TestCase):
......
...@@ -10,6 +10,9 @@ What's New in Python 3.3.0 Alpha 3? ...@@ -10,6 +10,9 @@ What's New in Python 3.3.0 Alpha 3?
Core and Builtins 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__ - 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. 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 Raise also a NameError instead of ImportError if __build_class__ name if not
......
...@@ -1639,6 +1639,29 @@ raise_exception(PyObject *self, PyObject *args) ...@@ -1639,6 +1639,29 @@ raise_exception(PyObject *self, PyObject *args)
return NULL; 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; static int test_run_counter = 0;
...@@ -2471,6 +2494,7 @@ static PyMethodDef TestMethods[] = { ...@@ -2471,6 +2494,7 @@ static PyMethodDef TestMethods[] = {
#endif #endif
{"traceback_print", traceback_print, METH_VARARGS}, {"traceback_print", traceback_print, METH_VARARGS},
{"exception_print", exception_print, METH_VARARGS}, {"exception_print", exception_print, METH_VARARGS},
{"set_exc_info", test_set_exc_info, METH_VARARGS},
{"argparsing", argparsing, METH_VARARGS}, {"argparsing", argparsing, METH_VARARGS},
{"code_newempty", code_newempty, METH_VARARGS}, {"code_newempty", code_newempty, METH_VARARGS},
{"make_exception_with_doc", (PyCFunction)make_exception_with_doc, {"make_exception_with_doc", (PyCFunction)make_exception_with_doc,
......
...@@ -320,6 +320,39 @@ PyErr_Clear(void) ...@@ -320,6 +320,39 @@ PyErr_Clear(void)
PyErr_Restore(NULL, NULL, NULL); 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 */ /* Convenience functions to set a type error exception and return 0 */
int int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment