From b5b2396a3a6ba4a2029c29870cd2b27768ae5196 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Thu, 13 Feb 2025 00:15:03 +0000 Subject: [PATCH] gh-129958: Properly disallow newlines in format specs in single-quoted f-strings --- Lib/test/test_fstring.py | 25 +++++++++++++ Lib/test/test_tokenize.py | 35 +++---------------- ...-02-13-00-14-24.gh-issue-129958.Uj7lyY.rst | 2 ++ Parser/lexer/lexer.c | 8 +++++ 4 files changed, 39 insertions(+), 31 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-02-13-00-14-24.gh-issue-129958.Uj7lyY.rst diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 1d96b7a2c2459b..9789e3d3e86bd6 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1782,6 +1782,31 @@ def test_gh129093(self): self.assertEqual(f'{f'{1!=2=}'=}', "f'{1!=2=}'='1!=2=True'") self.assertEqual(f'{f'{1 != 2=}'=}', "f'{1 != 2=}'='1 != 2=True'") + def test_newlines_in_format_specifiers(self): + cases = [ + """f'{1:d\n}'""", + """f'__{ + 1:d + }__'""", + '''f"{value:. + {'2f'}}"''', + '''f"{value: + {'.2f'}f}"''', + '''f"{value: + #{'x'}}"''', + ] + self.assertAllRaise(SyntaxError, "f-string: newlines are not allowed in format specifiers", cases) + + valid_cases = [ + """f'''__{ + 1:d + }__'''""", + """f'''{1:d\n}'''""", + ] + + for case in valid_cases: + compile(case, "", "exec") + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 52d3341975088b..726a01b692c1cf 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -600,22 +600,6 @@ def test_string(self): OP '}' (6, 0) (6, 1) FSTRING_MIDDLE '__' (6, 1) (6, 3) FSTRING_END "'''" (6, 3) (6, 6) - """) - self.check_tokenize("""\ -f'__{ - x:d -}__'""", """\ - FSTRING_START "f'" (1, 0) (1, 2) - FSTRING_MIDDLE '__' (1, 2) (1, 4) - OP '{' (1, 4) (1, 5) - NL '\\n' (1, 5) (1, 6) - NAME 'x' (2, 4) (2, 5) - OP ':' (2, 5) (2, 6) - FSTRING_MIDDLE 'd' (2, 6) (2, 7) - NL '\\n' (2, 7) (2, 8) - OP '}' (3, 0) (3, 1) - FSTRING_MIDDLE '__' (3, 1) (3, 3) - FSTRING_END "'" (3, 3) (3, 4) """) self.check_tokenize("""\ @@ -2466,21 +2450,6 @@ def test_string(self): RBRACE '}' (6, 0) (6, 1) FSTRING_MIDDLE '__' (6, 1) (6, 3) FSTRING_END "'''" (6, 3) (6, 6) - """) - - self.check_tokenize("""\ -f'__{ - x:d -}__'""", """\ - FSTRING_START "f'" (1, 0) (1, 2) - FSTRING_MIDDLE '__' (1, 2) (1, 4) - LBRACE '{' (1, 4) (1, 5) - NAME 'x' (2, 4) (2, 5) - COLON ':' (2, 5) (2, 6) - FSTRING_MIDDLE 'd' (2, 6) (2, 7) - RBRACE '}' (3, 0) (3, 1) - FSTRING_MIDDLE '__' (3, 1) (3, 3) - FSTRING_END "'" (3, 3) (3, 4) """) def test_function(self): @@ -3036,6 +3005,10 @@ def get_tokens(string): "'''sdfsdf''", "("*1000+"a"+")"*1000, "]", + """\ + f'__{ + x:d + }__'""", ]: with self.subTest(case=case): self.assertRaises(tokenize.TokenError, get_tokens, case) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-02-13-00-14-24.gh-issue-129958.Uj7lyY.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-13-00-14-24.gh-issue-129958.Uj7lyY.rst new file mode 100644 index 00000000000000..c0fa76c89e4c4e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-13-00-14-24.gh-issue-129958.Uj7lyY.rst @@ -0,0 +1,2 @@ +Fix a bug that was allowing newlines inconsitently in format specifiers for +single-quoted f-strings. Patch by Pablo Galindo. diff --git a/Parser/lexer/lexer.c b/Parser/lexer/lexer.c index 8c5ae37fa90860..ad119a84d9ca6b 100644 --- a/Parser/lexer/lexer.c +++ b/Parser/lexer/lexer.c @@ -1339,6 +1339,14 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct // it means that the format spec ends here and we should // return to the regular mode. if (in_format_spec && c == '\n') { + if (current_tok->f_string_quote_size == 1) { + return MAKE_TOKEN( + _PyTokenizer_syntaxerror( + tok, + "f-string: newlines are not allowed in format specifiers for single quoted f-strings" + ) + ); + } tok_backup(tok, c); TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE; current_tok->in_format_spec = 0;