From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Mon, 30 Sep 2024 01:13:36 +0000 (+0200) Subject: [3.13] gh-122145: Handle an empty AST body when reporting tracebacks (GH-122161)... X-Git-Tag: v3.13.0rc3~24 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=99dc0893c7e680a3d6b7c2a917a569681b95b8de;p=thirdparty%2FPython%2Fcpython.git [3.13] gh-122145: Handle an empty AST body when reporting tracebacks (GH-122161) (#124214) gh-122145: Handle an empty AST body when reporting tracebacks (GH-122161) (cherry picked from commit 5cd50cb6eb28e525f0c838e049e900ea982a5a23) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 574d5dab97b5..a78aded4ccf7 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -3304,6 +3304,41 @@ class TestStack(unittest.TestCase): f' File "{__file__}", line {lno}, in f\n 1/0\n' ) + def test_summary_should_show_carets(self): + # See: https://github.com/python/cpython/issues/122353 + + # statement to execute and to get a ZeroDivisionError for a traceback + statement = "abcdef = 1 / 0 and 2.0" + colno = statement.index('1 / 0') + end_colno = colno + len('1 / 0') + + # Actual line to use when rendering the traceback + # and whose AST will be extracted (it will be empty). + cached_line = '# this line will be used during rendering' + self.addCleanup(unlink, TESTFN) + with open(TESTFN, "w") as file: + file.write(cached_line) + linecache.updatecache(TESTFN, {}) + + try: + exec(compile(statement, TESTFN, "exec")) + except ZeroDivisionError as exc: + # This is the simplest way to create a StackSummary + # whose FrameSummary items have their column offsets. + s = traceback.TracebackException.from_exception(exc).stack + self.assertIsInstance(s, traceback.StackSummary) + with unittest.mock.patch.object(s, '_should_show_carets', + wraps=s._should_show_carets) as ff: + self.assertEqual(len(s), 2) + self.assertListEqual( + s.format_frame_summary(s[1]).splitlines(), + [ + f' File "{TESTFN}", line 1, in ', + f' {cached_line}' + ] + ) + ff.assert_called_with(colno, end_colno, [cached_line], None) + class Unrepresentable: def __repr__(self) -> str: raise Exception("Unrepresentable") diff --git a/Lib/traceback.py b/Lib/traceback.py index 3e708c6f86a4..0fe7187a0c61 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -698,6 +698,8 @@ class StackSummary(list): with suppress(SyntaxError, ImportError): import ast tree = ast.parse('\n'.join(all_lines)) + if not tree.body: + return False statement = tree.body[0] value = None def _spawns_full_line(value): diff --git a/Misc/NEWS.d/next/Library/2024-07-23-12-38-14.gh-issue-122145.sTO8nX.rst b/Misc/NEWS.d/next/Library/2024-07-23-12-38-14.gh-issue-122145.sTO8nX.rst new file mode 100644 index 000000000000..a4282f12d974 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-07-23-12-38-14.gh-issue-122145.sTO8nX.rst @@ -0,0 +1,3 @@ +Fix an issue when reporting tracebacks corresponding to Python code +emitting an empty AST body. +Patch by Nikita Sobolev and Bénédikt Tran.