From 73f520d3c1890b1f9434ebf52d28ece37a936686 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sat, 25 Jan 2025 13:00:23 +0000 Subject: [PATCH 1/4] gh-128799: Add frame of except* to traceback when wrapping a naked exception (#128971) (cherry picked from commit c39ae8922bad3e5ceeafa05891536c1584b6f3db) --- Include/internal/pycore_ceval.h | 2 +- Lib/test/test_traceback.py | 27 +++++++++++++++++++ ...-01-18-01-06-58.gh-issue-128799.vSNagk.rst | 1 + Python/bytecodes.c | 2 +- Python/ceval.c | 14 ++++++++-- Python/executor_cases.c.h | 2 +- Python/generated_cases.c.h | 2 +- 7 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-01-18-01-06-58.gh-issue-128799.vSNagk.rst diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 043f5957d481e5..746b21ba744596 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -247,7 +247,7 @@ PyAPI_DATA(const conversion_func) _PyEval_ConversionFuncs[]; PyAPI_FUNC(int) _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right); PyAPI_FUNC(int) _PyEval_CheckExceptTypeValid(PyThreadState *tstate, PyObject* right); -PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); +PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *, PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); PyAPI_FUNC(void) _PyEval_FormatAwaitableError(PyThreadState *tstate, PyTypeObject *type, int oparg); PyAPI_FUNC(void) _PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj); PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg); diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 2f543bccf566d5..f89fe8b26dc1bf 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -2938,6 +2938,33 @@ def exc(): report = self.get_report(exc) self.assertEqual(report, expected) + def test_exception_group_wrapped_naked(self): + # See gh-128799 + + def exc(): + try: + raise Exception(42) + except* Exception as e: + raise + + expected = (f' + Exception Group Traceback (most recent call last):\n' + f' | File "{__file__}", line {self.callable_line}, in get_exception\n' + f' | exception_or_callable()\n' + f' | ~~~~~~~~~~~~~~~~~~~~~^^\n' + f' | File "{__file__}", line {exc.__code__.co_firstlineno + 3}, in exc\n' + f' | except* Exception as e:\n' + f' | raise\n' + f' | ExceptionGroup: (1 sub-exception)\n' + f' +-+---------------- 1 ----------------\n' + f' | Traceback (most recent call last):\n' + f' | File "{__file__}", line {exc.__code__.co_firstlineno + 2}, in exc\n' + f' | raise Exception(42)\n' + f' | Exception: 42\n' + f' +------------------------------------\n') + + report = self.get_report(exc) + self.assertEqual(report, expected) + def test_KeyboardInterrupt_at_first_line_of_frame(self): # see GH-93249 def f(): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-18-01-06-58.gh-issue-128799.vSNagk.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-18-01-06-58.gh-issue-128799.vSNagk.rst new file mode 100644 index 00000000000000..eb2361bb5d4525 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-18-01-06-58.gh-issue-128799.vSNagk.rst @@ -0,0 +1 @@ +Add frame of ``except*`` to traceback when it wraps a naked exception. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1e6185d3c9e489..e9aec83d30b512 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2340,7 +2340,7 @@ dummy_func( match = NULL; rest = NULL; - int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, + int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, &match, &rest); DECREF_INPUTS(); ERROR_IF(res < 0, error); diff --git a/Python/ceval.c b/Python/ceval.c index 2f67d40874ba41..fe5dfc9b98a5d9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -27,6 +27,7 @@ #include "pycore_setobject.h" // _PySet_Update() #include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs #include "pycore_sysmodule.h" // _PySys_Audit() +#include "pycore_traceback.h" // _PyTraceBack_FromFrame #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_typeobject.h" // _PySuper_Lookup() #include "pycore_uop_ids.h" // Uops @@ -1991,8 +1992,8 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause) */ int -_PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, - PyObject **match, PyObject **rest) +_PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value, + PyObject *match_type, PyObject **match, PyObject **rest) { if (Py_IsNone(exc_value)) { *match = Py_NewRef(Py_None); @@ -2018,6 +2019,15 @@ _PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, if (wrapped == NULL) { return -1; } + PyFrameObject *f = _PyFrame_GetFrameObject(frame); + if (f != NULL) { + PyObject *tb = _PyTraceBack_FromFrame(NULL, f); + if (tb == NULL) { + return -1; + } + PyException_SetTraceback(wrapped, tb); + Py_DECREF(tb); + } *match = wrapped; } *rest = Py_NewRef(Py_None); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index df7c19a80e40c5..b7a36c2031cccb 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2447,7 +2447,7 @@ } match = NULL; rest = NULL; - int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, + int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, &match, &rest); Py_DECREF(exc_value); Py_DECREF(match_type); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 1488e4215cf579..73e36182759425 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2109,7 +2109,7 @@ } match = NULL; rest = NULL; - int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, + int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, &match, &rest); Py_DECREF(exc_value); Py_DECREF(match_type); From ac173b7bab737bb521867d9fe827e83db12438af Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 29 Jan 2025 23:35:27 +0000 Subject: [PATCH 2/4] avoid changing ABI --- Include/internal/pycore_ceval.h | 3 ++- Python/bytecodes.c | 4 ++-- Python/ceval.c | 14 ++++++++++++-- Python/executor_cases.c.h | 2 +- Python/generated_cases.c.h | 2 +- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 746b21ba744596..27f158209657fa 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -247,7 +247,7 @@ PyAPI_DATA(const conversion_func) _PyEval_ConversionFuncs[]; PyAPI_FUNC(int) _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right); PyAPI_FUNC(int) _PyEval_CheckExceptTypeValid(PyThreadState *tstate, PyObject* right); -PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *, PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); +PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); PyAPI_FUNC(void) _PyEval_FormatAwaitableError(PyThreadState *tstate, PyTypeObject *type, int oparg); PyAPI_FUNC(void) _PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj); PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg); @@ -258,6 +258,7 @@ PyAPI_FUNC(int) _PyEval_UnpackIterable(PyThreadState *tstate, PyObject *v, int a PyAPI_FUNC(void) _PyEval_MonitorRaise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); PyAPI_FUNC(void) _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame); +extern int _Py_exception_group_match(_PyInterpreterFrame *frame, PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); /* Bits that can be set in PyThreadState.eval_breaker */ #define _PY_GIL_DROP_REQUEST_BIT (1U << 0) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e9aec83d30b512..2584150ac086e3 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2340,8 +2340,8 @@ dummy_func( match = NULL; rest = NULL; - int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, - &match, &rest); + int res = _Py_exception_group_match(frame, exc_value, match_type, + &match, &rest); DECREF_INPUTS(); ERROR_IF(res < 0, error); diff --git a/Python/ceval.c b/Python/ceval.c index fe5dfc9b98a5d9..19bfa38db3c672 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1992,8 +1992,8 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause) */ int -_PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value, - PyObject *match_type, PyObject **match, PyObject **rest) +_Py_exception_group_match(_PyInterpreterFrame *frame, PyObject* exc_value, + PyObject *match_type, PyObject **match, PyObject **rest) { if (Py_IsNone(exc_value)) { *match = Py_NewRef(Py_None); @@ -2073,6 +2073,16 @@ _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value, return 0; } +int +_PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, + PyObject **match, PyObject **rest) +{ + PyThreadState *tstate = _PyThreadState_GET(); + _PyInterpreterFrame *frame = _PyThreadState_GetFrame(tstate); + return _Py_exception_group_match(frame, exc_value, match_type, match, rest); +} + + /* Iterate v argcnt times and store the results on the stack (via decreasing sp). Return 1 for success, 0 if error. diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index b7a36c2031cccb..ceed18fd0cb862 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2447,7 +2447,7 @@ } match = NULL; rest = NULL; - int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, + int res = _Py_exception_group_match(frame, exc_value, match_type, &match, &rest); Py_DECREF(exc_value); Py_DECREF(match_type); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 73e36182759425..08b8ebe585cd6d 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2109,7 +2109,7 @@ } match = NULL; rest = NULL; - int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, + int res = _Py_exception_group_match(frame, exc_value, match_type, &match, &rest); Py_DECREF(exc_value); Py_DECREF(match_type); From 078036e72618db0b152a62e1840bb5e2ff21752d Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 30 Jan 2025 11:12:43 +0000 Subject: [PATCH 3/4] Revert "avoid changing ABI" This reverts commit ac173b7bab737bb521867d9fe827e83db12438af. --- Include/internal/pycore_ceval.h | 3 +-- Python/bytecodes.c | 4 ++-- Python/ceval.c | 14 ++------------ Python/executor_cases.c.h | 2 +- Python/generated_cases.c.h | 2 +- 5 files changed, 7 insertions(+), 18 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 27f158209657fa..746b21ba744596 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -247,7 +247,7 @@ PyAPI_DATA(const conversion_func) _PyEval_ConversionFuncs[]; PyAPI_FUNC(int) _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right); PyAPI_FUNC(int) _PyEval_CheckExceptTypeValid(PyThreadState *tstate, PyObject* right); -PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); +PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *, PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); PyAPI_FUNC(void) _PyEval_FormatAwaitableError(PyThreadState *tstate, PyTypeObject *type, int oparg); PyAPI_FUNC(void) _PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj); PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg); @@ -258,7 +258,6 @@ PyAPI_FUNC(int) _PyEval_UnpackIterable(PyThreadState *tstate, PyObject *v, int a PyAPI_FUNC(void) _PyEval_MonitorRaise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); PyAPI_FUNC(void) _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame); -extern int _Py_exception_group_match(_PyInterpreterFrame *frame, PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); /* Bits that can be set in PyThreadState.eval_breaker */ #define _PY_GIL_DROP_REQUEST_BIT (1U << 0) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 2584150ac086e3..e9aec83d30b512 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2340,8 +2340,8 @@ dummy_func( match = NULL; rest = NULL; - int res = _Py_exception_group_match(frame, exc_value, match_type, - &match, &rest); + int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, + &match, &rest); DECREF_INPUTS(); ERROR_IF(res < 0, error); diff --git a/Python/ceval.c b/Python/ceval.c index 19bfa38db3c672..fe5dfc9b98a5d9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1992,8 +1992,8 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause) */ int -_Py_exception_group_match(_PyInterpreterFrame *frame, PyObject* exc_value, - PyObject *match_type, PyObject **match, PyObject **rest) +_PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value, + PyObject *match_type, PyObject **match, PyObject **rest) { if (Py_IsNone(exc_value)) { *match = Py_NewRef(Py_None); @@ -2073,16 +2073,6 @@ _Py_exception_group_match(_PyInterpreterFrame *frame, PyObject* exc_value, return 0; } -int -_PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, - PyObject **match, PyObject **rest) -{ - PyThreadState *tstate = _PyThreadState_GET(); - _PyInterpreterFrame *frame = _PyThreadState_GetFrame(tstate); - return _Py_exception_group_match(frame, exc_value, match_type, match, rest); -} - - /* Iterate v argcnt times and store the results on the stack (via decreasing sp). Return 1 for success, 0 if error. diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index ceed18fd0cb862..b7a36c2031cccb 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2447,7 +2447,7 @@ } match = NULL; rest = NULL; - int res = _Py_exception_group_match(frame, exc_value, match_type, + int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, &match, &rest); Py_DECREF(exc_value); Py_DECREF(match_type); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 08b8ebe585cd6d..73e36182759425 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2109,7 +2109,7 @@ } match = NULL; rest = NULL; - int res = _Py_exception_group_match(frame, exc_value, match_type, + int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, &match, &rest); Py_DECREF(exc_value); Py_DECREF(match_type); From 49eb82d3b8848d62adc7f5a0ce41206c2c571644 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 30 Jan 2025 11:25:40 +0000 Subject: [PATCH 4/4] do not change signature --- Include/internal/pycore_ceval.h | 2 +- Python/bytecodes.c | 2 +- Python/ceval.c | 6 ++++-- Python/executor_cases.c.h | 2 +- Python/generated_cases.c.h | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 746b21ba744596..043f5957d481e5 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -247,7 +247,7 @@ PyAPI_DATA(const conversion_func) _PyEval_ConversionFuncs[]; PyAPI_FUNC(int) _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right); PyAPI_FUNC(int) _PyEval_CheckExceptTypeValid(PyThreadState *tstate, PyObject* right); -PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *, PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); +PyAPI_FUNC(int) _PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); PyAPI_FUNC(void) _PyEval_FormatAwaitableError(PyThreadState *tstate, PyTypeObject *type, int oparg); PyAPI_FUNC(void) _PyEval_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj); PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e9aec83d30b512..1e6185d3c9e489 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2340,7 +2340,7 @@ dummy_func( match = NULL; rest = NULL; - int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, + int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, &match, &rest); DECREF_INPUTS(); ERROR_IF(res < 0, error); diff --git a/Python/ceval.c b/Python/ceval.c index fe5dfc9b98a5d9..763c8688266f9d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1992,8 +1992,8 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause) */ int -_PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value, - PyObject *match_type, PyObject **match, PyObject **rest) +_PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type, + PyObject **match, PyObject **rest) { if (Py_IsNone(exc_value)) { *match = Py_NewRef(Py_None); @@ -2019,6 +2019,8 @@ _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value, if (wrapped == NULL) { return -1; } + PyThreadState *tstate = _PyThreadState_GET(); + _PyInterpreterFrame *frame = _PyThreadState_GetFrame(tstate); PyFrameObject *f = _PyFrame_GetFrameObject(frame); if (f != NULL) { PyObject *tb = _PyTraceBack_FromFrame(NULL, f); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index b7a36c2031cccb..df7c19a80e40c5 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2447,7 +2447,7 @@ } match = NULL; rest = NULL; - int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, + int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, &match, &rest); Py_DECREF(exc_value); Py_DECREF(match_type); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 73e36182759425..1488e4215cf579 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2109,7 +2109,7 @@ } match = NULL; rest = NULL; - int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type, + int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, &match, &rest); Py_DECREF(exc_value); Py_DECREF(match_type); 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