[Python-checkins] [3.12] gh-106396: Special-case empty format spec to gen empty JoinedStr node (GH-106401) (#106416)

lysnikolaou webhook-mailer at python.org
Tue Jul 4 09:00:52 EDT 2023


https://github.com/python/cpython/commit/930df7b07e774636ad200a62a7b4b56564f502b0
commit: 930df7b07e774636ad200a62a7b4b56564f502b0
branch: 3.12
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: lysnikolaou <lisandrosnik at gmail.com>
date: 2023-07-04T13:00:47Z
summary:

[3.12] gh-106396: Special-case empty format spec to gen empty JoinedStr node (GH-106401) (#106416)

(cherry picked from commit dfe4de203881e8d068e6fc5b8e31075841a86d25)

Co-authored-by: Lysandros Nikolaou <lisandrosnik at gmail.com>

files:
A Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst
M Lib/test/test_fstring.py
M Parser/action_helpers.c

diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py
index ba223ae124a8f..cb14bba2602de 100644
--- a/Lib/test/test_fstring.py
+++ b/Lib/test/test_fstring.py
@@ -496,6 +496,24 @@ def test_ast_line_numbers_with_parentheses(self):
         self.assertEqual(wat2.end_col_offset, 17)
         self.assertEqual(fstring.end_col_offset, 18)
 
+    def test_ast_fstring_empty_format_spec(self):
+        expr = "f'{expr:}'"
+
+        mod = ast.parse(expr)
+        self.assertEqual(type(mod), ast.Module)
+        self.assertEqual(len(mod.body), 1)
+
+        fstring = mod.body[0].value
+        self.assertEqual(type(fstring), ast.JoinedStr)
+        self.assertEqual(len(fstring.values), 1)
+
+        fv = fstring.values[0]
+        self.assertEqual(type(fv), ast.FormattedValue)
+
+        format_spec = fv.format_spec
+        self.assertEqual(type(format_spec), ast.JoinedStr)
+        self.assertEqual(len(format_spec.values), 0)
+
     def test_docstring(self):
         def f():
             f'''Not a docstring'''
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst
new file mode 100644
index 0000000000000..c5767e97271d9
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst	
@@ -0,0 +1,3 @@
+When the format specification of an f-string expression is empty, the parser now
+generates an empty :class:`ast.JoinedStr` node for it instead of an one-element
+:class:`ast.JoinedStr` with an empty string :class:`ast.Constant`.
diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c
index dbad56b5164b6..e68a9cac25908 100644
--- a/Parser/action_helpers.c
+++ b/Parser/action_helpers.c
@@ -1003,6 +1003,18 @@ _PyPegen_setup_full_format_spec(Parser *p, Token *colon, asdl_expr_seq *spec, in
     if (!spec) {
         return NULL;
     }
+
+    // This is needed to keep compatibility with 3.11, where an empty format spec is parsed
+    // as an *empty* JoinedStr node, instead of having an empty constant in it.
+    if (asdl_seq_LEN(spec) == 1) {
+        expr_ty e = asdl_seq_GET(spec, 0);
+        if (e->kind == Constant_kind
+                && PyUnicode_Check(e->v.Constant.value)
+                && PyUnicode_GetLength(e->v.Constant.value) == 0) {
+            spec = _Py_asdl_expr_seq_new(0, arena);
+        }
+    }
+
     expr_ty res = _PyAST_JoinedStr(spec, lineno, col_offset, end_lineno, end_col_offset, p->arena);
     if (!res) {
         return NULL;



More information about the Python-checkins mailing list