diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst index 1daf6628013bf0..f6f4be84b50367 100644 --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -611,8 +611,11 @@ Functions .. function:: iselement(element) - Check if an object appears to be a valid element object. *element* is an - element instance. Return ``True`` if this is an element object. + Check if *element* appears to be a valid element object or type. Return + ``True`` if this is an element object or type. + + Because ``iselement`` behaves identically for both objects and types, code + requiring an object should check for this, see :func:`iselement`. .. function:: iterparse(source, events=None, parser=None) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 38be2cd437f200..bf6d5074fdebd8 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -218,6 +218,33 @@ 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()) + + def test_setroot(self): + # Test _setroot behavior. + + tree = ET.ElementTree() + element = ET.Element("tag") + tree._setroot(element) + self.assertEqual(tree.getroot().tag, "tag") + self.assertEqual(tree.getroot(), element) + + # Test behavior with an invalid root element + + tree = ET.ElementTree() + with self.assertRaises(TypeError): + tree._setroot("") + with self.assertRaises(TypeError): + tree._setroot(ET.ElementTree()) + with self.assertRaises(TypeError): + tree._setroot(None) + def test_interface(self): # Test element tree interface. diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index 44ab5d18624e73..dafe5b1b8a0c3f 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -527,7 +527,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('expected an Element, not %s' % + type(element).__name__) self._root = element # first node if file: self.parse(file) @@ -543,7 +545,9 @@ def _setroot(self, element): with the given element. Use with care! """ - # assert iselement(element) + if not iselement(element): + raise TypeError('expected an Element, not %s' + % type(element).__name__) self._root = element def parse(self, source, parser=None): @@ -709,6 +713,8 @@ def write(self, file_or_filename, of start/end tags """ + if self._root is None: + raise TypeError('ElementTree not initialized') if not method: method = "xml" elif method not in _serialize: diff --git a/Misc/NEWS.d/next/Documentation/2025-07-09-15-06-27.gh-issue-136231.Wx8W-w.rst b/Misc/NEWS.d/next/Documentation/2025-07-09-15-06-27.gh-issue-136231.Wx8W-w.rst new file mode 100644 index 00000000000000..d5082eaf48158f --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2025-07-09-15-06-27.gh-issue-136231.Wx8W-w.rst @@ -0,0 +1,2 @@ +Document that :func:`xml.etree.ElementTree.iselement` works identically on +both object instances and types. 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..ad217b57b4b510 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-06-22-02-16-17.gh-issue-135640.FXyFL6.rst @@ -0,0 +1,4 @@ +Address bug where it was possible to call +:func:`xml.etree.ElementTree.ElementTree.write` on an ElementTree object with +an invalid root element. This behavior blanked the file passed to ``write`` +if it already existed.