Skip to content

Commit 747abc0

Browse files
[3.12] pythongh-123213: Fixed xml.etree.ElementTree.Element.extend and assignment to no longer hide exceptions (pythonGH-123214) (python#123258)
Co-authored-by: Bar Harel <bharel@barharel.com>
1 parent 17249f3 commit 747abc0

File tree

4 files changed

+38
-11
lines changed

4 files changed

+38
-11
lines changed

Doc/library/xml.etree.elementtree.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,7 @@ Element Objects
966966

967967
.. method:: extend(subelements)
968968

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

972972
.. versionadded:: 3.2

Lib/test/test_xml_etree.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2343,6 +2343,22 @@ def test_39495_treebuilder_start(self):
23432343
self.assertRaises(TypeError, ET.TreeBuilder().start, "tag")
23442344
self.assertRaises(TypeError, ET.TreeBuilder().start, "tag", None)
23452345

2346+
def test_issue123213_correct_extend_exception(self):
2347+
# Does not hide the internal exception when extending the element
2348+
self.assertRaises(ZeroDivisionError, ET.Element('tag').extend,
2349+
(1/0 for i in range(2)))
2350+
2351+
# Still raises the TypeError when extending with a non-iterable
2352+
self.assertRaises(TypeError, ET.Element('tag').extend, None)
2353+
2354+
# Preserves the TypeError message when extending with a generator
2355+
def f():
2356+
raise TypeError("mymessage")
2357+
2358+
self.assertRaisesRegex(
2359+
TypeError, 'mymessage',
2360+
ET.Element('tag').extend, (f() for i in range(2)))
2361+
23462362

23472363

23482364
# --------------------------------------------------------------------
@@ -3669,6 +3685,22 @@ def test_setslice_negative_steps(self):
36693685
e[1::-sys.maxsize<<64] = [ET.Element('d')]
36703686
self.assertEqual(self._subelem_tags(e), ['a0', 'd', 'a2', 'a3'])
36713687

3688+
def test_issue123213_setslice_exception(self):
3689+
e = ET.Element('tag')
3690+
# Does not hide the internal exception when assigning to the element
3691+
with self.assertRaises(ZeroDivisionError):
3692+
e[:1] = (1/0 for i in range(2))
3693+
3694+
# Still raises the TypeError when assigning with a non-iterable
3695+
with self.assertRaises(TypeError):
3696+
e[:1] = None
3697+
3698+
# Preserve the original TypeError message when assigning.
3699+
def f():
3700+
raise TypeError("mymessage")
3701+
3702+
with self.assertRaisesRegex(TypeError, 'mymessage'):
3703+
e[:1] = (f() for i in range(2))
36723704

36733705
class IOTest(unittest.TestCase):
36743706
def test_encoding(self):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:meth:`xml.etree.ElementTree.Element.extend` and
2+
:class:`~xml.etree.ElementTree.Element` assignment no longer hide the internal
3+
exception if an erronous generator is passed. Patch by Bar Harel.

Modules/_elementtree.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,12 +1213,8 @@ _elementtree_Element_extend_impl(ElementObject *self, PyTypeObject *cls,
12131213
PyObject* seq;
12141214
Py_ssize_t i;
12151215

1216-
seq = PySequence_Fast(elements, "");
1216+
seq = PySequence_Fast(elements, "'elements' must be an iterable");
12171217
if (!seq) {
1218-
PyErr_Format(
1219-
PyExc_TypeError,
1220-
"expected sequence, not \"%.200s\"", Py_TYPE(elements)->tp_name
1221-
);
12221218
return NULL;
12231219
}
12241220

@@ -1920,12 +1916,8 @@ element_ass_subscr(PyObject* self_, PyObject* item, PyObject* value)
19201916
}
19211917

19221918
/* A new slice is actually being assigned */
1923-
seq = PySequence_Fast(value, "");
1919+
seq = PySequence_Fast(value, "assignment expects an iterable");
19241920
if (!seq) {
1925-
PyErr_Format(
1926-
PyExc_TypeError,
1927-
"expected sequence, not \"%.200s\"", Py_TYPE(value)->tp_name
1928-
);
19291921
return -1;
19301922
}
19311923
newlen = PySequence_Fast_GET_SIZE(seq);

0 commit comments

Comments
 (0)