Commit cf51fa4e authored by Stefan Behnel's avatar Stefan Behnel

make Coroutine type a non-iterable/iterator and instead let __await__() return...

make Coroutine type a non-iterable/iterator and instead let __await__() return a thin Iterator wrapper
parent 1e784ef4
...@@ -19,8 +19,8 @@ static CYTHON_INLINE PyObject* __Pyx_Generator_Yield_From(__pyx_CoroutineObject ...@@ -19,8 +19,8 @@ static CYTHON_INLINE PyObject* __Pyx_Generator_Yield_From(__pyx_CoroutineObject
&& __Pyx_Coroutine_CheckExact(source)) { && __Pyx_Coroutine_CheckExact(source)) {
PyErr_Clear(); PyErr_Clear();
// TODO: this should only happen for types.coroutine()ed generators, but we can't determine that here // TODO: this should only happen for types.coroutine()ed generators, but we can't determine that here
Py_INCREF(source); source_gen = __Pyx__Coroutine_await(source);
source_gen = source; if (unlikely(!source_gen)) return NULL;
} else } else
#endif #endif
return NULL; return NULL;
...@@ -257,12 +257,14 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue); ...@@ -257,12 +257,14 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue);
#define __Pyx_Coroutine_USED #define __Pyx_Coroutine_USED
static PyTypeObject *__pyx_CoroutineType = 0; static PyTypeObject *__pyx_CoroutineType = 0;
static PyTypeObject *__pyx_CoroutineAwaitType = 0;
#define __Pyx_Coroutine_CheckExact(obj) (Py_TYPE(obj) == __pyx_CoroutineType) #define __Pyx_Coroutine_CheckExact(obj) (Py_TYPE(obj) == __pyx_CoroutineType)
#define __Pyx_Coroutine_New(body, closure, name, qualname) \ #define __Pyx_Coroutine_New(body, closure, name, qualname) \
__Pyx__Coroutine_New(__pyx_CoroutineType, body, closure, name, qualname) __Pyx__Coroutine_New(__pyx_CoroutineType, body, closure, name, qualname)
static int __pyx_Coroutine_init(void); static int __pyx_Coroutine_init(void);
static CYTHON_INLINE PyObject *__Pyx__Coroutine_await(PyObject *coroutine);
//////////////////// Generator.proto //////////////////// //////////////////// Generator.proto ////////////////////
...@@ -943,6 +945,105 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_New(PyTypeObject* type, __pyx_cor ...@@ -943,6 +945,105 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_New(PyTypeObject* type, __pyx_cor
//@requires: CoroutineBase //@requires: CoroutineBase
//@requires: PatchGeneratorABC //@requires: PatchGeneratorABC
typedef struct {
PyObject_HEAD
PyObject *coroutine;
} __pyx_CoroutineAwaitObject;
static void __Pyx_CoroutineAwait_dealloc(PyObject *self) {
PyObject_GC_UnTrack(self);
Py_CLEAR(((__pyx_CoroutineAwaitObject*)self)->coroutine);
PyObject_GC_Del(self);
}
static int __Pyx_CoroutineAwait_traverse(__pyx_CoroutineAwaitObject *self, visitproc visit, void *arg) {
Py_VISIT(self->coroutine);
return 0;
}
static int __Pyx_CoroutineAwait_clear(__pyx_CoroutineAwaitObject *self) {
Py_CLEAR(self->coroutine);
return 0;
}
static PyObject *__Pyx_CoroutineAwait_Next(__pyx_CoroutineAwaitObject *self) {
return __Pyx_Generator_Next(self->coroutine);
}
static PyObject *__Pyx_CoroutineAwait_self(PyObject *self) {
Py_INCREF(self);
return self;
}
static PyTypeObject __pyx_CoroutineAwaitType_type = {
PyVarObject_HEAD_INIT(0, 0)
"coroutine_await", /*tp_name*/
sizeof(__pyx_CoroutineAwaitObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor) __Pyx_CoroutineAwait_dealloc,/*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_as_async resp. tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
0, /*tp_doc*/
(traverseproc) __Pyx_CoroutineAwait_traverse, /*tp_traverse*/
(inquiry) __Pyx_CoroutineAwait_clear, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
__Pyx_CoroutineAwait_self, /*tp_iter*/
(iternextfunc) __Pyx_CoroutineAwait_Next, /*tp_iternext*/
0, /*tp_methods*/
0 , /*tp_members*/
0 , /*tp_getset*/
0, /*tp_base*/
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
0, /*tp_dictoffset*/
0, /*tp_init*/
0, /*tp_alloc*/
0, /*tp_new*/
0, /*tp_free*/
0, /*tp_is_gc*/
0, /*tp_bases*/
0, /*tp_mro*/
0, /*tp_cache*/
0, /*tp_subclasses*/
0, /*tp_weaklist*/
0, /*tp_del*/
0, /*tp_version_tag*/
#if PY_VERSION_HEX >= 0x030400a1
0, /*tp_finalize*/
#endif
};
static CYTHON_INLINE PyObject *__Pyx__Coroutine_await(PyObject *coroutine) {
PyObject *await = __pyx_CoroutineAwaitType->tp_alloc(__pyx_CoroutineAwaitType, 0);
if (unlikely(!await)) return NULL;
Py_INCREF(coroutine);
((__pyx_CoroutineAwaitObject*)await)->coroutine = coroutine;
return await;
}
static PyObject *__Pyx_Coroutine_await(PyObject *coroutine) {
if (unlikely(!coroutine || !__Pyx_Coroutine_CheckExact(coroutine))) {
PyErr_SetString(PyExc_TypeError, "invalid input, expected coroutine");
return NULL;
}
return __Pyx__Coroutine_await(coroutine);
}
static void __Pyx_Coroutine_check_and_dealloc(PyObject *self) { static void __Pyx_Coroutine_check_and_dealloc(PyObject *self) {
__pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self; __pyx_CoroutineObject *gen = (__pyx_CoroutineObject *) self;
...@@ -991,24 +1092,19 @@ static void __Pyx_Coroutine_check_and_dealloc(PyObject *self) { ...@@ -991,24 +1092,19 @@ static void __Pyx_Coroutine_check_and_dealloc(PyObject *self) {
__Pyx_Coroutine_dealloc(self); __Pyx_Coroutine_dealloc(self);
} }
static PyObject *__Pyx_Coroutine_return_self(PyObject *self) {
Py_INCREF(self);
return self;
}
static PyMethodDef __pyx_Coroutine_methods[] = { static PyMethodDef __pyx_Coroutine_methods[] = {
{"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O, 0}, {"send", (PyCFunction) __Pyx_Coroutine_Send, METH_O, 0},
{"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS, 0}, {"throw", (PyCFunction) __Pyx_Coroutine_Throw, METH_VARARGS, 0},
{"close", (PyCFunction) __Pyx_Coroutine_Close, METH_NOARGS, 0}, {"close", (PyCFunction) __Pyx_Coroutine_Close, METH_NOARGS, 0},
#if PY_VERSION_HEX < 0x030500B1 #if PY_VERSION_HEX < 0x030500B1
{"__await__", (PyCFunction) __Pyx_Coroutine_return_self, METH_NOARGS, 0}, {"__await__", (PyCFunction) __Pyx_Coroutine_await, METH_NOARGS, 0},
#endif #endif
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
#if PY_VERSION_HEX >= 0x030500B1 #if PY_VERSION_HEX >= 0x030500B1
static PyAsyncMethods __pyx_Coroutine_as_async = { static PyAsyncMethods __pyx_Coroutine_as_async = {
__Pyx_Coroutine_return_self, /*am_await*/ __Pyx_Coroutine_await, /*am_await*/
0, /*am_aiter*/ 0, /*am_aiter*/
0, /*am_anext*/ 0, /*am_anext*/
}; };
...@@ -1046,7 +1142,7 @@ static PyTypeObject __pyx_CoroutineType_type = { ...@@ -1046,7 +1142,7 @@ static PyTypeObject __pyx_CoroutineType_type = {
offsetof(__pyx_CoroutineObject, gi_weakreflist), /*tp_weaklistoffset*/ offsetof(__pyx_CoroutineObject, gi_weakreflist), /*tp_weaklistoffset*/
// no tp_iter() as iterator is only available through __await__() // no tp_iter() as iterator is only available through __await__()
0, /*tp_iter*/ 0, /*tp_iter*/
(iternextfunc) __Pyx_Generator_Next, /*tp_iternext*/ 0, /*tp_iternext*/
__pyx_Coroutine_methods, /*tp_methods*/ __pyx_Coroutine_methods, /*tp_methods*/
__pyx_Coroutine_memberlist, /*tp_members*/ __pyx_Coroutine_memberlist, /*tp_members*/
__pyx_Coroutine_getsets, /*tp_getset*/ __pyx_Coroutine_getsets, /*tp_getset*/
...@@ -1081,9 +1177,12 @@ static int __pyx_Coroutine_init(void) { ...@@ -1081,9 +1177,12 @@ static int __pyx_Coroutine_init(void) {
__pyx_CoroutineType_type.tp_getattro = PyObject_GenericGetAttr; __pyx_CoroutineType_type.tp_getattro = PyObject_GenericGetAttr;
__pyx_CoroutineType = __Pyx_FetchCommonType(&__pyx_CoroutineType_type); __pyx_CoroutineType = __Pyx_FetchCommonType(&__pyx_CoroutineType_type);
if (unlikely(!__pyx_CoroutineType)) { if (unlikely(!__pyx_CoroutineType))
return -1;
__pyx_CoroutineAwaitType = __Pyx_FetchCommonType(&__pyx_CoroutineAwaitType_type);
if (unlikely(!__pyx_CoroutineType))
return -1; return -1;
}
return 0; return 0;
} }
...@@ -1230,6 +1329,7 @@ static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_c ...@@ -1230,6 +1329,7 @@ static PyObject* __Pyx_Coroutine_patch_module(PyObject* module, const char* py_c
globals = PyDict_New(); if (unlikely(!globals)) goto ignore; globals = PyDict_New(); if (unlikely(!globals)) goto ignore;
#ifdef __Pyx_Coroutine_USED #ifdef __Pyx_Coroutine_USED
if (unlikely(PyDict_SetItemString(globals, "_cython_coroutine_type", (PyObject*)__pyx_CoroutineType) < 0)) goto ignore; if (unlikely(PyDict_SetItemString(globals, "_cython_coroutine_type", (PyObject*)__pyx_CoroutineType) < 0)) goto ignore;
if (unlikely(PyDict_SetItemString(globals, "_cython_coroutine_await_type", (PyObject*)__pyx_CoroutineAwaitType) < 0)) goto ignore;
#endif #endif
#ifdef __Pyx_Generator_USED #ifdef __Pyx_Generator_USED
if (unlikely(PyDict_SetItemString(globals, "_cython_generator_type", (PyObject*)__pyx_GeneratorType) < 0)) goto ignore; if (unlikely(PyDict_SetItemString(globals, "_cython_generator_type", (PyObject*)__pyx_GeneratorType) < 0)) goto ignore;
......
...@@ -213,9 +213,8 @@ class CoroutineTest(unittest.TestCase): ...@@ -213,9 +213,8 @@ class CoroutineTest(unittest.TestCase):
with check(): with check():
iter(foo()) iter(foo())
# in Cython: not iterable, but an iterator ... with check():
#with check(): next(foo())
# next(foo())
with silence_coro_gc(), check(): with silence_coro_gc(), check():
for i in foo(): for i in foo():
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment