Author: Armin Rigo <armin.r...@gmail.com> Branch: py3.6 Changeset: r96995:0c8150a9aba8 Date: 2019-07-14 12:13 +0000 http://bitbucket.org/pypy/pypy/changeset/0c8150a9aba8/
Log: Merged in vxgmichel/pypy/bpo-35409 (pull request #655) Ignore GeneratorExit when throwing into the aclose coroutine of an asynchronous generator diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -661,15 +661,7 @@ return self.do_send(w_arg) def descr_throw(self, w_type, w_val=None, w_tb=None): - space = self.space - if self.state == self.ST_CLOSED: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_value = self.async_gen.throw(w_type, w_val, w_tb) - return self.unwrap_value(w_value) - except OperationError as e: - self.state = self.ST_CLOSED - raise + return self.do_throw(w_type, w_val, w_tb) def descr_close(self): self.state = self.ST_CLOSED @@ -715,6 +707,17 @@ self.state = self.ST_CLOSED raise + def do_throw(self, w_type, w_val, w_tb): + space = self.space + if self.state == self.ST_CLOSED: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_value = self.async_gen.throw(w_type, w_val, w_tb) + return self.unwrap_value(w_value) + except OperationError as e: + self.state = self.ST_CLOSED + raise + class AsyncGenAThrow(AsyncGenABase): @@ -756,21 +759,31 @@ w_value = self.async_gen.send_ex(w_arg_or_err) return self.unwrap_value(w_value) except OperationError as e: - if e.match(space, space.w_StopAsyncIteration): - self.state = self.ST_CLOSED - if self.w_exc_type is None: - # When aclose() is called we don't want to propagate - # StopAsyncIteration; just raise StopIteration, signalling - # that 'aclose()' is done. - raise OperationError(space.w_StopIteration, space.w_None) - if e.match(space, space.w_GeneratorExit): - self.state = self.ST_CLOSED - # Ignore this error. - raise OperationError(space.w_StopIteration, space.w_None) - raise + self.handle_error(e) - def descr_throw(self, w_type, w_val=None, w_tb=None): + def do_throw(self, w_type, w_val, w_tb): + space = self.space if self.state == self.ST_INIT: raise OperationError(self.space.w_RuntimeError, - self.space.newtext("can't do async_generator.athrow().throw()")) - return AsyncGenABase.descr_throw(self, w_type, w_val, w_tb) + space.newtext("can't do async_generator.athrow().throw()")) + if self.state == self.ST_CLOSED: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_value = self.async_gen.throw(w_type, w_val, w_tb) + return self.unwrap_value(w_value) + except OperationError as e: + self.handle_error(e) + + def handle_error(self, e): + space = self.space + self.state = self.ST_CLOSED + if e.match(space, space.w_StopAsyncIteration): + if self.w_exc_type is None: + # When aclose() is called we don't want to propagate + # StopAsyncIteration; just raise StopIteration, signalling + # that 'aclose()' is done. + raise OperationError(space.w_StopIteration, space.w_None) + if e.match(space, space.w_GeneratorExit): + # Ignore this error. + raise OperationError(space.w_StopIteration, space.w_None) + raise e diff --git a/pypy/interpreter/test/test_coroutine.py b/pypy/interpreter/test/test_coroutine.py --- a/pypy/interpreter/test/test_coroutine.py +++ b/pypy/interpreter/test/test_coroutine.py @@ -453,6 +453,15 @@ assert ex.value.args == expected """ + def test_async_yield_athrow_send_after_exception(self): """ + async def ag(): + yield 42 + + athrow_coro = ag().athrow(ValueError) + raises(ValueError, athrow_coro.send, None) + raises(StopIteration, athrow_coro.send, None) + """ + def test_async_yield_athrow_throw(self): """ async def ag(): yield 42 @@ -558,6 +567,42 @@ assert state == 2 """ + def test_async_aclose_await_in_finally_with_exception(self): """ + import types + + @types.coroutine + def coro(): + yield 'coro' + + state = 0 + async def ag(): + nonlocal state + try: + yield + finally: + state = 1 + try: + await coro() + except Exception as exc: + state = exc + + async def run(): + a = ag() + async for i in a: + break + await a.aclose() + a = run() + assert state == 0 + assert a.send(None) == 'coro' + assert state == 1 + exc = RuntimeError() + try: + a.throw(exc) + except StopIteration: + pass + assert state == exc + """ + def test_async_aclose_in_finalize_hook_await_in_finally(self): """ import gc import sys _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit