From 9165f77d5f93a2c12aa0e90853e3ae7212800d3c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 15 Nov 2017 08:49:40 +0200 Subject: bpo-32012: Disallow trailing comma after genexpr without parenthesis. (#4382) --- Doc/whatsnew/3.7.rst | 14 ++++++++++++++ Lib/test/test_syntax.py | 21 ++++++++++++++++++--- .../2017-11-13-00-37-11.bpo-32012.Kprjqe.rst | 4 ++++ Python/ast.c | 19 +++++++++---------- 4 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2017-11-13-00-37-11.bpo-32012.Kprjqe.rst diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index f6d051d..82b4840 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 5d36581..c8cb705 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -125,17 +125,32 @@ SyntaxError: invalid syntax 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 0000000..776a261 --- /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 79cef70..c88e7e3 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); -- cgit v0.12