From 04407ce2e81bceced54247c70c75e7724c5605e9 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 25 Nov 2021 17:31:07 +0000 Subject: [PATCH 1/8] bpo-45711: Change exc_info related APIs to derive type and traceback from the exception instance --- Doc/c-api/exceptions.rst | 7 +++- Doc/library/sys.rst | 11 +++++-- Doc/whatsnew/3.11.rst | 19 +++++++++++ Python/errors.c | 70 ++++++++++++++++++++++++++-------------- 4 files changed, 79 insertions(+), 28 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 5d90248f85a5d4..f8bafedc70dbe1 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -482,7 +482,6 @@ 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. - For general rules about the three arguments, see :c:func:`PyErr_Restore`. .. note:: @@ -493,6 +492,12 @@ Querying the error indicator .. versionadded:: 3.3 + .. versionchanged:: 3.11 + The ``type`` and ``traceback`` arguments are no longer used, the + interpreter now derives them the exception instance (the ``value`` + argument). The function still steals references of all three + arguments. + Signal Handling =============== diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 175fc091652068..7d1b21f05edb19 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -396,9 +396,14 @@ always available. ``(type, value, traceback)``. Their meaning is: *type* gets the type of the exception being handled (a subclass of :exc:`BaseException`); *value* gets the exception instance (an instance of the exception type); *traceback* gets - a :ref:`traceback object ` which encapsulates the call - stack at the point where the exception originally occurred. - + a :ref:`traceback object ` which typically encapsulates + the call stack at the point where the exception last occurred. + + .. versionchanged:: 3.11 + The ``type`` and ``traceback`` fields are now derived from the ``value`` + (the exception instance), so when an exception is modified while it is + being handled, the changes are reflected in the results of subsequent + calls to :func:`exc_info`. .. data:: exec_prefix diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 9751f894f9a9a5..959978c2a3ab2f 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -258,6 +258,14 @@ sqlite3 threading mode the underlying SQLite library has been compiled with. (Contributed by Erlend E. Aasland in :issue:`45613`.) +sys +--- + +* :func:`sys.exc_info` now derives the ``type`` and ``traceback`` fields + from the ``value`` (the exception instance), so when an exception is + modified while it is being handled, the changes are reflected in + the results of subsequent calls to :func:`exc_info`. + (Contributed by Irit Katriel in :issue:`45711`.) threading --------- @@ -572,6 +580,17 @@ New Features suspend and resume tracing and profiling. (Contributed by Victor Stinner in :issue:`43760`.) +* :c:func:`PyErr_SetExcInfo()` no longer uses the ``type`` and ``traceback`` + arguments, the interpreter now derives those values from the exception + instance (the ``value`` argument). The function still steals references + of all three arguments. + (Contributed by Irit Katriel in :issue:`45711`.) + +* :c:func:`PyErr_GetExcInfo()` now derives the ``type`` and ``traceback`` + fields of the result from the exception instance (the ``value`` field). + (Contributed by Irit Katriel in :issue:`45711`.) + + Porting to Python 3.11 ---------------------- diff --git a/Python/errors.c b/Python/errors.c index 6e74d19b78ef33..7415f17f3720c4 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -470,6 +470,33 @@ PyErr_Clear(void) _PyErr_Clear(tstate); } +static PyObject* +get_exc_type(PyObject *exc_value) /* returns a borrowed ref */ +{ + if (exc_value == NULL || exc_value == Py_None) { + return exc_value; + } + else { + assert(PyExceptionInstance_Check(exc_value)); + PyObject *type = PyExceptionInstance_Class(exc_value); + assert(type != NULL); + return type; + } +} + +static PyObject* +get_exc_traceback(PyObject *exc_value) /* returns a borrowed ref */ +{ + if (exc_value == NULL || exc_value == Py_None) { + return Py_None; + } + else { + assert(PyExceptionInstance_Check(exc_value)); + PyObject *tb = PyException_GetTraceback(exc_value); + Py_XDECREF(tb); + return tb ? tb : Py_None; + } +} void _PyErr_GetExcInfo(PyThreadState *tstate, @@ -477,18 +504,9 @@ _PyErr_GetExcInfo(PyThreadState *tstate, { _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); + *p_type = get_exc_type(exc_info->exc_value); *p_value = exc_info->exc_value; - *p_traceback = exc_info->exc_traceback; - - if (*p_value == NULL || *p_value == Py_None) { - assert(exc_info->exc_type == NULL || exc_info->exc_type == Py_None); - *p_type = Py_None; - } - else { - assert(PyExceptionInstance_Check(*p_value)); - assert(exc_info->exc_type == PyExceptionInstance_Class(*p_value)); - *p_type = PyExceptionInstance_Class(*p_value); - } + *p_traceback = get_exc_traceback(exc_info->exc_value); Py_XINCREF(*p_type); Py_XINCREF(*p_value); @@ -513,9 +531,16 @@ PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback) oldvalue = tstate->exc_info->exc_value; oldtraceback = tstate->exc_info->exc_traceback; - tstate->exc_info->exc_type = p_type; + + tstate->exc_info->exc_type = get_exc_type(p_value); + Py_XINCREF(tstate->exc_info->exc_type); tstate->exc_info->exc_value = p_value; - tstate->exc_info->exc_traceback = p_traceback; + tstate->exc_info->exc_traceback = get_exc_traceback(p_value); + Py_XINCREF(tstate->exc_info->exc_traceback); + + /* These args are no longer used, but we still need to steal a ref */ + Py_XDECREF(p_type); + Py_XDECREF(p_traceback); Py_XDECREF(oldtype); Py_XDECREF(oldvalue); @@ -527,22 +552,19 @@ PyObject* _PyErr_StackItemToExcInfoTuple(_PyErr_StackItem *err_info) { PyObject *exc_value = err_info->exc_value; - if (exc_value == NULL) { - exc_value = Py_None; - } - assert(exc_value == Py_None || PyExceptionInstance_Check(exc_value)); + assert(exc_value == NULL || + exc_value == Py_None || + PyExceptionInstance_Check(exc_value)); - PyObject *exc_type = PyExceptionInstance_Check(exc_value) ? - PyExceptionInstance_Class(exc_value) : - Py_None; + PyObject *exc_type = get_exc_type(exc_value); + PyObject *exc_traceback = get_exc_traceback(exc_value); return Py_BuildValue( "(OOO)", - exc_type, - exc_value, - err_info->exc_traceback != NULL ? - err_info->exc_traceback : Py_None); + exc_type ? exc_type : Py_None, + exc_value ? exc_value : Py_None, + exc_traceback ? exc_traceback : Py_None); } From e8645ff29a651f28a41792ed9746cd251bf3831b Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 25 Nov 2021 17:51:30 +0000 Subject: [PATCH 2/8] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst b/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst new file mode 100644 index 00000000000000..ffb6688a67d23c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst @@ -0,0 +1 @@ +The three values of ``exc_info`` are now always consistent with each other. In particular, the ``type`` and ``traceback`` fields are now derived from the exception instance. This impacts the return values of :func:`sys.exc_info` and :c:func:`PyErr_GetExcInfo()` if the exception instance is modified while the exception is handled, as well as :c:func:`PyErr_SetExcInfo()`, which now ignores the ``type`` and ``traceback`` arguments that are provided to it. \ No newline at end of file From 971887a4e3d508531c76bc9f3fb05259acfbcfd9 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 26 Nov 2021 10:50:01 +0000 Subject: [PATCH 3/8] Tweak news text Co-authored-by: Guido van Rossum --- .../Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst b/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst index ffb6688a67d23c..9ede833a6f6f1b 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst @@ -1 +1 @@ -The three values of ``exc_info`` are now always consistent with each other. In particular, the ``type`` and ``traceback`` fields are now derived from the exception instance. This impacts the return values of :func:`sys.exc_info` and :c:func:`PyErr_GetExcInfo()` if the exception instance is modified while the exception is handled, as well as :c:func:`PyErr_SetExcInfo()`, which now ignores the ``type`` and ``traceback`` arguments that are provided to it. \ No newline at end of file +The three values of ``exc_info`` are now always consistent with each other. In particular, the ``type`` and ``traceback`` fields are now derived from the exception instance. This impacts the return values of :func:`sys.exc_info` and :c:func:`PyErr_GetExcInfo()` if the exception instance is modified while the exception is handled, as well as :c:func:`PyErr_SetExcInfo()`, which now ignores the ``type`` and ``traceback`` arguments provided to it. \ No newline at end of file From 995ec591eb4e00af481cd33bcec3e4a928aa4efe Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 26 Nov 2021 10:53:17 +0000 Subject: [PATCH 4/8] remove p_ prefix from arg names in PyErr_SetExcInfo --- Python/errors.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Python/errors.c b/Python/errors.c index 7415f17f3720c4..b3b11a60a94013 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -522,7 +522,7 @@ PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) } void -PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback) +PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback) { PyObject *oldtype, *oldvalue, *oldtraceback; PyThreadState *tstate = _PyThreadState_GET(); @@ -532,15 +532,15 @@ PyErr_SetExcInfo(PyObject *p_type, PyObject *p_value, PyObject *p_traceback) oldtraceback = tstate->exc_info->exc_traceback; - tstate->exc_info->exc_type = get_exc_type(p_value); + tstate->exc_info->exc_type = get_exc_type(value); Py_XINCREF(tstate->exc_info->exc_type); - tstate->exc_info->exc_value = p_value; - tstate->exc_info->exc_traceback = get_exc_traceback(p_value); + tstate->exc_info->exc_value = value; + tstate->exc_info->exc_traceback = get_exc_traceback(value); Py_XINCREF(tstate->exc_info->exc_traceback); /* These args are no longer used, but we still need to steal a ref */ - Py_XDECREF(p_type); - Py_XDECREF(p_traceback); + Py_XDECREF(type); + Py_XDECREF(traceback); Py_XDECREF(oldtype); Py_XDECREF(oldvalue); From 92835f000c35c1e692d272246b142180c434d955 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 26 Nov 2021 10:56:00 +0000 Subject: [PATCH 5/8] type is None if value is None or NULL --- Python/errors.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/errors.c b/Python/errors.c index b3b11a60a94013..0a8b5a257fb2c7 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -474,7 +474,7 @@ static PyObject* get_exc_type(PyObject *exc_value) /* returns a borrowed ref */ { if (exc_value == NULL || exc_value == Py_None) { - return exc_value; + return Py_None; } else { assert(PyExceptionInstance_Check(exc_value)); From 4602710afd4a0e55a8e6ff5acb08063965153732 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 26 Nov 2021 11:02:38 +0000 Subject: [PATCH 6/8] wrap news text --- .../2021-11-25-17-51-29.bpo-45711.D2igmz.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst b/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst index 9ede833a6f6f1b..c499f185d2038f 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2021-11-25-17-51-29.bpo-45711.D2igmz.rst @@ -1 +1,6 @@ -The three values of ``exc_info`` are now always consistent with each other. In particular, the ``type`` and ``traceback`` fields are now derived from the exception instance. This impacts the return values of :func:`sys.exc_info` and :c:func:`PyErr_GetExcInfo()` if the exception instance is modified while the exception is handled, as well as :c:func:`PyErr_SetExcInfo()`, which now ignores the ``type`` and ``traceback`` arguments provided to it. \ No newline at end of file +The three values of ``exc_info`` are now always consistent with each other. +In particular, the ``type`` and ``traceback`` fields are now derived from +the exception instance. This impacts the return values of :func:`sys.exc_info` +and :c:func:`PyErr_GetExcInfo()` if the exception instance is modified while +the exception is handled, as well as :c:func:`PyErr_SetExcInfo()`, which now +ignores the ``type`` and ``traceback`` arguments provided to it. From 7bc139fdaf9739db53e519173a30a1aa0f6b4fb1 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 26 Nov 2021 11:03:42 +0000 Subject: [PATCH 7/8] tweak doc wording to add 'and can be NULL' --- Doc/c-api/exceptions.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index f8bafedc70dbe1..27feab92dede6e 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -493,10 +493,10 @@ Querying the error indicator .. versionadded:: 3.3 .. versionchanged:: 3.11 - The ``type`` and ``traceback`` arguments are no longer used, the - interpreter now derives them the exception instance (the ``value`` - argument). The function still steals references of all three - arguments. + The ``type`` and ``traceback`` arguments are no longer used and + can be NULL. The interpreter now derives them from the exception + instance (the ``value`` argument). The function still steals + references of all three arguments. Signal Handling From 05af230b8871e965028123daaba83e828a9fa84c Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 29 Nov 2021 00:00:15 +0000 Subject: [PATCH 8/8] Use traceback from exception instead of exc_info in reraise --- Doc/reference/simple_stmts.rst | 6 ++++++ Doc/whatsnew/3.11.rst | 6 ++++++ Python/ceval.c | 9 +++------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index bb1209dfc33beb..3d02074960ff3c 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -655,6 +655,12 @@ and information about handling exceptions is in section :ref:`try`. The ``__suppress_context__`` attribute to suppress automatic display of the exception context. +.. versionchanged:: 3.11 + If the traceback of the active exception is modified in an :keyword:`except` + clause, a subsequent ``raise`` statement re-raises the exception with the + modified traceback. Previously, the exception was re-raised with the + traceback it had when it was caught. + .. _break: The :keyword:`!break` statement diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 959978c2a3ab2f..cb706ead8261f3 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -181,6 +181,12 @@ Other CPython Implementation Changes hash-based pyc files now use ``siphash13``, too. (Contributed by Inada Naoki in :issue:`29410`.) +* When an active exception is re-raised by a :keyword:`raise` statement with no parameters, + the traceback attached to this exception is now always ``sys.exc_info()[1].__traceback__``. + This means that changes made to the traceback in the current :keyword:`except` clause are + reflected in the re-raised exception. + (Contributed by Irit Katriel in :issue:`45711`.) + New Modules =========== diff --git a/Python/ceval.c b/Python/ceval.c index 9beb1a4368226c..a893be0cf67924 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -5920,20 +5920,17 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause) if (exc == NULL) { /* Reraise */ _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); - PyObject *tb; - type = exc_info->exc_type; value = exc_info->exc_value; - tb = exc_info->exc_traceback; - assert(((Py_IsNone(value) || value == NULL)) == - ((Py_IsNone(type) || type == NULL))); if (Py_IsNone(value) || value == NULL) { _PyErr_SetString(tstate, PyExc_RuntimeError, "No active exception to reraise"); return 0; } + assert(PyExceptionInstance_Check(value)); + type = PyExceptionInstance_Class(value); Py_XINCREF(type); Py_XINCREF(value); - Py_XINCREF(tb); + PyObject *tb = PyException_GetTraceback(value); /* new ref */ _PyErr_Restore(tstate, type, value, tb); return 1; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy