Issue #14098: New functions PyErr_GetExcInfo and PyErr_SetExcInfo.
Patch by Stefan Behnel.
This commit is contained in:
parent
e27b3608ef
commit
aa2efcb0bc
|
@ -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);
|
||||||
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):
|
||||||
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?
|
||||||
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)
|
||||||
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[] = {
|
||||||
#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)
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue