Skip to content

Commit 4a08a75

Browse files
authored
gh-99180: Remove traceback anchors in return and assign statements that cover all the displayed range (#112670)
1 parent c1bf487 commit 4a08a75

File tree

3 files changed

+240
-33
lines changed

3 files changed

+240
-33
lines changed

Lib/test/test_traceback.py

Lines changed: 205 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,6 @@ def f_with_multiline():
695695
' ~~~~~~~~^^\n'
696696
f' File "{__file__}", line {lineno_f+2}, in f_with_multiline\n'
697697
' return compile(code, "?", "exec")\n'
698-
' ~~~~~~~^^^^^^^^^^^^^^^^^^^\n'
699698
' File "?", line 7\n'
700699
' foo(a, z\n'
701700
' ^'
@@ -785,8 +784,8 @@ def f_with_binary_operator():
785784
def test_caret_for_binary_operators_with_spaces_and_parenthesis(self):
786785
def f_with_binary_operator():
787786
a = 1
788-
b = ""
789-
return ( a ) +b
787+
b = c = ""
788+
return ( a ) +b + c
790789

791790
lineno_f = f_with_binary_operator.__code__.co_firstlineno
792791
expected_error = (
@@ -795,7 +794,7 @@ def f_with_binary_operator():
795794
' callable()\n'
796795
' ~~~~~~~~^^\n'
797796
f' File "{__file__}", line {lineno_f+3}, in f_with_binary_operator\n'
798-
' return ( a ) +b\n'
797+
' return ( a ) +b + c\n'
799798
' ~~~~~~~~~~^~\n'
800799
)
801800
result_lines = self.get_exception(f_with_binary_operator)
@@ -983,7 +982,7 @@ def f1(a):
983982
def f2(b):
984983
raise RuntimeError("fail")
985984
return f2
986-
return f1("x")("y")
985+
return f1("x")("y")("z")
987986

988987
lineno_f = f_with_call.__code__.co_firstlineno
989988
expected_error = (
@@ -992,7 +991,7 @@ def f2(b):
992991
' callable()\n'
993992
' ~~~~~~~~^^\n'
994993
f' File "{__file__}", line {lineno_f+5}, in f_with_call\n'
995-
' return f1("x")("y")\n'
994+
' return f1("x")("y")("z")\n'
996995
' ~~~~~~~^^^^^\n'
997996
f' File "{__file__}", line {lineno_f+3}, in f2\n'
998997
' raise RuntimeError("fail")\n'
@@ -1507,6 +1506,184 @@ def f():
15071506
' raise MemoryError()']
15081507
self.assertEqual(actual, expected)
15091508

1509+
def test_anchors_for_simple_return_statements_are_elided(self):
1510+
def g():
1511+
1/0
1512+
1513+
def f():
1514+
return g()
1515+
1516+
result_lines = self.get_exception(f)
1517+
expected = ['Traceback (most recent call last):',
1518+
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
1519+
" callable()",
1520+
" ~~~~~~~~^^",
1521+
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f",
1522+
" return g()",
1523+
f" File \"{__file__}\", line {g.__code__.co_firstlineno + 1}, in g",
1524+
" 1/0",
1525+
" ~^~"
1526+
]
1527+
self.assertEqual(result_lines, expected)
1528+
1529+
def g():
1530+
1/0
1531+
1532+
def f():
1533+
return g() + 1
1534+
1535+
result_lines = self.get_exception(f)
1536+
expected = ['Traceback (most recent call last):',
1537+
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
1538+
" callable()",
1539+
" ~~~~~~~~^^",
1540+
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f",
1541+
" return g() + 1",
1542+
" ~^^",
1543+
f" File \"{__file__}\", line {g.__code__.co_firstlineno + 1}, in g",
1544+
" 1/0",
1545+
" ~^~"
1546+
]
1547+
self.assertEqual(result_lines, expected)
1548+
1549+
def g(*args):
1550+
1/0
1551+
1552+
def f():
1553+
return g(1,
1554+
2, 4,
1555+
5)
1556+
1557+
result_lines = self.get_exception(f)
1558+
expected = ['Traceback (most recent call last):',
1559+
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
1560+
" callable()",
1561+
" ~~~~~~~~^^",
1562+
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f",
1563+
" return g(1,",
1564+
" 2, 4,",
1565+
" 5)",
1566+
f" File \"{__file__}\", line {g.__code__.co_firstlineno + 1}, in g",
1567+
" 1/0",
1568+
" ~^~"
1569+
]
1570+
self.assertEqual(result_lines, expected)
1571+
1572+
def g(*args):
1573+
1/0
1574+
1575+
def f():
1576+
return g(1,
1577+
2, 4,
1578+
5) + 1
1579+
1580+
result_lines = self.get_exception(f)
1581+
expected = ['Traceback (most recent call last):',
1582+
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
1583+
" callable()",
1584+
" ~~~~~~~~^^",
1585+
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f",
1586+
" return g(1,",
1587+
" ~^^^",
1588+
" 2, 4,",
1589+
" ^^^^^",
1590+
" 5) + 1",
1591+
" ^^",
1592+
f" File \"{__file__}\", line {g.__code__.co_firstlineno + 1}, in g",
1593+
" 1/0",
1594+
" ~^~"
1595+
]
1596+
self.assertEqual(result_lines, expected)
1597+
1598+
def test_anchors_for_simple_assign_statements_are_elided(self):
1599+
def g():
1600+
1/0
1601+
1602+
def f():
1603+
x = g()
1604+
1605+
result_lines = self.get_exception(f)
1606+
expected = ['Traceback (most recent call last):',
1607+
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
1608+
" callable()",
1609+
" ~~~~~~~~^^",
1610+
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f",
1611+
" x = g()",
1612+
f" File \"{__file__}\", line {g.__code__.co_firstlineno + 1}, in g",
1613+
" 1/0",
1614+
" ~^~"
1615+
]
1616+
self.assertEqual(result_lines, expected)
1617+
1618+
def g(*args):
1619+
1/0
1620+
1621+
def f():
1622+
x = g(1,
1623+
2, 3,
1624+
4)
1625+
1626+
result_lines = self.get_exception(f)
1627+
expected = ['Traceback (most recent call last):',
1628+
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
1629+
" callable()",
1630+
" ~~~~~~~~^^",
1631+
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f",
1632+
" x = g(1,",
1633+
" 2, 3,",
1634+
" 4)",
1635+
f" File \"{__file__}\", line {g.__code__.co_firstlineno + 1}, in g",
1636+
" 1/0",
1637+
" ~^~"
1638+
]
1639+
self.assertEqual(result_lines, expected)
1640+
1641+
def g():
1642+
1/0
1643+
1644+
def f():
1645+
x = y = g()
1646+
1647+
result_lines = self.get_exception(f)
1648+
expected = ['Traceback (most recent call last):',
1649+
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
1650+
" callable()",
1651+
" ~~~~~~~~^^",
1652+
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f",
1653+
" x = y = g()",
1654+
" ~^^",
1655+
f" File \"{__file__}\", line {g.__code__.co_firstlineno + 1}, in g",
1656+
" 1/0",
1657+
" ~^~"
1658+
]
1659+
self.assertEqual(result_lines, expected)
1660+
1661+
def g(*args):
1662+
1/0
1663+
1664+
def f():
1665+
x = y = g(1,
1666+
2, 3,
1667+
4)
1668+
1669+
result_lines = self.get_exception(f)
1670+
expected = ['Traceback (most recent call last):',
1671+
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
1672+
" callable()",
1673+
" ~~~~~~~~^^",
1674+
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f",
1675+
" x = y = g(1,",
1676+
" ~^^^",
1677+
" 2, 3,",
1678+
" ^^^^^",
1679+
" 4)",
1680+
" ^^",
1681+
f" File \"{__file__}\", line {g.__code__.co_firstlineno + 1}, in g",
1682+
" 1/0",
1683+
" ~^~"
1684+
]
1685+
self.assertEqual(result_lines, expected)
1686+
15101687

15111688
@requires_debug_ranges()
15121689
class PurePythonTracebackErrorCaretTests(
@@ -1701,7 +1878,7 @@ def f():
17011878
# Check a known (limited) number of recursive invocations
17021879
def g(count=10):
17031880
if count:
1704-
return g(count-1)
1881+
return g(count-1) + 1
17051882
raise ValueError
17061883

17071884
with captured_output("stderr") as stderr_g:
@@ -1715,13 +1892,13 @@ def g(count=10):
17151892
lineno_g = g.__code__.co_firstlineno
17161893
result_g = (
17171894
f' File "{__file__}", line {lineno_g+2}, in g\n'
1718-
' return g(count-1)\n'
1895+
' return g(count-1) + 1\n'
17191896
' ~^^^^^^^^^\n'
17201897
f' File "{__file__}", line {lineno_g+2}, in g\n'
1721-
' return g(count-1)\n'
1898+
' return g(count-1) + 1\n'
17221899
' ~^^^^^^^^^\n'
17231900
f' File "{__file__}", line {lineno_g+2}, in g\n'
1724-
' return g(count-1)\n'
1901+
' return g(count-1) + 1\n'
17251902
' ~^^^^^^^^^\n'
17261903
' [Previous line repeated 7 more times]\n'
17271904
f' File "{__file__}", line {lineno_g+3}, in g\n'
@@ -1760,13 +1937,10 @@ def h(count=10):
17601937
' ~^^\n'
17611938
f' File "{__file__}", line {lineno_h+2}, in h\n'
17621939
' return h(count-1)\n'
1763-
' ~^^^^^^^^^\n'
17641940
f' File "{__file__}", line {lineno_h+2}, in h\n'
17651941
' return h(count-1)\n'
1766-
' ~^^^^^^^^^\n'
17671942
f' File "{__file__}", line {lineno_h+2}, in h\n'
17681943
' return h(count-1)\n'
1769-
' ~^^^^^^^^^\n'
17701944
' [Previous line repeated 7 more times]\n'
17711945
f' File "{__file__}", line {lineno_h+3}, in h\n'
17721946
' g()\n'
@@ -1786,21 +1960,21 @@ def h(count=10):
17861960
self.fail("no error raised")
17871961
result_g = (
17881962
f' File "{__file__}", line {lineno_g+2}, in g\n'
1789-
' return g(count-1)\n'
1963+
' return g(count-1) + 1\n'
17901964
' ~^^^^^^^^^\n'
17911965
f' File "{__file__}", line {lineno_g+2}, in g\n'
1792-
' return g(count-1)\n'
1966+
' return g(count-1) + 1\n'
17931967
' ~^^^^^^^^^\n'
17941968
f' File "{__file__}", line {lineno_g+2}, in g\n'
1795-
' return g(count-1)\n'
1969+
' return g(count-1) + 1\n'
17961970
' ~^^^^^^^^^\n'
17971971
f' File "{__file__}", line {lineno_g+3}, in g\n'
17981972
' raise ValueError\n'
17991973
'ValueError\n'
18001974
)
18011975
tb_line = (
18021976
'Traceback (most recent call last):\n'
1803-
f' File "{__file__}", line {lineno_g+80}, in _check_recursive_traceback_display\n'
1977+
f' File "{__file__}", line {lineno_g+77}, in _check_recursive_traceback_display\n'
18041978
' g(traceback._RECURSIVE_CUTOFF)\n'
18051979
' ~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
18061980
)
@@ -1818,13 +1992,13 @@ def h(count=10):
18181992
self.fail("no error raised")
18191993
result_g = (
18201994
f' File "{__file__}", line {lineno_g+2}, in g\n'
1821-
' return g(count-1)\n'
1995+
' return g(count-1) + 1\n'
18221996
' ~^^^^^^^^^\n'
18231997
f' File "{__file__}", line {lineno_g+2}, in g\n'
1824-
' return g(count-1)\n'
1998+
' return g(count-1) + 1\n'
18251999
' ~^^^^^^^^^\n'
18262000
f' File "{__file__}", line {lineno_g+2}, in g\n'
1827-
' return g(count-1)\n'
2001+
' return g(count-1) + 1\n'
18282002
' ~^^^^^^^^^\n'
18292003
' [Previous line repeated 1 more time]\n'
18302004
f' File "{__file__}", line {lineno_g+3}, in g\n'
@@ -1833,7 +2007,7 @@ def h(count=10):
18332007
)
18342008
tb_line = (
18352009
'Traceback (most recent call last):\n'
1836-
f' File "{__file__}", line {lineno_g+112}, in _check_recursive_traceback_display\n'
2010+
f' File "{__file__}", line {lineno_g+109}, in _check_recursive_traceback_display\n'
18372011
' g(traceback._RECURSIVE_CUTOFF + 1)\n'
18382012
' ~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
18392013
)
@@ -4287,11 +4461,14 @@ def foo(*args):
42874461
x = {'a':{'b': None}}
42884462
y = x['a']['b']['c']
42894463

4290-
def baz(*args):
4291-
return foo(1,2,3,4)
4464+
def baz2(*args):
4465+
return (lambda *args: foo(*args))(1,2,3,4)
4466+
4467+
def baz1(*args):
4468+
return baz2(1,2,3,4)
42924469

42934470
def bar():
4294-
return baz(1,
4471+
return baz1(1,
42954472
2,3
42964473
,4)
42974474
try:
@@ -4305,10 +4482,10 @@ def bar():
43054482
boldr = traceback._ANSIColors.BOLD_RED
43064483
reset = traceback._ANSIColors.RESET
43074484
self.assertIn("y = " + red + "x['a']['b']" + reset + boldr + "['c']" + reset, lines)
4308-
self.assertIn("return " + red + "foo" + reset + boldr + "(1,2,3,4)" + reset, lines)
4309-
self.assertIn("return " + red + "baz" + reset + boldr + "(1," + reset, lines)
4310-
self.assertIn(boldr + "2,3" + reset, lines)
4311-
self.assertIn(boldr + ",4)" + reset, lines)
4485+
self.assertIn("return " + red + "(lambda *args: foo(*args))" + reset + boldr + "(1,2,3,4)" + reset, lines)
4486+
self.assertIn("return (lambda *args: " + red + "foo" + reset + boldr + "(*args)" + reset + ")(1,2,3,4)", lines)
4487+
self.assertIn("return baz2(1,2,3,4)", lines)
4488+
self.assertIn("return baz1(1,\n 2,3\n ,4)", lines)
43124489
self.assertIn(red + "bar" + reset + boldr + "()" + reset, lines)
43134490

43144491
def test_colorized_syntax_error(self):

0 commit comments

Comments
 (0)