From e972618117ca89b0ccc52db10668d7fc77d5d9d7 Mon Sep 17 00:00:00 2001
From: Stefan Behnel <stefan_ml@behnel.de>
Date: Sat, 29 Jul 2017 20:58:16 +0200
Subject: [PATCH] make async generator type async-iterable in older Python
 versions

---
 Cython/Utility/AsyncGen.c  |  8 +++++
 tests/run/test_asyncgen.py | 64 +++++++++++++++++++++++++++++++++++---
 2 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/Cython/Utility/AsyncGen.c b/Cython/Utility/AsyncGen.c
index 0b7a95f33..12b1d5d04 100644
--- a/Cython/Utility/AsyncGen.c
+++ b/Cython/Utility/AsyncGen.c
@@ -302,10 +302,18 @@ PyDoc_STRVAR(__Pyx_async_asend_doc,
 PyDoc_STRVAR(__Pyx_async_athrow_doc,
 "athrow(typ[,val[,tb]]) -> raise exception in generator.");
 
+PyDoc_STRVAR(__Pyx_async_aiter_doc,
+"__aiter__(v) -> return an asynchronous iterator.");
+
+PyDoc_STRVAR(__Pyx_async_anext_doc,
+"__anext__(v) -> continue asynchronous iteration and return the next element.");
+
 static PyMethodDef __Pyx_async_gen_methods[] = {
     {"asend", (PyCFunction)__Pyx_async_gen_asend, METH_O, __Pyx_async_asend_doc},
     {"athrow",(PyCFunction)__Pyx_async_gen_athrow, METH_VARARGS, __Pyx_async_athrow_doc},
     {"aclose", (PyCFunction)__Pyx_async_gen_aclose, METH_NOARGS, __Pyx_async_aclose_doc},
+    {"__aiter__", (PyCFunction)PyObject_SelfIter, METH_NOARGS, __Pyx_async_aiter_doc},
+    {"__anext__", (PyCFunction)__Pyx_async_gen_anext, METH_NOARGS, __Pyx_async_anext_doc},
     {0, 0, 0, 0}        /* Sentinel */
 };
 
diff --git a/tests/run/test_asyncgen.py b/tests/run/test_asyncgen.py
index c51b804f4..a07c7cfa4 100644
--- a/tests/run/test_asyncgen.py
+++ b/tests/run/test_asyncgen.py
@@ -6,8 +6,8 @@ from __future__ import generator_stop
 
 import os
 import sys
-import inspect
-import types
+#import inspect
+#import types
 import unittest
 import contextlib
 
@@ -36,8 +36,64 @@ else:
 try:
     from types import coroutine as types_coroutine
 except ImportError:
-    def types_coroutine(f):
-        return f
+    def types_coroutine(func):
+        from functools import wraps
+        wrapped = wraps(func)
+
+        # copied from types.py in Py3.6
+        class _GeneratorWrapper(object):
+            # TODO: Implement this in C.
+            def __init__(self, gen):
+                self.__wrapped = gen
+                self.__isgen = hasattr(gen, 'gi_running')
+                self.__name__ = getattr(gen, '__name__', None)
+                self.__qualname__ = getattr(gen, '__qualname__', None)
+
+            def send(self, val):
+                return self.__wrapped.send(val)
+
+            def throw(self, tp, *rest):
+                return self.__wrapped.throw(tp, *rest)
+
+            def close(self):
+                return self.__wrapped.close()
+
+            @property
+            def gi_code(self):
+                return self.__wrapped.gi_code
+
+            @property
+            def gi_frame(self):
+                return self.__wrapped.gi_frame
+
+            @property
+            def gi_running(self):
+                return self.__wrapped.gi_running
+
+            @property
+            def gi_yieldfrom(self):
+                return self.__wrapped.gi_yieldfrom
+
+            cr_code = gi_code
+            cr_frame = gi_frame
+            cr_running = gi_running
+            cr_await = gi_yieldfrom
+
+            def __next__(self):
+                return next(self.__wrapped)
+
+            def __iter__(self):
+                if self.__isgen:
+                    return self.__wrapped
+                return self
+
+            __await__ = __iter__
+
+        @wrapped
+        def call(*args, **kwargs):
+            return wrapped(_GeneratorWrapper(func(*args, **kwargs)))
+
+        return call
 
 try:
     from inspect import isawaitable as inspect_isawaitable
-- 
2.30.9