From 2f8b08da475152adea59b6bf98e2d0cb73dd8a59 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Fri, 18 Apr 2025 13:30:04 +0100 Subject: gh-129958: Properly disallow newlines in format specs in single-quoted f-strings (GH-130063) --- Lib/test/test_fstring.py | 25 ++++++++++++++++ Lib/test/test_tokenize.py | 35 +++------------------- .../2025-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 5974024..e75e7db 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1795,6 +1795,31 @@ print(f'''{{ 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 4e05a38..2d41a5e 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -606,22 +606,6 @@ f'''__{ 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("""\ '''Autorzy, którzy tą jednostkę mają wpisani jako AKTUALNA -- czyli @@ -2473,21 +2457,6 @@ f'''__{ 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): self.check_tokenize('def d22(a, b, c=2, d=2, *k): pass', """\ @@ -3041,6 +3010,10 @@ async def f(): "'''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 0000000..c0fa76c --- /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 45604b1..5e68e5d 100644 --- a/Parser/lexer/lexer.c +++ b/Parser/lexer/lexer.c @@ -1341,6 +1341,14 @@ f_string_middle: // 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; -- cgit v0.12