@@ -5442,6 +5442,66 @@ def expected(t, m, fn, l, f, E, e, z, n):
54425442 ]
54435443 self .assertEqual (actual [2 :4 ], expected (** colors ))
54445444
5445+ def test_colorized_syntax_error_ascii_display_width (self ):
5446+ """Caret alignment for ASCII edge cases handled by _wlen.
5447+
5448+ The old ASCII fast track in _display_width returned the raw character
5449+ offset for ASCII strings, which is wrong for CTRL-Z (display width 2)
5450+ and ANSI escape sequences (display width 0).
5451+ """
5452+ E = colors ["E" ]
5453+ z = colors ["z" ]
5454+ t = colors ["t" ]
5455+ m = colors ["m" ]
5456+ fn = colors ["fn" ]
5457+ l = colors ["l" ]
5458+
5459+ def _make_syntax_error (text , offset , end_offset ):
5460+ err = SyntaxError ("invalid syntax" )
5461+ err .filename = "<string>"
5462+ err .lineno = 1
5463+ err .end_lineno = 1
5464+ err .text = text
5465+ err .offset = offset
5466+ err .end_offset = end_offset
5467+ return err
5468+
5469+ # CTRL-Z (\x1a) is ASCII but displayed as ^Z (2 columns).
5470+ # Verify caret aligns when CTRL-Z precedes the error.
5471+ err = _make_syntax_error ("a\x1a $\n " , offset = 3 , end_offset = 4 )
5472+ exc = traceback .TracebackException .from_exception (err )
5473+ actual = "" .join (exc .format (colorize = True ))
5474+ # 'a' (1 col) + '\x1a' (2 cols) = 3 cols before '$'
5475+ self .assertIn (
5476+ f' File { fn } "<string>"{ z } , line { l } 1{ z } \n '
5477+ f' a\x1a { E } ${ z } \n '
5478+ f' { " " * 3 } { E } ^{ z } \n '
5479+ f'{ t } SyntaxError{ z } : { m } invalid syntax{ z } \n ' ,
5480+ actual ,
5481+ )
5482+
5483+ # CTRL-Z in the highlighted (error) region counts as 2 columns.
5484+ err = _make_syntax_error ("$\x1a \n " , offset = 1 , end_offset = 3 )
5485+ exc = traceback .TracebackException .from_exception (err )
5486+ actual = "" .join (exc .format (colorize = True ))
5487+ # '$' (1 col) + '\x1a' (2 cols) = 3 columns of carets
5488+ self .assertIn (
5489+ f' { E } $\x1a { z } \n '
5490+ f' { E } { "^" * 3 } { z } \n ' ,
5491+ actual ,
5492+ )
5493+
5494+ # ANSI escape sequences are ASCII but take 0 display columns.
5495+ err = _make_syntax_error ("a\x1b [1mb$\n " , offset = 7 , end_offset = 8 )
5496+ exc = traceback .TracebackException .from_exception (err )
5497+ actual = "" .join (exc .format (colorize = True ))
5498+ # 'a' (1 col) + '\x1b[1m' (0 cols) + 'b' (1 col) = 2 before '$'
5499+ self .assertIn (
5500+ f' a\x1b [1mb{ E } ${ z } \n '
5501+ f' { " " * 2 } { E } ^{ z } \n ' ,
5502+ actual ,
5503+ )
5504+
54455505class TestLazyImportSuggestions (unittest .TestCase ):
54465506 """Test that lazy imports are not reified when computing AttributeError suggestions."""
54475507
0 commit comments