From ded35aeb9d5ae1671174f10c0ae8a7166693b17c Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sun, 25 Nov 2012 14:36:26 +0000 Subject: [PATCH] Issue #16546: make ast.YieldFrom argument mandatory. --- Lib/test/test_ast.py | 8 ++++++++ Misc/NEWS | 2 ++ Parser/Python.asdl | 2 +- Python/Python-ast.c | 8 +++++++- Python/ast.c | 3 +-- Python/compile.c | 25 +++++++++++-------------- Python/symtable.c | 12 ++++++------ 7 files changed, 36 insertions(+), 24 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index a8853c7e21f..dc24126b219 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -399,6 +399,14 @@ def test_invalid_string(self): compile(m, "", "exec") self.assertIn("string must be of type str", str(cm.exception)) + def test_empty_yield_from(self): + # Issue 16546: yield from value is not optional. + empty_yield_from = ast.parse("def f():\n yield from g()") + empty_yield_from.body[0].body[0].value.value = None + with self.assertRaises(ValueError) as cm: + compile(empty_yield_from, "", "exec") + self.assertIn("field value is required", str(cm.exception)) + class ASTHelpers_Test(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS index f17cfea4d35..b2e41dda921 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,8 @@ What's New in Python 3.3.1? Core and Builtins ----------------- +- Issue #16546: Fix: ast.YieldFrom argument is now mandatory. + - Issue #16514: Fix regression causing a traceback when sys.path[0] is None (actually, any non-string or non-bytes type). diff --git a/Parser/Python.asdl b/Parser/Python.asdl index 6b06dec3759..c24d8406192 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -60,7 +60,7 @@ module Python | GeneratorExp(expr elt, comprehension* generators) -- the grammar constrains where yield expressions can occur | Yield(expr? value) - | YieldFrom(expr? value) + | YieldFrom(expr value) -- need sequences for compare to distinguish between -- x < 4 < 3 and (x < 4) < 3 | Compare(expr left, cmpop* ops, expr* comparators) diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 805f2b8af11..e6f1e58252e 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -1802,6 +1802,11 @@ expr_ty YieldFrom(expr_ty value, int lineno, int col_offset, PyArena *arena) { expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for YieldFrom"); + return NULL; + } p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; @@ -5431,7 +5436,8 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena) Py_XDECREF(tmp); tmp = NULL; } else { - value = NULL; + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom"); + return 1; } *out = YieldFrom(value, lineno, col_offset, arena); if (*out == NULL) goto failed; diff --git a/Python/ast.c b/Python/ast.c index 0c0c1a68d96..7657b22459f 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -224,8 +224,7 @@ validate_expr(expr_ty exp, expr_context_ty ctx) case Yield_kind: return !exp->v.Yield.value || validate_expr(exp->v.Yield.value, Load); case YieldFrom_kind: - return !exp->v.YieldFrom.value || - validate_expr(exp->v.YieldFrom.value, Load); + return validate_expr(exp->v.YieldFrom.value, Load); case Compare_kind: if (!asdl_seq_LEN(exp->v.Compare.comparators)) { PyErr_SetString(PyExc_ValueError, "Compare with no comparators"); diff --git a/Python/compile.c b/Python/compile.c index 5016f99af3a..3cf71ef09e2 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -3341,27 +3341,24 @@ compiler_visit_expr(struct compiler *c, expr_ty e) case DictComp_kind: return compiler_dictcomp(c, e); case Yield_kind: - case YieldFrom_kind: { - expr_ty value; if (c->u->u_ste->ste_type != FunctionBlock) return compiler_error(c, "'yield' outside function"); - value = (e->kind == YieldFrom_kind) ? e->v.YieldFrom.value : e->v.Yield.value; - if (value) { - VISIT(c, expr, value); + if (e->v.Yield.value) { + VISIT(c, expr, e->v.Yield.value); } else { ADDOP_O(c, LOAD_CONST, Py_None, consts); } - if (e->kind == YieldFrom_kind) { - ADDOP(c, GET_ITER); - ADDOP_O(c, LOAD_CONST, Py_None, consts); - ADDOP(c, YIELD_FROM); - } - else { - ADDOP(c, YIELD_VALUE); - } + ADDOP(c, YIELD_VALUE); + break; + case YieldFrom_kind: + if (c->u->u_ste->ste_type != FunctionBlock) + return compiler_error(c, "'yield' outside function"); + VISIT(c, expr, e->v.YieldFrom.value); + ADDOP(c, GET_ITER); + ADDOP_O(c, LOAD_CONST, Py_None, consts); + ADDOP(c, YIELD_FROM); break; - } case Compare_kind: return compiler_compare(c, e); case Call_kind: diff --git a/Python/symtable.c b/Python/symtable.c index 9dde9088322..55898f99bf1 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1371,14 +1371,14 @@ symtable_visit_expr(struct symtable *st, expr_ty e) VISIT_QUIT(st, 0); break; case Yield_kind: - case YieldFrom_kind: { - expr_ty value; - value = (e->kind == YieldFrom_kind) ? e->v.YieldFrom.value : e->v.Yield.value; - if (value) - VISIT(st, expr, value); + if (e->v.Yield.value) + VISIT(st, expr, e->v.Yield.value); + st->st_cur->ste_generator = 1; + break; + case YieldFrom_kind: + VISIT(st, expr, e->v.YieldFrom.value); st->st_cur->ste_generator = 1; break; - } case Compare_kind: VISIT(st, expr, e->v.Compare.left); VISIT_SEQ(st, expr, e->v.Compare.comparators);