Skip to content

Commit

Permalink
pythongh-99103: Normalize positions of specialized traceback anchors …
Browse files Browse the repository at this point in the history
…against the current line
  • Loading branch information
isidentical committed Nov 12, 2022
1 parent c95f554 commit f5af20e
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 5 deletions.
34 changes: 34 additions & 0 deletions Lib/test/test_traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,23 @@ def f_with_binary_operator():
result_lines = self.get_exception(f_with_binary_operator)
self.assertEqual(result_lines, expected_error.splitlines())

def test_caret_for_binary_operators_with_unicode(self):
def f_with_binary_operator():
áóí = 20
return 10 + áóí / 0 + 30

lineno_f = f_with_binary_operator.__code__.co_firstlineno
expected_error = (
'Traceback (most recent call last):\n'
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
' callable()\n'
f' File "{__file__}", line {lineno_f+2}, in f_with_binary_operator\n'
' return 10 + áóí / 0 + 30\n'
' ~~~~^~~\n'
)
result_lines = self.get_exception(f_with_binary_operator)
self.assertEqual(result_lines, expected_error.splitlines())

def test_caret_for_binary_operators_two_char(self):
def f_with_binary_operator():
divisor = 20
Expand Down Expand Up @@ -593,6 +610,23 @@ def f_with_subscript():
result_lines = self.get_exception(f_with_subscript)
self.assertEqual(result_lines, expected_error.splitlines())

def test_caret_for_subscript_unicode(self):
def f_with_subscript():
some_dict = {'ó': {'á': {'í': {'theta': 1}}}}
return some_dict['ó']['á']['í']['beta']

lineno_f = f_with_subscript.__code__.co_firstlineno
expected_error = (
'Traceback (most recent call last):\n'
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
' callable()\n'
f' File "{__file__}", line {lineno_f+2}, in f_with_subscript\n'
" return some_dict['ó']['á']['í']['beta']\n"
' ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^\n'
)
result_lines = self.get_exception(f_with_subscript)
self.assertEqual(result_lines, expected_error.splitlines())

def test_traceback_specialization_with_syntax_error(self):
bytecode = compile("1 / 0 / 1 / 2\n", TESTFN, "exec")

Expand Down
7 changes: 4 additions & 3 deletions Lib/traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,12 +586,13 @@ def _extract_caret_anchors_from_line_segment(segment):
if len(tree.body) != 1:
return None

normalize = lambda offset: _byte_offset_to_character_offset(segment, offset)
statement = tree.body[0]
match statement:
case ast.Expr(expr):
match expr:
case ast.BinOp():
operator_str = segment[expr.left.end_col_offset:expr.right.col_offset]
operator_str = segment[normalize(expr.left.end_col_offset):normalize(expr.right.col_offset)]
operator_offset = len(operator_str) - len(operator_str.lstrip())

left_anchor = expr.left.end_col_offset + operator_offset
Expand All @@ -601,9 +602,9 @@ def _extract_caret_anchors_from_line_segment(segment):
and not operator_str[operator_offset + 1].isspace()
):
right_anchor += 1
return _Anchors(left_anchor, right_anchor)
return _Anchors(normalize(left_anchor), normalize(right_anchor))
case ast.Subscript():
return _Anchors(expr.value.end_col_offset, expr.slice.end_col_offset + 1)
return _Anchors(normalize(expr.value.end_col_offset), normalize(expr.slice.end_col_offset + 1))

return None

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix the error reporting positions of specialized traceback anchors when the
source line contains unicode characters.
7 changes: 5 additions & 2 deletions Python/traceback.c
Original file line number Diff line number Diff line change
Expand Up @@ -700,8 +700,11 @@ extract_anchors_from_line(PyObject *filename, PyObject *line,

done:
if (res > 0) {
*left_anchor += start_offset;
*right_anchor += start_offset;
// Normalize the AST offsets to byte offsets and adjust it with the
// start of the actual line (instead of the source code segment).
assert(segment != NULL);
*left_anchor = _PyPegen_byte_offset_to_character_offset(segment, *left_anchor) + start_offset;
*right_anchor = _PyPegen_byte_offset_to_character_offset(segment, *right_anchor) + start_offset;
}
Py_XDECREF(segment);
if (arena) {
Expand Down

0 comments on commit f5af20e

Please sign in to comment.