https://github.com/python/cpython/commit/c39ae8922bad3e5ceeafa05891536c1584b6f3db
commit: c39ae8922bad3e5ceeafa05891536c1584b6f3db
branch: main
author: Irit Katriel <[email protected]>
committer: iritkatriel <[email protected]>
date: 2025-01-25T13:00:23Z
summary:
gh-128799: Add frame of except* to traceback when wrapping a naked exception
(#128971)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-01-18-01-06-58.gh-issue-128799.vSNagk.rst
M Include/internal/pycore_ceval.h
M Lib/test/test_traceback.py
M Python/bytecodes.c
M Python/ceval.c
M Python/executor_cases.c.h
M Python/generated_cases.c.h
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index 80bd19a887871c..fea8665ae39ab5 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -264,7 +264,7 @@ PyAPI_DATA(const size_t) _Py_FunctionAttributeOffsets[];
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 867088a4c56bd7..89980ae6f8573a 100644
--- a/Lib/test/test_traceback.py
+++ b/Lib/test/test_traceback.py
@@ -2937,6 +2937,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 b70ed7f4d10b27..12aae969340cbd 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2717,7 +2717,7 @@ dummy_func(
PyObject *match_o = NULL;
PyObject *rest_o = NULL;
- int res = _PyEval_ExceptionGroupMatch(exc_value, match_type,
+ int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type,
&match_o, &rest_o);
DECREF_INPUTS();
ERROR_IF(res < 0, error);
diff --git a/Python/ceval.c b/Python/ceval.c
index 5469874e97828b..100f99ea8e35be 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -27,6 +27,7 @@
#include "pycore_range.h" // _PyRangeIterObject
#include "pycore_setobject.h" // _PySet_Update()
#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
+#include "pycore_traceback.h" // _PyTraceBack_FromFrame
#include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "pycore_uop_ids.h" // Uops
#include "pycore_pyerrors.h"
@@ -2074,8 +2075,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);
@@ -2101,6 +2102,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 d336f73c4a2de5..b253850e78ddbb 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -3452,7 +3452,7 @@
PyObject *match_o = NULL;
PyObject *rest_o = NULL;
_PyFrame_SetStackPointer(frame, stack_pointer);
- int res = _PyEval_ExceptionGroupMatch(exc_value, match_type,
+ int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type,
&match_o, &rest_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
PyStackRef_CLOSE(exc_value_st);
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 4fb3ce6f6da9cd..027849180a81ad 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -3201,7 +3201,7 @@
PyObject *match_o = NULL;
PyObject *rest_o = NULL;
_PyFrame_SetStackPointer(frame, stack_pointer);
- int res = _PyEval_ExceptionGroupMatch(exc_value, match_type,
+ int res = _PyEval_ExceptionGroupMatch(frame, exc_value, match_type,
&match_o, &rest_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
PyStackRef_CLOSE(exc_value_st);
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]