mirror of
https://github.com/python/cpython.git
synced 2025-08-03 00:23:06 +00:00
gh-128799: Add frame of except* to traceback when wrapping a naked exception (#128971)
This commit is contained in:
parent
9e52e553f4
commit
c39ae8922b
7 changed files with 44 additions and 6 deletions
|
@ -264,7 +264,7 @@ PyAPI_DATA(const size_t) _Py_FunctionAttributeOffsets[];
|
||||||
|
|
||||||
PyAPI_FUNC(int) _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right);
|
PyAPI_FUNC(int) _PyEval_CheckExceptStarTypeValid(PyThreadState *tstate, PyObject* right);
|
||||||
PyAPI_FUNC(int) _PyEval_CheckExceptTypeValid(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_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_FormatExcCheckArg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj);
|
||||||
PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg);
|
PyAPI_FUNC(void) _PyEval_FormatExcUnbound(PyThreadState *tstate, PyCodeObject *co, int oparg);
|
||||||
|
|
|
@ -2937,6 +2937,33 @@ class BaseExceptionReportingTests:
|
||||||
report = self.get_report(exc)
|
report = self.get_report(exc)
|
||||||
self.assertEqual(report, expected)
|
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):
|
def test_KeyboardInterrupt_at_first_line_of_frame(self):
|
||||||
# see GH-93249
|
# see GH-93249
|
||||||
def f():
|
def f():
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add frame of ``except*`` to traceback when it wraps a naked exception.
|
|
@ -2717,7 +2717,7 @@ dummy_func(
|
||||||
|
|
||||||
PyObject *match_o = NULL;
|
PyObject *match_o = NULL;
|
||||||
PyObject *rest_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);
|
&match_o, &rest_o);
|
||||||
DECREF_INPUTS();
|
DECREF_INPUTS();
|
||||||
ERROR_IF(res < 0, error);
|
ERROR_IF(res < 0, error);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "pycore_range.h" // _PyRangeIterObject
|
#include "pycore_range.h" // _PyRangeIterObject
|
||||||
#include "pycore_setobject.h" // _PySet_Update()
|
#include "pycore_setobject.h" // _PySet_Update()
|
||||||
#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
|
#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
|
||||||
|
#include "pycore_traceback.h" // _PyTraceBack_FromFrame
|
||||||
#include "pycore_tuple.h" // _PyTuple_ITEMS()
|
#include "pycore_tuple.h" // _PyTuple_ITEMS()
|
||||||
#include "pycore_uop_ids.h" // Uops
|
#include "pycore_uop_ids.h" // Uops
|
||||||
#include "pycore_pyerrors.h"
|
#include "pycore_pyerrors.h"
|
||||||
|
@ -2074,8 +2075,8 @@ raise_error:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type,
|
_PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value,
|
||||||
PyObject **match, PyObject **rest)
|
PyObject *match_type, PyObject **match, PyObject **rest)
|
||||||
{
|
{
|
||||||
if (Py_IsNone(exc_value)) {
|
if (Py_IsNone(exc_value)) {
|
||||||
*match = Py_NewRef(Py_None);
|
*match = Py_NewRef(Py_None);
|
||||||
|
@ -2101,6 +2102,15 @@ _PyEval_ExceptionGroupMatch(PyObject* exc_value, PyObject *match_type,
|
||||||
if (wrapped == NULL) {
|
if (wrapped == NULL) {
|
||||||
return -1;
|
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;
|
*match = wrapped;
|
||||||
}
|
}
|
||||||
*rest = Py_NewRef(Py_None);
|
*rest = Py_NewRef(Py_None);
|
||||||
|
|
2
Python/executor_cases.c.h
generated
2
Python/executor_cases.c.h
generated
|
@ -3452,7 +3452,7 @@
|
||||||
PyObject *match_o = NULL;
|
PyObject *match_o = NULL;
|
||||||
PyObject *rest_o = NULL;
|
PyObject *rest_o = NULL;
|
||||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
_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);
|
&match_o, &rest_o);
|
||||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||||
PyStackRef_CLOSE(exc_value_st);
|
PyStackRef_CLOSE(exc_value_st);
|
||||||
|
|
2
Python/generated_cases.c.h
generated
2
Python/generated_cases.c.h
generated
|
@ -3201,7 +3201,7 @@
|
||||||
PyObject *match_o = NULL;
|
PyObject *match_o = NULL;
|
||||||
PyObject *rest_o = NULL;
|
PyObject *rest_o = NULL;
|
||||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
_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);
|
&match_o, &rest_o);
|
||||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||||
PyStackRef_CLOSE(exc_value_st);
|
PyStackRef_CLOSE(exc_value_st);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue