From 5578182ec97509dcc37521b78da5ee31b96f6b4e Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 29 Oct 2019 21:04:55 +1100 Subject: py/objgenerator: Allow pend_throw to an unstarted generator. Replace the is_running field with a tri-state variable to indicate running/not-running/pending-exception. Update tests to cover the various cases. This allows cancellation in uasyncio even if the coroutine hasn't been executed yet. Fixes #5242 --- tests/basics/generator_pend_throw.py | 76 ++++++++++++++++++++++++++++++-- tests/basics/generator_pend_throw.py.exp | 12 ++++- 2 files changed, 84 insertions(+), 4 deletions(-) (limited to 'tests/basics') diff --git a/tests/basics/generator_pend_throw.py b/tests/basics/generator_pend_throw.py index f00ff793b..ae8c21189 100644 --- a/tests/basics/generator_pend_throw.py +++ b/tests/basics/generator_pend_throw.py @@ -13,6 +13,7 @@ except AttributeError: raise SystemExit +# Verify that an injected exception will be raised from next(). print(next(g)) print(next(g)) g.pend_throw(ValueError()) @@ -25,7 +26,76 @@ except Exception as e: print("ret was:", v) + +# Verify that pend_throw works on an unstarted coroutine. +g = gen() +g.pend_throw(OSError()) +try: + next(g) +except Exception as e: + print("raised", repr(e)) + + +# Verify that you can't resume the coroutine from within the running coroutine. +def gen_next(): + next(g) + yield 1 + +g = gen_next() + +try: + next(g) +except Exception as e: + print("raised", repr(e)) + + +# Verify that you can't pend_throw from within the running coroutine. +def gen_pend_throw(): + g.pend_throw(ValueError()) + yield 1 + +g = gen_pend_throw() + +try: + next(g) +except Exception as e: + print("raised", repr(e)) + + +# Verify that the pend_throw exception can be ignored. +class CancelledError(Exception): + pass + +def gen_cancelled(): + for i in range(5): + try: + yield i + except CancelledError: + print('ignore CancelledError') + +g = gen_cancelled() +print(next(g)) +g.pend_throw(CancelledError()) +print(next(g)) +# ...but not if the generator hasn't started. +g = gen_cancelled() +g.pend_throw(CancelledError()) try: - gen().pend_throw(ValueError()) -except TypeError: - print("TypeError") + next(g) +except Exception as e: + print("raised", repr(e)) + + +# Verify that calling pend_throw returns the previous exception. +g = gen() +next(g) +print(repr(g.pend_throw(CancelledError()))) +print(repr(g.pend_throw(OSError))) + + +# Verify that you can pend_throw(None) to cancel a previous pend_throw. +g = gen() +next(g) +g.pend_throw(CancelledError()) +print(repr(g.pend_throw(None))) +print(next(g)) diff --git a/tests/basics/generator_pend_throw.py.exp b/tests/basics/generator_pend_throw.py.exp index ed4d88295..8a3dadfec 100644 --- a/tests/basics/generator_pend_throw.py.exp +++ b/tests/basics/generator_pend_throw.py.exp @@ -2,4 +2,14 @@ 1 raised ValueError() ret was: None -TypeError +raised OSError() +raised ValueError('generator already executing',) +raised ValueError('generator already executing',) +0 +ignore CancelledError +1 +raised CancelledError() +None +CancelledError() +CancelledError() +1 -- cgit v1.2.3