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