diff --git a/Include/internal/pycore_genobject.h b/Include/internal/pycore_genobject.h index c1fc3511f849ad..4a2b23410715a8 100644 --- a/Include/internal/pycore_genobject.h +++ b/Include/internal/pycore_genobject.h @@ -34,6 +34,7 @@ PyAPI_FUNC(PyObject *)_PyCoro_GetAwaitableIter(PyObject *o); extern PyObject *_PyAsyncGenValueWrapperNew(PyThreadState *state, PyObject *); extern PyTypeObject _PyCoroWrapper_Type; +extern PyTypeObject _PyGenWrapper_Type; extern PyTypeObject _PyAsyncGenWrappedValue_Type; extern PyTypeObject _PyAsyncGenAThrow_Type; diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 9bde4faaf5a040..71fb198e5b44da 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -988,6 +988,11 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(get_source)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(getattr)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(getstate)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(gi_code)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(gi_frame)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(gi_running)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(gi_suspended)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(gi_yieldfrom)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(gid)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(globals)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(groupindex)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 3a83fd6b6042e2..cadcd1ffe82790 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -479,6 +479,11 @@ struct _Py_global_strings { STRUCT_FOR_ID(get_source) STRUCT_FOR_ID(getattr) STRUCT_FOR_ID(getstate) + STRUCT_FOR_ID(gi_code) + STRUCT_FOR_ID(gi_frame) + STRUCT_FOR_ID(gi_running) + STRUCT_FOR_ID(gi_suspended) + STRUCT_FOR_ID(gi_yieldfrom) STRUCT_FOR_ID(gid) STRUCT_FOR_ID(globals) STRUCT_FOR_ID(groupindex) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 4a34ffa559e124..405bc09f48e6f6 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -986,6 +986,11 @@ extern "C" { INIT_ID(get_source), \ INIT_ID(getattr), \ INIT_ID(getstate), \ + INIT_ID(gi_code), \ + INIT_ID(gi_frame), \ + INIT_ID(gi_running), \ + INIT_ID(gi_suspended), \ + INIT_ID(gi_yieldfrom), \ INIT_ID(gid), \ INIT_ID(globals), \ INIT_ID(groupindex), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index fefacef77c89ee..f130f20844b1e9 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1704,6 +1704,26 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(gi_code); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(gi_frame); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(gi_running); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(gi_suspended); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(gi_yieldfrom); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(gid); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 3552b6b4ef846c..c664e79e02c200 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -2241,21 +2241,26 @@ def foo(): return gen self.assertIs(wrapper.__name__, gen.__name__) # Test AttributeErrors - for name in {'gi_running', 'gi_frame', 'gi_code', 'gi_yieldfrom', - 'cr_running', 'cr_frame', 'cr_code', 'cr_await'}: + for name in ( + 'gi_running', 'gi_suspended', 'gi_frame', 'gi_code', 'gi_yieldfrom', + 'cr_running', 'cr_suspended', 'cr_frame', 'cr_code', 'cr_await' + ): with self.assertRaises(AttributeError): getattr(wrapper, name) # Test attributes pass-through gen.gi_running = object() + gen.gi_suspended = object() gen.gi_frame = object() gen.gi_code = object() gen.gi_yieldfrom = object() self.assertIs(wrapper.gi_running, gen.gi_running) + self.assertIs(wrapper.gi_suspended, gen.gi_suspended) self.assertIs(wrapper.gi_frame, gen.gi_frame) self.assertIs(wrapper.gi_code, gen.gi_code) self.assertIs(wrapper.gi_yieldfrom, gen.gi_yieldfrom) self.assertIs(wrapper.cr_running, gen.gi_running) + self.assertIs(wrapper.cr_suspended, gen.gi_suspended) self.assertIs(wrapper.cr_frame, gen.gi_frame) self.assertIs(wrapper.cr_code, gen.gi_code) self.assertIs(wrapper.cr_await, gen.gi_yieldfrom) diff --git a/Lib/types.py b/Lib/types.py index 6efac3394345a5..5398ef6f1776af 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -33,7 +33,7 @@ def _g(): async def _c(): pass _c = _c() CoroutineType = type(_c) - _c.close() # Prevent ResourceWarning + _c.close() # Prevent RuntimeWarning async def _ag(): yield @@ -250,7 +250,6 @@ def deleter(self, fdel): class _GeneratorWrapper: - # TODO: Implement this in C. def __init__(self, gen): self.__wrapped = gen self.__isgen = gen.__class__ is GeneratorType @@ -272,11 +271,15 @@ def gi_frame(self): def gi_running(self): return self.__wrapped.gi_running @property + def gi_suspended(self): + return self.__wrapped.gi_suspended + @property def gi_yieldfrom(self): return self.__wrapped.gi_yieldfrom cr_code = gi_code cr_frame = gi_frame cr_running = gi_running + cr_suspended = gi_suspended cr_await = gi_yieldfrom def __next__(self): return next(self.__wrapped) @@ -286,6 +289,12 @@ def __iter__(self): return self __await__ = __iter__ +try: + from _types import _GeneratorWrapper +except ImportError: + # Leave the pure Python version in place. + pass + def coroutine(func): """Convert regular generator function to a coroutine.""" diff --git a/Misc/NEWS.d/next/Library/2025-05-04-15-50-41.gh-issue-133372.ExoQUd.rst b/Misc/NEWS.d/next/Library/2025-05-04-15-50-41.gh-issue-133372.ExoQUd.rst new file mode 100644 index 00000000000000..ca8496ac79adfc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-04-15-50-41.gh-issue-133372.ExoQUd.rst @@ -0,0 +1 @@ +Add a C implementation of :class:`~types._GeneratorWrapper`. diff --git a/Modules/_typesmodule.c b/Modules/_typesmodule.c index a30a88196e7192..d26f8923e549b1 100644 --- a/Modules/_typesmodule.c +++ b/Modules/_typesmodule.c @@ -5,6 +5,7 @@ #include "pycore_namespace.h" // _PyNamespace_Type #include "pycore_object.h" // _PyNone_Type, _PyNotImplemented_Type #include "pycore_unionobject.h" // _PyUnion_Type +#include "pycore_genobject.h" // _PyGenWrapper_Type static int _types_exec(PyObject *m) @@ -46,6 +47,7 @@ _types_exec(PyObject *m) EXPORT_STATIC_TYPE("TracebackType", PyTraceBack_Type); EXPORT_STATIC_TYPE("UnionType", _PyUnion_Type); EXPORT_STATIC_TYPE("WrapperDescriptorType", PyWrapperDescr_Type); + EXPORT_STATIC_TYPE("_GeneratorWrapper", _PyGenWrapper_Type); #undef EXPORT_STATIC_TYPE return 0; } diff --git a/Objects/genobject.c b/Objects/genobject.c index 98b2c5004df8ac..f719a61c9105f9 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1201,7 +1201,7 @@ PyDoc_STRVAR(coro_close_doc, static PyMethodDef coro_methods[] = { {"send", gen_send, METH_O, coro_send_doc}, - {"throw",_PyCFunction_CAST(gen_throw), METH_FASTCALL, coro_throw_doc}, + {"throw", _PyCFunction_CAST(gen_throw), METH_FASTCALL, coro_throw_doc}, {"close", gen_close, METH_NOARGS, coro_close_doc}, {"__sizeof__", gen_sizeof, METH_NOARGS, sizeof__doc__}, {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, @@ -2414,3 +2414,307 @@ async_gen_athrow_new(PyAsyncGenObject *gen, PyObject *args) _PyObject_GC_TRACK((PyObject*)o); return (PyObject*)o; } + +/* Generator Wrapper Object */ + +typedef struct { + PyObject_HEAD + PyObject *gw_gen; + PyObject *gw_name; + PyObject *gw_qualname; + PyObject *gw_weakreflist; + char gw_is_gen; +} PyGenWrapper; + +#define _PyGenWrapper_CAST(op) \ + (assert(Py_IS_TYPE((op), &_PyGenWrapper_Type)), \ + _Py_CAST(PyGenWrapper*, (op))) + +static void +gen_wrapper_dealloc(PyObject *self) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + _PyObject_GC_UNTRACK((PyObject *)gw); + Py_CLEAR(gw->gw_gen); + Py_CLEAR(gw->gw_name); + Py_CLEAR(gw->gw_qualname); + if (gw->gw_weakreflist != NULL) + PyObject_ClearWeakRefs(self); + PyObject_GC_Del(gw); +} + +static int +gen_wrapper_traverse(PyObject *self, visitproc visit, void *arg) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + Py_VISIT(gw->gw_gen); + Py_VISIT(gw->gw_name); + Py_VISIT(gw->gw_qualname); + return 0; +} + +static PyObject * +gen_wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *gen = NULL; + + if ((type == &_PyGenWrapper_Type || + type->tp_init == _PyGenWrapper_Type.tp_init) && + !_PyArg_NoKeywords(type->tp_name, kwds)) { + return NULL; + } + + if (!PyArg_UnpackTuple(args, type->tp_name, 1, 1, &gen)) { + return NULL; + } + + PyGenWrapper *gw = _PyGenWrapper_CAST(type->tp_alloc(type, 0)); + if (gw == NULL) + return NULL; + + gw->gw_gen = Py_NewRef(gen); + gw->gw_is_gen = Py_IS_TYPE(gen, &PyGen_Type); + + PyObject *gen_name; + (void)PyObject_GetOptionalAttr(gen, &_Py_ID(__name__), &gen_name); + if (gen_name != NULL) + gw->gw_name = Py_NewRef(gen_name); + else + gw->gw_name = NULL; + + PyObject *gen_qualname; + (void)PyObject_GetOptionalAttr(gen, &_Py_ID(__qualname__), &gen_qualname); + if (gen_qualname != NULL) + gw->gw_qualname = Py_NewRef(gen_qualname); + else + gw->gw_qualname = NULL; + + gw->gw_weakreflist = NULL; + + return (PyObject *)gw; +} + +static PyObject * +gen_wrapper_iter(PyObject *self) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + if (gw->gw_is_gen) + return Py_NewRef(gw->gw_gen); + + return Py_NewRef(gw); +} + +static PyObject * +gen_wrapper_iternext(PyObject *self) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + PyTypeObject *tp = Py_TYPE(gw->gw_gen); + if (!PyIter_Check(gw->gw_gen)) { + PyErr_Format(PyExc_TypeError, + "'%.200s' object is not an iterator", + tp->tp_name); + return NULL; + } + return tp->tp_iternext(gw->gw_gen); +} + +static PyObject * +gen_wrapper_send(PyObject *self, PyObject *arg) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + return PyObject_CallMethodObjArgs(gw->gw_gen, &_Py_ID(send), arg, NULL); +} + +static PyObject * +gen_wrapper_throw(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + PyObject *typ; + PyObject *tb; + PyObject *val; + + if (!_PyArg_CheckPositional("throw", nargs, 1, 3)) { + return NULL; + } + + typ = args[0]; + if (nargs == 3) { + val = args[1]; + tb = args[2]; + return PyObject_CallMethodObjArgs(gw->gw_gen, &_Py_ID(throw), typ, val, tb, NULL); + } + else if (nargs == 2) { + val = args[1]; + return PyObject_CallMethodObjArgs(gw->gw_gen, &_Py_ID(throw), typ, val, NULL); + } + return PyObject_CallMethodObjArgs(gw->gw_gen, &_Py_ID(throw), typ, NULL); +} + +static PyObject * +gen_wrapper_close(PyObject *self, PyObject *args) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + return PyObject_CallMethodObjArgs(gw->gw_gen, &_Py_ID(close), NULL); +} + +static PyObject * +gen_wrapper_get_name(PyObject *self, void *Py_UNUSED(ignored)) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + if (!gw->gw_name) + return Py_None; + + return Py_NewRef(gw->gw_name); +} + +static int +gen_wrapper_set_name(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + /* Not legal to del gw.__name__ or to set it to anything + * other than a string object. */ + if (value == NULL || !PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__name__ must be set to a string object"); + return -1; + } + Py_XSETREF(gw->gw_name, Py_NewRef(value)); + return 0; +} + +static PyObject * +gen_wrapper_get_qualname(PyObject *self, void *Py_UNUSED(ignored)) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + if (!gw->gw_qualname) + return Py_None; + + return Py_NewRef(gw->gw_qualname); +} + +static int +gen_wrapper_set_qualname(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + /* Not legal to del gw.__qualname__ or to set it to anything + * other than a string object. */ + if (value == NULL || !PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__qualname__ must be set to a string object"); + return -1; + } + Py_XSETREF(gw->gw_qualname, Py_NewRef(value)); + return 0; +} + +static PyObject * +gen_wrapper_getyieldfrom(PyObject *self, void *Py_UNUSED(ignored)) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + return PyObject_GetAttr(gw->gw_gen, &_Py_ID(gi_yieldfrom)); +} + +static PyObject * +gen_wrapper_getrunning(PyObject *self, void *Py_UNUSED(ignored)) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + return PyObject_GetAttr(gw->gw_gen, &_Py_ID(gi_running)); +} + +static PyObject * +gen_wrapper_getsuspended(PyObject *self, void *Py_UNUSED(ignored)) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + return PyObject_GetAttr(gw->gw_gen, &_Py_ID(gi_suspended)); +} + +static PyObject * +gen_wrapper_getframe(PyObject *self, void *Py_UNUSED(ignored)) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + return PyObject_GetAttr(gw->gw_gen, &_Py_ID(gi_frame)); +} + +static PyObject * +gen_wrapper_getcode(PyObject *self, void *Py_UNUSED(ignored)) +{ + PyGenWrapper *gw = _PyGenWrapper_CAST(self); + return PyObject_GetAttr(gw->gw_gen, &_Py_ID(gi_code)); +} + +static PyGetSetDef gen_wrapper_getsetlist[] = { + {"__name__", gen_wrapper_get_name, gen_wrapper_set_name, + PyDoc_STR("name of the generator wrapper")}, + {"__qualname__", gen_wrapper_get_qualname, gen_wrapper_set_qualname, + PyDoc_STR("qualified name of the generator wrapper")}, + {"gi_yieldfrom", gen_wrapper_getyieldfrom, NULL, + PyDoc_STR("object being iterated by yield from, or None")}, + {"gi_running", gen_wrapper_getrunning, NULL, NULL}, + {"gi_frame", gen_wrapper_getframe, NULL, NULL}, + {"gi_suspended", gen_wrapper_getsuspended, NULL, NULL}, + {"gi_code", gen_wrapper_getcode, NULL, NULL}, + {"cr_await", gen_wrapper_getyieldfrom, NULL, + PyDoc_STR("object being awaited on, or None")}, + {"cr_running", gen_wrapper_getrunning, NULL, NULL}, + {"cr_frame", gen_wrapper_getframe, NULL, NULL}, + {"cr_code", gen_wrapper_getcode, NULL, NULL}, + {"cr_suspended", gen_wrapper_getsuspended, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +static PyMethodDef gen_wrapper_methods[] = { + {"send", gen_wrapper_send, METH_O, coro_send_doc}, + {"throw", _PyCFunction_CAST(gen_wrapper_throw), METH_FASTCALL, + coro_throw_doc}, + {"close", gen_wrapper_close, METH_NOARGS, coro_close_doc}, + {NULL, NULL} /* Sentinel */ +}; + +static PyAsyncMethods gen_wrapper_as_async = { + gen_wrapper_iter, /* am_await */ + 0, /* am_aiter */ + 0, /* am_anext */ + PyGen_am_send, /* am_send */ +}; + +PyTypeObject _PyGenWrapper_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "_GeneratorWrapper", + sizeof(PyGenWrapper), /* tp_basicsize */ + 0, /* tp_itemsize */ + gen_wrapper_dealloc, /* destructor tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + &gen_wrapper_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 */ + "A wrapper object that makes coroutines from generators.", + gen_wrapper_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyGenWrapper, gw_weakreflist), /* tp_weaklistoffset */ + gen_wrapper_iter, /* tp_iter */ + gen_wrapper_iternext, /* tp_iternext */ + gen_wrapper_methods, /* tp_methods */ + 0, /* tp_members */ + gen_wrapper_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + gen_wrapper_new, /* tp_new */ + 0, /* tp_free */ +}; diff --git a/Objects/object.c b/Objects/object.c index 0974a231ec101a..89cde44e6c491e 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2404,6 +2404,7 @@ static PyTypeObject* static_types[] = { &_PyContextTokenMissing_Type, &_PyCoroWrapper_Type, &_Py_GenericAliasIterType, + &_PyGenWrapper_Type, &_PyHamtItems_Type, &_PyHamtKeys_Type, &_PyHamtValues_Type, diff --git a/Tools/c-analyzer/TODO b/Tools/c-analyzer/TODO index 2077534ccf4128..e25c40f7ddd095 100644 --- a/Tools/c-analyzer/TODO +++ b/Tools/c-analyzer/TODO @@ -794,6 +794,7 @@ Objects/genobject.c:_PyAsyncGenASend_Type PyTypeObject _P Objects/genobject.c:_PyAsyncGenAThrow_Type PyTypeObject _PyAsyncGenAThrow_Type Objects/genobject.c:_PyAsyncGenWrappedValue_Type PyTypeObject _PyAsyncGenWrappedValue_Type Objects/genobject.c:_PyCoroWrapper_Type PyTypeObject _PyCoroWrapper_Type +Objects/genobject.c:_PyGenWrapper_Type PyTypeObject _PyGenWrapper_Type Objects/interpolationobject.c:_PyInterpolation_Type PyTypeObject _PyInterpolation_Type Objects/interpreteridobject.c:_PyInterpreterID_Type PyTypeObject _PyInterpreterID_Type Objects/iterobject.c:PyCallIter_Type PyTypeObject PyCallIter_Type diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 3c3cb2f9c86f16..9f9a15fc08ed07 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -55,6 +55,7 @@ Objects/genobject.c - _PyAsyncGenASend_Type - Objects/genobject.c - _PyAsyncGenAThrow_Type - Objects/genobject.c - _PyAsyncGenWrappedValue_Type - Objects/genobject.c - _PyCoroWrapper_Type - +Objects/genobject.c - _PyGenWrapper_Type - Objects/interpolationobject.c - _PyInterpolation_Type - Objects/iterobject.c - PyCallIter_Type - Objects/iterobject.c - PySeqIter_Type -