From 90b6d0e0f8f07d7443695e14a18488cb499d3b4d Mon Sep 17 00:00:00 2001 From: Bar Harel Date: Fri, 23 Aug 2024 12:12:58 +0300 Subject: [PATCH] gh-123213: Fixed xml.etree.ElementTree.Element.extend and assignment to no longer hide exceptions (GH-123214) --- Doc/library/xml.etree.elementtree.rst | 2 +- Lib/test/test_xml_etree.py | 32 +++++++++++++++++++ ...-08-22-09-37-48.gh-issue-123213.owmXnP.rst | 3 ++ Modules/_elementtree.c | 12 ++----- 4 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-08-22-09-37-48.gh-issue-123213.owmXnP.rst diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst index 51bf88313e5..9fad463d936 100644 --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -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 diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 930501633d1..ae06a9cc118 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -2423,6 +2423,22 @@ class BugsTest(unittest.TestCase): 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))) + # -------------------------------------------------------------------- @@ -3748,6 +3764,22 @@ class ElementSlicingTest(unittest.TestCase): 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): diff --git a/Misc/NEWS.d/next/Library/2024-08-22-09-37-48.gh-issue-123213.owmXnP.rst b/Misc/NEWS.d/next/Library/2024-08-22-09-37-48.gh-issue-123213.owmXnP.rst new file mode 100644 index 00000000000..6bbd194b916 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-08-22-09-37-48.gh-issue-123213.owmXnP.rst @@ -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. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 3818e20b4f0..ec999582d2f 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -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; } @@ -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);