]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-122145: Handle an empty AST body when reporting tracebacks (#122161)
authorBénédikt Tran <10796600+picnixz@users.noreply.github.com>
Wed, 18 Sep 2024 16:42:33 +0000 (18:42 +0200)
committerGitHub <noreply@github.com>
Wed, 18 Sep 2024 16:42:33 +0000 (18:42 +0200)
Lib/test/test_traceback.py
Lib/traceback.py
Misc/NEWS.d/next/Library/2024-07-23-12-38-14.gh-issue-122145.sTO8nX.rst [new file with mode: 0644]

index b568221212d71fe44bb8d118d3cb1cd628335fd0..455fea034198a605a41083e5be795c7a468e4f28 100644 (file)
@@ -3307,6 +3307,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 <module>',
+                        f'    {cached_line}'
+                     ]
+                )
+                ff.assert_called_with(colno, end_colno, [cached_line], None)
+
 class Unrepresentable:
     def __repr__(self) -> str:
         raise Exception("Unrepresentable")
index 3e708c6f86a4c5acf0e501b7b81895d4d18bb214..0fe7187a0c619391f558b5290194837154bc5603 100644 (file)
@@ -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 (file)
index 0000000..a4282f1
--- /dev/null
@@ -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.