[Python-checkins] [3.6] bpo-34941: Fix searching Element subclasses. (GH-9766) (GH-9868)

Serhiy Storchaka webhook-mailer at python.org
Sun Oct 14 04:40:24 EDT 2018


https://github.com/python/cpython/commit/7c1c42b3209f1d2546daab6cd77f953eb255df6c
commit: 7c1c42b3209f1d2546daab6cd77f953eb255df6c
branch: 3.6
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2018-10-14T11:40:13+03:00
summary:

[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)

files:
A Misc/NEWS.d/next/Library/2018-10-09-14-42-16.bpo-34941.1Q5QKv.rst
M Lib/test/test_xml_etree.py
M Modules/_elementtree.c

diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 2b8c5e598656..b01709e90162 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -2145,6 +2145,21 @@ def newmethod(self):
         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 000000000000..402372489bef
--- /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 53f05f937ffb..00fa0ae1ede4 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);



More information about the Python-checkins mailing list