Skip to content

Commit 7c6b342

Browse files
[3.13] gh-120343: Fix column offsets of multiline tokens in tokenize (GH-120391) (#120427)
(cherry picked from commit 4b5d3e0) Co-authored-by: Lysandros Nikolaou <[email protected]>
1 parent 0041087 commit 7c6b342

File tree

2 files changed

+24
-4
lines changed

2 files changed

+24
-4
lines changed

Lib/test/test_tokenize.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,20 @@ def test_multiline_non_ascii_fstring(self):
12101210
FSTRING_END "\'\'\'" (2, 68) (2, 71)
12111211
""")
12121212

1213+
def test_multiline_non_ascii_fstring_with_expr(self):
1214+
self.check_tokenize("""\
1215+
f'''
1216+
🔗 This is a test {test_arg1}🔗
1217+
🔗'''""", """\
1218+
FSTRING_START "f\'\'\'" (1, 0) (1, 4)
1219+
FSTRING_MIDDLE '\\n 🔗 This is a test ' (1, 4) (2, 21)
1220+
OP '{' (2, 21) (2, 22)
1221+
NAME 'test_arg1' (2, 22) (2, 31)
1222+
OP '}' (2, 31) (2, 32)
1223+
FSTRING_MIDDLE '🔗\\n🔗' (2, 32) (3, 1)
1224+
FSTRING_END "\'\'\'" (3, 1) (3, 4)
1225+
""")
1226+
12131227
class GenerateTokensTest(TokenizeTest):
12141228
def check_tokenize(self, s, expected):
12151229
# Format the tokens in s in a table format.

Python/Python-tokenize.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ tokenizeriter_next(tokenizeriterobject *it)
215215

216216
const char *line_start = ISSTRINGLIT(type) ? it->tok->multi_line_start : it->tok->line_start;
217217
PyObject* line = NULL;
218+
int line_changed = 1;
218219
if (it->tok->tok_extra_tokens && is_trailing_token) {
219220
line = PyUnicode_FromString("");
220221
} else {
@@ -229,12 +230,11 @@ tokenizeriter_next(tokenizeriterobject *it)
229230
Py_XDECREF(it->last_line);
230231
line = PyUnicode_DecodeUTF8(line_start, size, "replace");
231232
it->last_line = line;
232-
if (it->tok->lineno != it->last_end_lineno) {
233-
it->byte_col_offset_diff = 0;
234-
}
233+
it->byte_col_offset_diff = 0;
235234
} else {
236235
// Line hasn't changed so we reuse the cached one.
237236
line = it->last_line;
237+
line_changed = 0;
238238
}
239239
}
240240
if (line == NULL) {
@@ -252,7 +252,13 @@ tokenizeriter_next(tokenizeriterobject *it)
252252
Py_ssize_t byte_offset = -1;
253253
if (token.start != NULL && token.start >= line_start) {
254254
byte_offset = token.start - line_start;
255-
col_offset = byte_offset - it->byte_col_offset_diff;
255+
if (line_changed) {
256+
col_offset = _PyPegen_byte_offset_to_character_offset_line(line, 0, byte_offset);
257+
it->byte_col_offset_diff = byte_offset - col_offset;
258+
}
259+
else {
260+
col_offset = byte_offset - it->byte_col_offset_diff;
261+
}
256262
}
257263
if (token.end != NULL && token.end >= it->tok->line_start) {
258264
Py_ssize_t end_byte_offset = token.end - it->tok->line_start;

0 commit comments

Comments
 (0)