diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 206e22e791e02a..10d34ab89723bd 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -260,7 +260,7 @@ def testSyntaxErrorOffset(self): check('class foo:return 1', 1, 11) check('def f():\n continue', 2, 3) check('def f():\n break', 2, 3) - check('try:\n pass\nexcept:\n pass\nexcept ValueError:\n pass', 3, 1) + check('try:\n pass\nexcept:\n pass\nexcept ValueError:\n pass', 3, 0) check('try:\n pass\nexcept*:\n pass', 3, 8) check('try:\n pass\nexcept*:\n pass\nexcept* ValueError:\n pass', 3, 8) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index abdfc4638f2e9c..60b7b026321c2f 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -2919,6 +2919,47 @@ def exc(): report = self.get_report(exc) self.assertEqual(report, expected) + def test_except_star_lineno(self): + def exc(): + class Bad(ExceptionGroup): + def split(*args): + 1/0 + + try: + raise Bad("", [ValueError(), TypeError()]) + except* ValueError: + 1 + 2 + 3 + + expected = (f' + Exception Group Traceback (most recent call last):\n' + f' | File "{__file__}", line {exc.__code__.co_firstlineno + 6}, in exc\n' + f' | raise Bad("", [ValueError(), TypeError()])\n' + f' | test.test_traceback.BaseExceptionReportingTests.test_except_star_lineno..exc..Bad: (2 sub-exceptions)\n' + f' +-+---------------- 1 ----------------\n' + f' | ValueError\n' + f' +---------------- 2 ----------------\n' + f' | TypeError\n' + f' +------------------------------------\n' + f'\n' + f'During handling of the above exception, another exception occurred:\n' + f'\n' + f'Traceback (most recent call last):\n' + f' File "{__file__}", line ' + f'{self.callable_line}, in get_exception\n' + f' exception_or_callable()\n' + f' ~~~~~~~~~~~~~~~~~~~~~^^\n' + f' File "{__file__}", line {exc.__code__.co_firstlineno + 7}, in exc\n' + f' except* ValueError:\n' + f' \n' + f' File "{__file__}", line {exc.__code__.co_firstlineno + 3}, in split\n' + f' 1/0\n' + f' ~^~\n' + f'ZeroDivisionError: division by zero\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-19-14-36-37.gh-issue-129025.QFXeS2.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-19-14-36-37.gh-issue-129025.QFXeS2.rst new file mode 100644 index 00000000000000..980cb19b6ced65 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-19-14-36-37.gh-issue-129025.QFXeS2.rst @@ -0,0 +1,2 @@ +Fix too wide source locations of instructions emitted for ``except`` and +``except*``. diff --git a/Python/codegen.c b/Python/codegen.c index 61707ba677097c..38e402d78d526f 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -2365,7 +2365,8 @@ codegen_try_except(compiler *c, stmt_ty s) for (i = 0; i < n; i++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( s->v.Try.handlers, i); - location loc = LOC(handler); + /* Set location to the entire line of the except keyword */ + location loc = LOCATION(handler->lineno, handler->lineno, 0, 0); if (!handler->v.ExceptHandler.type && i < n-1) { return _PyCompile_Error(c, loc, "default 'except:' must be last"); } @@ -2546,7 +2547,8 @@ codegen_try_star_except(compiler *c, stmt_ty s) for (Py_ssize_t i = 0; i < n; i++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( s->v.TryStar.handlers, i); - location loc = LOC(handler); + /* Set location to the entire line of the except keyword */ + location loc = LOCATION(handler->lineno, handler->lineno, 0, 0); NEW_JUMP_TARGET_LABEL(c, next_except); except = next_except; NEW_JUMP_TARGET_LABEL(c, except_with_error);