Skip to content

Commit 1318217

Browse files
committed
Remove ASCII fast track that was too eager
1 parent 37a4fd9 commit 1318217

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed

Lib/test/test_traceback.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
54455505
class TestLazyImportSuggestions(unittest.TestCase):
54465506
"""Test that lazy imports are not reified when computing AttributeError suggestions."""
54475507

Lib/traceback.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,11 +1023,7 @@ def _display_width(line, offset=None):
10231023
width output device. Supports wide unicode characters and emojis."""
10241024

10251025
if offset is None:
1026-
offset = len(line)
1027-
1028-
# Fast track for ASCII-only strings
1029-
if line.isascii():
1030-
return offset
1026+
return _wlen(line)
10311027

10321028
return _wlen(line[:offset])
10331029

0 commit comments

Comments
 (0)