Skip to content

Commit 396e8fc

Browse files
committed
Issue #13782: streamline argument type-checking in ET.Element
append, extend and insert now consistently type-check their argument in both the C and Python implementations, and raise TypeError for non-Element argument. Added tests
1 parent 42243c4 commit 396e8fc

File tree

4 files changed

+33
-12
lines changed

4 files changed

+33
-12
lines changed

Doc/library/xml.etree.elementtree.rst

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,15 @@ Element Objects
281281

282282
.. method:: append(subelement)
283283

284-
Adds the element *subelement* to the end of this elements internal list
285-
of subelements.
284+
Adds the element *subelement* to the end of this element's internal list
285+
of subelements. Raises :exc:`TypeError` if *subelement* is not an
286+
:class:`Element`.
286287

287288

288289
.. method:: extend(subelements)
289290

290291
Appends *subelements* from a sequence object with zero or more elements.
291-
Raises :exc:`AssertionError` if a subelement is not a valid object.
292+
Raises :exc:`TypeError` if a subelement is not an :class:`Element`.
292293

293294
.. versionadded:: 3.2
294295

@@ -325,9 +326,10 @@ Element Objects
325326
Use method :meth:`Element.iter` instead.
326327

327328

328-
.. method:: insert(index, element)
329+
.. method:: insert(index, subelement)
329330

330-
Inserts a subelement at the given position in this element.
331+
Inserts *subelement* at the given position in this element. Raises
332+
:exc:`TypeError` if *subelement* is not an :class:`Element`.
331333

332334

333335
.. method:: iter(tag=None)

Lib/test/test_xml_etree.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,8 +1839,15 @@ def check_issue10777():
18391839
# --------------------------------------------------------------------
18401840

18411841

1842-
class ElementTreeTest(unittest.TestCase):
1842+
class BasicElementTest(unittest.TestCase):
1843+
def test_augmentation_type_errors(self):
1844+
e = ET.Element('joe')
1845+
self.assertRaises(TypeError, e.append, 'b')
1846+
self.assertRaises(TypeError, e.extend, [ET.Element('bar'), 'foo'])
1847+
self.assertRaises(TypeError, e.insert, 0, 'foo')
1848+
18431849

1850+
class ElementTreeTest(unittest.TestCase):
18441851
def test_istype(self):
18451852
self.assertIsInstance(ET.ParseError, type)
18461853
self.assertIsInstance(ET.QName, type)
@@ -1879,7 +1886,6 @@ def newmethod(self):
18791886

18801887

18811888
class TreeBuilderTest(unittest.TestCase):
1882-
18831889
sample1 = ('<!DOCTYPE html PUBLIC'
18841890
' "-//W3C//DTD XHTML 1.0 Transitional//EN"'
18851891
' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
@@ -1931,7 +1937,6 @@ def close(self):
19311937

19321938

19331939
class NoAcceleratorTest(unittest.TestCase):
1934-
19351940
# Test that the C accelerator was not imported for pyET
19361941
def test_correct_import_pyET(self):
19371942
self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree')
@@ -2096,6 +2101,7 @@ def test_main(module=pyET):
20962101

20972102
test_classes = [
20982103
ElementSlicingTest,
2104+
BasicElementTest,
20992105
StringIOTest,
21002106
ParseErrorTest,
21012107
ElementTreeTest,

Lib/xml/etree/ElementTree.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ def __delitem__(self, index):
298298
# @param element The element to add.
299299

300300
def append(self, element):
301-
# assert iselement(element)
301+
self._assert_is_element(element)
302302
self._children.append(element)
303303

304304
##
@@ -308,8 +308,8 @@ def append(self, element):
308308
# @since 1.3
309309

310310
def extend(self, elements):
311-
# for element in elements:
312-
# assert iselement(element)
311+
for element in elements:
312+
self._assert_is_element(element)
313313
self._children.extend(elements)
314314

315315
##
@@ -318,9 +318,13 @@ def extend(self, elements):
318318
# @param index Where to insert the new subelement.
319319

320320
def insert(self, index, element):
321-
# assert iselement(element)
321+
self._assert_is_element(element)
322322
self._children.insert(index, element)
323323

324+
def _assert_is_element(self, e):
325+
if not isinstance(e, Element):
326+
raise TypeError('expected an Element, not %s' % type(e).__name__)
327+
324328
##
325329
# Removes a matching subelement. Unlike the <b>find</b> methods,
326330
# this method compares elements based on identity, not on tag

Modules/_elementtree.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,15 @@ element_extend(ElementObject* self, PyObject* args)
803803
seqlen = PySequence_Size(seq);
804804
for (i = 0; i < seqlen; i++) {
805805
PyObject* element = PySequence_Fast_GET_ITEM(seq, i);
806+
if (!PyObject_IsInstance(element, (PyObject *)&Element_Type)) {
807+
Py_DECREF(seq);
808+
PyErr_Format(
809+
PyExc_TypeError,
810+
"expected an Element, not \"%.200s\"",
811+
Py_TYPE(element)->tp_name);
812+
return NULL;
813+
}
814+
806815
if (element_add_subelement(self, element) < 0) {
807816
Py_DECREF(seq);
808817
return NULL;

0 commit comments

Comments
 (0)