[pypy-commit] pypy bpo-35409: Ignore GeneratorExit when throwing into the aclose coroutine of an asynchronous generator

vxgmichel pypy.commits at gmail.com
Sun Jul 14 08:14:18 EDT 2019


Author: Vincent Michel <vxgmichel at gmail.com>
Branch: bpo-35409
Changeset: r96993:f29b8a6e72dd
Date: 2019-07-13 18:12 +0200
http://bitbucket.org/pypy/pypy/changeset/f29b8a6e72dd/

Log:	Ignore GeneratorExit when throwing into the aclose coroutine of an
	asynchronous generator

	Related issues and pull requests on cpython:
	- https://bugs.python.org/issue35409
	- https://github.com/python/cpython/pull/14755

diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -770,7 +770,20 @@
             raise
 
     def descr_throw(self, w_type, w_val=None, w_tb=None):
+        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()"))
+        try:
+            return AsyncGenABase.descr_throw(self, w_type, w_val, w_tb)
+        except OperationError as e:
+            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
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
@@ -558,6 +558,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


More information about the pypy-commit mailing list