diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 2af2d1fd64520b..fb35bb6a5f442f 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1068,6 +1068,34 @@ def bxml(encoding, body=''):
self.assertRaises(ValueError, ET.XML, xml('undefined').encode('ascii'))
self.assertRaises(LookupError, ET.XML, xml('xxx').encode('ascii'))
+ def test_parse_text_source(self):
+ # gh-99064: The encoding declared in the document does not apply
+ # to a source which is already decoded.
+ def check(encoding, body):
+ xml = (f""
+ f"{body}")
+ with self.subTest(encoding=encoding):
+ self.assertEqual(ET.parse(io.StringIO(xml)).getroot().text,
+ body)
+ # the same with an explicitly created parser
+ self.assertEqual(
+ ET.parse(io.StringIO(xml), ET.XMLParser()).getroot().text,
+ body)
+ check("ascii", 'a')
+ check("iso-8859-1", '\xbd')
+ check("iso-8859-15", '\u20ac')
+ check("cp437", '\u221a')
+ check("utf-8", '\u4e2d')
+ # not ASCII compatible, unsupported for a bytes source
+ check("utf-16", '\u4e2d')
+ check("utf-32", '\u4e2d')
+
+ def test_parse_text_source_multiple_chunks(self):
+ # the encoding is overridden before the first chunk is parsed
+ body = '\xe4' * 100_000
+ xml = "%s" % body
+ self.assertEqual(ET.parse(io.StringIO(xml)).getroot().text, body)
+
@support.subTests('sample,exception', [
(b' \xa1', UnicodeDecodeError), # crashed
(b' \xa1state;
+ int first = 1;
for (;;) {
buffer = PyObject_CallFunction(reader, "i", 64*1024);
@@ -4100,6 +4101,11 @@ _elementtree_XMLParser__parse_whole_impl(XMLParserObject *self,
Py_DECREF(buffer);
break;
}
+ if (first) {
+ /* The text is already decoded, the encoding declared in the
+ document does not apply to it. Return code ignored. */
+ (void)EXPAT(st, SetEncoding)(self->parser, "utf-8");
+ }
temp = PyUnicode_AsEncodedString(buffer, "utf-8", "surrogatepass");
Py_DECREF(buffer);
if (!temp) {
@@ -4123,6 +4129,7 @@ _elementtree_XMLParser__parse_whole_impl(XMLParserObject *self,
res = expat_parse(
st, self, PyBytes_AS_STRING(buffer), (int)PyBytes_GET_SIZE(buffer),
0);
+ first = 0;
Py_DECREF(buffer);