Skip to content

Commit a3480ec

Browse files
authored
[3.11] gh-99103: Normalize specialized traceback anchors against the current line (#99423)
[3.11] gh-99103: Normalize specialized traceback anchors against the current line (GH-99145) Automerge-Triggered-By: GH:isidentical. (cherry picked from commit 57be545) Co-authored-by: Batuhan Taskaya <isidentical@gmail.com>
1 parent 2d5f4ba commit a3480ec

File tree

4 files changed

+51
-5
lines changed

4 files changed

+51
-5
lines changed

Lib/test/test_traceback.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,23 @@ def f_with_binary_operator():
532532
result_lines = self.get_exception(f_with_binary_operator)
533533
self.assertEqual(result_lines, expected_error.splitlines())
534534

535+
def test_caret_for_binary_operators_with_unicode(self):
536+
def f_with_binary_operator():
537+
áóí = 20
538+
return 10 + áóí / 0 + 30
539+
540+
lineno_f = f_with_binary_operator.__code__.co_firstlineno
541+
expected_error = (
542+
'Traceback (most recent call last):\n'
543+
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
544+
' callable()\n'
545+
f' File "{__file__}", line {lineno_f+2}, in f_with_binary_operator\n'
546+
' return 10 + áóí / 0 + 30\n'
547+
' ~~~~^~~\n'
548+
)
549+
result_lines = self.get_exception(f_with_binary_operator)
550+
self.assertEqual(result_lines, expected_error.splitlines())
551+
535552
def test_caret_for_binary_operators_two_char(self):
536553
def f_with_binary_operator():
537554
divisor = 20
@@ -566,6 +583,23 @@ def f_with_subscript():
566583
result_lines = self.get_exception(f_with_subscript)
567584
self.assertEqual(result_lines, expected_error.splitlines())
568585

586+
def test_caret_for_subscript_unicode(self):
587+
def f_with_subscript():
588+
some_dict = {'ó': {'á': {'í': {'theta': 1}}}}
589+
return some_dict['ó']['á']['í']['beta']
590+
591+
lineno_f = f_with_subscript.__code__.co_firstlineno
592+
expected_error = (
593+
'Traceback (most recent call last):\n'
594+
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
595+
' callable()\n'
596+
f' File "{__file__}", line {lineno_f+2}, in f_with_subscript\n'
597+
" return some_dict['ó']['á']['í']['beta']\n"
598+
' ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^\n'
599+
)
600+
result_lines = self.get_exception(f_with_subscript)
601+
self.assertEqual(result_lines, expected_error.splitlines())
602+
569603
def test_traceback_specialization_with_syntax_error(self):
570604
bytecode = compile("1 / 0 / 1 / 2\n", TESTFN, "exec")
571605

Lib/traceback.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -585,12 +585,15 @@ def _extract_caret_anchors_from_line_segment(segment):
585585
if len(tree.body) != 1:
586586
return None
587587

588+
normalize = lambda offset: _byte_offset_to_character_offset(segment, offset)
588589
statement = tree.body[0]
589590
match statement:
590591
case ast.Expr(expr):
591592
match expr:
592593
case ast.BinOp():
593-
operator_str = segment[expr.left.end_col_offset:expr.right.col_offset]
594+
operator_start = normalize(expr.left.end_col_offset)
595+
operator_end = normalize(expr.right.col_offset)
596+
operator_str = segment[operator_start:operator_end]
594597
operator_offset = len(operator_str) - len(operator_str.lstrip())
595598

596599
left_anchor = expr.left.end_col_offset + operator_offset
@@ -600,9 +603,11 @@ def _extract_caret_anchors_from_line_segment(segment):
600603
and not operator_str[operator_offset + 1].isspace()
601604
):
602605
right_anchor += 1
603-
return _Anchors(left_anchor, right_anchor)
606+
return _Anchors(normalize(left_anchor), normalize(right_anchor))
604607
case ast.Subscript():
605-
return _Anchors(expr.value.end_col_offset, expr.slice.end_col_offset + 1)
608+
subscript_start = normalize(expr.value.end_col_offset)
609+
subscript_end = normalize(expr.slice.end_col_offset + 1)
610+
return _Anchors(subscript_start, subscript_end)
606611

607612
return None
608613

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix the error reporting positions of specialized traceback anchors when the
2+
source line contains Unicode characters.

Python/traceback.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -705,8 +705,13 @@ extract_anchors_from_line(PyObject *filename, PyObject *line,
705705

706706
done:
707707
if (res > 0) {
708-
*left_anchor += start_offset;
709-
*right_anchor += start_offset;
708+
// Normalize the AST offsets to byte offsets and adjust them with the
709+
// start of the actual line (instead of the source code segment).
710+
assert(segment != NULL);
711+
assert(*left_anchor >= 0);
712+
assert(*right_anchor >= 0);
713+
*left_anchor = _PyPegen_byte_offset_to_character_offset(segment, *left_anchor) + start_offset;
714+
*right_anchor = _PyPegen_byte_offset_to_character_offset(segment, *right_anchor) + start_offset;
710715
}
711716
Py_XDECREF(segment);
712717
if (arena) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy