]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-42806: Fix ast locations of f-strings inside parentheses (GH-24067)
authorPablo Galindo <Pablogsal@gmail.com>
Sun, 3 Jan 2021 01:11:41 +0000 (01:11 +0000)
committerGitHub <noreply@github.com>
Sun, 3 Jan 2021 01:11:41 +0000 (01:11 +0000)
Lib/test/test_fstring.py
Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst [new file with mode: 0644]
Parser/string_parser.c

index b53661aa0a46fc5ff4d4213775c1344f3d798b24..2345832abce6242f42849db8872308e00ddafdfa 100644 (file)
@@ -332,6 +332,59 @@ non-important content
         self.assertEqual(binop.left.col_offset, 4)
         self.assertEqual(binop.right.col_offset, 7)
 
+    def test_ast_line_numbers_with_parentheses(self):
+        expr = """
+x = (
+    f" {test(t)}"
+)"""
+        t = ast.parse(expr)
+        self.assertEqual(type(t), ast.Module)
+        self.assertEqual(len(t.body), 1)
+        # check the test(t) location
+        call = t.body[0].value.values[1].value
+        self.assertEqual(type(call), ast.Call)
+        self.assertEqual(call.lineno, 3)
+        self.assertEqual(call.end_lineno, 3)
+        self.assertEqual(call.col_offset, 8)
+        self.assertEqual(call.end_col_offset, 15)
+
+        expr = """
+x = (
+        'PERL_MM_OPT', (
+            f'wat'
+            f'some_string={f(x)} '
+            f'wat'
+        ),
+)
+"""
+        t = ast.parse(expr)
+        self.assertEqual(type(t), ast.Module)
+        self.assertEqual(len(t.body), 1)
+        # check the fstring
+        fstring = t.body[0].value.elts[1]
+        self.assertEqual(type(fstring), ast.JoinedStr)
+        self.assertEqual(len(fstring.values), 3)
+        wat1, middle, wat2 = fstring.values
+        # check the first wat
+        self.assertEqual(type(wat1), ast.Constant)
+        self.assertEqual(wat1.lineno, 4)
+        self.assertEqual(wat1.end_lineno, 6)
+        self.assertEqual(wat1.col_offset, 12)
+        self.assertEqual(wat1.end_col_offset, 18)
+        # check the call
+        call = middle.value
+        self.assertEqual(type(call), ast.Call)
+        self.assertEqual(call.lineno, 5)
+        self.assertEqual(call.end_lineno, 5)
+        self.assertEqual(call.col_offset, 27)
+        self.assertEqual(call.end_col_offset, 31)
+        # check the second wat
+        self.assertEqual(type(wat2), ast.Constant)
+        self.assertEqual(wat2.lineno, 4)
+        self.assertEqual(wat2.end_lineno, 6)
+        self.assertEqual(wat2.col_offset, 12)
+        self.assertEqual(wat2.end_col_offset, 18)
+
     def test_docstring(self):
         def f():
             f'''Not a docstring'''
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst b/Misc/NEWS.d/next/Core and Builtins/2021-01-03-00-20-38.bpo-42806.mLAobJ.rst
new file mode 100644 (file)
index 0000000..10314fd
--- /dev/null
@@ -0,0 +1,2 @@
+Fix the column offsets for f-strings :mod:`ast` nodes surrounded by
+parentheses and for nodes that spawn multiple lines. Patch by Pablo Galindo.
index 09b8c35106e76a7366a1b8992e3639da504c6a2e..a41f41ce2784d17bf547513a84ca0314ec51e9ce 100644 (file)
@@ -405,7 +405,7 @@ fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end,
     Parser *p2 = _PyPegen_Parser_New(tok, Py_fstring_input, p->flags, p->feature_version,
                                      NULL, p->arena);
     p2->starting_lineno = t->lineno + lines - 1;
-    p2->starting_col_offset = p->tok->first_lineno == p->tok->lineno ? t->col_offset + cols : cols;
+    p2->starting_col_offset = t->col_offset + cols;
 
     expr = _PyPegen_run_parser(p2);