From 2b4d518e15b55262f6e0fb5df37e2029a3ed03ec Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 11 Jan 2022 12:54:33 +0000 Subject: [PATCH 01/19] bpo-46343: Add PyErr_GetActiveException and PyErr_SetActiveException --- Doc/c-api/exceptions.rst | 41 +++++++++++++++++-- Include/cpython/pyerrors.h | 1 + Include/pyerrors.h | 2 + Lib/test/test_capi.py | 22 ++++++++++ .../2022-01-11-12-52-37.bpo-46343.JQJWhZ.rst | 5 +++ Misc/stable_abi.txt | 5 +++ Modules/_testcapimodule.c | 19 +++++++++ Python/errors.c | 32 +++++++++++---- 8 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2022-01-11-12-52-37.bpo-46343.JQJWhZ.rst diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 27feab92dede6e..8ebfd3819b9da8 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -459,12 +459,45 @@ Querying the error indicator } -.. c:function:: void PyErr_GetExcInfo(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback) +.. c:function:: void PyErr_GetActiveException(PyObject **pexc) + + Retrieve the active exception instance, as would be returned by ``sys.exception()``. + This refers to an exception that was *already caught*, not to an exception that was + freshly raised. Returns a new reference to the exception or to ``Py_None``. + Does not modify the exception 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_SetActiveException` to restore or + clear the exception state. + + .. versionadded:: 3.11 - Retrieve the exception info, as known from ``sys.exc_info()``. This refers +.. c:function:: void PyErr_SetActiveException(PyObject *exc) + + Set the active exception, as known from ``sys.exception()``. 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. + freshly raised. This function steals the reference of the argument. + To clear the exception state, pass ``NULL``. + + .. 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_GetActiveException` to read the exception + state. + + .. versionadded:: 3.11 + +.. c:function:: void PyErr_GetExcInfo(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback) + + Retrieve the old-style representation of 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:: diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 5281fde1f1a54c..2cb89dd4ab227f 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -91,6 +91,7 @@ typedef PyOSErrorObject PyWindowsErrorObject; PyAPI_FUNC(void) _PyErr_SetKeyError(PyObject *); PyAPI_FUNC(_PyErr_StackItem*) _PyErr_GetTopmostException(PyThreadState *tstate); +PyAPI_FUNC(void) _PyErr_GetActiveException(PyThreadState *, PyObject **); PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, PyObject **); /* Context manipulation (PEP 3134) */ diff --git a/Include/pyerrors.h b/Include/pyerrors.h index 77d791427d4928..672cccb0461e9b 100644 --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -19,6 +19,8 @@ PyAPI_FUNC(void) PyErr_Clear(void); PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *); #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 +PyAPI_FUNC(void) PyErr_GetActiveException(PyObject **); +PyAPI_FUNC(void) PyErr_SetActiveException(PyObject *); PyAPI_FUNC(void) PyErr_GetExcInfo(PyObject **, PyObject **, PyObject **); PyAPI_FUNC(void) PyErr_SetExcInfo(PyObject *, PyObject *, PyObject *); #endif diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 99263bff091beb..bec05d4ad0745a 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -82,6 +82,28 @@ def test_no_FatalError_infinite_loop(self): def test_memoryview_from_NULL_pointer(self): self.assertRaises(ValueError, _testcapi.make_memoryview_from_NULL_pointer) + def test_exception(self): + raised_exception = ValueError("5") + new_exc = TypeError("TEST") + try: + raise raised_exception + except ValueError as e: + orig_sys_exception = sys.exc_info()[1] + orig_exception = _testcapi.set_exception(new_exc) + new_sys_exception = sys.exc_info()[1] + new_exception = _testcapi.set_exception(orig_exception) + reset_sys_exception = sys.exc_info()[1] + + self.assertEqual(orig_exception, e) + + self.assertEqual(orig_exception, raised_exception) + self.assertEqual(orig_sys_exception, orig_exception) + self.assertEqual(reset_sys_exception, orig_exception) + self.assertEqual(new_exception, new_exc) + self.assertEqual(new_sys_exception, new_exception) + else: + self.assertTrue(False) + def test_exc_info(self): raised_exception = ValueError("5") new_exc = TypeError("TEST") diff --git a/Misc/NEWS.d/next/C API/2022-01-11-12-52-37.bpo-46343.JQJWhZ.rst b/Misc/NEWS.d/next/C API/2022-01-11-12-52-37.bpo-46343.JQJWhZ.rst new file mode 100644 index 00000000000000..54894ab5a14fa8 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-01-11-12-52-37.bpo-46343.JQJWhZ.rst @@ -0,0 +1,5 @@ +Added :c:func:`PyErr_GetActiveException` and +:c:func:`PyErr_SetActiveException` as simpler alternatives to +:c:func:`PyErr_GetExcInfo` and :c:func:`PyErr_SetExcInfo`. + +They are included in the stable ABI. diff --git a/Misc/stable_abi.txt b/Misc/stable_abi.txt index c4f5318712a541..d856471eb2712f 100644 --- a/Misc/stable_abi.txt +++ b/Misc/stable_abi.txt @@ -2196,3 +2196,8 @@ data PyStructSequence_UnnamedField data Py_Version added 3.11 +function PyErr_GetActiveException + added 3.11 +function PyErr_SetActiveException + added 3.11 + diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 7369f094faedde..a5af17c1b4f93d 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2558,6 +2558,24 @@ set_errno(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +test_set_exception(PyObject *self, PyObject *args) +{ + PyObject *orig_exc; + PyObject *new_exc; + PyObject *exc; + if (!PyArg_ParseTuple(args, "O:test_set_exception", + &new_exc)) { + return NULL; + } + + PyErr_GetActiveException(&exc); + + Py_INCREF(new_exc); + PyErr_SetActiveException(new_exc); + return exc; +} + static PyObject * test_set_exc_info(PyObject *self, PyObject *args) { @@ -5930,6 +5948,7 @@ static PyMethodDef TestMethods[] = { #endif {"traceback_print", traceback_print, METH_VARARGS}, {"exception_print", exception_print, METH_VARARGS}, + {"set_exception", test_set_exception, METH_VARARGS}, {"set_exc_info", test_set_exc_info, METH_VARARGS}, {"argparsing", argparsing, METH_VARARGS}, {"code_newempty", code_newempty, METH_VARARGS}, diff --git a/Python/errors.c b/Python/errors.c index 6c5fe41142304c..803fc0c6926575 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -510,28 +510,44 @@ _PyErr_GetExcInfo(PyThreadState *tstate, Py_XINCREF(*p_traceback); } +void +_PyErr_GetActiveException(PyThreadState *tstate, PyObject **p_exc) +{ + _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); + *p_exc = exc_info->exc_value; + Py_XINCREF(*p_exc); +} void -PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) +PyErr_GetActiveException(PyObject **p_exc) { PyThreadState *tstate = _PyThreadState_GET(); - _PyErr_GetExcInfo(tstate, p_type, p_value, p_traceback); + _PyErr_GetActiveException(tstate, p_exc); } void -PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback) +PyErr_SetActiveException(PyObject *exc) { PyThreadState *tstate = _PyThreadState_GET(); + PyObject *oldexc = tstate->exc_info->exc_value; + tstate->exc_info->exc_value = exc; + Py_XDECREF(oldexc); +} - PyObject *oldvalue = tstate->exc_info->exc_value; - - tstate->exc_info->exc_value = value; +void +PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) +{ + PyThreadState *tstate = _PyThreadState_GET(); + _PyErr_GetExcInfo(tstate, p_type, p_value, p_traceback); +} +void +PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback) +{ + PyErr_SetActiveException(value); /* These args are no longer used, but we still need to steal a ref */ Py_XDECREF(type); Py_XDECREF(traceback); - - Py_XDECREF(oldvalue); } From 87e6087fde2ad5fce12dbbeed5c53692042efe6c Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 11 Jan 2022 18:09:40 +0000 Subject: [PATCH 02/19] GetActiveException returns exception as its return value --- Doc/c-api/exceptions.rst | 2 +- Include/cpython/pyerrors.h | 2 +- Include/pyerrors.h | 2 +- Modules/_testcapimodule.c | 4 +--- Python/errors.c | 15 ++++++++------- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 8ebfd3819b9da8..7173d886eb1f6e 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -459,7 +459,7 @@ Querying the error indicator } -.. c:function:: void PyErr_GetActiveException(PyObject **pexc) +.. c:function:: PyObject* PyErr_GetActiveException() Retrieve the active exception instance, as would be returned by ``sys.exception()``. This refers to an exception that was *already caught*, not to an exception that was diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 2cb89dd4ab227f..fe455a4f57433a 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -91,7 +91,7 @@ typedef PyOSErrorObject PyWindowsErrorObject; PyAPI_FUNC(void) _PyErr_SetKeyError(PyObject *); PyAPI_FUNC(_PyErr_StackItem*) _PyErr_GetTopmostException(PyThreadState *tstate); -PyAPI_FUNC(void) _PyErr_GetActiveException(PyThreadState *, PyObject **); +PyAPI_FUNC(PyObject*) _PyErr_GetActiveException(PyThreadState *); PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, PyObject **); /* Context manipulation (PEP 3134) */ diff --git a/Include/pyerrors.h b/Include/pyerrors.h index 672cccb0461e9b..cdda2005004dd3 100644 --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -19,7 +19,7 @@ PyAPI_FUNC(void) PyErr_Clear(void); PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *); #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 -PyAPI_FUNC(void) PyErr_GetActiveException(PyObject **); +PyAPI_FUNC(PyObject*) PyErr_GetActiveException(void); PyAPI_FUNC(void) PyErr_SetActiveException(PyObject *); PyAPI_FUNC(void) PyErr_GetExcInfo(PyObject **, PyObject **, PyObject **); PyAPI_FUNC(void) PyErr_SetExcInfo(PyObject *, PyObject *, PyObject *); diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index a5af17c1b4f93d..1b33b301875b39 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2561,15 +2561,13 @@ set_errno(PyObject *self, PyObject *args) static PyObject * test_set_exception(PyObject *self, PyObject *args) { - PyObject *orig_exc; PyObject *new_exc; - PyObject *exc; if (!PyArg_ParseTuple(args, "O:test_set_exception", &new_exc)) { return NULL; } - PyErr_GetActiveException(&exc); + PyObject *exc = PyErr_GetActiveException(); Py_INCREF(new_exc); PyErr_SetActiveException(new_exc); diff --git a/Python/errors.c b/Python/errors.c index 803fc0c6926575..77da5de93ee699 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -510,19 +510,20 @@ _PyErr_GetExcInfo(PyThreadState *tstate, Py_XINCREF(*p_traceback); } -void -_PyErr_GetActiveException(PyThreadState *tstate, PyObject **p_exc) +PyObject* +_PyErr_GetActiveException(PyThreadState *tstate) { _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); - *p_exc = exc_info->exc_value; - Py_XINCREF(*p_exc); + PyObject *exc = exc_info->exc_value; + Py_XINCREF(exc); + return exc; } -void -PyErr_GetActiveException(PyObject **p_exc) +PyObject* +PyErr_GetActiveException() { PyThreadState *tstate = _PyThreadState_GET(); - _PyErr_GetActiveException(tstate, p_exc); + return _PyErr_GetActiveException(tstate); } void From ee4d98ed5cfa171f719bfed76831c2d8cd55af56 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 11 Jan 2022 19:03:47 +0000 Subject: [PATCH 03/19] fix test --- Lib/test/test_stable_abi_ctypes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 9fd6b14b0232a4..57d005f7765a06 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -143,6 +143,7 @@ def test_available_symbols(self): "PyErr_Fetch", "PyErr_Format", "PyErr_FormatV", + "PyErr_GetActiveException", "PyErr_GetExcInfo", "PyErr_GivenExceptionMatches", "PyErr_NewException", @@ -155,6 +156,7 @@ def test_available_symbols(self): "PyErr_ProgramText", "PyErr_ResourceWarning", "PyErr_Restore", + "PyErr_SetActiveException", "PyErr_SetExcInfo", "PyErr_SetFromErrno", "PyErr_SetFromErrnoWithFilename", From ebd9278ec6f612d7e23f3ca2bf93b83efad86713 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 13 Jan 2022 14:06:42 +0000 Subject: [PATCH 04/19] use sys.exception instead of sys.exc_info --- Lib/test/test_capi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index bec05d4ad0745a..e50e42b3b9627d 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -88,11 +88,11 @@ def test_exception(self): try: raise raised_exception except ValueError as e: - orig_sys_exception = sys.exc_info()[1] + orig_sys_exception = sys.exception() orig_exception = _testcapi.set_exception(new_exc) - new_sys_exception = sys.exc_info()[1] + new_sys_exception = sys.exception() new_exception = _testcapi.set_exception(orig_exception) - reset_sys_exception = sys.exc_info()[1] + reset_sys_exception = sys.exception() self.assertEqual(orig_exception, e) From 5631d32fbce6e7d1bb634076ab09d10827b89b59 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 13 Jan 2022 14:15:40 +0000 Subject: [PATCH 05/19] updated whatsnew --- Doc/whatsnew/3.11.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 28ac57e9544385..6182841792bece 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -653,6 +653,12 @@ New Features :c:macro:`PY_VERSION_HEX`. (Contributed by Gabriele N. Tornetta in :issue:`43931`.) +* Added two new functions to get and set the active exception instance: + :c:func:`PyErr_GetActiveException` and :c:func:`PyErr_SetActiveException`. + These are alternatives to :c:func:`PyErr_SetExcInfo()` and + :c:func:`PyErr_GetExcInfo()` which work with the legacy 3-tuple + representation of exceptions. + (Contributed by Irit Katriel in :issue:`46343`.) Porting to Python 3.11 ---------------------- From 20fa4217e676c342185753036c992f42244a4094 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 13 Jan 2022 14:19:27 +0000 Subject: [PATCH 06/19] regen-limited-abi --- Doc/data/stable_abi.dat | 2 ++ PC/python3dll.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 02e54e5d7f14ab..c194199976eaad 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -128,6 +128,7 @@ function,PyErr_ExceptionMatches,3.2, function,PyErr_Fetch,3.2, function,PyErr_Format,3.2, function,PyErr_FormatV,3.5, +function,PyErr_GetActiveException,3.11, function,PyErr_GetExcInfo,3.7, function,PyErr_GivenExceptionMatches,3.2, function,PyErr_NewException,3.2, @@ -140,6 +141,7 @@ function,PyErr_PrintEx,3.2, function,PyErr_ProgramText,3.2, function,PyErr_ResourceWarning,3.6, function,PyErr_Restore,3.2, +function,PyErr_SetActiveException,3.11, function,PyErr_SetExcFromWindowsErr,3.7,on Windows function,PyErr_SetExcFromWindowsErrWithFilename,3.7,on Windows function,PyErr_SetExcFromWindowsErrWithFilenameObject,3.7,on Windows diff --git a/PC/python3dll.c b/PC/python3dll.c index b2bb1706c4a2eb..16496b1e9dbcdf 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -187,6 +187,7 @@ EXPORT_FUNC(PyErr_ExceptionMatches) EXPORT_FUNC(PyErr_Fetch) EXPORT_FUNC(PyErr_Format) EXPORT_FUNC(PyErr_FormatV) +EXPORT_FUNC(PyErr_GetActiveException) EXPORT_FUNC(PyErr_GetExcInfo) EXPORT_FUNC(PyErr_GivenExceptionMatches) EXPORT_FUNC(PyErr_NewException) @@ -199,6 +200,7 @@ EXPORT_FUNC(PyErr_PrintEx) EXPORT_FUNC(PyErr_ProgramText) EXPORT_FUNC(PyErr_ResourceWarning) EXPORT_FUNC(PyErr_Restore) +EXPORT_FUNC(PyErr_SetActiveException) EXPORT_FUNC(PyErr_SetExcFromWindowsErr) EXPORT_FUNC(PyErr_SetExcFromWindowsErrWithFilename) EXPORT_FUNC(PyErr_SetExcFromWindowsErrWithFilenameObject) From 3a7ab17573c0ade0089262c1d165da7eb005dbca Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 13 Jan 2022 16:25:02 +0000 Subject: [PATCH 07/19] [1] Do not steal reference. [2] () --> (void) Co-authored-by: Victor Stinner --- Doc/c-api/exceptions.rst | 4 ++-- Python/errors.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 7173d886eb1f6e..559e24b4b154e8 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -459,7 +459,7 @@ Querying the error indicator } -.. c:function:: PyObject* PyErr_GetActiveException() +.. c:function:: PyObject* PyErr_GetActiveException(void) Retrieve the active exception instance, as would be returned by ``sys.exception()``. This refers to an exception that was *already caught*, not to an exception that was @@ -479,7 +479,7 @@ Querying the error indicator Set the active exception, as known from ``sys.exception()``. This refers to an exception that was *already caught*, not to an exception that was - freshly raised. This function steals the reference of the argument. + freshly raised. To clear the exception state, pass ``NULL``. .. note:: diff --git a/Python/errors.c b/Python/errors.c index 77da5de93ee699..74e4e0741b19a6 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -520,7 +520,7 @@ _PyErr_GetActiveException(PyThreadState *tstate) } PyObject* -PyErr_GetActiveException() +PyErr_GetActiveException(void) { PyThreadState *tstate = _PyThreadState_GET(); return _PyErr_GetActiveException(tstate); @@ -531,7 +531,7 @@ PyErr_SetActiveException(PyObject *exc) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *oldexc = tstate->exc_info->exc_value; - tstate->exc_info->exc_value = exc; + tstate->exc_info->exc_value = Py_XNewRef(exc); Py_XDECREF(oldexc); } From dbfd9d4d50fabd820d84b1350a51d4aa8e279161 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 17 Jan 2022 13:32:44 +0000 Subject: [PATCH 08/19] Use the new Py_(X)NewRef in a couple of places. Use self.fail() in test. Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> --- Lib/test/test_capi.py | 2 +- Modules/_testcapimodule.c | 3 +-- Python/errors.c | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index e50e42b3b9627d..7dea95d5647275 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -102,7 +102,7 @@ def test_exception(self): self.assertEqual(new_exception, new_exc) self.assertEqual(new_sys_exception, new_exception) else: - self.assertTrue(False) + self.fail("Exception not raised") def test_exc_info(self): raised_exception = ValueError("5") diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 1b33b301875b39..22645d6185a1b5 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2569,8 +2569,7 @@ test_set_exception(PyObject *self, PyObject *args) PyObject *exc = PyErr_GetActiveException(); - Py_INCREF(new_exc); - PyErr_SetActiveException(new_exc); + PyErr_SetActiveException(Py_NewRef(new_exc)); return exc; } diff --git a/Python/errors.c b/Python/errors.c index 74e4e0741b19a6..c136e8df90ba17 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -515,8 +515,7 @@ _PyErr_GetActiveException(PyThreadState *tstate) { _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); PyObject *exc = exc_info->exc_value; - Py_XINCREF(exc); - return exc; + return Py_XNewRef(exc); } PyObject* From a412e4b8636b2ed5278018f63b9d034a2f1f191b Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 17 Jan 2022 13:35:36 +0000 Subject: [PATCH 09/19] add :func: markup in doc Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> --- Doc/c-api/exceptions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 559e24b4b154e8..2a817330c6b36b 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -461,7 +461,7 @@ Querying the error indicator .. c:function:: PyObject* PyErr_GetActiveException(void) - Retrieve the active exception instance, as would be returned by ``sys.exception()``. + Retrieve the active exception instance, as would be returned by :func:`sys.exception`. This refers to an exception that was *already caught*, not to an exception that was freshly raised. Returns a new reference to the exception or to ``Py_None``. Does not modify the exception state. @@ -494,7 +494,7 @@ Querying the error indicator .. c:function:: void PyErr_GetExcInfo(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback) Retrieve the old-style representation of the exception info, as known from - ``sys.exc_info()``. This refers to an exception that was *already caught*, + :func:`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. From bcdf5995104dca67662ace45001be4be0042512d Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 1 Feb 2022 19:47:46 +0000 Subject: [PATCH 10/19] split out _PyErr_SetActiveException(tstate, exc) --- Include/cpython/pyerrors.h | 1 + Python/errors.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index fe455a4f57433a..23b0dbca968a01 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -92,6 +92,7 @@ typedef PyOSErrorObject PyWindowsErrorObject; PyAPI_FUNC(void) _PyErr_SetKeyError(PyObject *); PyAPI_FUNC(_PyErr_StackItem*) _PyErr_GetTopmostException(PyThreadState *tstate); PyAPI_FUNC(PyObject*) _PyErr_GetActiveException(PyThreadState *); +PyAPI_FUNC(void) _PyErr_SetActiveException(PyThreadState *, PyObject *); PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, PyObject **); /* Context manipulation (PEP 3134) */ diff --git a/Python/errors.c b/Python/errors.c index c136e8df90ba17..317b459e15c0c7 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -526,14 +526,20 @@ PyErr_GetActiveException(void) } void -PyErr_SetActiveException(PyObject *exc) +_PyErr_SetActiveException(PyThreadState *tstate, PyObject *exc) { - PyThreadState *tstate = _PyThreadState_GET(); PyObject *oldexc = tstate->exc_info->exc_value; tstate->exc_info->exc_value = Py_XNewRef(exc); Py_XDECREF(oldexc); } +void +PyErr_SetActiveException(PyObject *exc) +{ + PyThreadState *tstate = _PyThreadState_GET(); + _PyErr_SetActiveException(tstate, exc); +} + void PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) { From 18eb35c54eed1002b309c1c510d423fa015dff5f Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Wed, 23 Mar 2022 10:46:21 +0000 Subject: [PATCH 11/19] read --> get Co-authored-by: Victor Stinner --- Doc/c-api/exceptions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 75743849c46f0b..095f59bb39fc74 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -487,7 +487,7 @@ Querying the error indicator 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_GetActiveException` to read the exception + state temporarily. Use :c:func:`PyErr_GetActiveException` to get the exception state. .. versionadded:: 3.11 From 87981ab5a17e306dafc414e91cc7850f068a9ebb Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 23 Mar 2022 11:54:52 +0000 Subject: [PATCH 12/19] fix limited api version --- Include/pyerrors.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Include/pyerrors.h b/Include/pyerrors.h index cdda2005004dd3..de79d35dee405d 100644 --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -18,9 +18,11 @@ PyAPI_FUNC(PyObject *) PyErr_Occurred(void); PyAPI_FUNC(void) PyErr_Clear(void); PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *); -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030b0000 PyAPI_FUNC(PyObject*) PyErr_GetActiveException(void); PyAPI_FUNC(void) PyErr_SetActiveException(PyObject *); +#endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 PyAPI_FUNC(void) PyErr_GetExcInfo(PyObject **, PyObject **, PyObject **); PyAPI_FUNC(void) PyErr_SetExcInfo(PyObject *, PyObject *, PyObject *); #endif From 95555975f8c0d355acd5c25f705602a0b62dbac4 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 23 Mar 2022 18:54:01 +0000 Subject: [PATCH 13/19] PyErr_GetActiveException always returns NULL if no exception. Fix refleak in test_set_exception. Use METH_O in test_set_exception --- Doc/c-api/exceptions.rst | 2 +- Modules/_testcapimodule.c | 13 ++++--------- Python/errors.c | 5 ++++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 095f59bb39fc74..016bb63103ba91 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -464,7 +464,7 @@ Querying the error indicator Retrieve the active exception instance, as would be returned by :func:`sys.exception`. This refers to an exception that was *already caught*, not to an exception that was - freshly raised. Returns a new reference to the exception or to ``Py_None``. + freshly raised. Returns a new reference to the exception or ``NULL``. Does not modify the exception state. .. note:: diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 11b666516956f3..fd8ba611b10efa 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2563,17 +2563,12 @@ set_errno(PyObject *self, PyObject *args) } static PyObject * -test_set_exception(PyObject *self, PyObject *args) +test_set_exception(PyObject *self, PyObject *new_exc) { - PyObject *new_exc; - if (!PyArg_ParseTuple(args, "O:test_set_exception", - &new_exc)) { - return NULL; - } - PyObject *exc = PyErr_GetActiveException(); + assert(PyExceptionInstance_Check(exc) || exc == NULL); - PyErr_SetActiveException(Py_NewRef(new_exc)); + PyErr_SetActiveException(new_exc); return exc; } @@ -6028,7 +6023,7 @@ static PyMethodDef TestMethods[] = { #endif {"traceback_print", traceback_print, METH_VARARGS}, {"exception_print", exception_print, METH_VARARGS}, - {"set_exception", test_set_exception, METH_VARARGS}, + {"set_exception", test_set_exception, METH_O}, {"set_exc_info", test_set_exc_info, METH_VARARGS}, {"argparsing", argparsing, METH_VARARGS}, {"code_newempty", code_newempty, METH_VARARGS}, diff --git a/Python/errors.c b/Python/errors.c index c3154cd0d9c913..e23e4c02b0a1f2 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -504,7 +504,10 @@ _PyErr_GetActiveException(PyThreadState *tstate) { _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); PyObject *exc = exc_info->exc_value; - return Py_XNewRef(exc); + if (exc == NULL || exc == Py_None) { + return NULL; + } + return Py_NewRef(exc); } PyObject* From e0ee504de7ca59cdcace273f59a46330bc785be5 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 23 Mar 2022 19:12:11 +0000 Subject: [PATCH 14/19] doc changes following review by Victor --- Doc/c-api/exceptions.rst | 5 ++++- Doc/library/sys.rst | 17 +++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 016bb63103ba91..256d8ee36e074c 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -498,7 +498,8 @@ Querying the error indicator :func:`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. + info state. This function is kept for backwards compatibility. Prefer using + :c:func:`PyErr_GetActiveException`. .. note:: @@ -516,6 +517,8 @@ Querying the error indicator 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. + This function is kept for backwards compatibility. Prefer using + :c:func:`PyErr_SetActiveException`. .. note:: diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index b83b1167e8aad5..7517860ccc5b81 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -381,19 +381,12 @@ always available. .. function:: exception() - This function returns the exception instance that is currently being - handled. This exception is specific both to the current thread and - to the current stack frame. If the current stack frame is not handling - an exception, the exception is taken from the calling stack frame, or its - caller, and so on until a stack frame is found that is handling an - exception. Here, "handling an exception" is defined as "executing an - except clause." For any stack frame, only the exception being currently - handled is accessible. + This function, when called while an exception handler is executing (such as + an ``except`` or ``except*`` clause), returns the exception instance that + was caught by this handler. When exception handlers are nested within one + another, only the exception handled by the innermost handler is accessible. - .. index:: object: traceback - - If no exception is being handled anywhere on the stack, ``None`` is - returned. + If no exception handler is executing, this function returns ``None``. .. versionadded:: 3.11 From e6a3a7e01b8a4c18bac0af652b826416981927bc Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 13 Apr 2022 14:24:05 +0100 Subject: [PATCH 15/19] renamed Get/SetActiveException --> Get/SetHandledException --- Doc/c-api/exceptions.rst | 12 ++++++------ Doc/data/stable_abi.dat | 4 ++-- Doc/whatsnew/3.11.rst | 2 +- Include/cpython/pyerrors.h | 4 ++-- Include/pyerrors.h | 4 ++-- Lib/test/test_stable_abi_ctypes.py | 4 ++-- .../C API/2022-01-11-12-52-37.bpo-46343.JQJWhZ.rst | 4 ++-- Misc/stable_abi.txt | 4 ++-- Modules/_testcapimodule.c | 4 ++-- PC/python3dll.c | 4 ++-- Python/errors.c | 14 +++++++------- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 256d8ee36e074c..944b727191661a 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -460,7 +460,7 @@ Querying the error indicator } -.. c:function:: PyObject* PyErr_GetActiveException(void) +.. c:function:: PyObject* PyErr_GetHandledException(void) Retrieve the active exception instance, as would be returned by :func:`sys.exception`. This refers to an exception that was *already caught*, not to an exception that was @@ -471,12 +471,12 @@ Querying the error indicator 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_SetActiveException` to restore or + state temporarily. Use :c:func:`PyErr_SetHandledException` to restore or clear the exception state. .. versionadded:: 3.11 -.. c:function:: void PyErr_SetActiveException(PyObject *exc) +.. c:function:: void PyErr_SetHandledException(PyObject *exc) Set the active exception, as known from ``sys.exception()``. This refers to an exception that was *already caught*, not to an exception that was @@ -487,7 +487,7 @@ Querying the error indicator 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_GetActiveException` to get the exception + state temporarily. Use :c:func:`PyErr_GetHandledException` to get the exception state. .. versionadded:: 3.11 @@ -499,7 +499,7 @@ Querying the error indicator 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. This function is kept for backwards compatibility. Prefer using - :c:func:`PyErr_GetActiveException`. + :c:func:`PyErr_GetHandledException`. .. note:: @@ -518,7 +518,7 @@ Querying the error indicator freshly raised. This function steals the references of the arguments. To clear the exception state, pass ``NULL`` for all three arguments. This function is kept for backwards compatibility. Prefer using - :c:func:`PyErr_SetActiveException`. + :c:func:`PyErr_SetHandledException`. .. note:: diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index fb266d56854994..312d9b775fd45c 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -136,7 +136,7 @@ function,PyErr_ExceptionMatches,3.2, function,PyErr_Fetch,3.2, function,PyErr_Format,3.2, function,PyErr_FormatV,3.5, -function,PyErr_GetActiveException,3.11, +function,PyErr_GetHandledException,3.11, function,PyErr_GetExcInfo,3.7, function,PyErr_GivenExceptionMatches,3.2, function,PyErr_NewException,3.2, @@ -149,7 +149,7 @@ function,PyErr_PrintEx,3.2, function,PyErr_ProgramText,3.2, function,PyErr_ResourceWarning,3.6, function,PyErr_Restore,3.2, -function,PyErr_SetActiveException,3.11, +function,PyErr_SetHandledException,3.11, function,PyErr_SetExcFromWindowsErr,3.7,on Windows function,PyErr_SetExcFromWindowsErrWithFilename,3.7,on Windows function,PyErr_SetExcFromWindowsErrWithFilenameObject,3.7,on Windows diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index a7f947a46b3baf..005d837e851679 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -782,7 +782,7 @@ New Features (Contributed by Victor Stinner in :issue:`46906`.) * Added two new functions to get and set the active exception instance: - :c:func:`PyErr_GetActiveException` and :c:func:`PyErr_SetActiveException`. + :c:func:`PyErr_GetHandledException` and :c:func:`PyErr_SetHandledException`. These are alternatives to :c:func:`PyErr_SetExcInfo()` and :c:func:`PyErr_GetExcInfo()` which work with the legacy 3-tuple representation of exceptions. diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 23b0dbca968a01..08630cce8ac90a 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -91,8 +91,8 @@ typedef PyOSErrorObject PyWindowsErrorObject; PyAPI_FUNC(void) _PyErr_SetKeyError(PyObject *); PyAPI_FUNC(_PyErr_StackItem*) _PyErr_GetTopmostException(PyThreadState *tstate); -PyAPI_FUNC(PyObject*) _PyErr_GetActiveException(PyThreadState *); -PyAPI_FUNC(void) _PyErr_SetActiveException(PyThreadState *, PyObject *); +PyAPI_FUNC(PyObject*) _PyErr_GetHandledException(PyThreadState *); +PyAPI_FUNC(void) _PyErr_SetHandledException(PyThreadState *, PyObject *); PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, PyObject **); /* Context manipulation (PEP 3134) */ diff --git a/Include/pyerrors.h b/Include/pyerrors.h index de79d35dee405d..34e3de3328f410 100644 --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -19,8 +19,8 @@ PyAPI_FUNC(void) PyErr_Clear(void); PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *); #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030b0000 -PyAPI_FUNC(PyObject*) PyErr_GetActiveException(void); -PyAPI_FUNC(void) PyErr_SetActiveException(PyObject *); +PyAPI_FUNC(PyObject*) PyErr_GetHandledException(void); +PyAPI_FUNC(void) PyErr_SetHandledException(PyObject *); #endif #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 PyAPI_FUNC(void) PyErr_GetExcInfo(PyObject **, PyObject **, PyObject **); diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 121b72a45302e8..90f309091aca15 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -151,7 +151,7 @@ def test_available_symbols(self): "PyErr_Fetch", "PyErr_Format", "PyErr_FormatV", - "PyErr_GetActiveException", + "PyErr_GetHandledException", "PyErr_GetExcInfo", "PyErr_GivenExceptionMatches", "PyErr_NewException", @@ -164,7 +164,7 @@ def test_available_symbols(self): "PyErr_ProgramText", "PyErr_ResourceWarning", "PyErr_Restore", - "PyErr_SetActiveException", + "PyErr_SetHandledException", "PyErr_SetExcInfo", "PyErr_SetFromErrno", "PyErr_SetFromErrnoWithFilename", diff --git a/Misc/NEWS.d/next/C API/2022-01-11-12-52-37.bpo-46343.JQJWhZ.rst b/Misc/NEWS.d/next/C API/2022-01-11-12-52-37.bpo-46343.JQJWhZ.rst index 54894ab5a14fa8..1ac8da853c8796 100644 --- a/Misc/NEWS.d/next/C API/2022-01-11-12-52-37.bpo-46343.JQJWhZ.rst +++ b/Misc/NEWS.d/next/C API/2022-01-11-12-52-37.bpo-46343.JQJWhZ.rst @@ -1,5 +1,5 @@ -Added :c:func:`PyErr_GetActiveException` and -:c:func:`PyErr_SetActiveException` as simpler alternatives to +Added :c:func:`PyErr_GetHandledException` and +:c:func:`PyErr_SetHandledException` as simpler alternatives to :c:func:`PyErr_GetExcInfo` and :c:func:`PyErr_SetExcInfo`. They are included in the stable ABI. diff --git a/Misc/stable_abi.txt b/Misc/stable_abi.txt index 76803d7606a876..c616cd4dafa0cf 100644 --- a/Misc/stable_abi.txt +++ b/Misc/stable_abi.txt @@ -2224,8 +2224,8 @@ function PyMemoryView_FromBuffer data Py_Version added 3.11 -function PyErr_GetActiveException +function PyErr_GetHandledException added 3.11 -function PyErr_SetActiveException +function PyErr_SetHandledException added 3.11 diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index fd8ba611b10efa..dfbd29c4a2aa56 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2565,10 +2565,10 @@ set_errno(PyObject *self, PyObject *args) static PyObject * test_set_exception(PyObject *self, PyObject *new_exc) { - PyObject *exc = PyErr_GetActiveException(); + PyObject *exc = PyErr_GetHandledException(); assert(PyExceptionInstance_Check(exc) || exc == NULL); - PyErr_SetActiveException(new_exc); + PyErr_SetHandledException(new_exc); return exc; } diff --git a/PC/python3dll.c b/PC/python3dll.c index c5febbd15abc2d..7475e5c5fcff05 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -195,7 +195,7 @@ EXPORT_FUNC(PyErr_ExceptionMatches) EXPORT_FUNC(PyErr_Fetch) EXPORT_FUNC(PyErr_Format) EXPORT_FUNC(PyErr_FormatV) -EXPORT_FUNC(PyErr_GetActiveException) +EXPORT_FUNC(PyErr_GetHandledException) EXPORT_FUNC(PyErr_GetExcInfo) EXPORT_FUNC(PyErr_GivenExceptionMatches) EXPORT_FUNC(PyErr_NewException) @@ -208,7 +208,7 @@ EXPORT_FUNC(PyErr_PrintEx) EXPORT_FUNC(PyErr_ProgramText) EXPORT_FUNC(PyErr_ResourceWarning) EXPORT_FUNC(PyErr_Restore) -EXPORT_FUNC(PyErr_SetActiveException) +EXPORT_FUNC(PyErr_SetHandledException) EXPORT_FUNC(PyErr_SetExcFromWindowsErr) EXPORT_FUNC(PyErr_SetExcFromWindowsErrWithFilename) EXPORT_FUNC(PyErr_SetExcFromWindowsErrWithFilenameObject) diff --git a/Python/errors.c b/Python/errors.c index e23e4c02b0a1f2..ce7785855b8e54 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -500,7 +500,7 @@ _PyErr_GetExcInfo(PyThreadState *tstate, } PyObject* -_PyErr_GetActiveException(PyThreadState *tstate) +_PyErr_GetHandledException(PyThreadState *tstate) { _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); PyObject *exc = exc_info->exc_value; @@ -511,14 +511,14 @@ _PyErr_GetActiveException(PyThreadState *tstate) } PyObject* -PyErr_GetActiveException(void) +PyErr_GetHandledException(void) { PyThreadState *tstate = _PyThreadState_GET(); - return _PyErr_GetActiveException(tstate); + return _PyErr_GetHandledException(tstate); } void -_PyErr_SetActiveException(PyThreadState *tstate, PyObject *exc) +_PyErr_SetHandledException(PyThreadState *tstate, PyObject *exc) { PyObject *oldexc = tstate->exc_info->exc_value; tstate->exc_info->exc_value = Py_XNewRef(exc); @@ -526,10 +526,10 @@ _PyErr_SetActiveException(PyThreadState *tstate, PyObject *exc) } void -PyErr_SetActiveException(PyObject *exc) +PyErr_SetHandledException(PyObject *exc) { PyThreadState *tstate = _PyThreadState_GET(); - _PyErr_SetActiveException(tstate, exc); + _PyErr_SetHandledException(tstate, exc); } void @@ -542,7 +542,7 @@ PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) void PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback) { - PyErr_SetActiveException(value); + PyErr_SetHandledException(value); /* These args are no longer used, but we still need to steal a ref */ Py_XDECREF(type); Py_XDECREF(traceback); From 0355cc9539c6845bedd02435941503bd75f4e317 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 13 Apr 2022 14:30:55 +0100 Subject: [PATCH 16/19] add new functions to Doc/data/stable_abi.dat --- Doc/data/stable_abi.dat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 849a2cfd51f24a..61c28996f27150 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -137,6 +137,7 @@ function,PyErr_Fetch,3.2,, function,PyErr_Format,3.2,, function,PyErr_FormatV,3.5,, function,PyErr_GetExcInfo,3.7,, +function,PyErr_GetHandledException,3.11, function,PyErr_GivenExceptionMatches,3.2,, function,PyErr_NewException,3.2,, function,PyErr_NewExceptionWithDoc,3.2,, @@ -159,6 +160,7 @@ function,PyErr_SetFromErrnoWithFilenameObject,3.2,, function,PyErr_SetFromErrnoWithFilenameObjects,3.7,, function,PyErr_SetFromWindowsErr,3.7,on Windows, function,PyErr_SetFromWindowsErrWithFilename,3.7,on Windows, +function,PyErr_SetHandledException,3.11, function,PyErr_SetImportError,3.7,, function,PyErr_SetImportErrorSubclass,3.6,, function,PyErr_SetInterrupt,3.2,, From 938221535b77d76680ad80023643cfe9649d238e Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 13 Apr 2022 14:56:11 +0100 Subject: [PATCH 17/19] alphabetical --- Lib/test/test_stable_abi_ctypes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 5c0d43263697da..0656ff5581be5d 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -151,8 +151,8 @@ def test_available_symbols(self): "PyErr_Fetch", "PyErr_Format", "PyErr_FormatV", - "PyErr_GetHandledException", "PyErr_GetExcInfo", + "PyErr_GetHandledException", "PyErr_GivenExceptionMatches", "PyErr_NewException", "PyErr_NewExceptionWithDoc", @@ -164,12 +164,12 @@ def test_available_symbols(self): "PyErr_ProgramText", "PyErr_ResourceWarning", "PyErr_Restore", - "PyErr_SetHandledException", "PyErr_SetExcInfo", "PyErr_SetFromErrno", "PyErr_SetFromErrnoWithFilename", "PyErr_SetFromErrnoWithFilenameObject", "PyErr_SetFromErrnoWithFilenameObjects", + "PyErr_SetHandledException", "PyErr_SetImportError", "PyErr_SetImportErrorSubclass", "PyErr_SetInterrupt", From 1cc3a4b6000cb5a8f41e0e621a2c20357f6ab0d5 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 13 Apr 2022 16:00:14 +0100 Subject: [PATCH 18/19] make regen-limited-abi --- Doc/data/stable_abi.dat | 4 ++-- PC/python3dll.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 61c28996f27150..5387d0bf983fa2 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -137,7 +137,7 @@ function,PyErr_Fetch,3.2,, function,PyErr_Format,3.2,, function,PyErr_FormatV,3.5,, function,PyErr_GetExcInfo,3.7,, -function,PyErr_GetHandledException,3.11, +function,PyErr_GetHandledException,3.11,, function,PyErr_GivenExceptionMatches,3.2,, function,PyErr_NewException,3.2,, function,PyErr_NewExceptionWithDoc,3.2,, @@ -160,7 +160,7 @@ function,PyErr_SetFromErrnoWithFilenameObject,3.2,, function,PyErr_SetFromErrnoWithFilenameObjects,3.7,, function,PyErr_SetFromWindowsErr,3.7,on Windows, function,PyErr_SetFromWindowsErrWithFilename,3.7,on Windows, -function,PyErr_SetHandledException,3.11, +function,PyErr_SetHandledException,3.11,, function,PyErr_SetImportError,3.7,, function,PyErr_SetImportErrorSubclass,3.6,, function,PyErr_SetInterrupt,3.2,, diff --git a/PC/python3dll.c b/PC/python3dll.c index 7475e5c5fcff05..0aee2aec847261 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -195,8 +195,8 @@ EXPORT_FUNC(PyErr_ExceptionMatches) EXPORT_FUNC(PyErr_Fetch) EXPORT_FUNC(PyErr_Format) EXPORT_FUNC(PyErr_FormatV) -EXPORT_FUNC(PyErr_GetHandledException) EXPORT_FUNC(PyErr_GetExcInfo) +EXPORT_FUNC(PyErr_GetHandledException) EXPORT_FUNC(PyErr_GivenExceptionMatches) EXPORT_FUNC(PyErr_NewException) EXPORT_FUNC(PyErr_NewExceptionWithDoc) @@ -208,7 +208,6 @@ EXPORT_FUNC(PyErr_PrintEx) EXPORT_FUNC(PyErr_ProgramText) EXPORT_FUNC(PyErr_ResourceWarning) EXPORT_FUNC(PyErr_Restore) -EXPORT_FUNC(PyErr_SetHandledException) EXPORT_FUNC(PyErr_SetExcFromWindowsErr) EXPORT_FUNC(PyErr_SetExcFromWindowsErrWithFilename) EXPORT_FUNC(PyErr_SetExcFromWindowsErrWithFilenameObject) @@ -220,6 +219,7 @@ EXPORT_FUNC(PyErr_SetFromErrnoWithFilenameObject) EXPORT_FUNC(PyErr_SetFromErrnoWithFilenameObjects) EXPORT_FUNC(PyErr_SetFromWindowsErr) EXPORT_FUNC(PyErr_SetFromWindowsErrWithFilename) +EXPORT_FUNC(PyErr_SetHandledException) EXPORT_FUNC(PyErr_SetImportError) EXPORT_FUNC(PyErr_SetImportErrorSubclass) EXPORT_FUNC(PyErr_SetInterrupt) From ffa870b046aaa9119c588318eff6d5458a71be72 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 15 Apr 2022 19:20:35 +0100 Subject: [PATCH 19/19] clearer doc --- Doc/c-api/exceptions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 0ba6b358b7d635..7bfeca5958cc42 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -465,7 +465,7 @@ Querying the error indicator Retrieve the active exception instance, as would be returned by :func:`sys.exception`. This refers to an exception that was *already caught*, not to an exception that was freshly raised. Returns a new reference to the exception or ``NULL``. - Does not modify the exception state. + Does not modify the interpreter's exception state. .. note::