diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 38be2cd437f200..4d0acc7fc04bb6 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -218,6 +218,42 @@ class ElementTreeTest(unittest.TestCase): def serialize_check(self, elem, expected): self.assertEqual(serialize(elem), expected) + def test_constructor(self): + # Test constructor behavior. + + with self.assertRaises(TypeError): + tree = ET.ElementTree("") + with self.assertRaises(TypeError): + tree = ET.ElementTree(ET.ElementTree()) + + # Test _setroot as well, since it also sets the _root object. + + tree = ET.ElementTree() + with self.assertRaises(TypeError): + tree._setroot("") + with self.assertRaises(TypeError): + tree._setroot(ET.ElementTree()) + + # Make sure it accepts an Element-like object. + + class ElementLike: + def __init__(self): + self.tag = "tag" + self.text = None + self.tail = None + def iter(self): + pass + def items(self): + pass + def __len__(self): + pass + + element_like = ElementLike() + try: + tree = ET.ElementTree(element_like) + except Exception as err: + self.fail(err) + def test_interface(self): # Test element tree interface. diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index 44ab5d18624e73..4bef7d5710b7c0 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -120,8 +120,9 @@ class ParseError(SyntaxError): def iselement(element): """Return True if *element* appears to be an Element.""" - return hasattr(element, 'tag') - + return (hasattr(element, 'tag') and hasattr(element, 'text') and + hasattr(element, 'tail') and callable(element.iter) and + callable(element.items) and callable(element.__len__)) class Element: """An XML element. @@ -527,7 +528,9 @@ class ElementTree: """ def __init__(self, element=None, file=None): - # assert element is None or iselement(element) + if element is not None and not iselement(element): + raise TypeError(f"element must be xml.etree.Element, " + f"not {type(element).__name__}") self._root = element # first node if file: self.parse(file) @@ -543,7 +546,9 @@ def _setroot(self, element): with the given element. Use with care! """ - # assert iselement(element) + if not iselement(element): + raise TypeError(f"element must be xml.etree.Element, " + f"not {type(element).__name__}") self._root = element def parse(self, source, parser=None): diff --git a/Misc/NEWS.d/next/Library/2025-06-22-02-16-17.gh-issue-135640.FXyFL6.rst b/Misc/NEWS.d/next/Library/2025-06-22-02-16-17.gh-issue-135640.FXyFL6.rst new file mode 100644 index 00000000000000..49d1c5fead8843 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-06-22-02-16-17.gh-issue-135640.FXyFL6.rst @@ -0,0 +1,3 @@ +Address bug where calling :func:`xml.etree.ElementTree.ElementTree.write` on +an ElementTree object with an invalid root element would blank the file +passed to ``write`` if it already existed.