Skip to content

Commit 817e76a

Browse files
committed
objgenerator.throw(GeneratorExit) is not equivalent to .close().
.throw() propagates any exceptions, and .close() swallows them. Yielding in reponse to .throw(GeneratorExit) is still fatal, and we need to handle it for .throw() case separately (previously it was handled only for .close() case). Obscure corner cases due to test_pep380.py.
1 parent 1eac05d commit 817e76a

1 file changed

Lines changed: 3 additions & 7 deletions

File tree

py/objgenerator.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o
134134
}
135135

136136
case MP_VM_RETURN_YIELD:
137+
if (throw_value != MP_OBJ_NULL && mp_obj_is_subclass_fast(mp_obj_get_type(throw_value), &mp_type_GeneratorExit)) {
138+
nlr_jump(mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit"));
139+
}
137140
return ret;
138141

139142
case MP_VM_RETURN_EXCEPTION:
@@ -171,13 +174,6 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in);
171174
STATIC mp_obj_t gen_instance_throw(uint n_args, const mp_obj_t *args) {
172175
mp_obj_t exc = (n_args == 2) ? args[1] : args[2];
173176
exc = mp_make_raise_obj(exc);
174-
if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_GeneratorExit)) {
175-
// Throwing GeneratorExit is equivalent of calling close aka
176-
// GeneratorExit should be handled specially
177-
// TODO: Calling .close() will throw new exception instance, not one
178-
// given to throw, which is not ok.
179-
return gen_instance_close(args[0]);
180-
}
181177

182178
mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc);
183179
if (ret == MP_OBJ_NULL) {

0 commit comments

Comments
 (0)