Skip to content
Permalink
Browse files

py/objgenerator: Fix handling of None passed as 2nd arg to throw().

Fixes issue micropython#4527.
  • Loading branch information...
dpgeorge committed Feb 21, 2019
1 parent 29865e3 commit dac9d4767175541aaaaf0e2f873322f5f1db3b0c
Showing with 48 additions and 5 deletions.
  1. +16 −1 py/objgenerator.c
  2. +20 −2 tests/basics/gen_yield_from_throw.py
  3. +12 −2 tests/basics/generator_throw.py
@@ -252,7 +252,22 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send);

STATIC mp_obj_t gen_instance_close(mp_obj_t self_in);
STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) {
mp_obj_t exc = (n_args == 2) ? args[1] : args[2];
// The signature of this function is: throw(type[, value[, traceback]])
// CPython will pass all given arguments through the call chain and process them
// at the point they are used (native generators will handle them differently to
// user-defined generators with a throw() method). To save passing multiple
// values, MicroPython instead does partial processing here to reduce it down to
// one argument and passes that through:
// - if only args[1] is given, or args[2] is given but is None, args[1] is
// passed through (in the standard case it is an exception class or instance)
// - if args[2] is given and not None it is passed through (in the standard
// case it would be an exception instance and args[1] its corresponding class)
// - args[3] is always ignored

mp_obj_t exc = args[1];
if (n_args > 2 && args[2] != mp_const_none) {
exc = args[2];
}

mp_obj_t ret = gen_resume_and_raise(args[0], mp_const_none, exc);
if (ret == MP_OBJ_STOP_ITERATION) {
@@ -1,8 +1,8 @@
def gen():
try:
yield 1
except ValueError:
print("got ValueError from upstream!")
except ValueError as e:
print("got ValueError from upstream!", repr(e.args))
yield "str1"
raise TypeError

@@ -16,3 +16,21 @@ def gen2():
print(next(g))
except TypeError:
print("got TypeError from downstream!")

# passing None as second argument to throw
g = gen2()
print(next(g))
print(g.throw(ValueError, None))
try:
print(next(g))
except TypeError:
print("got TypeError from downstream!")

# passing an exception instance as second argument to throw
g = gen2()
print(next(g))
print(g.throw(ValueError, ValueError(123)))
try:
print(next(g))
except TypeError:
print("got TypeError from downstream!")
@@ -28,8 +28,8 @@ def gen():
def gen():
try:
yield 123
except GeneratorExit:
print('GeneratorExit')
except GeneratorExit as e:
print('GeneratorExit', repr(e.args))
yield 456

# thrown a class
@@ -41,3 +41,13 @@ def gen():
g = gen()
print(next(g))
print(g.throw(GeneratorExit()))

# thrown an instance with None as second arg
g = gen()
print(next(g))
print(g.throw(GeneratorExit(), None))

# thrown a class and instance
g = gen()
print(next(g))
print(g.throw(GeneratorExit, GeneratorExit(123)))

0 comments on commit dac9d47

Please sign in to comment.
You can’t perform that action at this time.