Skip to content

Commit

Permalink
gh-123213: Fixed xml.etree.ElementTree.Element.extend and assignment …
Browse files Browse the repository at this point in the history
…to no longer hide exceptions (GH-123214)

(cherry picked from commit 90b6d0e)

Co-authored-by: Bar Harel <[email protected]>
  • Loading branch information
bharel authored and miss-islington committed Aug 23, 2024
1 parent fda8aec commit 84735b7
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 11 deletions.
2 changes: 1 addition & 1 deletion Doc/library/xml.etree.elementtree.rst
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,7 @@ Element Objects

.. method:: extend(subelements)

Appends *subelements* from a sequence object with zero or more elements.
Appends *subelements* from an iterable of elements.
Raises :exc:`TypeError` if a subelement is not an :class:`Element`.

.. versionadded:: 3.2
Expand Down
32 changes: 32 additions & 0 deletions Lib/test/test_xml_etree.py
Original file line number Diff line number Diff line change
Expand Up @@ -2423,6 +2423,22 @@ def test_39495_treebuilder_start(self):
self.assertRaises(TypeError, ET.TreeBuilder().start, "tag")
self.assertRaises(TypeError, ET.TreeBuilder().start, "tag", None)

def test_issue123213_correct_extend_exception(self):
# Does not hide the internal exception when extending the element
self.assertRaises(ZeroDivisionError, ET.Element('tag').extend,
(1/0 for i in range(2)))

# Still raises the TypeError when extending with a non-iterable
self.assertRaises(TypeError, ET.Element('tag').extend, None)

# Preserves the TypeError message when extending with a generator
def f():
raise TypeError("mymessage")

self.assertRaisesRegex(
TypeError, 'mymessage',
ET.Element('tag').extend, (f() for i in range(2)))



# --------------------------------------------------------------------
Expand Down Expand Up @@ -3748,6 +3764,22 @@ def test_setslice_negative_steps(self):
e[1::-sys.maxsize<<64] = [ET.Element('d')]
self.assertEqual(self._subelem_tags(e), ['a0', 'd', 'a2', 'a3'])

def test_issue123213_setslice_exception(self):
e = ET.Element('tag')
# Does not hide the internal exception when assigning to the element
with self.assertRaises(ZeroDivisionError):
e[:1] = (1/0 for i in range(2))

# Still raises the TypeError when assigning with a non-iterable
with self.assertRaises(TypeError):
e[:1] = None

# Preserve the original TypeError message when assigning.
def f():
raise TypeError("mymessage")

with self.assertRaisesRegex(TypeError, 'mymessage'):
e[:1] = (f() for i in range(2))

class IOTest(unittest.TestCase):
def test_encoding(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:meth:`xml.etree.ElementTree.Element.extend` and
:class:`~xml.etree.ElementTree.Element` assignment no longer hide the internal
exception if an erronous generator is passed. Patch by Bar Harel.
12 changes: 2 additions & 10 deletions Modules/_elementtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1213,12 +1213,8 @@ _elementtree_Element_extend_impl(ElementObject *self, PyTypeObject *cls,
PyObject* seq;
Py_ssize_t i;

seq = PySequence_Fast(elements, "");
seq = PySequence_Fast(elements, "'elements' must be an iterable");
if (!seq) {
PyErr_Format(
PyExc_TypeError,
"expected sequence, not \"%.200s\"", Py_TYPE(elements)->tp_name
);
return NULL;
}

Expand Down Expand Up @@ -1918,12 +1914,8 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
}

/* A new slice is actually being assigned */
seq = PySequence_Fast(value, "");
seq = PySequence_Fast(value, "assignment expects an iterable");
if (!seq) {
PyErr_Format(
PyExc_TypeError,
"expected sequence, not \"%.200s\"", Py_TYPE(value)->tp_name
);
return -1;
}
newlen = PySequence_Fast_GET_SIZE(seq);
Expand Down

0 comments on commit 84735b7

Please sign in to comment.