cpython: fef7f041c1a7 (original) (raw)
--- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -182,10 +182,12 @@ class ElementTreeTest(unittest.TestCase) def check_element(element): self.assertTrue(ET.iselement(element), msg="not an element")
self.assertTrue(hasattr(element, "tag"), msg="no tag member")[](#l1.7)
self.assertTrue(hasattr(element, "attrib"), msg="no attrib member")[](#l1.8)
self.assertTrue(hasattr(element, "text"), msg="no text member")[](#l1.9)
self.assertTrue(hasattr(element, "tail"), msg="no tail member")[](#l1.10)
direlem = dir(element)[](#l1.11)
for attr in 'tag', 'attrib', 'text', 'tail':[](#l1.12)
self.assertTrue(hasattr(element, attr),[](#l1.13)
msg='no %s member' % attr)[](#l1.14)
self.assertIn(attr, direlem,[](#l1.15)
msg='no %s visible by dir' % attr)[](#l1.16)
check_string(element.tag) check_mapping(element.attrib)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -95,6 +95,9 @@ Core and Builtins Library ------- +- Issue #7990: dir() on ElementTree.Element now lists properties: "tag",
- Issue #25725: Fixed a reference leak in pickle.loads() when unpickling invalid data including tuple instructions.
--- a/Modules/_elementtree.c +++ b/Modules/elementtree.c @@ -1870,94 +1870,92 @@ element_ass_subscr(PyObject* self, PyOb } static PyObject* -element_getattro(ElementObject* self, PyObject* nameobj) +element_tag_getter(ElementObject *self, void *closure) {
- /* handle common attributes first */
- if (strcmp(name, "tag") == 0) {
res = self->tag;[](#l3.21)
Py_INCREF(res);[](#l3.22)
return res;[](#l3.23)
- } else if (strcmp(name, "text") == 0) {
res = element_get_text(self);[](#l3.25)
Py_XINCREF(res);[](#l3.26)
return res;[](#l3.27)
- }
- /* methods */
- res = PyObject_GenericGetAttr((PyObject*) self, nameobj);
- if (res)
return res;[](#l3.33)
- /* less common attributes */
- if (strcmp(name, "tail") == 0) {
PyErr_Clear();[](#l3.37)
res = element_get_tail(self);[](#l3.38)
- } else if (strcmp(name, "attrib") == 0) {
PyErr_Clear();[](#l3.40)
if (!self->extra) {[](#l3.41)
if (create_extra(self, NULL) < 0)[](#l3.42)
return NULL;[](#l3.43)
}[](#l3.44)
res = element_get_attrib(self);[](#l3.45)
- }
-static int -element_setattro(ElementObject* self, PyObject* nameobj, PyObject* value) +static PyObject* +element_text_getter(ElementObject *self, void *closure) +{
+} + +static PyObject* +element_tail_getter(ElementObject *self, void *closure) {
- if (value == NULL) {
PyErr_SetString(PyExc_AttributeError,[](#l3.72)
"can't delete attribute");[](#l3.73)
return -1;[](#l3.74)
+} + +static PyObject* +element_attrib_getter(ElementObject *self, void *closure) +{
- PyObject *res;
- if (!self->extra) {
if (create_extra(self, NULL) < 0)[](#l3.85)
return NULL;[](#l3.86)
- }
- res = element_get_attrib(self);
- Py_XINCREF(res);
- return res;
+} + +/* macro for setter validation */ +#define _VALIDATE_ATTR_VALUE(V) [](#l3.94)
- if ((V) == NULL) { [](#l3.95)
PyErr_SetString( \[](#l3.96)
PyExc_AttributeError, \[](#l3.97)
"can't delete element attribute"); \[](#l3.98)
}return -1; \[](#l3.99)
- if (PyUnicode_Check(nameobj))
name = _PyUnicode_AsString(nameobj);[](#l3.102)
- if (name == NULL)
return -1;[](#l3.104)
- if (strcmp(name, "tag") == 0) {
Py_DECREF(self->tag);[](#l3.107)
self->tag = value;[](#l3.108)
Py_INCREF(self->tag);[](#l3.109)
- } else if (strcmp(name, "text") == 0) {
Py_DECREF(JOIN_OBJ(self->text));[](#l3.111)
self->text = value;[](#l3.112)
Py_INCREF(self->text);[](#l3.113)
- } else if (strcmp(name, "tail") == 0) {
Py_DECREF(JOIN_OBJ(self->tail));[](#l3.115)
self->tail = value;[](#l3.116)
Py_INCREF(self->tail);[](#l3.117)
- } else if (strcmp(name, "attrib") == 0) {
if (!self->extra) {[](#l3.119)
if (create_extra(self, NULL) < 0)[](#l3.120)
return -1;[](#l3.121)
}[](#l3.122)
Py_DECREF(self->extra->attrib);[](#l3.123)
self->extra->attrib = value;[](#l3.124)
Py_INCREF(self->extra->attrib);[](#l3.125)
- } else {
PyErr_SetString(PyExc_AttributeError,[](#l3.127)
"Can't set arbitrary attributes on Element");[](#l3.128)
return -1;[](#l3.129)
+ +static int +element_tag_setter(ElementObject *self, PyObject *value, void *closure) +{
+} + +static int +element_text_setter(ElementObject *self, PyObject *value, void *closure) +{
- _VALIDATE_ATTR_VALUE(value);
- Py_INCREF(value);
- Py_DECREF(JOIN_OBJ(self->text));
- self->text = value;
- return 0;
+} + +static int +element_tail_setter(ElementObject *self, PyObject *value, void *closure) +{
- _VALIDATE_ATTR_VALUE(value);
- Py_INCREF(value);
- Py_DECREF(JOIN_OBJ(self->tail));
- self->tail = value;
- return 0;
+} + +static int +element_attrib_setter(ElementObject *self, PyObject *value, void *closure) +{
- _VALIDATE_ATTR_VALUE(value);
- if (!self->extra) {
if (create_extra(self, NULL) < 0)[](#l3.166)
} -return -1;[](#l3.167)
- Py_INCREF(value);
- Py_DECREF(self->extra->attrib);
- self->extra->attrib = value; return 0; }
@@ -3770,6 +3768,26 @@ static PyMappingMethods element_as_mappi (objobjargproc) element_ass_subscr, }; +static PyGetSetDef element_getsetlist[] = {
- {"tag",
(getter)element_tag_getter,[](#l3.182)
(setter)element_tag_setter,[](#l3.183)
"A string identifying what kind of data this element represents"},[](#l3.184)
- {"text",
(getter)element_text_getter,[](#l3.186)
(setter)element_text_setter,[](#l3.187)
"A string of text directly after the start tag, or None"},[](#l3.188)
- {"tail",
(getter)element_tail_getter,[](#l3.190)
(setter)element_tail_setter,[](#l3.191)
"A string of text directly after the end tag, or None"},[](#l3.192)
- {"attrib",
(getter)element_attrib_getter,[](#l3.194)
(setter)element_attrib_setter,[](#l3.195)
"A dictionary containing the element's attributes"},[](#l3.196)
- {NULL},
+}; + static PyTypeObject Element_Type = { PyVarObject_HEAD_INIT(NULL, 0) "xml.etree.ElementTree.Element", sizeof(ElementObject), 0, @@ -3786,8 +3804,8 @@ static PyTypeObject Element_Type = { 0, /* tp_hash / 0, / tp_call / 0, / tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro / 0, / tp_as_buffer / Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, / tp_flags */
@@ -3800,7 +3818,7 @@ static PyTypeObject Element_Type = { 0, /* tp_iternext / element_methods, / tp_methods / 0, / tp_members */