bpo-34941: Fix searching Element subclasses. (GH-9766)
Methods find(), findtext() and findall() of xml.etree.ElementTree.Element were not able to find chldren which are instances of Element subclasses.
This commit is contained in:
parent
d274afb5e5
commit
b11c5667f9
|
@ -2160,6 +2160,21 @@ class ElementTreeTypeTest(unittest.TestCase):
|
||||||
mye = MyElement('joe')
|
mye = MyElement('joe')
|
||||||
self.assertEqual(mye.newmethod(), '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):
|
class ElementFindTest(unittest.TestCase):
|
||||||
def test_find_simple(self):
|
def test_find_simple(self):
|
||||||
|
|
|
@ -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.
|
|
@ -204,6 +204,8 @@ typedef struct {
|
||||||
|
|
||||||
|
|
||||||
#define Element_CheckExact(op) (Py_TYPE(op) == &Element_Type)
|
#define Element_CheckExact(op) (Py_TYPE(op) == &Element_Type)
|
||||||
|
#define Element_Check(op) PyObject_TypeCheck(op, &Element_Type)
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* Element constructors and destructor */
|
/* Element constructors and destructor */
|
||||||
|
@ -1132,7 +1134,7 @@ _elementtree_Element_extend(ElementObject *self, PyObject *elements)
|
||||||
for (i = 0; i < PySequence_Fast_GET_SIZE(seq); i++) {
|
for (i = 0; i < PySequence_Fast_GET_SIZE(seq); i++) {
|
||||||
PyObject* element = PySequence_Fast_GET_ITEM(seq, i);
|
PyObject* element = PySequence_Fast_GET_ITEM(seq, i);
|
||||||
Py_INCREF(element);
|
Py_INCREF(element);
|
||||||
if (!PyObject_TypeCheck(element, (PyTypeObject *)&Element_Type)) {
|
if (!Element_Check(element)) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
PyExc_TypeError,
|
PyExc_TypeError,
|
||||||
"expected an Element, not \"%.200s\"",
|
"expected an Element, not \"%.200s\"",
|
||||||
|
@ -1184,7 +1186,7 @@ _elementtree_Element_find_impl(ElementObject *self, PyObject *path,
|
||||||
for (i = 0; i < self->extra->length; i++) {
|
for (i = 0; i < self->extra->length; i++) {
|
||||||
PyObject* item = self->extra->children[i];
|
PyObject* item = self->extra->children[i];
|
||||||
int rc;
|
int rc;
|
||||||
if (!Element_CheckExact(item))
|
if (!Element_Check(item))
|
||||||
continue;
|
continue;
|
||||||
Py_INCREF(item);
|
Py_INCREF(item);
|
||||||
rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ);
|
rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ);
|
||||||
|
@ -1229,14 +1231,14 @@ _elementtree_Element_findtext_impl(ElementObject *self, PyObject *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < self->extra->length; i++) {
|
for (i = 0; i < self->extra->length; i++) {
|
||||||
ElementObject* item = (ElementObject*) self->extra->children[i];
|
PyObject *item = self->extra->children[i];
|
||||||
int rc;
|
int rc;
|
||||||
if (!Element_CheckExact(item))
|
if (!Element_Check(item))
|
||||||
continue;
|
continue;
|
||||||
Py_INCREF(item);
|
Py_INCREF(item);
|
||||||
rc = PyObject_RichCompareBool(item->tag, path, Py_EQ);
|
rc = PyObject_RichCompareBool(((ElementObject*)item)->tag, path, Py_EQ);
|
||||||
if (rc > 0) {
|
if (rc > 0) {
|
||||||
PyObject* text = element_get_text(item);
|
PyObject* text = element_get_text((ElementObject*)item);
|
||||||
if (text == Py_None) {
|
if (text == Py_None) {
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
return PyUnicode_New(0, 0);
|
return PyUnicode_New(0, 0);
|
||||||
|
@ -1269,13 +1271,12 @@ _elementtree_Element_findall_impl(ElementObject *self, PyObject *path,
|
||||||
{
|
{
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
PyObject* out;
|
PyObject* out;
|
||||||
PyObject* tag = path;
|
|
||||||
elementtreestate *st = ET_STATE_GLOBAL;
|
elementtreestate *st = ET_STATE_GLOBAL;
|
||||||
|
|
||||||
if (checkpath(tag) || namespaces != Py_None) {
|
if (checkpath(path) || namespaces != Py_None) {
|
||||||
_Py_IDENTIFIER(findall);
|
_Py_IDENTIFIER(findall);
|
||||||
return _PyObject_CallMethodIdObjArgs(
|
return _PyObject_CallMethodIdObjArgs(
|
||||||
st->elementpath_obj, &PyId_findall, self, tag, namespaces, NULL
|
st->elementpath_obj, &PyId_findall, self, path, namespaces, NULL
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1289,10 +1290,10 @@ _elementtree_Element_findall_impl(ElementObject *self, PyObject *path,
|
||||||
for (i = 0; i < self->extra->length; i++) {
|
for (i = 0; i < self->extra->length; i++) {
|
||||||
PyObject* item = self->extra->children[i];
|
PyObject* item = self->extra->children[i];
|
||||||
int rc;
|
int rc;
|
||||||
if (!Element_CheckExact(item))
|
if (!Element_Check(item))
|
||||||
continue;
|
continue;
|
||||||
Py_INCREF(item);
|
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)) {
|
if (rc != 0 && (rc < 0 || PyList_Append(out, item) < 0)) {
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
Py_DECREF(out);
|
Py_DECREF(out);
|
||||||
|
@ -2173,7 +2174,7 @@ elementiter_next(ElementIterObject *it)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PyObject_TypeCheck(extra->children[child_index], &Element_Type)) {
|
if (!Element_Check(extra->children[child_index])) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
"'%.100s' object has no attribute 'iter'",
|
"'%.100s' object has no attribute 'iter'",
|
||||||
Py_TYPE(extra->children[child_index])->tp_name);
|
Py_TYPE(extra->children[child_index])->tp_name);
|
||||||
|
|
Loading…
Reference in New Issue