cpython: 0ca32013d77e (original) (raw)
--- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -14,9 +14,10 @@
Don't re-import "xml.etree.ElementTree" module in the docstring,
except if the test is specific to the Python implementation.
-import sys +import gc import html import io +import sys import unittest from test import support @@ -1846,6 +1847,30 @@ class BasicElementTest(unittest.TestCase self.assertRaises(TypeError, e.extend, [ET.Element('bar'), 'foo']) self.assertRaises(TypeError, e.insert, 0, 'foo')
- def test_cyclic_gc(self):
class ShowGC:[](#l1.20)
def __init__(self, flaglist):[](#l1.21)
self.flaglist = flaglist[](#l1.22)
def __del__(self):[](#l1.23)
self.flaglist.append(1)[](#l1.24)
# Test the shortest cycle: lst->element->lst[](#l1.26)
fl = [][](#l1.27)
lst = [ShowGC(fl)][](#l1.28)
lst.append(ET.Element('joe', attr=lst))[](#l1.29)
del lst[](#l1.30)
gc.collect()[](#l1.31)
self.assertEqual(fl, [1])[](#l1.32)
# A longer cycle: lst->e->e2->lst[](#l1.34)
fl = [][](#l1.35)
e = ET.Element('joe')[](#l1.36)
lst = [ShowGC(fl), e][](#l1.37)
e2 = ET.SubElement(e, 'foo', attr=lst)[](#l1.38)
del lst, e, e2[](#l1.39)
gc.collect()[](#l1.40)
self.assertEqual(fl, [1])[](#l1.41)
+ class ElementTreeTest(unittest.TestCase): def test_istype(self):
--- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -282,7 +282,7 @@ create_new_element(PyObject* tag, PyObje { ElementObject* self;
@@ -309,7 +309,7 @@ create_new_element(PyObject* tag, PyObje self->tail = Py_None; ALLOC(sizeof(ElementObject), "create element"); -
@@ -556,19 +556,51 @@ subelement(PyObject* self, PyObject* arg return elem; } +static int +element_gc_traverse(ElementObject *self, visitproc visit, void *arg) +{
for (i = 0; i < self->extra->length; ++i)[](#l2.36)
Py_VISIT(self->extra->children[i]);[](#l2.37)
- }
- return 0;
+} + +static int +element_gc_clear(ElementObject *self) +{
- PyObject *text = JOIN_OBJ(self->text);
- PyObject *tail = JOIN_OBJ(self->tail);
- Py_CLEAR(self->tag);
- Py_CLEAR(text);
- Py_CLEAR(tail);
- /* After dropping all references from extra, it's no longer valid anyway,
- ** so fully deallocate it (see also element_clearmethod)
- */
- if (self->extra) {
dealloc_extra(self);[](#l2.55)
self->extra = NULL;[](#l2.56)
- }
- return 0;
+} + static void element_dealloc(ElementObject* self) {
- /* discard attributes */
- Py_DECREF(self->tag);
- Py_DECREF(JOIN_OBJ(self->text));
- Py_DECREF(JOIN_OBJ(self->tail));
- PyObject_GC_UnTrack(self);
- /* element_gc_clear clears all references and deallocates extra
- */
- element_gc_clear(self);
RELEASE(sizeof(ElementObject), "destroy element"); - Py_TYPE(self)->tp_free((PyObject )self); } @@ -589,7 +621,7 @@ element_append(ElementObject self, PyOb } static PyObject* -element_clear(ElementObject* self, PyObject* args) +element_clearmethod(ElementObject* self, PyObject* args) { if (!PyArg_ParseTuple(args, ":clear")) return NULL; @@ -1505,7 +1537,7 @@ element_ass_subscr(PyObject* self_, PyOb static PyMethodDef element_methods[] = {
{"get", (PyCFunction) element_get, METH_VARARGS}, {"set", (PyCFunction) element_set, METH_VARARGS}, @@ -1655,10 +1687,11 @@ static PyTypeObject Element_Type = { (getattrofunc)element_getattro, /* tp_getattro / 0, / tp_setattro / 0, / tp_as_buffer */