Skip to content

Commit 210aa61

Browse files
committed
gh-153569: preserve tolerant f-string delimiter state
1 parent 73b794e commit 210aa61

2 files changed

Lines changed: 31 additions & 1 deletion

File tree

Lib/test/test_tokenize.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2726,6 +2726,34 @@ def test_tolerant_fstring_closer_at_expression_entry_depth(self):
27262726
("f-string: unmatched ']'", position),
27272727
)
27282728

2729+
def test_tolerant_fstring_mismatch_keeps_delimiter_state(self):
2730+
sources = [
2731+
("f'{x:{)}!]", (1, 10)),
2732+
("f'{x:{)}!\n]", (2, 1)),
2733+
]
2734+
for source, tolerant_position in sources:
2735+
cases = [
2736+
(False, ("f-string: unmatched ')'", (1, 7))),
2737+
(True, ("f-string: unmatched ']'", tolerant_position)),
2738+
]
2739+
for extra_tokens, expected in cases:
2740+
with self.subTest(
2741+
source=source, extra_tokens=extra_tokens
2742+
):
2743+
with self.assertRaises(tokenize.TokenError) as caught:
2744+
self._get_tokens(source, extra_tokens=extra_tokens)
2745+
self.assertEqual(caught.exception.args, expected)
2746+
2747+
with self.subTest(source=source, public=True):
2748+
with self.assertRaises(tokenize.TokenError) as caught:
2749+
list(tokenize.tokenize(
2750+
BytesIO(source.encode()).readline
2751+
))
2752+
self.assertEqual(
2753+
caught.exception.args,
2754+
("f-string: unmatched ']'", tolerant_position),
2755+
)
2756+
27292757
def test_int(self):
27302758

27312759
self.check_tokenize('0xff <= 255', """\

Parser/lexer/string.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,9 @@ _PyTok_LexOperator(struct _PyTokenizer *tok, _PyTok_Frame *frame,
381381
case ']':
382382
case '}':
383383
if (INSIDE_FSTRING_EXPR(frame) && c != '}' &&
384-
tok->level == frame->paren_depth_at_entry) {
384+
tok->level == (tok->extra_tokens
385+
? frame_body_paren_depth(tok)
386+
: frame->paren_depth_at_entry)) {
385387
_PyTok_SyntaxError(
386388
tok, "%c-string: unmatched '%c'",
387389
_PyTok_FramePrefix(tok), c);

0 commit comments

Comments
 (0)