Skip to content

Commit 1f9d26c

Browse files
author
Alessio Attilio
committed
gh-153837: Fix IndentationError offset in tokenize to point to the indentation error, not end of line
1 parent eca3b26 commit 1f9d26c

3 files changed

Lines changed: 28 additions & 2 deletions

File tree

Lib/test/test_tokenize.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,26 @@ def k(x):
151151
self.assertEqual(
152152
e.exception.msg,
153153
'unindent does not match any outer indentation level')
154-
self.assertEqual(e.exception.offset, 9)
154+
self.assertEqual(e.exception.offset, 2)
155155
self.assertEqual(e.exception.text, ' x += 5')
156156

157+
# gh-153837: offset should point to the indentation error, not end of line
158+
indent_error_long_line = b"""\
159+
def foo():
160+
x = 1
161+
x = "some_very_long_expression"
162+
"""
163+
readline = BytesIO(indent_error_long_line).readline
164+
with self.assertRaisesRegex(IndentationError,
165+
"unindent does not match any "
166+
"outer indentation level") as e:
167+
for tok in tokenize.tokenize(readline):
168+
pass
169+
self.assertEqual(e.exception.lineno, 3)
170+
self.assertEqual(e.exception.offset, 3)
171+
self.assertEqual(e.exception.text,
172+
' x = "some_very_long_expression"')
173+
157174
def test_int(self):
158175
# Ordinary integers and binary operators
159176
self.check_tokenize("0xff <= 255", """\
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix incorrect column offset in :exc:`IndentationError` raised by the :mod:`tokenize` module. The offset now points to the first non-whitespace character on the line where the indentation error occurs, instead of incorrectly pointing to the end of the line.

Python/Python-tokenize.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,15 @@ _tokenizer_error(tokenizeriterobject *it)
148148
goto exit;
149149
}
150150

151-
Py_ssize_t offset = _PyPegen_byte_offset_to_character_offset(error_line, tok->inp - tok->buf);
151+
Py_ssize_t byte_offset = tok->inp - tok->buf;
152+
if (tok->done == E_DEDENT || tok->done == E_TABSPACE || tok->done == E_TOODEEP) {
153+
const char *line_start = tok->line_start ? tok->line_start : tok->buf;
154+
byte_offset = line_start - tok->buf;
155+
while (byte_offset < size && (tok->buf[byte_offset] == ' ' || tok->buf[byte_offset] == '\t')) {
156+
byte_offset++;
157+
}
158+
}
159+
Py_ssize_t offset = _PyPegen_byte_offset_to_character_offset(error_line, byte_offset);
152160
if (offset == -1) {
153161
result = -1;
154162
goto exit;

0 commit comments

Comments
 (0)