mirror of
https://github.com/python/cpython.git
synced 2025-07-19 09:15:34 +00:00
bpo-32012: Disallow trailing comma after genexpr without parenthesis. (#4382)
This commit is contained in:
parent
3bda02222a
commit
9165f77d5f
4 changed files with 45 additions and 13 deletions
|
@ -630,6 +630,20 @@ This section lists previously described changes and other bugfixes
|
||||||
that may require changes to your code.
|
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
|
Changes in the Python API
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
|
|
@ -125,17 +125,32 @@ SyntaxError: invalid syntax
|
||||||
|
|
||||||
From ast_for_call():
|
From ast_for_call():
|
||||||
|
|
||||||
>>> def f(it, *varargs):
|
>>> def f(it, *varargs, **kwargs):
|
||||||
... return list(it)
|
... return list(it)
|
||||||
>>> L = range(10)
|
>>> L = range(10)
|
||||||
>>> f(x for x in L)
|
>>> f(x for x in L)
|
||||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
>>> f(x for x in L, 1)
|
>>> f(x for x in L, 1)
|
||||||
Traceback (most recent call last):
|
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)
|
>>> f(x for x in L, y for y in L)
|
||||||
Traceback (most recent call last):
|
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)
|
>>> f((x for x in L), 1)
|
||||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
|
||||||
|
|
|
@ -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.
|
19
Python/ast.c
19
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 )
|
argument: ( test [comp_for] | '*' test | test '=' test | '**' test )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int i, nargs, nkeywords, ngens;
|
int i, nargs, nkeywords;
|
||||||
int ndoublestars;
|
int ndoublestars;
|
||||||
asdl_seq *args;
|
asdl_seq *args;
|
||||||
asdl_seq *keywords;
|
asdl_seq *keywords;
|
||||||
|
@ -2721,14 +2721,18 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func)
|
||||||
|
|
||||||
nargs = 0;
|
nargs = 0;
|
||||||
nkeywords = 0;
|
nkeywords = 0;
|
||||||
ngens = 0;
|
|
||||||
for (i = 0; i < NCH(n); i++) {
|
for (i = 0; i < NCH(n); i++) {
|
||||||
node *ch = CHILD(n, i);
|
node *ch = CHILD(n, i);
|
||||||
if (TYPE(ch) == argument) {
|
if (TYPE(ch) == argument) {
|
||||||
if (NCH(ch) == 1)
|
if (NCH(ch) == 1)
|
||||||
nargs++;
|
nargs++;
|
||||||
else if (TYPE(CHILD(ch, 1)) == comp_for)
|
else if (TYPE(CHILD(ch, 1)) == comp_for) {
|
||||||
ngens++;
|
nargs++;
|
||||||
|
if (NCH(n) > 1) {
|
||||||
|
ast_error(c, ch, "Generator expression must be parenthesized");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (TYPE(CHILD(ch, 0)) == STAR)
|
else if (TYPE(CHILD(ch, 0)) == STAR)
|
||||||
nargs++;
|
nargs++;
|
||||||
else
|
else
|
||||||
|
@ -2736,13 +2740,8 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func)
|
||||||
nkeywords++;
|
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)
|
if (!args)
|
||||||
return NULL;
|
return NULL;
|
||||||
keywords = _Py_asdl_seq_new(nkeywords, c->c_arena);
|
keywords = _Py_asdl_seq_new(nkeywords, c->c_arena);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue