diff options
| author | shadchin <[email protected]> | 2022-04-18 12:39:32 +0300 |
|---|---|---|
| committer | shadchin <[email protected]> | 2022-04-18 12:39:32 +0300 |
| commit | d4be68e361f4258cf0848fc70018dfe37a2acc24 (patch) | |
| tree | 153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Objects/iterobject.c | |
| parent | 260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff) | |
IGNIETFERRO-1816 Update Python 3 from 3.9.12 to 3.10.4
ref:9f96be6d02ee8044fdd6f124b799b270c20ce641
Diffstat (limited to 'contrib/tools/python3/src/Objects/iterobject.c')
| -rw-r--r-- | contrib/tools/python3/src/Objects/iterobject.c | 215 |
1 files changed, 213 insertions, 2 deletions
diff --git a/contrib/tools/python3/src/Objects/iterobject.c b/contrib/tools/python3/src/Objects/iterobject.c index 6cac41ad539..e493e41131b 100644 --- a/contrib/tools/python3/src/Objects/iterobject.c +++ b/contrib/tools/python3/src/Objects/iterobject.c @@ -157,7 +157,7 @@ PyTypeObject PySeqIter_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)iter_traverse, /* tp_traverse */ 0, /* tp_clear */ @@ -276,7 +276,7 @@ PyTypeObject PyCallIter_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)calliter_traverse, /* tp_traverse */ 0, /* tp_clear */ @@ -288,3 +288,214 @@ PyTypeObject PyCallIter_Type = { }; +/* -------------------------------------- */ + +typedef struct { + PyObject_HEAD + PyObject *wrapped; + PyObject *default_value; +} anextawaitableobject; + +static void +anextawaitable_dealloc(anextawaitableobject *obj) +{ + _PyObject_GC_UNTRACK(obj); + Py_XDECREF(obj->wrapped); + Py_XDECREF(obj->default_value); + PyObject_GC_Del(obj); +} + +static int +anextawaitable_traverse(anextawaitableobject *obj, visitproc visit, void *arg) +{ + Py_VISIT(obj->wrapped); + Py_VISIT(obj->default_value); + return 0; +} + +static PyObject * +anextawaitable_getiter(anextawaitableobject *obj) +{ + assert(obj->wrapped != NULL); + PyObject *awaitable = _PyCoro_GetAwaitableIter(obj->wrapped); + if (awaitable == NULL) { + return NULL; + } + if (Py_TYPE(awaitable)->tp_iternext == NULL) { + /* _PyCoro_GetAwaitableIter returns a Coroutine, a Generator, + * or an iterator. Of these, only coroutines lack tp_iternext. + */ + assert(PyCoro_CheckExact(awaitable)); + unaryfunc getter = Py_TYPE(awaitable)->tp_as_async->am_await; + PyObject *new_awaitable = getter(awaitable); + if (new_awaitable == NULL) { + Py_DECREF(awaitable); + return NULL; + } + Py_SETREF(awaitable, new_awaitable); + if (!PyIter_Check(awaitable)) { + PyErr_SetString(PyExc_TypeError, + "__await__ returned a non-iterable"); + Py_DECREF(awaitable); + return NULL; + } + } + return awaitable; +} + +static PyObject * +anextawaitable_iternext(anextawaitableobject *obj) +{ + /* Consider the following class: + * + * class A: + * async def __anext__(self): + * ... + * a = A() + * + * Then `await anext(a)` should call + * a.__anext__().__await__().__next__() + * + * On the other hand, given + * + * async def agen(): + * yield 1 + * yield 2 + * gen = agen() + * + * Then `await anext(gen)` can just call + * gen.__anext__().__next__() + */ + PyObject *awaitable = anextawaitable_getiter(obj); + if (awaitable == NULL) { + return NULL; + } + PyObject *result = (*Py_TYPE(awaitable)->tp_iternext)(awaitable); + Py_DECREF(awaitable); + if (result != NULL) { + return result; + } + if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) { + _PyGen_SetStopIterationValue(obj->default_value); + } + return NULL; +} + + +static PyObject * +anextawaitable_proxy(anextawaitableobject *obj, char *meth, PyObject *arg) { + PyObject *awaitable = anextawaitable_getiter(obj); + if (awaitable == NULL) { + return NULL; + } + PyObject *ret = PyObject_CallMethod(awaitable, meth, "O", arg); + Py_DECREF(awaitable); + if (ret != NULL) { + return ret; + } + if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) { + /* `anextawaitableobject` is only used by `anext()` when + * a default value is provided. So when we have a StopAsyncIteration + * exception we replace it with a `StopIteration(default)`, as if + * it was the return value of `__anext__()` coroutine. + */ + _PyGen_SetStopIterationValue(obj->default_value); + } + return NULL; +} + + +static PyObject * +anextawaitable_send(anextawaitableobject *obj, PyObject *arg) { + return anextawaitable_proxy(obj, "send", arg); +} + + +static PyObject * +anextawaitable_throw(anextawaitableobject *obj, PyObject *arg) { + return anextawaitable_proxy(obj, "throw", arg); +} + + +static PyObject * +anextawaitable_close(anextawaitableobject *obj, PyObject *arg) { + return anextawaitable_proxy(obj, "close", arg); +} + + +PyDoc_STRVAR(send_doc, +"send(arg) -> send 'arg' into the wrapped iterator,\n\ +return next yielded value or raise StopIteration."); + + +PyDoc_STRVAR(throw_doc, +"throw(typ[,val[,tb]]) -> raise exception in the wrapped iterator,\n\ +return next yielded value or raise StopIteration."); + + +PyDoc_STRVAR(close_doc, +"close() -> raise GeneratorExit inside generator."); + + +static PyMethodDef anextawaitable_methods[] = { + {"send",(PyCFunction)anextawaitable_send, METH_O, send_doc}, + {"throw",(PyCFunction)anextawaitable_throw, METH_VARARGS, throw_doc}, + {"close",(PyCFunction)anextawaitable_close, METH_VARARGS, close_doc}, + {NULL, NULL} /* Sentinel */ +}; + + +static PyAsyncMethods anextawaitable_as_async = { + PyObject_SelfIter, /* am_await */ + 0, /* am_aiter */ + 0, /* am_anext */ + 0, /* am_send */ +}; + +PyTypeObject _PyAnextAwaitable_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "anext_awaitable", /* tp_name */ + sizeof(anextawaitableobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)anextawaitable_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + &anextawaitable_as_async, /* tp_as_async */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)anextawaitable_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (unaryfunc)anextawaitable_iternext, /* tp_iternext */ + anextawaitable_methods, /* tp_methods */ +}; + +PyObject * +PyAnextAwaitable_New(PyObject *awaitable, PyObject *default_value) +{ + anextawaitableobject *anext = PyObject_GC_New( + anextawaitableobject, &_PyAnextAwaitable_Type); + if (anext == NULL) { + return NULL; + } + Py_INCREF(awaitable); + anext->wrapped = awaitable; + Py_INCREF(default_value); + anext->default_value = default_value; + _PyObject_GC_TRACK(anext); + return (PyObject *)anext; +} |
