]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-142306: Improve errors for Element.remove() (GH-142308)
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 12 Jan 2026 09:49:18 +0000 (11:49 +0200)
committerGitHub <noreply@github.com>
Mon, 12 Jan 2026 09:49:18 +0000 (11:49 +0200)
* Raise TypeError for non-element argument in the Python implementation
  too.
* Include the repr of the elements in the ValueError error message.

Lib/test/test_xml_etree.py
Lib/xml/etree/ElementTree.py
Misc/NEWS.d/next/Library/2025-12-05-17-22-25.gh-issue-142306.Gj3_1m.rst [new file with mode: 0644]
Modules/_elementtree.c

index 7aa949b2819172ecba0b96471d6b7095cc31adf0..93162f52ba03440d521e272a4b639b8883868ba8 100644 (file)
@@ -370,8 +370,7 @@ class ElementTreeTest(unittest.TestCase):
         self.serialize_check(element, '<tag key="value"><subtag /></tag>') # 4
         element.remove(subelement)
         self.serialize_check(element, '<tag key="value" />') # 5
-        with self.assertRaisesRegex(ValueError,
-                                    r'Element\.remove\(.+\): element not found'):
+        with self.assertRaises(ValueError):
             element.remove(subelement)
         self.serialize_check(element, '<tag key="value" />') # 6
         element[0:0] = [subelement, subelement, subelement]
@@ -2758,6 +2757,17 @@ class BasicElementTest(ElementTestCase, unittest.TestCase):
                 self.assertEqual(e2.tag, 'group')
                 self.assertEqual(e2[0].tag, 'dogs')
 
+    def test_remove_errors(self):
+        e = ET.Element('tag')
+        with self.assertRaisesRegex(ValueError,
+                r"<Element 'subtag'.*> not in <Element 'tag'.*>"):
+            e.remove(ET.Element('subtag'))
+        with self.assertRaisesRegex(TypeError,
+                r".*\bElement, not type"):
+            e.remove(ET.Element)
+        with self.assertRaisesRegex(TypeError,
+                r".*\bElement, not int"):
+            e.remove(1)
 
 class BadElementTest(ElementTestCase, unittest.TestCase):
 
index 92f902b9a8b875457678e56ea188ec5a2aeb8aeb..e3d81a2c4560d97e6de6712533f97fe1a0774a9a 100644 (file)
@@ -263,12 +263,15 @@ class Element:
         ValueError is raised if a matching element could not be found.
 
         """
-        # assert iselement(element)
         try:
             self._children.remove(subelement)
         except ValueError:
+            # to align the error type with the C implementation
+            if isinstance(subelement, type) or not iselement(subelement):
+                raise TypeError('expected an Element, not %s' %
+                                type(subelement).__name__) from None
             # to align the error message with the C implementation
-            raise ValueError("Element.remove(x): element not found") from None
+            raise ValueError(f"{subelement!r} not in {self!r}") from None
 
     def find(self, path, namespaces=None):
         """Find first matching element by tag name or path.
diff --git a/Misc/NEWS.d/next/Library/2025-12-05-17-22-25.gh-issue-142306.Gj3_1m.rst b/Misc/NEWS.d/next/Library/2025-12-05-17-22-25.gh-issue-142306.Gj3_1m.rst
new file mode 100644 (file)
index 0000000..ac39490
--- /dev/null
@@ -0,0 +1,2 @@
+Improve errors for :meth:`Element.remove
+<xml.etree.ElementTree.Element.remove>`.
index 22d3205e6ad31483411bf47e6a6ab386645a3bcc..f60a4c295e6495b4fdcd12a20e34e61f01016b2f 100644 (file)
@@ -1679,8 +1679,7 @@ _elementtree_Element_remove_impl(ElementObject *self, PyObject *subelement)
     }
 
     if (rc == 0) {
-        PyErr_SetString(PyExc_ValueError,
-                        "Element.remove(x): element not found");
+        PyErr_Format(PyExc_ValueError, "%R not in %R", subelement, self);
         return NULL;
     }