]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-128799: Add frame of except* to traceback when wrapping a naked exception...
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>
Thu, 30 Jan 2025 12:02:46 +0000 (12:02 +0000)
committerGitHub <noreply@github.com>
Thu, 30 Jan 2025 12:02:46 +0000 (12:02 +0000)
Lib/test/test_traceback.py
Misc/NEWS.d/next/Core_and_Builtins/2025-01-18-01-06-58.gh-issue-128799.vSNagk.rst [new file with mode: 0644]
Python/bytecodes.c
Python/ceval.c
Python/generated_cases.c.h

index 119143e4f3a009ffc364a4ac827a0b26ccea443d..86d509744517ada9f91d587d0ea954530b2f1d10 100644 (file)
@@ -2157,6 +2157,31 @@ class BaseExceptionReportingTests:
         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'  |   File "{__file__}", line {exc.__code__.co_firstlineno + 3}, in exc\n'
+                    f'  |     except* Exception as e:\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 (file)
index 0000000..eb2361b
--- /dev/null
@@ -0,0 +1 @@
+Add frame of ``except*`` to traceback when it wraps a naked exception.
index b307edd57dff56db663f3c170b1bdc910100e02e..6ee3bda6f703bfb9859f3b118f8618e25cfae79c 100644 (file)
@@ -2114,7 +2114,7 @@ dummy_func(
 
             match = NULL;
             rest = NULL;
-            int res = exception_group_match(exc_value, match_type,
+            int res = exception_group_match(frame, exc_value, match_type,
                                             &match, &rest);
             DECREF_INPUTS();
             ERROR_IF(res < 0, error);
index b979294b20ff6bded58762929d2eef1347db0f27..3985b52649cc827ccb4b919b1ed7cf7d06f6a32f 100644 (file)
@@ -20,6 +20,7 @@
 #include "pycore_range.h"         // _PyRangeIterObject
 #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_emscripten_signal.h"  // _Py_CHECK_EMSCRIPTEN_SIGNALS
@@ -544,6 +545,7 @@ fail:
 
 static int do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause);
 static int exception_group_match(
+    _PyInterpreterFrame *frame,
     PyObject* exc_value, PyObject *match_type,
     PyObject **match, PyObject **rest);
 
@@ -1856,7 +1858,7 @@ raise_error:
 */
 
 static int
-exception_group_match(PyObject* exc_value, PyObject *match_type,
+exception_group_match(_PyInterpreterFrame *frame, PyObject* exc_value, PyObject *match_type,
                       PyObject **match, PyObject **rest)
 {
     if (Py_IsNone(exc_value)) {
@@ -1883,6 +1885,15 @@ exception_group_match(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);
index bbaf589e2ef82c9fa3ef5f274f0061abf8368395..246d37e771e3c30845d726f9dc24b956e82a7568 100644 (file)
 
             match = NULL;
             rest = NULL;
-            int res = exception_group_match(exc_value, match_type,
+            int res = exception_group_match(frame, exc_value, match_type,
                                             &match, &rest);
             #line 2958 "Python/generated_cases.c.h"
             Py_DECREF(exc_value);