diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py old mode 100644 new mode 100755 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -130,14 +130,13 @@ def check_element(element): if not ET.iselement(element): print("not an element") - if not hasattr(element, "tag"): - print("no tag member") - if not hasattr(element, "attrib"): - print("no attrib member") - if not hasattr(element, "text"): - print("no text member") - if not hasattr(element, "tail"): - print("no tail member") + + direlem = dir(element) + for attr in ('tag', 'attrib', 'text', 'tail'): + if not hasattr(element, attr): + print('no %s member' % attr) + if not attr in direlem: + print('no %s visible by dir' % attr) check_string(element.tag) check_mapping(element.attrib) diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py old mode 100644 new mode 100755 --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -17,12 +17,6 @@ Issue #6697. - >>> e = cElementTree.Element('a') - >>> getattr(e, '\uD800') # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - UnicodeEncodeError: ... - >>> p = cElementTree.XMLParser() >>> p.version.split()[0] 'Expat' diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -1476,85 +1476,89 @@ }; static PyObject* -element_getattro(ElementObject* self, PyObject* nameobj) +element_get__tag(ElementObject *self, void *closure) { - PyObject* res; - char *name = ""; - - if (PyUnicode_Check(nameobj)) - name = _PyUnicode_AsString(nameobj); - - if (name == NULL) - return NULL; - - /* handle common attributes first */ - if (strcmp(name, "tag") == 0) { - res = self->tag; - Py_INCREF(res); - return res; - } else if (strcmp(name, "text") == 0) { - res = element_get_text(self); - Py_INCREF(res); - return res; - } - - /* methods */ - res = PyObject_GenericGetAttr((PyObject*) self, nameobj); - if (res) - return res; - - /* less common attributes */ - if (strcmp(name, "tail") == 0) { - PyErr_Clear(); - res = element_get_tail(self); - } else if (strcmp(name, "attrib") == 0) { - PyErr_Clear(); - if (!self->extra) - element_new_extra(self, NULL); - res = element_get_attrib(self); - } - - if (!res) - return NULL; - + PyObject *res = self->tag; Py_INCREF(res); return res; } +static PyObject* +element_get__text(ElementObject *self, void *closure) +{ + PyObject *res = element_get_text(self); + Py_INCREF(res); + return res; +} + +static PyObject* +element_get__tail(ElementObject *self, void *closure) +{ + PyObject *res = element_get_tail(self); + Py_INCREF(res); + return res; +} + +static PyObject* +element_get__attrib(ElementObject *self, void *closure) +{ + PyObject *res; + + if (!self->extra) + element_new_extra(self, NULL); + res = element_get_attrib(self); + Py_INCREF(res); + return res; +} + +/* macro for setter validation */ +#define _VALIDATE_ATTR_VALUE(V) \ + if ((V) == NULL) { \ + PyErr_SetString( \ + PyExc_AttributeError, \ + "can't delete element attribute"); \ + return -1; \ + } + static int -element_setattr(ElementObject* self, const char* name, PyObject* value) +element_set__tag(ElementObject *self, PyObject *value, void *closure) { - if (value == NULL) { - PyErr_SetString( - PyExc_AttributeError, - "can't delete element attributes" - ); - return -1; - } - - if (strcmp(name, "tag") == 0) { - Py_DECREF(self->tag); - self->tag = value; - Py_INCREF(self->tag); - } else if (strcmp(name, "text") == 0) { - Py_DECREF(JOIN_OBJ(self->text)); - self->text = value; - Py_INCREF(self->text); - } else if (strcmp(name, "tail") == 0) { - Py_DECREF(JOIN_OBJ(self->tail)); - self->tail = value; - Py_INCREF(self->tail); - } else if (strcmp(name, "attrib") == 0) { - if (!self->extra) - element_new_extra(self, NULL); - Py_DECREF(self->extra->attrib); - self->extra->attrib = value; - Py_INCREF(self->extra->attrib); - } else { - PyErr_SetString(PyExc_AttributeError, name); - return -1; - } - + _VALIDATE_ATTR_VALUE(value); + Py_DECREF(self->tag); + self->tag = value; + Py_INCREF(self->tag); + return 0; +} + +static int +element_set__text(ElementObject *self, PyObject *value, void *closure) +{ + _VALIDATE_ATTR_VALUE(value); + Py_DECREF(JOIN_OBJ(self->text)); + self->text = value; + Py_INCREF(self->text); + return 0; +} + +static int +element_set__tail(ElementObject *self, PyObject *value, void *closure) +{ + _VALIDATE_ATTR_VALUE(value); + Py_DECREF(JOIN_OBJ(self->tail)); + self->tail = value; + Py_INCREF(self->tail); + return 0; +} + +static int +element_set__attrib(ElementObject *self, PyObject *value, void *closure) +{ + _VALIDATE_ATTR_VALUE(value); + if (!self->extra) + element_new_extra(self, NULL); + Py_DECREF(self->extra->attrib); + self->extra->attrib = value; + Py_INCREF(self->extra->attrib); return 0; } @@ -1574,6 +1578,28 @@ (objobjargproc) element_ass_subscr, }; +static PyGetSetDef element_getsetlist[] = { + {"attrib", + (getter)element_get__attrib, + (setter)element_set__attrib, + "A dictionary containing the element's attributes"}, + {"tag", + (getter)element_get__tag, + (setter)element_set__tag, + "A string identifying what kind of data this element represents"}, + {"text", + (getter)element_get__text, + (setter)element_set__text, + "The text attribute can be used to hold additional data associated " + "with the element"}, + {"tail", + (getter)element_get__tail, + (setter)element_set__tail, + "The tail attribute can be used to hold additional data associated " + "with the element"}, + {NULL}, +}; + static PyTypeObject Element_Type = { PyVarObject_HEAD_INIT(NULL, 0) "Element", sizeof(ElementObject), 0, @@ -1581,7 +1607,7 @@ (destructor)element_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ - (setattrfunc)element_setattr, /* tp_setattr */ + 0, /* tp_setattr */ 0, /* tp_reserved */ (reprfunc)element_repr, /* tp_repr */ 0, /* tp_as_number */ @@ -1590,7 +1616,7 @@ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ - (getattrofunc)element_getattro, /* tp_getattro */ + PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ @@ -1603,6 +1629,7 @@ 0, /* tp_iternext */ element_methods, /* tp_methods */ 0, /* tp_members */ + element_getsetlist, /* tp_getset */ }; /* ==================================================================== */