From: Pablo Galindo Salgado Date: Fri, 18 Apr 2025 12:30:04 +0000 (+0100) Subject: gh-129958: Properly disallow newlines in format specs in single-quoted f-strings... X-Git-Tag: v3.14.0b1~418 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2f8b08da475152adea59b6bf98e2d0cb73dd8a59;p=thirdparty%2FPython%2Fcpython.git gh-129958: Properly disallow newlines in format specs in single-quoted f-strings (GH-130063) --- diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 5974024c170c..e75e7db378ce 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 4e05a38394cd..2d41a5e5ac06 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -605,22 +605,6 @@ f'''__{ 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("""\ @@ -2471,21 +2455,6 @@ f'''__{ 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): @@ -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 000000000000..c0fa76c89e4c --- /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 45604b197f43..5e68e5d035c5 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;