Skip to content

Commit ded35ae

Browse files
committed
Issue #16546: make ast.YieldFrom argument mandatory.
1 parent 9982c53 commit ded35ae

File tree

7 files changed

+36
-24
lines changed

7 files changed

+36
-24
lines changed

Lib/test/test_ast.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,14 @@ def test_invalid_string(self):
399399
compile(m, "<test>", "exec")
400400
self.assertIn("string must be of type str", str(cm.exception))
401401

402+
def test_empty_yield_from(self):
403+
# Issue 16546: yield from value is not optional.
404+
empty_yield_from = ast.parse("def f():\n yield from g()")
405+
empty_yield_from.body[0].body[0].value.value = None
406+
with self.assertRaises(ValueError) as cm:
407+
compile(empty_yield_from, "<test>", "exec")
408+
self.assertIn("field value is required", str(cm.exception))
409+
402410

403411
class ASTHelpers_Test(unittest.TestCase):
404412

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ What's New in Python 3.3.1?
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #16546: Fix: ast.YieldFrom argument is now mandatory.
16+
1517
- Issue #16514: Fix regression causing a traceback when sys.path[0] is None
1618
(actually, any non-string or non-bytes type).
1719

Parser/Python.asdl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ module Python
6060
| GeneratorExp(expr elt, comprehension* generators)
6161
-- the grammar constrains where yield expressions can occur
6262
| Yield(expr? value)
63-
| YieldFrom(expr? value)
63+
| YieldFrom(expr value)
6464
-- need sequences for compare to distinguish between
6565
-- x < 4 < 3 and (x < 4) < 3
6666
| Compare(expr left, cmpop* ops, expr* comparators)

Python/Python-ast.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,11 @@ expr_ty
18021802
YieldFrom(expr_ty value, int lineno, int col_offset, PyArena *arena)
18031803
{
18041804
expr_ty p;
1805+
if (!value) {
1806+
PyErr_SetString(PyExc_ValueError,
1807+
"field value is required for YieldFrom");
1808+
return NULL;
1809+
}
18051810
p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
18061811
if (!p)
18071812
return NULL;
@@ -5431,7 +5436,8 @@ obj2ast_expr(PyObject* obj, expr_ty* out, PyArena* arena)
54315436
Py_XDECREF(tmp);
54325437
tmp = NULL;
54335438
} else {
5434-
value = NULL;
5439+
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom");
5440+
return 1;
54355441
}
54365442
*out = YieldFrom(value, lineno, col_offset, arena);
54375443
if (*out == NULL) goto failed;

Python/ast.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,7 @@ validate_expr(expr_ty exp, expr_context_ty ctx)
224224
case Yield_kind:
225225
return !exp->v.Yield.value || validate_expr(exp->v.Yield.value, Load);
226226
case YieldFrom_kind:
227-
return !exp->v.YieldFrom.value ||
228-
validate_expr(exp->v.YieldFrom.value, Load);
227+
return validate_expr(exp->v.YieldFrom.value, Load);
229228
case Compare_kind:
230229
if (!asdl_seq_LEN(exp->v.Compare.comparators)) {
231230
PyErr_SetString(PyExc_ValueError, "Compare with no comparators");

Python/compile.c

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3341,27 +3341,24 @@ compiler_visit_expr(struct compiler *c, expr_ty e)
33413341
case DictComp_kind:
33423342
return compiler_dictcomp(c, e);
33433343
case Yield_kind:
3344-
case YieldFrom_kind: {
3345-
expr_ty value;
33463344
if (c->u->u_ste->ste_type != FunctionBlock)
33473345
return compiler_error(c, "'yield' outside function");
3348-
value = (e->kind == YieldFrom_kind) ? e->v.YieldFrom.value : e->v.Yield.value;
3349-
if (value) {
3350-
VISIT(c, expr, value);
3346+
if (e->v.Yield.value) {
3347+
VISIT(c, expr, e->v.Yield.value);
33513348
}
33523349
else {
33533350
ADDOP_O(c, LOAD_CONST, Py_None, consts);
33543351
}
3355-
if (e->kind == YieldFrom_kind) {
3356-
ADDOP(c, GET_ITER);
3357-
ADDOP_O(c, LOAD_CONST, Py_None, consts);
3358-
ADDOP(c, YIELD_FROM);
3359-
}
3360-
else {
3361-
ADDOP(c, YIELD_VALUE);
3362-
}
3352+
ADDOP(c, YIELD_VALUE);
3353+
break;
3354+
case YieldFrom_kind:
3355+
if (c->u->u_ste->ste_type != FunctionBlock)
3356+
return compiler_error(c, "'yield' outside function");
3357+
VISIT(c, expr, e->v.YieldFrom.value);
3358+
ADDOP(c, GET_ITER);
3359+
ADDOP_O(c, LOAD_CONST, Py_None, consts);
3360+
ADDOP(c, YIELD_FROM);
33633361
break;
3364-
}
33653362
case Compare_kind:
33663363
return compiler_compare(c, e);
33673364
case Call_kind:

Python/symtable.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,14 +1371,14 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
13711371
VISIT_QUIT(st, 0);
13721372
break;
13731373
case Yield_kind:
1374-
case YieldFrom_kind: {
1375-
expr_ty value;
1376-
value = (e->kind == YieldFrom_kind) ? e->v.YieldFrom.value : e->v.Yield.value;
1377-
if (value)
1378-
VISIT(st, expr, value);
1374+
if (e->v.Yield.value)
1375+
VISIT(st, expr, e->v.Yield.value);
1376+
st->st_cur->ste_generator = 1;
1377+
break;
1378+
case YieldFrom_kind:
1379+
VISIT(st, expr, e->v.YieldFrom.value);
13791380
st->st_cur->ste_generator = 1;
13801381
break;
1381-
}
13821382
case Compare_kind:
13831383
VISIT(st, expr, e->v.Compare.left);
13841384
VISIT_SEQ(st, expr, e->v.Compare.comparators);

0 commit comments

Comments
 (0)