https://github.com/python/cpython/commit/a37d719d37ba0f45d0e88f1f70ccd66f2a4f209e
commit: a37d719d37ba0f45d0e88f1f70ccd66f2a4f209e
branch: 3.13
author: Ɓukasz Langa <luk...@langa.pl>
committer: ambv <luk...@langa.pl>
date: 2025-04-18T17:41:42+02:00
summary:

[3.13] gh-129958: Properly disallow newlines in format specs in single-quoted 
f-strings (GH-130063) (GH-132692)

(cherry picked from commit 2f8b08da475152adea59b6bf98e2d0cb73dd8a59)

Co-authored-by: Pablo Galindo Salgado <pablog...@gmail.com>

files:
A Misc/NEWS.d/next/Core and 
Builtins/2025-02-13-00-14-24.gh-issue-129958.Uj7lyY.rst
M Lib/test/test_fstring.py
M Lib/test/test_tokenize.py
M Parser/lexer/lexer.c

diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py
index f5111b38a45707..1ad16937b2b5ba 100644
--- a/Lib/test/test_fstring.py
+++ b/Lib/test/test_fstring.py
@@ -1784,6 +1784,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, "<string>", "exec")
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py
index 940ea21754ea37..e9701eb130d3e3 100644
--- a/Lib/test/test_tokenize.py
+++ b/Lib/test/test_tokenize.py
@@ -603,22 +603,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("""\
@@ -2468,21 +2452,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):
@@ -3038,6 +3007,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 15e6332ee35718..e4b02aee51d3cf 100644
--- a/Parser/lexer/lexer.c
+++ b/Parser/lexer/lexer.c
@@ -1347,6 +1347,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;

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to