From 1e784ef4fbbf9aa5e405c295979707e23a34fb00 Mon Sep 17 00:00:00 2001
From: Stefan Behnel <stefan_ml@behnel.de>
Date: Wed, 27 May 2015 21:11:24 +0200
Subject: [PATCH] make sure Cython's generator and coroutine types are
 registered with the Generator/Coroutine ABCs also in Py3.5 patch both types
 also into asyncio (in Py<3.5)

---
 Cython/Utility/Coroutine.c | 142 ++++++++++++++++++++-----------------
 1 file changed, 78 insertions(+), 64 deletions(-)

diff --git a/Cython/Utility/Coroutine.c b/Cython/Utility/Coroutine.c
index 44f216943..2a1bab9e6 100644
--- a/Cython/Utility/Coroutine.c
+++ b/Cython/Utility/Coroutine.c
@@ -1267,7 +1267,8 @@ static int __Pyx_patch_abc(void); /*proto*/
 //@requires: PatchModuleWithCoroutine
 
 static int __Pyx_patch_abc(void) {
-#if (defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)) && (!defined(CYTHON_PATCH_ABC) || CYTHON_PATCH_ABC)
+#if (defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED)) && \
+        (!defined(CYTHON_PATCH_ABC) || CYTHON_PATCH_ABC)
     static int abc_patched = 0;
     if (!abc_patched) {
         PyObject *module;
@@ -1281,35 +1282,10 @@ static int __Pyx_patch_abc(void) {
                 return -1;
             }
         } else {
-            PyObject *abc;
-            int needs_generator = 1, needs_coroutine = 1;
-            #ifdef __Pyx_Generator_USED
-            abc = PyObject_GetAttrString(module, "Generator");
-            if (abc) {
-                needs_generator = 0;
-                Py_DECREF(abc);
-            } else {
-                PyErr_Clear();
-            }
-            #else
-            needs_generator = 0;
-            #endif
-            #ifdef __Pyx_Coroutine_USED
-            abc = PyObject_GetAttrString(module, "Coroutine");
-            if (abc) {
-                needs_coroutine = 0;
-                Py_DECREF(abc);
-            } else {
-                PyErr_Clear();
-            }
-            #else
-            needs_coroutine = 0;
-            #endif
-            if (needs_coroutine || needs_generator) {
-                module = __Pyx_Coroutine_patch_module(
-                    module,
+            module = __Pyx_Coroutine_patch_module(
+                module,
 #ifdef __Pyx_Generator_USED
-                    CSTRING("""\
+                CSTRING("""\
 def mk_gen():
     from abc import abstractmethod
 
@@ -1364,29 +1340,31 @@ def mk_gen():
 
     generator = type((lambda: (yield))())
     Generator.register(generator)
-    Generator.register(_cython_generator_type)
     return Generator
 
-_module.Generator = mk_gen()
+try:
+    Generator = _module.Generator
+except AttributeError:
+    Generator = _module.Generator = mk_gen()
+Generator.register(_cython_generator_type)
 """)
 #endif
 #ifdef __Pyx_Coroutine_USED
-                    CSTRING("""\
+                CSTRING("""\
 def mk_coroutine():
     from abc import abstractmethod, ABCMeta
-
 """)
 #if PY_MAJOR_VERSION >= 3
-                    CSTRING("""\
+                CSTRING("""\
     class Coroutine(metaclass=ABCMeta):
 """)
 #else
-                    CSTRING("""\
+                CSTRING("""\
     class Coroutine(object):
         __metaclass__ = ABCMeta
 """)
 #endif
-                    CSTRING("""\
+                CSTRING("""\
         __slots__ = ()
 
         @abstractmethod
@@ -1419,18 +1397,28 @@ def mk_coroutine():
             else:
                 raise RuntimeError('coroutine ignored GeneratorExit')
 
+    return Coroutine
+
+try:
+    Coroutine = _module.Coroutine
+except AttributeError:
+    Coroutine = _module.Coroutine = mk_coroutine()
+Coroutine.register(_cython_coroutine_type)
+
+def mk_awaitable():
+    from abc import abstractmethod, ABCMeta
 """)
 #if PY_MAJOR_VERSION >= 3
-                    CSTRING("""\
+                CSTRING("""\
     class Awaitable(metaclass=ABCMeta):
 """)
 #else
-                    CSTRING("""\
+                CSTRING("""\
     class Awaitable(object):
         __metaclass__ = ABCMeta
 """)
 #endif
-                    CSTRING("""\
+                CSTRING("""\
         __slots__ = ()
 
         @abstractmethod
@@ -1447,23 +1435,21 @@ def mk_coroutine():
                         break
             return NotImplemented
 
-    try:
-        _module.Awaitable
-    except AttributeError:
-        Awaitable.register(Coroutine)
-        _module.Awaitable = Awaitable
+    return Awaitable
 
-    Coroutine.register(_cython_coroutine_type)
-    return Coroutine
+try:
+    Awaitable = _module.Awaitable
+except AttributeError:
+    Awaitable = _module.Awaitable = mk_awaitable()
+    Awaitable.register(Coroutine)
 
-_module.Coroutine = mk_coroutine()
+Awaitable.register(_cython_coroutine_type)
 """)
 #endif
-                );
-                abc_patched = 1;
-                if (unlikely(!module))
-                    return -1;
-            }
+            );
+            abc_patched = 1;
+            if (unlikely(!module))
+                return -1;
             Py_DECREF(module);
         }
     }
@@ -1481,11 +1467,14 @@ _module.Coroutine = mk_coroutine()
 static PyObject* __Pyx_patch_asyncio(PyObject* module); /*proto*/
 
 //////////////////// PatchAsyncIO ////////////////////
+//@requires: ImportExport.c::Import
 //@requires: PatchModuleWithCoroutine
 //@requires: PatchInspect
 
 static PyObject* __Pyx_patch_asyncio(PyObject* module) {
-#if defined(__Pyx_Generator_USED) && (!defined(CYTHON_PATCH_ASYNCIO) || CYTHON_PATCH_ASYNCIO)
+#if PY_VERSION_HEX < 0x030500B1 && \
+        (defined(__Pyx_Coroutine_USED) || defined(__Pyx_Generator_USED)) && \
+        (!defined(CYTHON_PATCH_ASYNCIO) || CYTHON_PATCH_ASYNCIO)
     PyObject *patch_module = NULL;
     static int asyncio_patched = 0;
     if (unlikely((!asyncio_patched) && module)) {
@@ -1494,12 +1483,25 @@ static PyObject* __Pyx_patch_asyncio(PyObject* module) {
         if (package) {
             patch_module = __Pyx_Coroutine_patch_module(
                 PyObject_GetAttrString(package, "coroutines"), CSTRING("""\
-old_types = getattr(_module, '_COROUTINE_TYPES', None)
-if old_types is not None and _cython_generator_type not in old_types:
-    _module._COROUTINE_TYPES = type(old_types) (tuple(old_types) + (_cython_generator_type,))
+coro_types = getattr(_module, '_COROUTINE_TYPES', None)
+""")
+#ifdef __Pyx_Coroutine_USED
+CSTRING("""\
+if coro_types is not None and _cython_coroutine_type not in coro_types:
+    coro_types = type(coro_types) (tuple(coro_types) + (_cython_coroutine_type,))
+""")
+#endif
+#ifdef __Pyx_Generator_USED
+CSTRING("""\
+if coro_types is not None and _cython_generator_type not in coro_types:
+    coro_types = type(coro_types) (tuple(coro_types) + (_cython_generator_type,))
+""")
+#endif
+CSTRING("""
+_module._COROUTINE_TYPES = coro_types
 """)
             );
-        #if PY_VERSION_HEX < 0x03050000
+#if PY_VERSION_HEX < 0x03050000
         } else {
             // Py3.4 used to have asyncio.tasks instead of asyncio.coroutines
             PyErr_Clear();
@@ -1507,14 +1509,26 @@ if old_types is not None and _cython_generator_type not in old_types:
             if (unlikely(!package)) goto asyncio_done;
             patch_module = __Pyx_Coroutine_patch_module(
                 PyObject_GetAttrString(package, "tasks"), CSTRING("""\
-if (hasattr(_module, 'iscoroutine') and
-        getattr(_module.iscoroutine, '_cython_generator_type', None) is not _cython_generator_type):
-    def cy_wrap(orig_func, cython_generator_type=_cython_generator_type, type=type):
-        def cy_iscoroutine(obj): return type(obj) is cython_generator_type or orig_func(obj)
-        cy_iscoroutine._cython_generator_type = cython_generator_type
-        return cy_iscoroutine
-    _module.iscoroutine = cy_wrap(_module.iscoroutine)
+if hasattr(_module, 'iscoroutine'):
+    old_coroutine_types = getattr(_module.iscoroutine, '_cython_coroutine_types', None)
+    if old_coroutine_types is None or not isinstance(old_coroutine_types, list):
+        old_coroutine_types = []
+        def cy_wrap(orig_func, type=type, cython_coroutine_types=old_coroutine_types):
+            def cy_iscoroutine(obj): return type(obj) in cython_coroutine_types or orig_func(obj)
+            cy_iscoroutine._cython_coroutine_types = cython_coroutine_types
+            return cy_iscoroutine
+        _module.iscoroutine = cy_wrap(_module.iscoroutine)
+""")
+#ifdef __Pyx_Coroutine_USED
+CSTRING("""\
+    if _cython_coroutine_type not in old_coroutine_types: old_coroutine_types.append(_cython_coroutine_type)
 """)
+#endif
+#ifdef __Pyx_Generator_USED
+CSTRING("""\
+    if _cython_generator_type not in old_coroutine_types: old_coroutine_types.append(_cython_generator_type)
+""")
+#endif
             );
         #endif
         }
-- 
2.30.9