diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index acec4ec2ca257c..78ccf4581f7c81 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -2654,6 +2654,19 @@ def f(): class BasicElementTest(ElementTestCase, unittest.TestCase): + def test_reinit_releases_children(self): + # gh-153537: re-init should release the previous children. + e = ET.Element('a', {'k': 'v'}) + children = [ET.SubElement(e, 'b') for _ in range(3)] + refs = [weakref.ref(c) for c in children] + del children + self.assertEqual(len(e), 3) + e.__init__('a') + gc_collect() + self.assertEqual(len(e), 0) + self.assertEqual(e.attrib, {}) + self.assertTrue(all(ref() is None for ref in refs)) + def test___init__(self): tag = "foo" attrib = { "zix": "wyp" } diff --git a/Misc/NEWS.d/next/Library/2026-07-11-11-36-15.gh-issue-153537.2KySPQ.rst b/Misc/NEWS.d/next/Library/2026-07-11-11-36-15.gh-issue-153537.2KySPQ.rst new file mode 100644 index 00000000000000..5fa070be5f7f1c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-11-11-36-15.gh-issue-153537.2KySPQ.rst @@ -0,0 +1,3 @@ +Re-initializing an :class:`xml.etree.ElementTree.Element` in the C accelerator +now discards the previous children and attributes instead of leaking them, +matching the pure-Python implementation. Patch by tonghuaroot. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index f827274eeffba8..fdd31925604bb2 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -449,6 +449,9 @@ element_init(PyObject *self, PyObject *args, PyObject *kwds) self_elem = (ElementObject *)self; + /* On re-init, drop any children and attrib from a previous init. */ + clear_extra(self_elem); + if (attrib != NULL && !is_empty_dict(attrib)) { if (create_extra(self_elem, attrib) < 0) { Py_DECREF(attrib);