Issue #16546: make ast.YieldFrom argument mandatory.

This commit is contained in:
Mark Dickinson 2012-11-25 14:36:26 +00:00
parent 9982c53c2f
commit ded35aeb9d
7 changed files with 36 additions and 24 deletions

View File

@ -399,6 +399,14 @@ class AST_Tests(unittest.TestCase):
compile(m, "<test>", "exec") compile(m, "<test>", "exec")
self.assertIn("string must be of type str", str(cm.exception)) 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, "<test>", "exec")
self.assertIn("field value is required", str(cm.exception))
class ASTHelpers_Test(unittest.TestCase): class ASTHelpers_Test(unittest.TestCase):

View File

@ -12,6 +12,8 @@ What's New in Python 3.3.1?
Core and Builtins 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 - Issue #16514: Fix regression causing a traceback when sys.path[0] is None
(actually, any non-string or non-bytes type). (actually, any non-string or non-bytes type).

View File

@ -60,7 +60,7 @@ module Python
| GeneratorExp(expr elt, comprehension* generators) | GeneratorExp(expr elt, comprehension* generators)
-- the grammar constrains where yield expressions can occur -- the grammar constrains where yield expressions can occur
| Yield(expr? value) | Yield(expr? value)
| YieldFrom(expr? value) | YieldFrom(expr value)
-- need sequences for compare to distinguish between -- need sequences for compare to distinguish between
-- x < 4 < 3 and (x < 4) < 3 -- x < 4 < 3 and (x < 4) < 3
| Compare(expr left, cmpop* ops, expr* comparators) | Compare(expr left, cmpop* ops, expr* comparators)

View File

@ -1802,6 +1802,11 @@ expr_ty
YieldFrom(expr_ty value, int lineno, int col_offset, PyArena *arena) YieldFrom(expr_ty value, int lineno, int col_offset, PyArena *arena)
{ {
expr_ty p; 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)); p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
if (!p) if (!p)
return NULL; return NULL;
@ -5431,7 +5436,8 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
Py_XDECREF(tmp); Py_XDECREF(tmp);
tmp = NULL; tmp = NULL;
} else { } else {
value = NULL; PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom");
return 1;
} }
*out = YieldFrom(value, lineno, col_offset, arena); *out = YieldFrom(value, lineno, col_offset, arena);
if (*out == NULL) goto failed; if (*out == NULL) goto failed;

View File

@ -224,8 +224,7 @@ validate_expr(expr_ty exp, expr_context_ty ctx)
case Yield_kind: case Yield_kind:
return !exp->v.Yield.value || validate_expr(exp->v.Yield.value, Load); return !exp->v.Yield.value || validate_expr(exp->v.Yield.value, Load);
case YieldFrom_kind: case YieldFrom_kind:
return !exp->v.YieldFrom.value || return validate_expr(exp->v.YieldFrom.value, Load);
validate_expr(exp->v.YieldFrom.value, Load);
case Compare_kind: case Compare_kind:
if (!asdl_seq_LEN(exp->v.Compare.comparators)) { if (!asdl_seq_LEN(exp->v.Compare.comparators)) {
PyErr_SetString(PyExc_ValueError, "Compare with no comparators"); PyErr_SetString(PyExc_ValueError, "Compare with no comparators");

View File

@ -3341,27 +3341,24 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
case DictComp_kind: case DictComp_kind:
return compiler_dictcomp(c, e); return compiler_dictcomp(c, e);
case Yield_kind: case Yield_kind:
case YieldFrom_kind: {
expr_ty value;
if (c->u->u_ste->ste_type != FunctionBlock) if (c->u->u_ste->ste_type != FunctionBlock)
return compiler_error(c, "'yield' outside function"); return compiler_error(c, "'yield' outside function");
value = (e->kind == YieldFrom_kind) ? e->v.YieldFrom.value : e->v.Yield.value; if (e->v.Yield.value) {
if (value) { VISIT(c, expr, e->v.Yield.value);
VISIT(c, expr, value);
} }
else { else {
ADDOP_O(c, LOAD_CONST, Py_None, consts); ADDOP_O(c, LOAD_CONST, Py_None, consts);
} }
if (e->kind == YieldFrom_kind) { ADDOP(c, YIELD_VALUE);
ADDOP(c, GET_ITER); break;
ADDOP_O(c, LOAD_CONST, Py_None, consts); case YieldFrom_kind:
ADDOP(c, YIELD_FROM); if (c->u->u_ste->ste_type != FunctionBlock)
} return compiler_error(c, "'yield' outside function");
else { VISIT(c, expr, e->v.YieldFrom.value);
ADDOP(c, YIELD_VALUE); ADDOP(c, GET_ITER);
} ADDOP_O(c, LOAD_CONST, Py_None, consts);
ADDOP(c, YIELD_FROM);
break; break;
}
case Compare_kind: case Compare_kind:
return compiler_compare(c, e); return compiler_compare(c, e);
case Call_kind: case Call_kind:

View File

@ -1371,14 +1371,14 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
VISIT_QUIT(st, 0); VISIT_QUIT(st, 0);
break; break;
case Yield_kind: case Yield_kind:
case YieldFrom_kind: { if (e->v.Yield.value)
expr_ty value; VISIT(st, expr, e->v.Yield.value);
value = (e->kind == YieldFrom_kind) ? e->v.YieldFrom.value : e->v.Yield.value; st->st_cur->ste_generator = 1;
if (value) break;
VISIT(st, expr, value); case YieldFrom_kind:
VISIT(st, expr, e->v.YieldFrom.value);
st->st_cur->ste_generator = 1; st->st_cur->ste_generator = 1;
break; break;
}
case Compare_kind: case Compare_kind:
VISIT(st, expr, e->v.Compare.left); VISIT(st, expr, e->v.Compare.left);
VISIT_SEQ(st, expr, e->v.Compare.comparators); VISIT_SEQ(st, expr, e->v.Compare.comparators);