From 9a32ca904509a372c03a1830807e254c1017a43f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 15 Nov 2017 09:06:13 +0200 Subject: [PATCH 1/2] bpo-32012: Disallow genexprs without parenthesis in class definitions. --- Doc/whatsnew/3.7.rst | 6 +++++- Lib/test/test_syntax.py | 4 ++++ .../2017-11-13-00-37-11.bpo-32012.Kprjqe.rst | 6 ++++-- Python/ast.c | 15 ++++++++++----- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 82b48403555125..f64dfdc9fc5c85 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -638,9 +638,13 @@ 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. + 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`.) diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index c8cb7055c06b90..e161f56d30f214 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -153,6 +153,10 @@ 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-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 index 776a261013478e..1a9a375e415fb3 100644 --- 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 @@ -1,4 +1,6 @@ SyntaxError is now correctly raised when a generator expression without -parenthesis is passed as an argument, but followed by a trailing comma. +parenthesis is passed as an argument, but followed by a trailing comma, or +it is used instead of an inheritance list in a class definition. A generator expression always needs to be directly inside a set of parentheses -and cannot have a comma on either side. +and cannot have a comma on either side. The duplication of the parentheses +can be omitted only on calls. diff --git a/Python/ast.c b/Python/ast.c index c88e7e337332a4..e44ce516617a68 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; } From f30dcb243f55e132dd077d300012f250bdfc8384 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 15 Nov 2017 10:52:04 +0200 Subject: [PATCH 2/2] Redirect references to bpo-32023. --- Doc/whatsnew/3.7.rst | 2 +- .../2017-11-13-00-37-11.bpo-32012.Kprjqe.rst | 6 ++---- .../2017-11-15-10-49-35.bpo-32023.XnCGT5.rst | 3 +++ 3 files changed, 6 insertions(+), 5 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 f64dfdc9fc5c85..cbc166d519f023 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -645,7 +645,7 @@ Changes in Python behavior expression always needs to be directly inside a set of parentheses 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`.) + (Contributed by Serhiy Storchaka in :issue:`32012` and :issue:`32023`.) Changes in the Python API 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 index 1a9a375e415fb3..776a261013478e 100644 --- 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 @@ -1,6 +1,4 @@ SyntaxError is now correctly raised when a generator expression without -parenthesis is passed as an argument, but followed by a trailing comma, or -it is used instead of an inheritance list in a class definition. +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. The duplication of the parentheses -can be omitted only on calls. +and cannot have a comma on either side. 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 00000000000000..d4a84380521958 --- /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.