Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit