diff --git a/Misc/NEWS.d/next/Library/2026-09-12-15-50-23.gh-issue-157366.djwD2M.rst b/Misc/NEWS.d/next/Library/2026-09-12-15-50-23.gh-issue-157366.djwD2M.rst new file mode 100644 index 000000000000000..c29b132e4b3b198 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-12-15-50-23.gh-issue-157366.djwD2M.rst @@ -0,0 +1,7 @@ +Remove the accidental acceptance of :class:`bytes` in the C implementation of +:mod:`xml.etree.ElementTree`, a leftover of the Python 2 to Python 3 migration, +for paths of :meth:`~xml.etree.ElementTree.Element.find` +and similar methods, for the tag of :meth:`~xml.etree.ElementTree.Element.iter`, +and for the names of events of :class:`~xml.etree.ElementTree.XMLPullParser` +and :func:`~xml.etree.ElementTree.iterparse`. It now raises the same +exceptions as the Python implementation. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index f6dedeed981c40d..6f51f10b2b22759 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -1230,24 +1230,6 @@ checkpath(PyObject* tag) } return 0; } - if (PyBytes_Check(tag)) { - const char *p = PyBytes_AS_STRING(tag); - const Py_ssize_t len = PyBytes_GET_SIZE(tag); - if (len >= 3 && p[0] == '{' && ( - p[1] == '}' || (p[1] == '*' && p[2] == '}'))) { - /* wildcard: '{}tag' or '{*}tag' */ - return 1; - } - for (i = 0; i < len; i++) { - if (p[i] == '{') - check = 0; - else if (p[i] == '}') - check = 1; - else if (check && PATHCHAR(p[i])) - return 1; - } - return 0; - } return 1; /* unknown type; might be path expression */ } @@ -1552,10 +1534,6 @@ _elementtree_Element_iter_impl(ElementObject *self, PyTypeObject *cls, if (PyUnicode_GET_LENGTH(tag) == 1 && PyUnicode_READ_CHAR(tag, 0) == '*') tag = Py_None; } - else if (PyBytes_Check(tag)) { - if (PyBytes_GET_SIZE(tag) == 1 && *PyBytes_AS_STRING(tag) == '*') - tag = Py_None; - } elementtreestate *st = get_elementtree_state_by_cls(cls); return create_elementiter(st, self, tag, 0); @@ -2935,17 +2913,7 @@ treebuilder_handle_data(TreeBuilderObject* self, PyObject* data) self->data = Py_NewRef(data); } else { /* more than one item; use a list to collect items */ - if (PyBytes_CheckExact(self->data) - && _PyObject_IsUniquelyReferenced(self->data) - && PyBytes_CheckExact(data) && PyBytes_GET_SIZE(data) == 1) { - /* XXX this code path unused in Python 3? */ - /* expat often generates single character data sections; handle - the most common case by resizing the existing string... */ - Py_ssize_t size = PyBytes_GET_SIZE(self->data); - if (_PyBytes_Resize(&self->data, size + 1) < 0) - return NULL; - PyBytes_AS_STRING(self->data)[size] = PyBytes_AS_STRING(data)[0]; - } else if (PyList_CheckExact(self->data)) { + if (PyList_CheckExact(self->data)) { if (PyList_Append(self->data, data) < 0) return NULL; } else { @@ -4363,18 +4331,14 @@ _elementtree_XMLParser__setevents_impl(XMLParserObject *self, for (i = 0; i < PySequence_Fast_GET_SIZE(events_seq); ++i) { PyObject *event_name_obj = PySequence_Fast_GET_ITEM(events_seq, i); - const char *event_name = NULL; - if (PyUnicode_Check(event_name_obj)) { - event_name = PyUnicode_AsUTF8(event_name_obj); - } else if (PyBytes_Check(event_name_obj)) { - event_name = PyBytes_AS_STRING(event_name_obj); + if (!PyUnicode_Check(event_name_obj)) { + goto unknown_event; } + const char *event_name = PyUnicode_AsUTF8(event_name_obj); if (event_name == NULL) { Py_DECREF(events_seq); - PyErr_Format(PyExc_ValueError, "invalid events sequence"); return NULL; } - if (strcmp(event_name, "start") == 0) { Py_XSETREF(target->start_event_obj, Py_NewRef(event_name_obj)); } else if (strcmp(event_name, "end") == 0) { @@ -4406,7 +4370,8 @@ _elementtree_XMLParser__setevents_impl(XMLParserObject *self, (XML_ProcessingInstructionHandler) expat_pi_handler ); } else { - PyErr_Format(PyExc_ValueError, "unknown event '%s'", event_name); +unknown_event: + PyErr_Format(PyExc_ValueError, "unknown event %R", event_name_obj); Py_DECREF(events_seq); return NULL; }