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

Reply via email to