[Python-checkins] gh-92123: Convert `_elementtree` types to heap types (#99221)

erlend-aasland webhook-mailer at python.org
Fri Jan 20 06:40:17 EST 2023


https://github.com/python/cpython/commit/3847a6c64b96bb2cb93be394a590d4df2c35e876
commit: 3847a6c64b96bb2cb93be394a590d4df2c35e876
branch: main
author: Erlend E. Aasland <erlend.aasland at protonmail.com>
committer: erlend-aasland <erlend.aasland at protonmail.com>
date: 2023-01-20T12:40:06+01:00
summary:

gh-92123: Convert `_elementtree` types to heap types (#99221)

files:
A Misc/NEWS.d/next/Library/2020-11-20-21-06-08.bpo-40077.M-iZq3.rst
M Lib/test/test_xml_etree_c.py
M Modules/_elementtree.c
M Modules/clinic/_elementtree.c.h

diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py
index bec820857190..fd27b575ec8d 100644
--- a/Lib/test/test_xml_etree_c.py
+++ b/Lib/test/test_xml_etree_c.py
@@ -181,6 +181,26 @@ def __hash__(self):
         r = e.get(X())
         self.assertIsNone(r)
 
+    @support.cpython_only
+    def test_immutable_types(self):
+        root = cET.fromstring('<a></a>')
+        dataset = (
+            cET.Element,
+            cET.TreeBuilder,
+            cET.XMLParser,
+            type(root.iter()),
+        )
+        for tp in dataset:
+            with self.subTest(tp=tp):
+                with self.assertRaisesRegex(TypeError, "immutable"):
+                    tp.foo = 1
+
+    @support.cpython_only
+    def test_disallow_instantiation(self):
+        root = cET.fromstring('<a></a>')
+        iter_type = type(root.iter())
+        support.check_disallow_instantiation(self, iter_type)
+
 
 @unittest.skipUnless(cET, 'requires _elementtree')
 class TestAliasWorking(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Library/2020-11-20-21-06-08.bpo-40077.M-iZq3.rst b/Misc/NEWS.d/next/Library/2020-11-20-21-06-08.bpo-40077.M-iZq3.rst
new file mode 100644
index 000000000000..8a74477a4b35
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-11-20-21-06-08.bpo-40077.M-iZq3.rst
@@ -0,0 +1 @@
+Convert :mod:`elementtree` types to heap types. Patch by Erlend E. Aasland.
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index e0ab79103f06..93a9d609d7a0 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -70,10 +70,10 @@ static void _clear_joined_ptr(PyObject **p)
 }
 
 /* Types defined by this extension */
-static PyTypeObject Element_Type;
-static PyTypeObject ElementIter_Type;
-static PyTypeObject TreeBuilder_Type;
-static PyTypeObject XMLParser_Type;
+static PyTypeObject *Element_Type;
+static PyTypeObject *ElementIter_Type;
+static PyTypeObject *TreeBuilder_Type;
+static PyTypeObject *XMLParser_Type;
 
 
 /* Per-module state; PEP 3121 */
@@ -223,8 +223,8 @@ typedef struct {
 } ElementObject;
 
 
-#define Element_CheckExact(op) Py_IS_TYPE(op, &Element_Type)
-#define Element_Check(op) PyObject_TypeCheck(op, &Element_Type)
+#define Element_CheckExact(op) Py_IS_TYPE(op, Element_Type)
+#define Element_Check(op) PyObject_TypeCheck(op, Element_Type)
 
 
 /* -------------------------------------------------------------------- */
@@ -291,7 +291,7 @@ create_new_element(PyObject* tag, PyObject* attrib)
 {
     ElementObject* self;
 
-    self = PyObject_GC_New(ElementObject, &Element_Type);
+    self = PyObject_GC_New(ElementObject, Element_Type);
     if (self == NULL)
         return NULL;
     self->extra = NULL;
@@ -373,11 +373,11 @@ get_attrib_from_keywords(PyObject *kwds)
 
 /*[clinic input]
 module _elementtree
-class _elementtree.Element "ElementObject *" "&Element_Type"
-class _elementtree.TreeBuilder "TreeBuilderObject *" "&TreeBuilder_Type"
-class _elementtree.XMLParser "XMLParserObject *" "&XMLParser_Type"
+class _elementtree.Element "ElementObject *" "Element_Type"
+class _elementtree.TreeBuilder "TreeBuilderObject *" "TreeBuilder_Type"
+class _elementtree.XMLParser "XMLParserObject *" "XMLParser_Type"
 [clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=159aa50a54061c22]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1ecdb32b55d9d5de]*/
 
 static int
 element_init(PyObject *self, PyObject *args, PyObject *kwds)
@@ -579,7 +579,7 @@ subelement(PyObject *self, PyObject *args, PyObject *kwds)
     PyObject* tag;
     PyObject* attrib = NULL;
     if (!PyArg_ParseTuple(args, "O!O|O!:SubElement",
-                          &Element_Type, &parent, &tag,
+                          Element_Type, &parent, &tag,
                           &PyDict_Type, &attrib)) {
         return NULL;
     }
@@ -618,6 +618,7 @@ subelement(PyObject *self, PyObject *args, PyObject *kwds)
 static int
 element_gc_traverse(ElementObject *self, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(self));
     Py_VISIT(self->tag);
     Py_VISIT(JOIN_OBJ(self->text));
     Py_VISIT(JOIN_OBJ(self->tail));
@@ -649,6 +650,8 @@ element_gc_clear(ElementObject *self)
 static void
 element_dealloc(ElementObject* self)
 {
+    PyTypeObject *tp = Py_TYPE(self);
+
     /* bpo-31095: UnTrack is needed before calling any callbacks */
     PyObject_GC_UnTrack(self);
     Py_TRASHCAN_BEGIN(self, element_dealloc)
@@ -660,7 +663,8 @@ element_dealloc(ElementObject* self)
     */
     element_gc_clear(self);
 
-    Py_TYPE(self)->tp_free((PyObject *)self);
+    tp->tp_free((PyObject *)self);
+    Py_DECREF(tp);
     Py_TRASHCAN_END
 }
 
@@ -669,14 +673,14 @@ element_dealloc(ElementObject* self)
 /*[clinic input]
 _elementtree.Element.append
 
-    subelement: object(subclass_of='&Element_Type')
+    subelement: object(subclass_of='Element_Type')
     /
 
 [clinic start generated code]*/
 
 static PyObject *
 _elementtree_Element_append_impl(ElementObject *self, PyObject *subelement)
-/*[clinic end generated code: output=54a884b7cf2295f4 input=3ed648beb5bfa22a]*/
+/*[clinic end generated code: output=54a884b7cf2295f4 input=59866b732e6e2891]*/
 {
     if (element_add_subelement(self, subelement) < 0)
         return NULL;
@@ -1436,7 +1440,7 @@ element_getitem(PyObject* self_, Py_ssize_t index)
 _elementtree.Element.insert
 
     index: Py_ssize_t
-    subelement: object(subclass_of='&Element_Type')
+    subelement: object(subclass_of='Element_Type')
     /
 
 [clinic start generated code]*/
@@ -1444,7 +1448,7 @@ _elementtree.Element.insert
 static PyObject *
 _elementtree_Element_insert_impl(ElementObject *self, Py_ssize_t index,
                                  PyObject *subelement)
-/*[clinic end generated code: output=990adfef4d424c0b input=cd6fbfcdab52d7a8]*/
+/*[clinic end generated code: output=990adfef4d424c0b input=4382c42ab2659f9b]*/
 {
     Py_ssize_t i;
 
@@ -1543,14 +1547,14 @@ _elementtree_Element_makeelement_impl(ElementObject *self, PyObject *tag,
 /*[clinic input]
 _elementtree.Element.remove
 
-    subelement: object(subclass_of='&Element_Type')
+    subelement: object(subclass_of='Element_Type')
     /
 
 [clinic start generated code]*/
 
 static PyObject *
 _elementtree_Element_remove_impl(ElementObject *self, PyObject *subelement)
-/*[clinic end generated code: output=38fe6c07d6d87d1f input=d52fc28ededc0bd8]*/
+/*[clinic end generated code: output=38fe6c07d6d87d1f input=cbdf9f2ab34d93b0]*/
 {
     Py_ssize_t i;
     int rc;
@@ -2001,16 +2005,6 @@ element_attrib_setter(ElementObject *self, PyObject *value, void *closure)
     return 0;
 }
 
-static PySequenceMethods element_as_sequence = {
-    (lenfunc) element_length,
-    0, /* sq_concat */
-    0, /* sq_repeat */
-    element_getitem,
-    0,
-    element_setitem,
-    0,
-};
-
 /******************************* Element iterator ****************************/
 
 /* ElementIterObject represents the iteration state over an XML element in
@@ -2040,6 +2034,7 @@ typedef struct {
 static void
 elementiter_dealloc(ElementIterObject *it)
 {
+    PyTypeObject *tp = Py_TYPE(it);
     Py_ssize_t i = it->parent_stack_used;
     it->parent_stack_used = 0;
     /* bpo-31095: UnTrack is needed before calling any callbacks */
@@ -2051,7 +2046,8 @@ elementiter_dealloc(ElementIterObject *it)
     Py_XDECREF(it->sought_tag);
     Py_XDECREF(it->root_element);
 
-    PyObject_GC_Del(it);
+    tp->tp_free(it);
+    Py_DECREF(tp);
 }
 
 static int
@@ -2063,6 +2059,7 @@ elementiter_traverse(ElementIterObject *it, visitproc visit, void *arg)
 
     Py_VISIT(it->root_element);
     Py_VISIT(it->sought_tag);
+    Py_VISIT(Py_TYPE(it));
     return 0;
 }
 
@@ -2193,49 +2190,22 @@ elementiter_next(ElementIterObject *it)
     return NULL;
 }
 
+static PyType_Slot elementiter_slots[] = {
+    {Py_tp_dealloc, elementiter_dealloc},
+    {Py_tp_traverse, elementiter_traverse},
+    {Py_tp_iter, PyObject_SelfIter},
+    {Py_tp_iternext, elementiter_next},
+    {0, NULL},
+};
 
-static PyTypeObject ElementIter_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
+static PyType_Spec elementiter_spec = {
     /* Using the module's name since the pure-Python implementation does not
        have such a type. */
-    "_elementtree._element_iterator",           /* tp_name */
-    sizeof(ElementIterObject),                  /* tp_basicsize */
-    0,                                          /* tp_itemsize */
-    /* methods */
-    (destructor)elementiter_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 */
-    0,                                          /* tp_doc */
-    (traverseproc)elementiter_traverse,         /* tp_traverse */
-    0,                                          /* tp_clear */
-    0,                                          /* tp_richcompare */
-    0,                                          /* tp_weaklistoffset */
-    PyObject_SelfIter,                          /* tp_iter */
-    (iternextfunc)elementiter_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 */
+    .name = "_elementtree._element_iterator",
+    .basicsize = sizeof(ElementIterObject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+              Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
+    .slots = elementiter_slots,
 };
 
 #define INIT_PARENT_STACK_SIZE 8
@@ -2245,7 +2215,7 @@ create_elementiter(ElementObject *self, PyObject *tag, int gettext)
 {
     ElementIterObject *it;
 
-    it = PyObject_GC_New(ElementIterObject, &ElementIter_Type);
+    it = PyObject_GC_New(ElementIterObject, ElementIter_Type);
     if (!it)
         return NULL;
 
@@ -2302,7 +2272,7 @@ typedef struct {
     char insert_pis;
 } TreeBuilderObject;
 
-#define TreeBuilder_CheckExact(op) Py_IS_TYPE((op), &TreeBuilder_Type)
+#define TreeBuilder_CheckExact(op) Py_IS_TYPE((op), TreeBuilder_Type)
 
 /* -------------------------------------------------------------------- */
 /* constructor and destructor */
@@ -2393,6 +2363,7 @@ _elementtree_TreeBuilder___init___impl(TreeBuilderObject *self,
 static int
 treebuilder_gc_traverse(TreeBuilderObject *self, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(self));
     Py_VISIT(self->pi_event_obj);
     Py_VISIT(self->comment_event_obj);
     Py_VISIT(self->end_ns_event_obj);
@@ -2437,9 +2408,11 @@ treebuilder_gc_clear(TreeBuilderObject *self)
 static void
 treebuilder_dealloc(TreeBuilderObject *self)
 {
+    PyTypeObject *tp = Py_TYPE(self);
     PyObject_GC_UnTrack(self);
     treebuilder_gc_clear(self);
-    Py_TYPE(self)->tp_free((PyObject *)self);
+    tp->tp_free(self);
+    Py_DECREF(tp);
 }
 
 /* -------------------------------------------------------------------- */
@@ -3593,7 +3566,7 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target,
     if (target != Py_None) {
         Py_INCREF(target);
     } else {
-        target = treebuilder_new(&TreeBuilder_Type, NULL, NULL);
+        target = treebuilder_new(TreeBuilder_Type, NULL, NULL);
         if (!target) {
             Py_CLEAR(self->entity);
             Py_CLEAR(self->names);
@@ -3685,6 +3658,7 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target,
 static int
 xmlparser_gc_traverse(XMLParserObject *self, visitproc visit, void *arg)
 {
+    Py_VISIT(Py_TYPE(self));
     Py_VISIT(self->handle_close);
     Py_VISIT(self->handle_pi);
     Py_VISIT(self->handle_comment);
@@ -3731,9 +3705,11 @@ xmlparser_gc_clear(XMLParserObject *self)
 static void
 xmlparser_dealloc(XMLParserObject* self)
 {
+    PyTypeObject *tp = Py_TYPE(self);
     PyObject_GC_UnTrack(self);
     xmlparser_gc_clear(self);
-    Py_TYPE(self)->tp_free((PyObject *)self);
+    tp->tp_free(self);
+    Py_DECREF(tp);
 }
 
 Py_LOCAL_INLINE(int)
@@ -4106,10 +4082,9 @@ static PyMethodDef element_methods[] = {
     {NULL, NULL}
 };
 
-static PyMappingMethods element_as_mapping = {
-    (lenfunc) element_length,
-    (binaryfunc) element_subscr,
-    (objobjargproc) element_ass_subscr,
+static struct PyMemberDef element_members[] = {
+    {"__weaklistoffset__", T_PYSSIZET, offsetof(ElementObject, weakreflist), READONLY},
+    {NULL},
 };
 
 static PyGetSetDef element_getsetlist[] = {
@@ -4132,46 +4107,33 @@ static PyGetSetDef element_getsetlist[] = {
     {NULL},
 };
 
-static PyTypeObject Element_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "xml.etree.ElementTree.Element", sizeof(ElementObject), 0,
-    /* methods */
-    (destructor)element_dealloc,                    /* tp_dealloc */
-    0,                                              /* tp_vectorcall_offset */
-    0,                                              /* tp_getattr */
-    0,                                              /* tp_setattr */
-    0,                                              /* tp_as_async */
-    (reprfunc)element_repr,                         /* tp_repr */
-    0,                                              /* tp_as_number */
-    &element_as_sequence,                           /* tp_as_sequence */
-    &element_as_mapping,                            /* 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_BASETYPE | Py_TPFLAGS_HAVE_GC,
-                                                    /* tp_flags */
-    0,                                              /* tp_doc */
-    (traverseproc)element_gc_traverse,              /* tp_traverse */
-    (inquiry)element_gc_clear,                      /* tp_clear */
-    0,                                              /* tp_richcompare */
-    offsetof(ElementObject, weakreflist),           /* tp_weaklistoffset */
-    0,                                              /* tp_iter */
-    0,                                              /* tp_iternext */
-    element_methods,                                /* tp_methods */
-    0,                                              /* tp_members */
-    element_getsetlist,                             /* tp_getset */
-    0,                                              /* tp_base */
-    0,                                              /* tp_dict */
-    0,                                              /* tp_descr_get */
-    0,                                              /* tp_descr_set */
-    0,                                              /* tp_dictoffset */
-    (initproc)element_init,                         /* tp_init */
-    PyType_GenericAlloc,                            /* tp_alloc */
-    element_new,                                    /* tp_new */
-    0,                                              /* tp_free */
+static PyType_Slot element_slots[] = {
+    {Py_tp_dealloc, element_dealloc},
+    {Py_tp_repr, element_repr},
+    {Py_tp_getattro, PyObject_GenericGetAttr},
+    {Py_tp_traverse, element_gc_traverse},
+    {Py_tp_clear, element_gc_clear},
+    {Py_tp_methods, element_methods},
+    {Py_tp_members, element_members},
+    {Py_tp_getset, element_getsetlist},
+    {Py_tp_init, element_init},
+    {Py_tp_alloc, PyType_GenericAlloc},
+    {Py_tp_new, element_new},
+    {Py_sq_length, element_length},
+    {Py_sq_item, element_getitem},
+    {Py_sq_ass_item, element_setitem},
+    {Py_mp_length, element_length},
+    {Py_mp_subscript, element_subscr},
+    {Py_mp_ass_subscript, element_ass_subscr},
+    {0, NULL},
+};
+
+static PyType_Spec element_spec = {
+    .name = "xml.etree.ElementTree.Element",
+    .basicsize = sizeof(ElementObject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = element_slots,
 };
 
 static PyMethodDef treebuilder_methods[] = {
@@ -4184,46 +4146,22 @@ static PyMethodDef treebuilder_methods[] = {
     {NULL, NULL}
 };
 
-static PyTypeObject TreeBuilder_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "xml.etree.ElementTree.TreeBuilder", sizeof(TreeBuilderObject), 0,
-    /* methods */
-    (destructor)treebuilder_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_BASETYPE | Py_TPFLAGS_HAVE_GC,
-                                                    /* tp_flags */
-    0,                                              /* tp_doc */
-    (traverseproc)treebuilder_gc_traverse,          /* tp_traverse */
-    (inquiry)treebuilder_gc_clear,                  /* tp_clear */
-    0,                                              /* tp_richcompare */
-    0,                                              /* tp_weaklistoffset */
-    0,                                              /* tp_iter */
-    0,                                              /* tp_iternext */
-    treebuilder_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 */
-    _elementtree_TreeBuilder___init__,              /* tp_init */
-    PyType_GenericAlloc,                            /* tp_alloc */
-    treebuilder_new,                                /* tp_new */
-    0,                                              /* tp_free */
+static PyType_Slot treebuilder_slots[] = {
+    {Py_tp_dealloc, treebuilder_dealloc},
+    {Py_tp_traverse, treebuilder_gc_traverse},
+    {Py_tp_clear, treebuilder_gc_clear},
+    {Py_tp_methods, treebuilder_methods},
+    {Py_tp_init, _elementtree_TreeBuilder___init__},
+    {Py_tp_alloc, PyType_GenericAlloc},
+    {Py_tp_new, treebuilder_new},
+    {0, NULL},
+};
+
+static PyType_Spec treebuilder_spec = {
+    .name = "xml.etree.ElementTree.TreeBuilder",
+    .basicsize = sizeof(TreeBuilderObject),
+    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE,
+    .slots = treebuilder_slots,
 };
 
 static PyMethodDef xmlparser_methods[] = {
@@ -4234,46 +4172,25 @@ static PyMethodDef xmlparser_methods[] = {
     {NULL, NULL}
 };
 
-static PyTypeObject XMLParser_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "xml.etree.ElementTree.XMLParser", sizeof(XMLParserObject), 0,
-    /* methods */
-    (destructor)xmlparser_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_BASETYPE | Py_TPFLAGS_HAVE_GC,
-                                                    /* tp_flags */
-    0,                                              /* tp_doc */
-    (traverseproc)xmlparser_gc_traverse,            /* tp_traverse */
-    (inquiry)xmlparser_gc_clear,                    /* tp_clear */
-    0,                                              /* tp_richcompare */
-    0,                                              /* tp_weaklistoffset */
-    0,                                              /* tp_iter */
-    0,                                              /* tp_iternext */
-    xmlparser_methods,                              /* tp_methods */
-    xmlparser_members,                              /* tp_members */
-    xmlparser_getsetlist,                           /* tp_getset */
-    0,                                              /* tp_base */
-    0,                                              /* tp_dict */
-    0,                                              /* tp_descr_get */
-    0,                                              /* tp_descr_set */
-    0,                                              /* tp_dictoffset */
-    _elementtree_XMLParser___init__,                /* tp_init */
-    PyType_GenericAlloc,                            /* tp_alloc */
-    xmlparser_new,                                  /* tp_new */
-    0,                                              /* tp_free */
+static PyType_Slot xmlparser_slots[] = {
+    {Py_tp_dealloc, xmlparser_dealloc},
+    {Py_tp_traverse, xmlparser_gc_traverse},
+    {Py_tp_clear, xmlparser_gc_clear},
+    {Py_tp_methods, xmlparser_methods},
+    {Py_tp_members, xmlparser_members},
+    {Py_tp_getset, xmlparser_getsetlist},
+    {Py_tp_init, _elementtree_XMLParser___init__},
+    {Py_tp_alloc, PyType_GenericAlloc},
+    {Py_tp_new, xmlparser_new},
+    {0, NULL},
+};
+
+static PyType_Spec xmlparser_spec = {
+    .name = "xml.etree.ElementTree.XMLParser",
+    .basicsize = sizeof(XMLParserObject),
+    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+              Py_TPFLAGS_IMMUTABLETYPE),
+    .slots = xmlparser_slots,
 };
 
 /* ==================================================================== */
@@ -4298,40 +4215,47 @@ static struct PyModuleDef elementtreemodule = {
     elementtree_free
 };
 
+#define CREATE_TYPE(module, type, spec) \
+do {                                                                     \
+    if (type != NULL) {                                                  \
+        break;                                                           \
+    }                                                                    \
+    type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, NULL); \
+    if (type == NULL) {                                                  \
+        goto error;                                                      \
+    }                                                                    \
+} while (0)
+
 PyMODINIT_FUNC
 PyInit__elementtree(void)
 {
-    PyObject *m;
-    elementtreestate *st;
+    PyObject *m = NULL;
+    elementtreestate *st = NULL;
 
     m = PyState_FindModule(&elementtreemodule);
     if (m) {
         return Py_NewRef(m);
     }
 
-    /* Initialize object types */
-    if (PyType_Ready(&ElementIter_Type) < 0)
-        return NULL;
-    if (PyType_Ready(&TreeBuilder_Type) < 0)
-        return NULL;
-    if (PyType_Ready(&Element_Type) < 0)
-        return NULL;
-    if (PyType_Ready(&XMLParser_Type) < 0)
-        return NULL;
-
     m = PyModule_Create(&elementtreemodule);
     if (!m)
-        return NULL;
+        goto error;
     st = get_elementtree_state(m);
 
+    /* Initialize object types */
+    CREATE_TYPE(m, ElementIter_Type, &elementiter_spec);
+    CREATE_TYPE(m, TreeBuilder_Type, &treebuilder_spec);
+    CREATE_TYPE(m, Element_Type, &element_spec);
+    CREATE_TYPE(m, XMLParser_Type, &xmlparser_spec);
+
     st->deepcopy_obj = _PyImport_GetModuleAttrString("copy", "deepcopy");
     if (st->deepcopy_obj == NULL) {
-        return NULL;
+        goto error;
     }
 
     assert(!PyErr_Occurred());
     if (!(st->elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath")))
-        return NULL;
+        goto error;
 
     /* link against pyexpat */
     expat_capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0);
@@ -4344,62 +4268,66 @@ PyInit__elementtree(void)
             expat_capi->MICRO_VERSION != XML_MICRO_VERSION) {
             PyErr_SetString(PyExc_ImportError,
                             "pyexpat version is incompatible");
-            return NULL;
+            goto error;
         }
     } else {
-        return NULL;
+        goto error;
     }
 
     st->str_append = PyUnicode_InternFromString("append");
     if (st->str_append == NULL) {
-        return NULL;
+        goto error;
     }
     st->str_find = PyUnicode_InternFromString("find");
     if (st->str_find == NULL) {
-        return NULL;
+        goto error;
     }
     st->str_findall = PyUnicode_InternFromString("findall");
     if (st->str_findall == NULL) {
-        return NULL;
+        goto error;
     }
     st->str_findtext = PyUnicode_InternFromString("findtext");
     if (st->str_findtext == NULL) {
-        return NULL;
+        goto error;
     }
     st->str_iterfind = PyUnicode_InternFromString("iterfind");
     if (st->str_iterfind == NULL) {
-        return NULL;
+        goto error;
     }
     st->str_tail = PyUnicode_InternFromString("tail");
     if (st->str_tail == NULL) {
-        return NULL;
+        goto error;
     }
     st->str_text = PyUnicode_InternFromString("text");
     if (st->str_text == NULL) {
-        return NULL;
+        goto error;
     }
     st->str_doctype = PyUnicode_InternFromString("doctype");
     if (st->str_doctype == NULL) {
-        return NULL;
+        goto error;
     }
     st->parseerror_obj = PyErr_NewException(
         "xml.etree.ElementTree.ParseError", PyExc_SyntaxError, NULL
         );
     if (PyModule_AddObjectRef(m, "ParseError", st->parseerror_obj) < 0) {
-        return NULL;
+        goto error;
     }
 
     PyTypeObject *types[] = {
-        &Element_Type,
-        &TreeBuilder_Type,
-        &XMLParser_Type
+        Element_Type,
+        TreeBuilder_Type,
+        XMLParser_Type
     };
 
     for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) {
         if (PyModule_AddType(m, types[i]) < 0) {
-            return NULL;
+            goto error;
         }
     }
 
     return m;
+
+error:
+    Py_XDECREF(m);
+    return NULL;
 }
diff --git a/Modules/clinic/_elementtree.c.h b/Modules/clinic/_elementtree.c.h
index 33ccaf7e7c7e..b816e1bd8559 100644
--- a/Modules/clinic/_elementtree.c.h
+++ b/Modules/clinic/_elementtree.c.h
@@ -25,8 +25,8 @@ _elementtree_Element_append(ElementObject *self, PyObject *arg)
     PyObject *return_value = NULL;
     PyObject *subelement;
 
-    if (!PyObject_TypeCheck(arg, &Element_Type)) {
-        _PyArg_BadArgument("append", "argument", (&Element_Type)->tp_name, arg);
+    if (!PyObject_TypeCheck(arg, Element_Type)) {
+        _PyArg_BadArgument("append", "argument", (Element_Type)->tp_name, arg);
         goto exit;
     }
     subelement = arg;
@@ -586,8 +586,8 @@ _elementtree_Element_insert(ElementObject *self, PyObject *const *args, Py_ssize
         }
         index = ival;
     }
-    if (!PyObject_TypeCheck(args[1], &Element_Type)) {
-        _PyArg_BadArgument("insert", "argument 2", (&Element_Type)->tp_name, args[1]);
+    if (!PyObject_TypeCheck(args[1], Element_Type)) {
+        _PyArg_BadArgument("insert", "argument 2", (Element_Type)->tp_name, args[1]);
         goto exit;
     }
     subelement = args[1];
@@ -682,8 +682,8 @@ _elementtree_Element_remove(ElementObject *self, PyObject *arg)
     PyObject *return_value = NULL;
     PyObject *subelement;
 
-    if (!PyObject_TypeCheck(arg, &Element_Type)) {
-        _PyArg_BadArgument("remove", "argument", (&Element_Type)->tp_name, arg);
+    if (!PyObject_TypeCheck(arg, Element_Type)) {
+        _PyArg_BadArgument("remove", "argument", (Element_Type)->tp_name, arg);
         goto exit;
     }
     subelement = arg;
@@ -1105,4 +1105,4 @@ _elementtree_XMLParser__setevents(XMLParserObject *self, PyObject *const *args,
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=4ad006cadce01571 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=db3d6654de9f8013 input=a9049054013a1b77]*/



More information about the Python-checkins mailing list