Skip to content

Commit 6738c1d

Browse files
pfalcondpgeorge
authored andcommitted
vm: Properly handle StopIteration raised in user instance iterator.
I.e. in bytecode Python functions.
1 parent d5e629a commit 6738c1d

2 files changed

Lines changed: 28 additions & 0 deletions

File tree

py/vm.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,6 +1249,12 @@ unwind_jump:;
12491249
code_state->ip = ip + ulab; // jump to after for-block
12501250
code_state->sp -= 1; // pop the exhausted iterator
12511251
goto outer_dispatch_loop; // continue with dispatch loop
1252+
} else if (*code_state->ip == MP_BC_YIELD_FROM) {
1253+
// StopIteration inside yield from call means return a value of
1254+
// yield from, so inject exception's value as yield from's result
1255+
*++code_state->sp = mp_obj_exception_get_value(nlr.ret_val);
1256+
code_state->ip++; // yield from is over, move to next instruction
1257+
goto outer_dispatch_loop; // continue with dispatch loop
12521258
}
12531259
}
12541260
}

tests/basics/gen_yield_from_ducktype.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,25 @@ def gen3():
4242
print(next(g))
4343
print(g.send(5))
4444
print(g.send(100))
45+
46+
47+
#
48+
# Test proper handling of StopIteration vs other exceptions
49+
#
50+
class MyIter:
51+
def __iter__(self):
52+
return self
53+
def __next__(self):
54+
raise StopIteration(42)
55+
56+
def gen4():
57+
global ret
58+
ret = yield from MyIter()
59+
1//0
60+
61+
ret = None
62+
try:
63+
print(list(gen4()))
64+
except ZeroDivisionError:
65+
print("ZeroDivisionError")
66+
print(ret)

0 commit comments

Comments
 (0)