From ddbce1378644f9d5ad0651e1c9035bd8c6502edc Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 15 Nov 2017 17:39:37 +0200 Subject: bpo-32023: Disallow genexprs without parenthesis in class definitions. (#4400) --- Doc/whatsnew/3.7.rst | 8 ++++++-- Lib/test/test_syntax.py | 4 ++++ .../2017-11-15-10-49-35.bpo-32023.XnCGT5.rst | 3 +++ Python/ast.c | 15 ++++++++++----- 4 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2017-11-15-10-49-35.bpo-32023.XnCGT5.rst diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 82b4840..cbc166d 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -638,10 +638,14 @@ Changes in Python behavior f(1 for x in [1],) + class C(1 for x in [1]): + pass + 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`.) + and cannot have a comma on either side, and the duplication of the + parentheses can be omitted only on calls. + (Contributed by Serhiy Storchaka in :issue:`32012` and :issue:`32023`.) Changes in the Python API diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index c8cb705..e161f56d 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -153,6 +153,10 @@ 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] +>>> class C(x for x in L): +... pass +Traceback (most recent call last): +SyntaxError: invalid syntax >>> def g(*args, **kwargs): ... print(args, sorted(kwargs.items())) diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-11-15-10-49-35.bpo-32023.XnCGT5.rst b/Misc/NEWS.d/next/Core and Builtins/2017-11-15-10-49-35.bpo-32023.XnCGT5.rst new file mode 100644 index 0000000..d4a8438 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-11-15-10-49-35.bpo-32023.XnCGT5.rst @@ -0,0 +1,3 @@ +SyntaxError is now correctly raised when a generator expression without +parenthesis is used instead of an inheritance list in a class definition. +The duplication of the parentheses can be omitted only on calls. diff --git a/Python/ast.c b/Python/ast.c index c88e7e3..e44ce51 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -11,6 +11,7 @@ #include "pythonrun.h" #include +#include static int validate_stmts(asdl_seq *); static int validate_exprs(asdl_seq *, expr_context_ty, int); @@ -611,7 +612,7 @@ static stmt_ty ast_for_with_stmt(struct compiling *, const node *, int); static stmt_ty ast_for_for_stmt(struct compiling *, const node *, int); /* Note different signature for ast_for_call */ -static expr_ty ast_for_call(struct compiling *, const node *, expr_ty); +static expr_ty ast_for_call(struct compiling *, const node *, expr_ty, bool); static PyObject *parsenumber(struct compiling *, const char *); static expr_ty parsestrplus(struct compiling *, const node *n); @@ -1545,7 +1546,7 @@ ast_for_decorator(struct compiling *c, const node *n) name_expr = NULL; } else { - d = ast_for_call(c, CHILD(n, 3), name_expr); + d = ast_for_call(c, CHILD(n, 3), name_expr, true); if (!d) return NULL; name_expr = NULL; @@ -2368,7 +2369,7 @@ ast_for_trailer(struct compiling *c, const node *n, expr_ty left_expr) return Call(left_expr, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); else - return ast_for_call(c, CHILD(n, 1), left_expr); + return ast_for_call(c, CHILD(n, 1), left_expr, true); } else if (TYPE(CHILD(n, 0)) == DOT) { PyObject *attr_id = NEW_IDENTIFIER(CHILD(n, 1)); @@ -2705,7 +2706,7 @@ ast_for_expr(struct compiling *c, const node *n) } static expr_ty -ast_for_call(struct compiling *c, const node *n, expr_ty func) +ast_for_call(struct compiling *c, const node *n, expr_ty func, bool allowgen) { /* arglist: argument (',' argument)* [','] @@ -2728,6 +2729,10 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func) nargs++; else if (TYPE(CHILD(ch, 1)) == comp_for) { nargs++; + if (!allowgen) { + ast_error(c, ch, "invalid syntax"); + return NULL; + } if (NCH(n) > 1) { ast_error(c, ch, "Generator expression must be parenthesized"); return NULL; @@ -3973,7 +3978,7 @@ ast_for_classdef(struct compiling *c, const node *n, asdl_seq *decorator_seq) if (!dummy_name) return NULL; dummy = Name(dummy_name, Load, LINENO(n), n->n_col_offset, c->c_arena); - call = ast_for_call(c, CHILD(n, 3), dummy); + call = ast_for_call(c, CHILD(n, 3), dummy, false); if (!call) return NULL; } -- cgit v0.12