[Python-checkins] bpo-32012: Disallow trailing comma after genexpr without parenthesis. (#4382)

Serhiy Storchaka webhook-mailer at python.org
Wed Nov 15 01:49:48 EST 2017


https://github.com/python/cpython/commit/9165f77d5f93a2c12aa0e90853e3ae7212800d3c
commit: 9165f77d5f93a2c12aa0e90853e3ae7212800d3c
branch: master
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2017-11-15T08:49:40+02:00
summary:

bpo-32012: Disallow trailing comma after genexpr without parenthesis. (#4382)

files:
A Misc/NEWS.d/next/Core and Builtins/2017-11-13-00-37-11.bpo-32012.Kprjqe.rst
M Doc/whatsnew/3.7.rst
M Lib/test/test_syntax.py
M Python/ast.c

diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst
index f6d051de2eb..82b48403555 100644
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -630,6 +630,20 @@ This section lists previously described changes and other bugfixes
 that may require changes to your code.
 
 
+Changes in Python behavior
+--------------------------
+
+* Due to an oversight, earlier Python versions erroneously accepted the
+  following syntax::
+
+      f(1 for x in [1],)
+
+  Python 3.7 now correctly raises a :exc:`SyntaxError`, as a generator
+  expression always needs to be directly inside a set of parentheses
+  and cannot have a comma on either side.
+  (Contributed by Serhiy Storchaka in :issue:`32012`.)
+
+
 Changes in the Python API
 -------------------------
 
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 5d36581859b..c8cb7055c06 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -125,17 +125,32 @@
 
 From ast_for_call():
 
->>> def f(it, *varargs):
+>>> def f(it, *varargs, **kwargs):
 ...     return list(it)
 >>> L = range(10)
 >>> f(x for x in L)
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 >>> f(x for x in L, 1)
 Traceback (most recent call last):
-SyntaxError: Generator expression must be parenthesized if not sole argument
+SyntaxError: Generator expression must be parenthesized
+>>> f(x for x in L, y=1)
+Traceback (most recent call last):
+SyntaxError: Generator expression must be parenthesized
+>>> f(x for x in L, *[])
+Traceback (most recent call last):
+SyntaxError: Generator expression must be parenthesized
+>>> f(x for x in L, **{})
+Traceback (most recent call last):
+SyntaxError: Generator expression must be parenthesized
+>>> f(L, x for x in L)
+Traceback (most recent call last):
+SyntaxError: Generator expression must be parenthesized
 >>> f(x for x in L, y for y in L)
 Traceback (most recent call last):
-SyntaxError: Generator expression must be parenthesized if not sole argument
+SyntaxError: Generator expression must be parenthesized
+>>> f(x for x in L,)
+Traceback (most recent call last):
+SyntaxError: Generator expression must be parenthesized
 >>> f((x for x in L), 1)
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 
diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-11-13-00-37-11.bpo-32012.Kprjqe.rst b/Misc/NEWS.d/next/Core and Builtins/2017-11-13-00-37-11.bpo-32012.Kprjqe.rst
new file mode 100644
index 00000000000..776a2610134
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2017-11-13-00-37-11.bpo-32012.Kprjqe.rst	
@@ -0,0 +1,4 @@
+SyntaxError is now correctly raised when a generator expression without
+parenthesis is passed as an argument, but followed by a trailing comma.
+A generator expression always needs to be directly inside a set of parentheses
+and cannot have a comma on either side.
diff --git a/Python/ast.c b/Python/ast.c
index 79cef708a00..c88e7e33733 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -2712,7 +2712,7 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func)
       argument: ( test [comp_for] | '*' test | test '=' test | '**' test )
     */
 
-    int i, nargs, nkeywords, ngens;
+    int i, nargs, nkeywords;
     int ndoublestars;
     asdl_seq *args;
     asdl_seq *keywords;
@@ -2721,14 +2721,18 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func)
 
     nargs = 0;
     nkeywords = 0;
-    ngens = 0;
     for (i = 0; i < NCH(n); i++) {
         node *ch = CHILD(n, i);
         if (TYPE(ch) == argument) {
             if (NCH(ch) == 1)
                 nargs++;
-            else if (TYPE(CHILD(ch, 1)) == comp_for)
-                ngens++;
+            else if (TYPE(CHILD(ch, 1)) == comp_for) {
+                nargs++;
+                if (NCH(n) > 1) {
+                    ast_error(c, ch, "Generator expression must be parenthesized");
+                    return NULL;
+                }
+            }
             else if (TYPE(CHILD(ch, 0)) == STAR)
                 nargs++;
             else
@@ -2736,13 +2740,8 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func)
                 nkeywords++;
         }
     }
-    if (ngens > 1 || (ngens && (nargs || nkeywords))) {
-        ast_error(c, n, "Generator expression must be parenthesized "
-                  "if not sole argument");
-        return NULL;
-    }
 
-    args = _Py_asdl_seq_new(nargs + ngens, c->c_arena);
+    args = _Py_asdl_seq_new(nargs, c->c_arena);
     if (!args)
         return NULL;
     keywords = _Py_asdl_seq_new(nkeywords, c->c_arena);



More information about the Python-checkins mailing list