diff --git a/crates/stdlib/src/elementtree.rs b/crates/stdlib/src/elementtree.rs index 1e49c9ec1bb..ed8dc17c612 100644 --- a/crates/stdlib/src/elementtree.rs +++ b/crates/stdlib/src/elementtree.rs @@ -578,7 +578,21 @@ pub(crate) mod _elementtree { #[pymethod] fn remove(zelf: &Py, subelement: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { - check_element(&subelement, vm)?; + if !subelement.downcastable::() { + let name = if vm.is_none(&subelement) { + "None".into() + } else { + subelement.class().slot_name() + }; + let mut end = name.len().min(50); + while !name.is_char_boundary(end) { + end -= 1; + } + return Err(vm.new_type_error(format!( + "remove() argument must be xml.etree.ElementTree.Element, not {}", + &name[..end] + ))); + } // Identity first, then equality, the way `element_remove` does; // the equality test can run arbitrary code, so the lock is // dropped for it and the list re-read afterwards. diff --git a/extra_tests/snippets/stdlib_xml.py b/extra_tests/snippets/stdlib_xml.py index 34f1a726e4c..18e73004513 100644 --- a/extra_tests/snippets/stdlib_xml.py +++ b/extra_tests/snippets/stdlib_xml.py @@ -1,4 +1,6 @@ +import array import xml.sax +from xml.etree.ElementTree import Element from xml.parsers import expat from testutils import assert_raises @@ -66,3 +68,18 @@ def endElement(self, name): ("characters", "text"), ("end-cdata",), ] + +root = Element("root") +for value, type_name in ( + (None, "None"), + (1, "int"), + ("child", "str"), + (array.array("b"), "array.array"), + (type("A" * 60, (), {})(), "A" * 50), + (type("€" * 20, (), {})(), "€" * 16), +): + with assert_raises(TypeError) as caught: + root.remove(value) + assert str(caught.exception) == ( + "remove() argument must be xml.etree.ElementTree.Element, not " + type_name + )