[Python-checkins] gh-101277: Finalise isolating itertools (GH-101305)

miss-islington webhook-mailer at python.org
Fri Feb 10 06:58:21 EST 2023


https://github.com/python/cpython/commit/826bf0e6957fd0addc321d1baee1fa846e9457eb
commit: 826bf0e6957fd0addc321d1baee1fa846e9457eb
branch: main
author: Erlend E. Aasland <erlend.aasland at protonmail.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2023-02-10T03:58:14-08:00
summary:

gh-101277: Finalise isolating itertools (GH-101305)



Add repeat, islice, chain, tee, teedataobject, and batched types to module state.

Automerge-Triggered-By: GH:erlend-aasland

files:
A Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst
M Modules/clinic/itertoolsmodule.c.h
M Modules/itertoolsmodule.c
M Tools/c-analyzer/cpython/globals-to-fix.tsv

diff --git a/Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst b/Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst
new file mode 100644
index 000000000000..e09c0e09fb38
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst
@@ -0,0 +1,2 @@
+Remove global state from :mod:`itertools` module (:pep:`687`). Patches by
+Erlend E. Aasland.
diff --git a/Modules/clinic/itertoolsmodule.c.h b/Modules/clinic/itertoolsmodule.c.h
index d15d5f0890ca..32278bf715aa 100644
--- a/Modules/clinic/itertoolsmodule.c.h
+++ b/Modules/clinic/itertoolsmodule.c.h
@@ -232,7 +232,7 @@ static PyObject *
 itertools_teedataobject(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &teedataobject_type;
+    PyTypeObject *base_tp = clinic_state()->teedataobject_type;
     PyObject *it;
     PyObject *values;
     PyObject *next;
@@ -270,7 +270,7 @@ static PyObject *
 itertools__tee(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
     PyObject *return_value = NULL;
-    PyTypeObject *base_tp = &tee_type;
+    PyTypeObject *base_tp = clinic_state()->tee_type;
     PyObject *iterable;
 
     if ((type == base_tp || type->tp_init == base_tp->tp_init) &&
@@ -913,4 +913,4 @@ itertools_count(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=a08b58d7dac825da input=a9049054013a1b77]*/
+/*[clinic end generated code: output=111cbd102c2a23c9 input=a9049054013a1b77]*/
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index ce8720d0fd92..6986695e47b1 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -5,6 +5,7 @@
 #include "pycore_moduleobject.h"  // _PyModule_GetState()
 #include "pycore_object.h"        // _PyObject_GC_TRACK()
 #include "pycore_tuple.h"         // _PyTuple_ITEMS()
+#include "structmember.h"         // PyMemberDef
 #include <stddef.h>               // offsetof()
 
 /* Itertools module written and maintained
@@ -13,6 +14,8 @@
 
 typedef struct {
     PyTypeObject *accumulate_type;
+    PyTypeObject *batched_type;
+    PyTypeObject *chain_type;
     PyTypeObject *combinations_type;
     PyTypeObject *compress_type;
     PyTypeObject *count_type;
@@ -22,11 +25,15 @@ typedef struct {
     PyTypeObject *filterfalse_type;
     PyTypeObject *groupby_type;
     PyTypeObject *_grouper_type;
+    PyTypeObject *islice_type;
     PyTypeObject *pairwise_type;
     PyTypeObject *permutations_type;
     PyTypeObject *product_type;
+    PyTypeObject *repeat_type;
     PyTypeObject *starmap_type;
     PyTypeObject *takewhile_type;
+    PyTypeObject *tee_type;
+    PyTypeObject *teedataobject_type;
     PyTypeObject *ziplongest_type;
 } itertools_state;
 
@@ -60,14 +67,14 @@ find_state_by_type(PyTypeObject *tp)
 module itertools
 class itertools.groupby "groupbyobject *" "clinic_state()->groupby_type"
 class itertools._grouper "_grouperobject *" "clinic_state()->_grouper_type"
-class itertools.teedataobject "teedataobject *" "&teedataobject_type"
-class itertools._tee "teeobject *" "&tee_type"
-class itertools.batched "batchedobject *" "&batched_type"
+class itertools.teedataobject "teedataobject *" "clinic_state()->teedataobject_type"
+class itertools._tee "teeobject *" "clinic_state()->tee_type"
+class itertools.batched "batchedobject *" "clinic_state()->batched_type"
 class itertools.cycle "cycleobject *" "clinic_state()->cycle_type"
 class itertools.dropwhile "dropwhileobject *" "clinic_state()->dropwhile_type"
 class itertools.takewhile "takewhileobject *" "clinic_state()->takewhile_type"
 class itertools.starmap "starmapobject *" "clinic_state()->starmap_type"
-class itertools.chain "chainobject *" "&chain_type"
+class itertools.chain "chainobject *" "clinic_state()->chain_type"
 class itertools.combinations "combinationsobject *" "clinic_state()->combinations_type"
 class itertools.combinations_with_replacement "cwr_object *" "clinic_state()->cwr_type"
 class itertools.permutations "permutationsobject *" "clinic_state()->permutations_type"
@@ -77,11 +84,7 @@ class itertools.filterfalse "filterfalseobject *" "clinic_state()->filterfalse_t
 class itertools.count "countobject *" "clinic_state()->count_type"
 class itertools.pairwise "pairwiseobject *" "clinic_state()->pairwise_type"
 [clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=28ffff5c0c93eed7]*/
-
-static PyTypeObject teedataobject_type;
-static PyTypeObject tee_type;
-static PyTypeObject batched_type;
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=aa48fe4de9d4080f]*/
 
 #define clinic_state() (find_state_by_type(type))
 #define clinic_state_by_cls() (get_module_state_by_cls(base_tp))
@@ -162,17 +165,18 @@ batched_new_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t n)
 static void
 batched_dealloc(batchedobject *bo)
 {
+    PyTypeObject *tp = Py_TYPE(bo);
     PyObject_GC_UnTrack(bo);
     Py_XDECREF(bo->it);
-    Py_TYPE(bo)->tp_free(bo);
+    tp->tp_free(bo);
+    Py_DECREF(tp);
 }
 
 static int
 batched_traverse(batchedobject *bo, visitproc visit, void *arg)
 {
-    if (bo->it != NULL) {
-        Py_VISIT(bo->it);
-    }
+    Py_VISIT(Py_TYPE(bo));
+    Py_VISIT(bo->it);
     return 0;
 }
 
@@ -222,48 +226,25 @@ batched_next(batchedobject *bo)
     return result;
 }
 
