From 7c1c42b3209f1d2546daab6cd77f953eb255df6c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 14 Oct 2018 11:40:13 +0300 Subject: [3.6] bpo-34941: Fix searching Element subclasses. (GH-9766) (GH-9868) Methods find(), findtext() and findall() of xml.etree.ElementTree.Element were not able to find chldren which are instances of Element subclasses. (cherry picked from commit b11c5667f99c4f0018e3394c4d07c519d835671a) --- Lib/test/test_xml_etree.py | 15 +++++++++++++ .../2018-10-09-14-42-16.bpo-34941.1Q5QKv.rst | 3 +++ Modules/_elementtree.c | 25 +++++++++++----------- 3 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-10-09-14-42-16.bpo-34941.1Q5QKv.rst diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 2b8c5e5..b01709e 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -2145,6 +2145,21 @@ class ElementTreeTypeTest(unittest.TestCase): mye = MyElement('joe') self.assertEqual(mye.newmethod(), 'joe') + def test_Element_subclass_find(self): + class MyElement(ET.Element): + pass + + e = ET.Element('foo') + e.text = 'text' + sub = MyElement('bar') + sub.text = 'subtext' + e.append(sub) + self.assertEqual(e.findtext('bar'), 'subtext') + self.assertEqual(e.find('bar').tag, 'bar') + found = list(e.findall('bar')) + self.assertEqual(len(found), 1, found) + self.assertEqual(found[0].tag, 'bar') + class ElementFindTest(unittest.TestCase): def test_find_simple(self): diff --git a/Misc/NEWS.d/next/Library/2018-10-09-14-42-16.bpo-34941.1Q5QKv.rst b/Misc/NEWS.d/next/Library/2018-10-09-14-42-16.bpo-34941.1Q5QKv.rst new file mode 100644 index 0000000..4023724 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-10-09-14-42-16.bpo-34941.1Q5QKv.rst @@ -0,0 +1,3 @@ +Methods ``find()``, ``findtext()`` and ``findall()`` of the ``Element`` +class in the :mod:`xml.etree.ElementTree` module are now able to find +children which are instances of ``Element`` subclasses. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 53f05f9..00fa0ae 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -204,6 +204,8 @@ typedef struct { #define Element_CheckExact(op) (Py_TYPE(op) == &Element_Type) +#define Element_Check(op) PyObject_TypeCheck(op, &Element_Type) + /* -------------------------------------------------------------------- */ /* Element constructors and destructor */ @@ -1131,7 +1133,7 @@ _elementtree_Element_extend(ElementObject *self, PyObject *elements) for (i = 0; i < PySequence_Fast_GET_SIZE(seq); i++) { PyObject* element = PySequence_Fast_GET_ITEM(seq, i); Py_INCREF(element); - if (!PyObject_TypeCheck(element, (PyTypeObject *)&Element_Type)) { + if (!Element_Check(element)) { PyErr_Format( PyExc_TypeError, "expected an Element, not \"%.200s\"", @@ -1183,7 +1185,7 @@ _elementtree_Element_find_impl(ElementObject *self, PyObject *path, for (i = 0; i < self->extra->length; i++) { PyObject* item = self->extra->children[i]; int rc; - if (!Element_CheckExact(item)) + if (!Element_Check(item)) continue; Py_INCREF(item); rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ); @@ -1227,14 +1229,14 @@ _elementtree_Element_findtext_impl(ElementObject *self, PyObject *path, } for (i = 0; i < self->extra->length; i++) { - ElementObject* item = (ElementObject*) self->extra->children[i]; + PyObject *item = self->extra->children[i]; int rc; - if (!Element_CheckExact(item)) + if (!Element_Check(item)) continue; Py_INCREF(item); - rc = PyObject_RichCompareBool(item->tag, path, Py_EQ); + rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ); if (rc > 0) { - PyObject* text = element_get_text(item); + PyObject* text = element_get_text((ElementObject*)item); if (text == Py_None) { Py_DECREF(item); return PyUnicode_New(0, 0); @@ -1267,13 +1269,12 @@ _elementtree_Element_findall_impl(ElementObject *self, PyObject *path, { Py_ssize_t i; PyObject* out; - PyObject* tag = path; elementtreestate *st = ET_STATE_GLOBAL; - if (checkpath(tag) || namespaces != Py_None) { + if (checkpath(path) || namespaces != Py_None) { _Py_IDENTIFIER(findall); return _PyObject_CallMethodId( - st->elementpath_obj, &PyId_findall, "OOO", self, tag, namespaces + st->elementpath_obj, &PyId_findall, "OOO", self, path, namespaces ); } @@ -1287,10 +1288,10 @@ _elementtree_Element_findall_impl(ElementObject *self, PyObject *path, for (i = 0; i < self->extra->length; i++) { PyObject* item = self->extra->children[i]; int rc; - if (!Element_CheckExact(item)) + if (!Element_Check(item)) continue; Py_INCREF(item); - rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, tag, Py_EQ); + rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ); if (rc != 0 && (rc < 0 || PyList_Append(out, item) < 0)) { Py_DECREF(item); Py_DECREF(out); @@ -2145,7 +2146,7 @@ elementiter_next(ElementIterObject *it) continue; } - if (!PyObject_TypeCheck(extra->children[child_index], &Element_Type)) { + if (!Element_Check(extra->children[child_index])) { PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute 'iter'", Py_TYPE(extra->children[child_index])->tp_name); -- cgit v0.12