]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-41064: Improve syntax error for invalid usage of '**' in f-strings (GH-25006)
authorPablo Galindo <Pablogsal@gmail.com>
Wed, 24 Mar 2021 19:34:17 +0000 (19:34 +0000)
committerGitHub <noreply@github.com>
Wed, 24 Mar 2021 19:34:17 +0000 (19:34 +0000)
Grammar/python.gram
Lib/test/test_fstring.py
Misc/NEWS.d/next/Core and Builtins/2021-03-24-00-32-20.bpo-41064._H0K_g.rst [new file with mode: 0644]
Parser/parser.c

index 7247962d3b97174b44ee58d99a418a5e7064f6aa..4f3b649f9d57ee8cb7bd3c661f7c2c0e85bf561a 100644 (file)
@@ -842,6 +842,8 @@ invalid_for_target:
 invalid_group:
     | '(' a=starred_expression ')' {
         RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "can't use starred expression here") }
+    | '(' a='**' expression ')' {
+        RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "can't use double starred expression here") }
 invalid_import_from_targets:
     | import_from_as_names ',' {
         RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") }
index d7143d154a1bc1aa004756aa1dd68179da1085d9..79e123f4b8cec63bc2e58bc9d2eaa2766347a444 100644 (file)
@@ -1275,5 +1275,14 @@ x = (
         with self.assertRaisesRegex(ValueError, error_msg):
             f'{1:_,}'
 
+    def test_syntax_error_for_starred_expressions(self):
+        error_msg = re.escape("can't use starred expression here")
+        with self.assertRaisesRegex(SyntaxError, error_msg):
+            compile("f'{*a}'", "?", "exec")
+
+        error_msg = re.escape("can't use double starred expression here")
+        with self.assertRaisesRegex(SyntaxError, error_msg):
+            compile("f'{**a}'", "?", "exec")
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-03-24-00-32-20.bpo-41064._H0K_g.rst b/Misc/NEWS.d/next/Core and Builtins/2021-03-24-00-32-20.bpo-41064._H0K_g.rst
new file mode 100644 (file)
index 0000000..f6ea4d0
--- /dev/null
@@ -0,0 +1,2 @@
+Improve the syntax error for invalid usage of double starred elements ('**')
+in f-strings. Patch by Pablo Galindo.
index 6efaebe179b9c9505a2b4886a4ca16dd8104f706..de90c87db38e69a0a7582b6963781823ff7a7240 100644 (file)
@@ -18285,7 +18285,7 @@ invalid_for_target_rule(Parser *p)
     return _res;
 }
 
-// invalid_group: '(' starred_expression ')'
+// invalid_group: '(' starred_expression ')' | '(' '**' expression ')'
 static void *
 invalid_group_rule(Parser *p)
 {
@@ -18326,6 +18326,39 @@ invalid_group_rule(Parser *p)
         D(fprintf(stderr, "%*c%s invalid_group[%d-%d]: %s failed!\n", p->level, ' ',
                   p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' starred_expression ')'"));
     }
+    { // '(' '**' expression ')'
+        if (p->error_indicator) {
+            D(p->level--);
+            return NULL;
+        }
+        D(fprintf(stderr, "%*c> invalid_group[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' '**' expression ')'"));
+        Token * _literal;
+        Token * _literal_1;
+        Token * a;
+        expr_ty expression_var;
+        if (
+            (_literal = _PyPegen_expect_token(p, 7))  // token='('
+            &&
+            (a = _PyPegen_expect_token(p, 35))  // token='**'
+            &&
+            (expression_var = expression_rule(p))  // expression
+            &&
+            (_literal_1 = _PyPegen_expect_token(p, 8))  // token=')'
+        )
+        {
+            D(fprintf(stderr, "%*c+ invalid_group[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' '**' expression ')'"));
+            _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "can't use double starred expression here" );
+            if (_res == NULL && PyErr_Occurred()) {
+                p->error_indicator = 1;
+                D(p->level--);
+                return NULL;
+            }
+            goto done;
+        }
+        p->mark = _mark;
+        D(fprintf(stderr, "%*c%s invalid_group[%d-%d]: %s failed!\n", p->level, ' ',
+                  p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' '**' expression ')'"));
+    }
     _res = NULL;
   done:
     D(p->level--);