-static PyTypeObject batched_type = {
-    PyVarObject_HEAD_INIT(&PyType_Type, 0)
-    "itertools.batched",            /* tp_name */
-    sizeof(batchedobject),          /* tp_basicsize */
-    0,                              /* tp_itemsize */
-    /* methods */
-    (destructor)batched_dealloc,    /* tp_dealloc */
-    0,                              /* tp_vectorcall_offset */
-    0,                              /* tp_getattr */
-    0,                              /* tp_setattr */
-    0,                              /* 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 |
-        Py_TPFLAGS_BASETYPE,        /* tp_flags */
-    batched_new__doc__,             /* tp_doc */
-    (traverseproc)batched_traverse, /* tp_traverse */
-    0,                              /* tp_clear */
-    0,                              /* tp_richcompare */
-    0,                              /* tp_weaklistoffset */
-    PyObject_SelfIter,              /* tp_iter */
-    (iternextfunc)batched_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 */
-    PyType_GenericAlloc,            /* tp_alloc */
-    batched_new,                    /* tp_new */
-    PyObject_GC_Del,                /* tp_free */
+static PyType_Slot batched_slots[] = {
+    {Py_tp_dealloc, batched_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)batched_new__doc__},
+    {Py_tp_traverse, batched_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, batched_next},
+    {Py_tp_alloc, PyType_GenericAlloc},
+    {Py_tp_new, batched_new},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec batched_spec = {
+    .name = "itertools.batched",
+    .basicsize = sizeof(batchedobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = batched_slots,
 };
 
 
@@ -737,14 +718,15 @@ typedef struct {
     teedataobject *dataobj;
     int index;                  /* 0 <= index <= LINKCELLS */
     PyObject *weakreflist;
+    itertools_state *state;
 } teeobject;
 
 static PyObject *
-teedataobject_newinternal(PyObject *it)
+teedataobject_newinternal(itertools_state *state, PyObject *it)
 {
     teedataobject *tdo;
 
-    tdo = PyObject_GC_New(teedataobject, &teedataobject_type);
+    tdo = PyObject_GC_New(teedataobject, state->teedataobject_type);
     if (tdo == NULL)
         return NULL;
 
@@ -757,10 +739,10 @@ teedataobject_newinternal(PyObject *it)
 }
 
 static PyObject *
-teedataobject_jumplink(teedataobject *tdo)
+teedataobject_jumplink(itertools_state *state, teedataobject *tdo)
 {
     if (tdo->nextlink == NULL)
-        tdo->nextlink = teedataobject_newinternal(tdo->it);
+        tdo->nextlink = teedataobject_newinternal(state, tdo->it);
     return Py_XNewRef(tdo->nextlink);
 }
 
@@ -796,6 +778,7 @@ teedataobject_traverse(teedataobject *tdo, visitproc visit, void * arg)
 {
     int i;
 
+    Py_VISIT(Py_TYPE(tdo));
     Py_VISIT(tdo->it);
     for (i = 0; i < tdo->numread; i++)
         Py_VISIT(tdo->values[i]);
@@ -804,9 +787,9 @@ teedataobject_traverse(teedataobject *tdo, visitproc visit, void * arg)
 }
 
 static void
-teedataobject_safe_decref(PyObject *obj)
+teedataobject_safe_decref(PyObject *obj, PyTypeObject *tdo_type)
 {
-    while (obj && Py_IS_TYPE(obj, &teedataobject_type) &&
+    while (obj && Py_IS_TYPE(obj, tdo_type) &&
            Py_REFCNT(obj) == 1) {
         PyObject *nextlink = ((teedataobject *)obj)->nextlink;
         ((teedataobject *)obj)->nextlink = NULL;
@@ -826,16 +809,19 @@ teedataobject_clear(teedataobject *tdo)
         Py_CLEAR(tdo->values[i]);
     tmp = tdo->nextlink;
     tdo->nextlink = NULL;
-    teedataobject_safe_decref(tmp);
+    itertools_state *state = get_module_state_by_cls(Py_TYPE(tdo));
+    teedataobject_safe_decref(tmp, state->teedataobject_type);
     return 0;
 }
 
 static void
 teedataobject_dealloc(teedataobject *tdo)
 {
+    PyTypeObject *tp = Py_TYPE(tdo);
     PyObject_GC_UnTrack(tdo);
     teedataobject_clear(tdo);
     PyObject_GC_Del(tdo);
+    Py_DECREF(tp);
 }
 
 static PyObject *
@@ -874,9 +860,10 @@ itertools_teedataobject_impl(PyTypeObject *type, PyObject *it,
     teedataobject *tdo;
     Py_ssize_t i, len;
 
-    assert(type == &teedataobject_type);
+    itertools_state *state = get_module_state_by_cls(type);
+    assert(type == state->teedataobject_type);
 
-    tdo = (teedataobject *)teedataobject_newinternal(it);
+    tdo = (teedataobject *)teedataobject_newinternal(state, it);
     if (!tdo)
         return NULL;
 
@@ -892,7 +879,7 @@ itertools_teedataobject_impl(PyTypeObject *type, PyObject *it,
 
     if (len == LINKCELLS) {
         if (next != Py_None) {
-            if (!Py_IS_TYPE(next, &teedataobject_type))
+            if (!Py_IS_TYPE(next, state->teedataobject_type))
                 goto err;
             assert(tdo->nextlink == NULL);
             tdo->nextlink = Py_NewRef(next);
@@ -915,47 +902,24 @@ static PyMethodDef teedataobject_methods[] = {
     {NULL,              NULL}           /* sentinel */
 };
 
-static PyTypeObject teedataobject_type = {
-    PyVarObject_HEAD_INIT(0, 0)                 /* Must fill in type value later */
-    "itertools._tee_dataobject",                /* tp_name */
-    sizeof(teedataobject),                      /* tp_basicsize */
-    0,                                          /* tp_itemsize */
-    /* methods */
-    (destructor)teedataobject_dealloc,          /* tp_dealloc */
-    0,                                          /* tp_vectorcall_offset */
-    0,                                          /* tp_getattr */
-    0,                                          /* tp_setattr */
-    0,                                          /* 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 */
-    itertools_teedataobject__doc__,             /* tp_doc */
-    (traverseproc)teedataobject_traverse,       /* tp_traverse */
-    (inquiry)teedataobject_clear,               /* tp_clear */
-    0,                                          /* tp_richcompare */
-    0,                                          /* tp_weaklistoffset */
-    0,                                          /* tp_iter */
-    0,                                          /* tp_iternext */
-    teedataobject_methods,                      /* 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 */
-    itertools_teedataobject,                    /* tp_new */
-    PyObject_GC_Del,                            /* tp_free */
+static PyType_Slot teedataobject_slots[] = {
+    {Py_tp_dealloc, teedataobject_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)itertools_teedataobject__doc__},
+    {Py_tp_traverse, teedataobject_traverse},
+    {Py_tp_clear, teedataobject_clear},
+    {Py_tp_methods, teedataobject_methods},
+    {Py_tp_new, itertools_teedataobject},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec teedataobject_spec = {
+    .name = "itertools._tee_dataobject",
+    .basicsize = sizeof(teedataobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = teedataobject_slots,
 };
 
 
@@ -965,7 +929,7 @@ tee_next(teeobject *to)
     PyObject *value, *link;
 
     if (to->index >= LINKCELLS) {
-        link = teedataobject_jumplink(to->dataobj);
+        link = teedataobject_jumplink(to->state, to->dataobj);
         if (link == NULL)
             return NULL;
         Py_SETREF(to->dataobj, (teedataobject *)link);
@@ -981,6 +945,7 @@ tee_next(teeobject *to)
 static int
 tee_traverse(teeobject *to, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(to));
     Py_VISIT((PyObject *)to->dataobj);
     return 0;
 }
@@ -990,12 +955,13 @@ tee_copy(teeobject *to, PyObject *Py_UNUSED(ignored))
 {
     teeobject *newto;
 
-    newto = PyObject_GC_New(teeobject, &tee_type);
+    newto = PyObject_GC_New(teeobject, Py_TYPE(to));
     if (newto == NULL)
         return NULL;
     newto->dataobj = (teedataobject*)Py_NewRef(to->dataobj);
     newto->index = to->index;
     newto->weakreflist = NULL;
+    newto->state = to->state;
     PyObject_GC_Track(newto);
     return (PyObject *)newto;
 }
@@ -1003,7 +969,7 @@ tee_copy(teeobject *to, PyObject *Py_UNUSED(ignored))
 PyDoc_STRVAR(teecopy_doc, "Returns an independent iterator.");
 
 static PyObject *
-tee_fromiterable(PyObject *iterable)
+tee_fromiterable(itertools_state *state, PyObject *iterable)
 {
     teeobject *to;
     PyObject *it;
@@ -1011,17 +977,17 @@ tee_fromiterable(PyObject *iterable)
     it = PyObject_GetIter(iterable);
     if (it == NULL)
         return NULL;
-    if (PyObject_TypeCheck(it, &tee_type)) {
+    if (PyObject_TypeCheck(it, state->tee_type)) {
         to = (teeobject *)tee_copy((teeobject *)it, NULL);
         goto done;
     }
 
-    PyObject *dataobj = teedataobject_newinternal(it);
+    PyObject *dataobj = teedataobject_newinternal(state, it);
     if (!dataobj) {
         to = NULL;
         goto done;
     }
-    to = PyObject_GC_New(teeobject, &tee_type);
+    to = PyObject_GC_New(teeobject, state->tee_type);
     if (to == NULL) {
         Py_DECREF(dataobj);
         goto done;
@@ -1029,6 +995,7 @@ tee_fromiterable(PyObject *iterable)
     to->dataobj = (teedataobject *)dataobj;
     to->index = 0;
     to->weakreflist = NULL;
+    to->state = state;
     PyObject_GC_Track(to);
 done:
     Py_DECREF(it);
@@ -1047,7 +1014,8 @@ static PyObject *
 itertools__tee_impl(PyTypeObject *type, PyObject *iterable)
 /*[clinic end generated code: output=b02d3fd26c810c3f input=adc0779d2afe37a2]*/
 {
-    return tee_fromiterable(iterable);
+    itertools_state *state = get_module_state_by_cls(type);
+    return tee_fromiterable(state, iterable);
 }
 
 static int
@@ -1062,9 +1030,11 @@ tee_clear(teeobject *to)
 static void
 tee_dealloc(teeobject *to)
 {
+    PyTypeObject *tp = Py_TYPE(to);
     PyObject_GC_UnTrack(to);
     tee_clear(to);
     PyObject_GC_Del(to);
+    Py_DECREF(tp);
 }
 
 static PyObject *
@@ -1082,7 +1052,8 @@ tee_setstate(teeobject *to, PyObject *state)
         PyErr_SetString(PyExc_TypeError, "state is not a tuple");
         return NULL;
     }
-    if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) {
+    PyTypeObject *tdo_type = to->state->teedataobject_type;
+    if (!PyArg_ParseTuple(state, "O!i", tdo_type, &tdo, &index)) {
         return NULL;
     }
     if (index < 0 || index > LINKCELLS) {
@@ -1102,47 +1073,31 @@ static PyMethodDef tee_methods[] = {
     {NULL,              NULL}           /* sentinel */
 };
 
-static PyTypeObject tee_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools._tee",                   /* tp_name */
-    sizeof(teeobject),                  /* tp_basicsize */
-    0,                                  /* tp_itemsize */
-    /* methods */
-    (destructor)tee_dealloc,            /* tp_dealloc */
-    0,                                  /* tp_vectorcall_offset */
-    0,                                  /* tp_getattr */
-    0,                                  /* tp_setattr */
-    0,                                  /* 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 */
-    0,                                  /* tp_getattro */
-    0,                                  /* tp_setattro */
-    0,                                  /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,            /* tp_flags */
-    itertools__tee__doc__,              /* tp_doc */
-    (traverseproc)tee_traverse,         /* tp_traverse */
-    (inquiry)tee_clear,                 /* tp_clear */
-    0,                                  /* tp_richcompare */
-    offsetof(teeobject, weakreflist),   /* tp_weaklistoffset */
-    PyObject_SelfIter,                  /* tp_iter */
-    (iternextfunc)tee_next,             /* tp_iternext */
-    tee_methods,                        /* 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 */
-    itertools__tee,                     /* tp_new */
-    PyObject_GC_Del,                    /* tp_free */
+static PyMemberDef tee_members[] = {
+    {"__weaklistoffset__", T_PYSSIZET, offsetof(teeobject, weakreflist), READONLY},
+    {NULL},
+};
+
+static PyType_Slot tee_slots[] = {
+    {Py_tp_dealloc, tee_dealloc},
+    {Py_tp_doc, (void *)itertools__tee__doc__},
+    {Py_tp_traverse, tee_traverse},
+    {Py_tp_clear, tee_clear},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, tee_next},
+    {Py_tp_methods, tee_methods},
+    {Py_tp_members, tee_members},
+    {Py_tp_new, itertools__tee},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec tee_spec = {
+    .name = "itertools._tee",
+    .basicsize = sizeof(teeobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = tee_slots,
 };
 
 /*[clinic input]
@@ -1184,7 +1139,8 @@ itertools_tee_impl(PyObject *module, PyObject *iterable, Py_ssize_t n)
         copyable = it;
     }
     else {
-        copyable = tee_fromiterable(it);
+        itertools_state *state = get_module_state(module);
+        copyable = tee_fromiterable(state, it);
         Py_DECREF(it);
         if (copyable == NULL) {
             Py_DECREF(result);
@@ -1682,8 +1638,6 @@ typedef struct {
     Py_ssize_t cnt;
 } isliceobject;
 
-static PyTypeObject islice_type;
-
 static PyObject *
 islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
@@ -1693,7 +1647,9 @@ islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     Py_ssize_t numargs;
     isliceobject *lz;
 
-    if ((type == &islice_type || type->tp_init == islice_type.tp_init) &&
+    itertools_state *st = find_state_by_type(type);
+    PyTypeObject *islice_type = st->islice_type;
+    if ((type == islice_type || type->tp_init == islice_type->tp_init) &&
         !_PyArg_NoKeywords("islice", kwds))
         return NULL;
 
@@ -1772,14 +1728,17 @@ islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 static void
 islice_dealloc(isliceobject *lz)
 {
+    PyTypeObject *tp = Py_TYPE(lz);
     PyObject_GC_UnTrack(lz);
     Py_XDECREF(lz->it);
-    Py_TYPE(lz)->tp_free(lz);
+    tp->tp_free(lz);
+    Py_DECREF(tp);
 }
 
 static int
 islice_traverse(isliceobject *lz, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(lz));
     Py_VISIT(lz->it);
     return 0;
 }
@@ -1885,48 +1844,25 @@ specified as another value, step determines how many values are\n\
 skipped between successive calls.  Works like a slice() on a list\n\
 but returns an iterator.");
 
-static PyTypeObject islice_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools.islice",                 /* tp_name */
-    sizeof(isliceobject),               /* tp_basicsize */
-    0,                                  /* tp_itemsize */
-    /* methods */
-    (destructor)islice_dealloc,         /* tp_dealloc */
-    0,                                  /* tp_vectorcall_offset */
-    0,                                  /* tp_getattr */
-    0,                                  /* tp_setattr */
-    0,                                  /* 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 |
-        Py_TPFLAGS_BASETYPE,            /* tp_flags */
-    islice_doc,                         /* tp_doc */
-    (traverseproc)islice_traverse,      /* tp_traverse */
-    0,                                  /* tp_clear */
-    0,                                  /* tp_richcompare */
-    0,                                  /* tp_weaklistoffset */
-    PyObject_SelfIter,                  /* tp_iter */
-    (iternextfunc)islice_next,          /* tp_iternext */
-    islice_methods,                     /* 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 */
-    islice_new,                         /* tp_new */
-    PyObject_GC_Del,                    /* tp_free */
+static PyType_Slot islice_slots[] = {
+    {Py_tp_dealloc, islice_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)islice_doc},
+    {Py_tp_traverse, islice_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, islice_next},
+    {Py_tp_methods, islice_methods},
+    {Py_tp_new, islice_new},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec islice_spec = {
+    .name = "itertools.islice",
+    .basicsize = sizeof(isliceobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = islice_slots,
 };
 
 
@@ -2056,8 +1992,6 @@ typedef struct {
     PyObject *active;                   /* Currently running input iterator */
 } chainobject;
 
-static PyTypeObject chain_type;
-
 static PyObject *
 chain_new_internal(PyTypeObject *type, PyObject *source)
 {
@@ -2079,7 +2013,9 @@ chain_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
     PyObject *source;
 
-    if ((type == &chain_type || type->tp_init == chain_type.tp_init) &&
+    itertools_state *state = find_state_by_type(type);
+    PyTypeObject *chain_type = state->chain_type;
+    if ((type == chain_type || type->tp_init == chain_type->tp_init) &&
         !_PyArg_NoKeywords("chain", kwds))
         return NULL;
 
@@ -2114,15 +2050,18 @@ itertools_chain_from_iterable(PyTypeObject *type, PyObject *arg)
 static void
 chain_dealloc(chainobject *lz)
 {
+    PyTypeObject *tp = Py_TYPE(lz);
     PyObject_GC_UnTrack(lz);
     Py_XDECREF(lz->active);
     Py_XDECREF(lz->source);
-    Py_TYPE(lz)->tp_free(lz);
+    tp->tp_free(lz);
+    Py_DECREF(tp);
 }
 
 static int
 chain_traverse(chainobject *lz, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(lz));
     Py_VISIT(lz->source);
     Py_VISIT(lz->active);
     return 0;
@@ -2227,48 +2166,25 @@ static PyMethodDef chain_methods[] = {
     {NULL,              NULL}           /* sentinel */
 };
 
-static PyTypeObject chain_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools.chain",                  /* tp_name */
-    sizeof(chainobject),                /* tp_basicsize */
-    0,                                  /* tp_itemsize */
-    /* methods */
-    (destructor)chain_dealloc,          /* tp_dealloc */
-    0,                                  /* tp_vectorcall_offset */
-    0,                                  /* tp_getattr */
-    0,                                  /* tp_setattr */
-    0,                                  /* 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 |
-        Py_TPFLAGS_BASETYPE,            /* tp_flags */
-    chain_doc,                          /* tp_doc */
-    (traverseproc)chain_traverse,       /* tp_traverse */
-    0,                                  /* tp_clear */
-    0,                                  /* tp_richcompare */
-    0,                                  /* tp_weaklistoffset */
-    PyObject_SelfIter,                  /* tp_iter */
-    (iternextfunc)chain_next,           /* tp_iternext */
-    chain_methods,                      /* 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 */
-    chain_new,                          /* tp_new */
-    PyObject_GC_Del,                    /* tp_free */
+static PyType_Slot chain_slots[] = {
+    {Py_tp_dealloc, chain_dealloc},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)chain_doc},
+    {Py_tp_traverse, chain_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, chain_next},
+    {Py_tp_methods, chain_methods},
+    {Py_tp_new, chain_new},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec chain_spec = {
+    .name = "itertools.chain",
+    .basicsize = sizeof(chainobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = chain_slots,
 };
 
 
@@ -3574,6 +3490,7 @@ typedef struct {
     PyObject *it;
     PyObject *binop;
     PyObject *initial;
+    itertools_state *state;
 } accumulateobject;
 
 /*[clinic input]
@@ -3612,6 +3529,7 @@ itertools_accumulate_impl(PyTypeObject *type, PyObject *iterable,
     lz->total = NULL;
     lz->it = it;
     lz->initial = Py_XNewRef(initial);
+    lz->state = find_state_by_type(type);
     return (PyObject *)lz;
 }
 
@@ -3674,13 +3592,13 @@ accumulate_next(accumulateobject *lz)
 static PyObject *
 accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored))
 {
+    itertools_state *state = lz->state;
+
     if (lz->initial != Py_None) {
         PyObject *it;
 
         assert(lz->total == NULL);
-        if (PyType_Ready(&chain_type) < 0)
-            return NULL;
-        it = PyObject_CallFunction((PyObject *)&chain_type, "(O)O",
+        it = PyObject_CallFunction((PyObject *)(state->chain_type), "(O)O",
                                    lz->initial, lz->it);
         if (it == NULL)
             return NULL;
@@ -3690,11 +3608,7 @@ accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored))
     if (lz->total == Py_None) {
         PyObject *it;
 
-        if (PyType_Ready(&chain_type) < 0)
-            return NULL;
-        if (PyType_Ready(&islice_type) < 0)
-            return NULL;
-        it = PyObject_CallFunction((PyObject *)&chain_type, "(O)O",
+        it = PyObject_CallFunction((PyObject *)(state->chain_type), "(O)O",
                                    lz->total, lz->it);
         if (it == NULL)
             return NULL;
@@ -3702,7 +3616,8 @@ accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored))
                                    it, lz->binop ? lz->binop : Py_None);
         if (it == NULL)
             return NULL;
-        return Py_BuildValue("O(NiO)", &islice_type, it, 1, Py_None);
+
+        return Py_BuildValue("O(NiO)", state->islice_type, it, 1, Py_None);
     }
     return Py_BuildValue("O(OO)O", Py_TYPE(lz),
                             lz->it, lz->binop?lz->binop:Py_None,
@@ -4261,8 +4176,6 @@ typedef struct {
     Py_ssize_t cnt;
 } repeatobject;
 
-static PyTypeObject repeat_type;
-
 static PyObject *
 repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
@@ -4292,14 +4205,17 @@ repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 static void
 repeat_dealloc(repeatobject *ro)
 {
+    PyTypeObject *tp = Py_TYPE(ro);
     PyObject_GC_UnTrack(ro);
     Py_XDECREF(ro->element);
-    Py_TYPE(ro)->tp_free(ro);
+    tp->tp_free(ro);
+    Py_DECREF(tp);
 }
 
 static int
 repeat_traverse(repeatobject *ro, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(ro));
     Py_VISIT(ro->element);
     return 0;
 }
@@ -4361,48 +4277,26 @@ PyDoc_STRVAR(repeat_doc,
 for the specified number of times.  If not specified, returns the object\n\
 endlessly.");
 
-static PyTypeObject repeat_type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "itertools.repeat",                 /* tp_name */
-    sizeof(repeatobject),               /* tp_basicsize */
-    0,                                  /* tp_itemsize */
-    /* methods */
-    (destructor)repeat_dealloc,         /* tp_dealloc */
-    0,                                  /* tp_vectorcall_offset */
-    0,                                  /* tp_getattr */
-    0,                                  /* tp_setattr */
-    0,                                  /* tp_as_async */
-    (reprfunc)repeat_repr,              /* 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 |
-        Py_TPFLAGS_BASETYPE,            /* tp_flags */
-    repeat_doc,                         /* tp_doc */
-    (traverseproc)repeat_traverse,      /* tp_traverse */
-    0,                                  /* tp_clear */
-    0,                                  /* tp_richcompare */
-    0,                                  /* tp_weaklistoffset */
-    PyObject_SelfIter,                  /* tp_iter */
-    (iternextfunc)repeat_next,          /* tp_iternext */
-    repeat_methods,                     /* 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 */
-    repeat_new,                         /* tp_new */
-    PyObject_GC_Del,                    /* tp_free */
+static PyType_Slot repeat_slots[] = {
+    {Py_tp_dealloc, repeat_dealloc},
+    {Py_tp_repr, repeat_repr},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_doc, (void *)repeat_doc},
+    {Py_tp_traverse, repeat_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, repeat_next},
+    {Py_tp_methods, repeat_methods},
+    {Py_tp_new, repeat_new},
+    {Py_tp_free, PyObject_GC_Del},
+    {0, NULL},
+};
+
+static PyType_Spec repeat_spec = {
+    .name = "itertools.repeat",
+    .basicsize = sizeof(repeatobject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = repeat_slots,
 };
 
 
@@ -4695,6 +4589,8 @@ itertoolsmodule_traverse(PyObject *mod, visitproc visit, void *arg)
 {
     itertools_state *state = get_module_state(mod);
     Py_VISIT(state->accumulate_type);
+    Py_VISIT(state->batched_type);
+    Py_VISIT(state->chain_type);
     Py_VISIT(state->combinations_type);
     Py_VISIT(state->compress_type);
     Py_VISIT(state->count_type);
@@ -4704,11 +4600,15 @@ itertoolsmodule_traverse(PyObject *mod, visitproc visit, void *arg)
     Py_VISIT(state->filterfalse_type);
     Py_VISIT(state->groupby_type);
     Py_VISIT(state->_grouper_type);
+    Py_VISIT(state->islice_type);
     Py_VISIT(state->pairwise_type);
     Py_VISIT(state->permutations_type);
     Py_VISIT(state->product_type);
+    Py_VISIT(state->repeat_type);
     Py_VISIT(state->starmap_type);
     Py_VISIT(state->takewhile_type);
+    Py_VISIT(state->tee_type);
+    Py_VISIT(state->teedataobject_type);
     Py_VISIT(state->ziplongest_type);
     return 0;
 }
@@ -4718,6 +4618,8 @@ itertoolsmodule_clear(PyObject *mod)
 {
     itertools_state *state = get_module_state(mod);
     Py_CLEAR(state->accumulate_type);
+    Py_CLEAR(state->batched_type);
+    Py_CLEAR(state->chain_type);
     Py_CLEAR(state->combinations_type);
     Py_CLEAR(state->compress_type);
     Py_CLEAR(state->count_type);
@@ -4727,11 +4629,15 @@ itertoolsmodule_clear(PyObject *mod)
     Py_CLEAR(state->filterfalse_type);
     Py_CLEAR(state->groupby_type);
     Py_CLEAR(state->_grouper_type);
+    Py_CLEAR(state->islice_type);
     Py_CLEAR(state->pairwise_type);
     Py_CLEAR(state->permutations_type);
     Py_CLEAR(state->product_type);
+    Py_CLEAR(state->repeat_type);
     Py_CLEAR(state->starmap_type);
     Py_CLEAR(state->takewhile_type);
+    Py_CLEAR(state->tee_type);
+    Py_CLEAR(state->teedataobject_type);
     Py_CLEAR(state->ziplongest_type);
     return 0;
 }
@@ -4758,6 +4664,8 @@ itertoolsmodule_exec(PyObject *mod)
 {
     itertools_state *state = get_module_state(mod);
     ADD_TYPE(mod, state->accumulate_type, &accumulate_spec);
+    ADD_TYPE(mod, state->batched_type, &batched_spec);
+    ADD_TYPE(mod, state->chain_type, &chain_spec);
     ADD_TYPE(mod, state->combinations_type, &combinations_spec);
     ADD_TYPE(mod, state->compress_type, &compress_spec);
     ADD_TYPE(mod, state->count_type, &count_spec);
@@ -4767,30 +4675,18 @@ itertoolsmodule_exec(PyObject *mod)
     ADD_TYPE(mod, state->filterfalse_type, &filterfalse_spec);
     ADD_TYPE(mod, state->groupby_type, &groupby_spec);
     ADD_TYPE(mod, state->_grouper_type, &_grouper_spec);
+    ADD_TYPE(mod, state->islice_type, &islice_spec);
     ADD_TYPE(mod, state->pairwise_type, &pairwise_spec);
     ADD_TYPE(mod, state->permutations_type, &permutations_spec);
     ADD_TYPE(mod, state->product_type, &product_spec);
+    ADD_TYPE(mod, state->repeat_type, &repeat_spec);
     ADD_TYPE(mod, state->starmap_type, &starmap_spec);
     ADD_TYPE(mod, state->takewhile_type, &takewhile_spec);
+    ADD_TYPE(mod, state->tee_type, &tee_spec);
+    ADD_TYPE(mod, state->teedataobject_type, &teedataobject_spec);
     ADD_TYPE(mod, state->ziplongest_type, &ziplongest_spec);
 
-    PyTypeObject *typelist[] = {
-        &batched_type,
-        &islice_type,
-        &chain_type,
-        &repeat_type,
-        &tee_type,
-        &teedataobject_type
-    };
-
-    Py_SET_TYPE(&teedataobject_type, &PyType_Type);
-
-    for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) {
-        if (PyModule_AddType(mod, typelist[i]) < 0) {
-            return -1;
-        }
-    }
-
+    Py_SET_TYPE(state->teedataobject_type, &PyType_Type);
     return 0;
 }
 
diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv
index cf2d5c368f1b..52ea0b4901d4 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -335,28 +335,6 @@ Modules/_testcapi/vectorcall.c	-	MethodDescriptorBase_Type	-
 Modules/_testcapi/vectorcall.c	-	MethodDescriptorDerived_Type	-
 Modules/_testcapi/vectorcall.c	-	MethodDescriptorNopGet_Type	-
 Modules/_testcapi/vectorcall.c	-	MethodDescriptor2_Type	-
-Modules/itertoolsmodule.c	-	_grouper_type	-
-Modules/itertoolsmodule.c	-	accumulate_type	-
-Modules/itertoolsmodule.c	-	batched_type	-
-Modules/itertoolsmodule.c	-	chain_type	-
-Modules/itertoolsmodule.c	-	combinations_type	-
-Modules/itertoolsmodule.c	-	compress_type	-
-Modules/itertoolsmodule.c	-	count_type	-
-Modules/itertoolsmodule.c	-	cwr_type	-
-Modules/itertoolsmodule.c	-	cycle_type	-
-Modules/itertoolsmodule.c	-	dropwhile_type	-
-Modules/itertoolsmodule.c	-	filterfalse_type	-
-Modules/itertoolsmodule.c	-	groupby_type	-
-Modules/itertoolsmodule.c	-	islice_type	-
-Modules/itertoolsmodule.c	-	pairwise_type	-
-Modules/itertoolsmodule.c	-	permutations_type	-
-Modules/itertoolsmodule.c	-	product_type	-
-Modules/itertoolsmodule.c	-	repeat_type	-
-Modules/itertoolsmodule.c	-	starmap_type	-
-Modules/itertoolsmodule.c	-	takewhile_type	-
-Modules/itertoolsmodule.c	-	tee_type	-
-Modules/itertoolsmodule.c	-	teedataobject_type	-
-Modules/itertoolsmodule.c	-	ziplongest_type	-
 
 
 ##################################



More information about the Python-checkins mailing list