Support multi-line error locations in traceback and other related improvements (PEP-657, 3.11)
Feature or enhancement
We propose a few improvements and fixes to PEP-657, namely:
- Support underlining errors that span across multiple lines instead of only showing the first line
- Use caret anchors for function calls as well
- Fix bracket/binary op heuristic in the caret anchor computation function
Pitch
We already implemented these items in PyTorch here: pytorch/pytorch#104676. We're seeing if these may be worth adding to CPython.
Rationale for 1
Multi-line expressions can negate the utility of PEP-657, for example:
really_long_expr_1 = 1 really_long_expr_2 = 2 really_long_expr_3 = 0 really_long_expr_4 = 4 y = ( ( really_long_expr_1 + really_long_expr_2 ) / really_long_expr_2 / really_long_expr_3 )
Current traceback:
Traceback (most recent call last):
File "/scratch/williamwen/work/pytorch/playground5.py", line 25, in <module>
(
ZeroDivisionError: float division by zero
Better traceback:
Traceback (most recent call last):
File "/scratch/williamwen/work/pytorch/playground5.py", line 25, in <module>
(
~
really_long_expr_1 +
~~~~~~~~~~~~~~~~~~~~
really_long_expr_2
~~~~~~~~~~~~~~~~~~
) /
~~^
really_long_expr_2 /
~~~~~~~~~~~~~~~~~~
ZeroDivisionError: float division by zero
Rationale for 2
Helpful for identifying function calls that cause errors in chained function calls. We may as well do it since we're already doing it for subscripts. For example:
def f1(x1): def f2(x2): raise RuntimeError() return f2 y = f1(1)(2)(3)
Current traceback:
Traceback (most recent call last):
File "/scratch/williamwen/work/pytorch/playground5.py", line 22, in <module>
y = f1(1)(2)(3)
^^^^^^^^
File "/scratch/williamwen/work/pytorch/playground5.py", line 6, in f2
raise RuntimeError()
RuntimeError
Better traceback:
Traceback (most recent call last):
File "/scratch/williamwen/work/pytorch/playground5.py", line 22, in <module>
y = f1(1)(2)(3)
~~~~~^^^
File "/scratch/williamwen/work/pytorch/playground5.py", line 6, in f2
raise RuntimeError()
RuntimeError
Rationale for 3
The binary op anchors are computed by taking the next non-space character after the left subexpression. This is incorrect in some simple cases:
x = (3) / 0
~~^~~~~
ZeroDivisionError: division by zero
We should expect
x = (3) / 0
~~~~^~~
ZeroDivisionError: division by zero
The fix is that we should continue advancing the anchor until we find a non-space character that is also not in )\# (for \#, we should move the anchor to the next line).
Subscript has a similar issue as well. We should continue advancing the left anchor until we find [, and the right anchor should be the end of the entire subscript expression.
cc @pablogsal @isidentical @ammaraskar @iritkatriel @ezyang
Linked PRs
- gh-106922: Fix error location for constructs with spaces and parentheses #108959
- [3.12] gh-106922: Fix error location for constructs with spaces and parentheses (GH-108959) #109147
- [3.11] gh-106922: Fix error location for constructs with spaces and parentheses (GH-108959) #109148
- gh-106922: Support multi-line error locations in traceback #109589
- gh-106922: Support multi-line error locations in traceback (attempt 2) #112097