bpo-33786: Fix asynchronous generators to handle GeneratorExit in athrow() (GH-7467)

diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index 1a58b50..c06ec73 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -187,7 +187,7 @@
             # in this implementation
             try:
                 await self.gen.athrow(typ, value, traceback)
-                raise RuntimeError("generator didn't stop after throw()")
+                raise RuntimeError("generator didn't stop after athrow()")
             except StopAsyncIteration as exc:
                 return exc is not value
             except RuntimeError as exc:
diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py
index 8dc76ce..9d60cb0 100644
--- a/Lib/test/test_asyncgen.py
+++ b/Lib/test/test_asyncgen.py
@@ -111,6 +111,31 @@
         def async_iterate(g):
             res = []
             while True:
+                an = g.__anext__()
+                try:
+                    while True:
+                        try:
+                            an.__next__()
+                        except StopIteration as ex:
+                            if ex.args:
+                                res.append(ex.args[0])
+                                break
+                            else:
+                                res.append('EMPTY StopIteration')
+                                break
+                        except StopAsyncIteration:
+                            raise
+                        except Exception as ex:
+                            res.append(str(type(ex)))
+                            break
+                except StopAsyncIteration:
+                    res.append('STOP')
+                    break
+            return res
+
+        def async_iterate(g):
+            res = []
+            while True:
                 try:
                     g.__anext__().__next__()
                 except StopAsyncIteration:
@@ -297,6 +322,37 @@
                                     "non-None value .* async generator"):
             gen().__anext__().send(100)
 
+    def test_async_gen_exception_11(self):
+        def sync_gen():
+            yield 10
+            yield 20
+
+        def sync_gen_wrapper():
+            yield 1
+            sg = sync_gen()
+            sg.send(None)
+            try:
+                sg.throw(GeneratorExit())
+            except GeneratorExit:
+                yield 2
+            yield 3
+
+        async def async_gen():
+            yield 10
+            yield 20
+
+        async def async_gen_wrapper():
+            yield 1
+            asg = async_gen()
+            await asg.asend(None)
+            try:
+                await asg.athrow(GeneratorExit())
+            except GeneratorExit:
+                yield 2
+            yield 3
+
+        self.compare_generators(sync_gen_wrapper(), async_gen_wrapper())
+
     def test_async_gen_api_01(self):
         async def gen():
             yield 123
diff --git a/Lib/test/test_contextlib_async.py b/Lib/test/test_contextlib_async.py
index 355955f..39dcd9b 100644
--- a/Lib/test/test_contextlib_async.py
+++ b/Lib/test/test_contextlib_async.py
@@ -36,6 +36,28 @@
         async with manager as context:
             self.assertIs(manager, context)
 
+    @_async_test
+    async def test_async_gen_propagates_generator_exit(self):
+        # A regression test for https://bugs.python.org/issue33786.
+
+        @asynccontextmanager
+        async def ctx():
+            yield
+
+        async def gen():
+            async with ctx():
+                yield 11
+
+        ret = []
+        exc = ValueError(22)
+        with self.assertRaises(ValueError):
+            async with ctx():
+                async for val in gen():
+                    ret.append(val)
+                    raise exc
+
+        self.assertEqual(ret, [11])
+
     def test_exit_is_abstract(self):
         class MissingAexit(AbstractAsyncContextManager):
             pass