cpython: 03b878d636cf (original) (raw)
--- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -13,7 +13,7 @@ from xml.sax.saxutils import XMLGenerato from xml.sax.expatreader import create_parser from xml.sax.handler import feature_namespaces from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl -from io import StringIO +from io import BytesIO, StringIO import os.path import shutil from test import support @@ -173,31 +173,29 @@ class SaxutilsTest(unittest.TestCase):
===== XMLGenerator
-start = '\n' - -class XmlgenTest(unittest.TestCase): +class XmlgenTest: def test_xmlgen_basic(self):
result = StringIO()[](#l1.21)
result = self.ioclass()[](#l1.22) gen = XMLGenerator(result)[](#l1.23) gen.startDocument()[](#l1.24) gen.startElement("doc", {})[](#l1.25) gen.endElement("doc")[](#l1.26) gen.endDocument()[](#l1.27)
self.assertEqual(result.getvalue(), start + "<doc></doc>")[](#l1.29)
self.assertEqual(result.getvalue(), self.xml("<doc></doc>"))[](#l1.30)
def test_xmlgen_basic_empty(self):
result = StringIO()[](#l1.33)
result = self.ioclass()[](#l1.34) gen = XMLGenerator(result, short_empty_elements=True)[](#l1.35) gen.startDocument()[](#l1.36) gen.startElement("doc", {})[](#l1.37) gen.endElement("doc")[](#l1.38) gen.endDocument()[](#l1.39)
self.assertEqual(result.getvalue(), start + "<doc/>")[](#l1.41)
self.assertEqual(result.getvalue(), self.xml("<doc/>"))[](#l1.42)
def test_xmlgen_content(self):
result = StringIO()[](#l1.45)
result = self.ioclass()[](#l1.46) gen = XMLGenerator(result)[](#l1.47)
gen.startDocument() @@ -206,10 +204,10 @@ class XmlgenTest(unittest.TestCase): gen.endElement("doc") gen.endDocument()
self.assertEqual(result.getvalue(), start + "<doc>huhei</doc>")[](#l1.54)
self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))[](#l1.55)
def test_xmlgen_content_empty(self):
result = StringIO()[](#l1.58)
result = self.ioclass()[](#l1.59) gen = XMLGenerator(result, short_empty_elements=True)[](#l1.60)
gen.startDocument() @@ -218,10 +216,10 @@ class XmlgenTest(unittest.TestCase): gen.endElement("doc") gen.endDocument()
self.assertEqual(result.getvalue(), start + "<doc>huhei</doc>")[](#l1.67)
self.assertEqual(result.getvalue(), self.xml("<doc>huhei</doc>"))[](#l1.68)
result = StringIO()[](#l1.71)
result = self.ioclass()[](#l1.72) gen = XMLGenerator(result)[](#l1.73)
gen.startDocument() @@ -230,10 +228,11 @@ class XmlgenTest(unittest.TestCase): gen.endElement("doc") gen.endDocument()
self.assertEqual(result.getvalue(), start + "<?test data?><doc></doc>")[](#l1.80)
self.assertEqual(result.getvalue(),[](#l1.81)
self.xml("<?test data?><doc></doc>"))[](#l1.82)
def test_xmlgen_content_escape(self):
result = StringIO()[](#l1.85)
result = self.ioclass()[](#l1.86) gen = XMLGenerator(result)[](#l1.87)
gen.startDocument() @@ -243,10 +242,10 @@ class XmlgenTest(unittest.TestCase): gen.endDocument() self.assertEqual(result.getvalue(),
start + "<doc><huhei&</doc>")[](#l1.94)
self.xml("<doc><huhei&</doc>"))[](#l1.95)
def test_xmlgen_attr_escape(self):
result = StringIO()[](#l1.98)
result = self.ioclass()[](#l1.99) gen = XMLGenerator(result)[](#l1.100)
gen.startDocument() @@ -260,13 +259,43 @@ class XmlgenTest(unittest.TestCase): gen.endElement("doc") gen.endDocument()
self.assertEqual(result.getvalue(), start +[](#l1.107)
("<doc a='\"'><e a=\"'\"></e>"[](#l1.108)
"<e a=\"'"\"></e>"[](#l1.109)
"<e a=\" 	\"></e></doc>"))[](#l1.110)
self.assertEqual(result.getvalue(), self.xml([](#l1.111)
"<doc a='\"'><e a=\"'\"></e>"[](#l1.112)
"<e a=\"'"\"></e>"[](#l1.113)
"<e a=\" 	\"></e></doc>"))[](#l1.114)
- def test_xmlgen_encoding(self):
encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig',[](#l1.117)
'utf-16', 'utf-16be', 'utf-16le',[](#l1.118)
'utf-32', 'utf-32be', 'utf-32le')[](#l1.119)
for encoding in encodings:[](#l1.120)
result = self.ioclass()[](#l1.121)
gen = XMLGenerator(result, encoding=encoding)[](#l1.122)
gen.startDocument()[](#l1.124)
gen.startElement("doc", {"a": '\u20ac'})[](#l1.125)
gen.characters("\u20ac")[](#l1.126)
gen.endElement("doc")[](#l1.127)
gen.endDocument()[](#l1.128)
self.assertEqual(result.getvalue(),[](#l1.130)
self.xml('<doc a="\u20ac">\u20ac</doc>', encoding=encoding))[](#l1.131)
- def test_xmlgen_unencodable(self):
result = self.ioclass()[](#l1.134)
gen = XMLGenerator(result, encoding='ascii')[](#l1.135)
gen.startDocument()[](#l1.137)
gen.startElement("doc", {"a": '\u20ac'})[](#l1.138)
gen.characters("\u20ac")[](#l1.139)
gen.endElement("doc")[](#l1.140)
gen.endDocument()[](#l1.141)
self.assertEqual(result.getvalue(),[](#l1.143)
self.xml('<doc a="€">€</doc>', encoding='ascii'))[](#l1.144)
def test_xmlgen_ignorable(self):
result = StringIO()[](#l1.147)
result = self.ioclass()[](#l1.148) gen = XMLGenerator(result)[](#l1.149)
gen.startDocument() @@ -275,10 +304,10 @@ class XmlgenTest(unittest.TestCase): gen.endElement("doc") gen.endDocument()
self.assertEqual(result.getvalue(), start + "<doc> </doc>")[](#l1.156)
self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))[](#l1.157)
def test_xmlgen_ignorable_empty(self):
result = StringIO()[](#l1.160)
result = self.ioclass()[](#l1.161) gen = XMLGenerator(result, short_empty_elements=True)[](#l1.162)
gen.startDocument() @@ -287,10 +316,10 @@ class XmlgenTest(unittest.TestCase): gen.endElement("doc") gen.endDocument()
self.assertEqual(result.getvalue(), start + "<doc> </doc>")[](#l1.169)
self.assertEqual(result.getvalue(), self.xml("<doc> </doc>"))[](#l1.170)
result = StringIO()[](#l1.173)
result = self.ioclass()[](#l1.174) gen = XMLGenerator(result)[](#l1.175)
gen.startDocument() @@ -303,12 +332,12 @@ class XmlgenTest(unittest.TestCase): gen.endPrefixMapping("ns1") gen.endDocument()
self.assertEqual(result.getvalue(), start + \[](#l1.182)
('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %[](#l1.183)
self.assertEqual(result.getvalue(), self.xml([](#l1.184)
'<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %[](#l1.185) ns_uri))[](#l1.186)
def test_xmlgen_ns_empty(self):
result = StringIO()[](#l1.189)
result = self.ioclass()[](#l1.190) gen = XMLGenerator(result, short_empty_elements=True)[](#l1.191)
gen.startDocument() @@ -321,12 +350,12 @@ class XmlgenTest(unittest.TestCase): gen.endPrefixMapping("ns1") gen.endDocument()
self.assertEqual(result.getvalue(), start + \[](#l1.198)
('<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %[](#l1.199)
self.assertEqual(result.getvalue(), self.xml([](#l1.200)
'<ns1:doc xmlns:ns1="%s"><udoc/></ns1:doc>' %[](#l1.201) ns_uri))[](#l1.202)
result = StringIO()[](#l1.205)
result = self.ioclass()[](#l1.206) gen = XMLGenerator(result)[](#l1.207)
gen.startDocument() @@ -334,10 +363,10 @@ class XmlgenTest(unittest.TestCase): gen.endElementNS((None, 'a'), 'a') gen.endDocument()
self.assertEqual(result.getvalue(), start+'<a b="c"></a>')[](#l1.214)
self.assertEqual(result.getvalue(), self.xml('<a b="c"></a>'))[](#l1.215)
def test_1463026_1_empty(self):
result = StringIO()[](#l1.218)
result = self.ioclass()[](#l1.219) gen = XMLGenerator(result, short_empty_elements=True)[](#l1.220)
gen.startDocument() @@ -345,10 +374,10 @@ class XmlgenTest(unittest.TestCase): gen.endElementNS((None, 'a'), 'a') gen.endDocument()
self.assertEqual(result.getvalue(), start+'<a b="c"/>')[](#l1.227)
self.assertEqual(result.getvalue(), self.xml('<a b="c"/>'))[](#l1.228)
result = StringIO()[](#l1.231)
result = self.ioclass()[](#l1.232) gen = XMLGenerator(result)[](#l1.233)
gen.startDocument() @@ -358,10 +387,10 @@ class XmlgenTest(unittest.TestCase): gen.endPrefixMapping(None) gen.endDocument()
self.assertEqual(result.getvalue(), start+'<a xmlns="qux"></a>')[](#l1.240)
self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"></a>'))[](#l1.241)
def test_1463026_2_empty(self):
result = StringIO()[](#l1.244)
result = self.ioclass()[](#l1.245) gen = XMLGenerator(result, short_empty_elements=True)[](#l1.246)
gen.startDocument() @@ -371,10 +400,10 @@ class XmlgenTest(unittest.TestCase): gen.endPrefixMapping(None) gen.endDocument()
self.assertEqual(result.getvalue(), start+'<a xmlns="qux"/>')[](#l1.253)
self.assertEqual(result.getvalue(), self.xml('<a xmlns="qux"/>'))[](#l1.254)
result = StringIO()[](#l1.257)
result = self.ioclass()[](#l1.258) gen = XMLGenerator(result)[](#l1.259)
gen.startDocument() @@ -385,10 +414,10 @@ class XmlgenTest(unittest.TestCase): gen.endDocument() self.assertEqual(result.getvalue(),
start+'<my:a xmlns:my="qux" b="c"></my:a>')[](#l1.266)
self.xml('<my:a xmlns:my="qux" b="c"></my:a>'))[](#l1.267)
def test_1463026_3_empty(self):
result = StringIO()[](#l1.270)
result = self.ioclass()[](#l1.271) gen = XMLGenerator(result, short_empty_elements=True)[](#l1.272)
gen.startDocument() @@ -399,7 +428,7 @@ class XmlgenTest(unittest.TestCase): gen.endDocument() self.assertEqual(result.getvalue(),
start+'<my:a xmlns:my="qux" b="c"/>')[](#l1.279)
self.xml('<my:a xmlns:my="qux" b="c"/>'))[](#l1.280)
def test_5027_1(self): # The xml prefix (as in xml:lang below) is reserved and bound by @@ -416,13 +445,13 @@ class XmlgenTest(unittest.TestCase): parser = make_parser() parser.setFeature(feature_namespaces, True)
result = StringIO()[](#l1.288)
result = self.ioclass()[](#l1.289) gen = XMLGenerator(result)[](#l1.290) parser.setContentHandler(gen)[](#l1.291) parser.parse(test_xml)[](#l1.292)
self.assertEqual(result.getvalue(),
start + ([](#l1.295)
self.xml([](#l1.296) '<a:g1 xmlns:a="http://example.com/ns">'[](#l1.297) '<a:g2 xml:lang="en">Hello</a:g2>'[](#l1.298) '</a:g1>'))[](#l1.299)
@@ -435,7 +464,7 @@ class XmlgenTest(unittest.TestCase): # # This test demonstrates the bug by direct manipulation of the # XMLGenerator.
result = StringIO()[](#l1.304)
result = self.ioclass()[](#l1.305) gen = XMLGenerator(result)[](#l1.306)
gen.startDocument() @@ -450,15 +479,57 @@ class XmlgenTest(unittest.TestCase): gen.endDocument() self.assertEqual(result.getvalue(),
start + ([](#l1.313)
self.xml([](#l1.314) '<a:g1 xmlns:a="http://example.com/ns">'[](#l1.315) '<a:g2 xml:lang="en">Hello</a:g2>'[](#l1.316) '</a:g1>'))[](#l1.317)
- def test_no_close_file(self):
result = self.ioclass()[](#l1.320)
def func(out):[](#l1.321)
gen = XMLGenerator(out)[](#l1.322)
gen.startDocument()[](#l1.323)
gen.startElement("doc", {})[](#l1.324)
func(result)[](#l1.325)
self.assertFalse(result.closed)[](#l1.326)
+ +class StringXmlgenTest(XmlgenTest, unittest.TestCase):
- def xml(self, doc, encoding='iso-8859-1'):
return '<?xml version="1.0" encoding="%s"?>\n%s' % (encoding, doc)[](#l1.332)
+ +class BytesXmlgenTest(XmlgenTest, unittest.TestCase):
- def xml(self, doc, encoding='iso-8859-1'):
return ('<?xml version="1.0" encoding="%s"?>\n%s' %[](#l1.340)
(encoding, doc)).encode(encoding, 'xmlcharrefreplace')[](#l1.341)
+ +class WriterXmlgenTest(BytesXmlgenTest):
def seekable(self):[](#l1.348)
return True[](#l1.349)
def tell(self):[](#l1.351)
# return 0 at start and not 0 after start[](#l1.352)
return len(self)[](#l1.353)
def getvalue(self):[](#l1.355)
return b''.join(self)[](#l1.356)
+ + +start = b'\n' + class XMLFilterBaseTest(unittest.TestCase): def test_filter_basic(self):
result = StringIO()[](#l1.364)
result = BytesIO()[](#l1.365) gen = XMLGenerator(result)[](#l1.366) filter = XMLFilterBase()[](#l1.367) filter.setContentHandler(gen)[](#l1.368)
@@ -470,7 +541,7 @@ class XMLFilterBaseTest(unittest.TestCas filter.endElement("doc") filter.endDocument()
self.assertEqual(result.getvalue(), start + "<doc>content </doc>")[](#l1.373)
self.assertEqual(result.getvalue(), start + b"<doc>content </doc>")[](#l1.374)
===========================================================================
# @@ -478,7 +549,7 @@ class XMLFilterBaseTest(unittest.TestCas #
===========================================================================
-with open(TEST_XMLFILE_OUT) as f: +with open(TEST_XMLFILE_OUT, 'rb') as f: xml_test_out = f.read() class ExpatReaderTest(XmlTestBase): @@ -487,11 +558,11 @@ class ExpatReaderTest(XmlTestBase): def test_expat_file(self): parser = create_parser()
result = StringIO()[](#l1.391)
result = BytesIO()[](#l1.392) xmlgen = XMLGenerator(result)[](#l1.393)
parser.setContentHandler(xmlgen)
with open(TEST_XMLFILE) as f:[](#l1.396)
with open(TEST_XMLFILE, 'rb') as f:[](#l1.397) parser.parse(f)[](#l1.398)
self.assertEqual(result.getvalue(), xml_test_out) @@ -503,7 +574,7 @@ class ExpatReaderTest(XmlTestBase): self.addCleanup(support.unlink, fname) parser = create_parser()
result = StringIO()[](#l1.405)
result = BytesIO()[](#l1.406) xmlgen = XMLGenerator(result)[](#l1.407)
parser.setContentHandler(xmlgen) @@ -547,13 +618,13 @@ class ExpatReaderTest(XmlTestBase): def resolveEntity(self, publicId, systemId): inpsrc = InputSource()
inpsrc.setByteStream(StringIO("<entity/>"))[](#l1.414)
inpsrc.setByteStream(BytesIO(b"<entity/>"))[](#l1.415) return inpsrc[](#l1.416)
def test_expat_entityresolver(self): parser = create_parser() parser.setEntityResolver(self.TestEntityResolver())
result = StringIO()[](#l1.421)
result = BytesIO()[](#l1.422) parser.setContentHandler(XMLGenerator(result))[](#l1.423)
parser.feed('<!DOCTYPE doc [\n') @@ -563,7 +634,7 @@ class ExpatReaderTest(XmlTestBase): parser.close() self.assertEqual(result.getvalue(), start +
"<doc><entity></entity></doc>")[](#l1.430)
b"<doc><entity></entity></doc>")[](#l1.431)
# ===== Attributes support @@ -632,7 +703,7 @@ class ExpatReaderTest(XmlTestBase): def test_expat_inpsource_filename(self): parser = create_parser()
result = StringIO()[](#l1.439)
result = BytesIO()[](#l1.440) xmlgen = XMLGenerator(result)[](#l1.441)
parser.setContentHandler(xmlgen) @@ -642,7 +713,7 @@ class ExpatReaderTest(XmlTestBase): def test_expat_inpsource_sysid(self): parser = create_parser()
result = StringIO()[](#l1.448)
result = BytesIO()[](#l1.449) xmlgen = XMLGenerator(result)[](#l1.450)
parser.setContentHandler(xmlgen) @@ -657,7 +728,7 @@ class ExpatReaderTest(XmlTestBase): self.addCleanup(support.unlink, fname) parser = create_parser()
result = StringIO()[](#l1.457)
result = BytesIO()[](#l1.458) xmlgen = XMLGenerator(result)[](#l1.459)
parser.setContentHandler(xmlgen) @@ -667,12 +738,12 @@ class ExpatReaderTest(XmlTestBase): def test_expat_inpsource_stream(self): parser = create_parser()
result = StringIO()[](#l1.466)
result = BytesIO()[](#l1.467) xmlgen = XMLGenerator(result)[](#l1.468)
parser.setContentHandler(xmlgen) inpsrc = InputSource()
with open(TEST_XMLFILE) as f:[](#l1.472)
with open(TEST_XMLFILE, 'rb') as f:[](#l1.473) inpsrc.setByteStream(f)[](#l1.474) parser.parse(inpsrc)[](#l1.475)
@@ -681,7 +752,7 @@ class ExpatReaderTest(XmlTestBase): # ===== IncrementalParser support def test_expat_incremental(self):
result = StringIO()[](#l1.481)
result = BytesIO()[](#l1.482) xmlgen = XMLGenerator(result)[](#l1.483) parser = create_parser()[](#l1.484) parser.setContentHandler(xmlgen)[](#l1.485)
@@ -690,10 +761,10 @@ class ExpatReaderTest(XmlTestBase): parser.feed("") parser.close()
self.assertEqual(result.getvalue(), start + "<doc></doc>")[](#l1.490)
self.assertEqual(result.getvalue(), start + b"<doc></doc>")[](#l1.491)
def test_expat_incremental_reset(self):
result = StringIO()[](#l1.494)
result = BytesIO()[](#l1.495) xmlgen = XMLGenerator(result)[](#l1.496) parser = create_parser()[](#l1.497) parser.setContentHandler(xmlgen)[](#l1.498)
@@ -701,7 +772,7 @@ class ExpatReaderTest(XmlTestBase): parser.feed("") parser.feed("text")
result = StringIO()[](#l1.503)
result = BytesIO()[](#l1.504) xmlgen = XMLGenerator(result)[](#l1.505) parser.setContentHandler(xmlgen)[](#l1.506) parser.reset()[](#l1.507)
@@ -711,12 +782,12 @@ class ExpatReaderTest(XmlTestBase): parser.feed("") parser.close()
self.assertEqual(result.getvalue(), start + "<doc>text</doc>")[](#l1.512)
self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")[](#l1.513)
# ===== Locator support def test_expat_locator_noinfo(self):
result = StringIO()[](#l1.518)
result = BytesIO()[](#l1.519) xmlgen = XMLGenerator(result)[](#l1.520) parser = create_parser()[](#l1.521) parser.setContentHandler(xmlgen)[](#l1.522)
@@ -730,7 +801,7 @@ class ExpatReaderTest(XmlTestBase): self.assertEqual(parser.getLineNumber(), 1) def test_expat_locator_withinfo(self):
result = StringIO()[](#l1.527)
result = BytesIO()[](#l1.528) xmlgen = XMLGenerator(result)[](#l1.529) parser = create_parser()[](#l1.530) parser.setContentHandler(xmlgen)[](#l1.531)
@@ -745,7 +816,7 @@ class ExpatReaderTest(XmlTestBase): shutil.copyfile(TEST_XMLFILE, fname) self.addCleanup(support.unlink, fname)
result = StringIO()[](#l1.536)
result = BytesIO()[](#l1.537) xmlgen = XMLGenerator(result)[](#l1.538) parser = create_parser()[](#l1.539) parser.setContentHandler(xmlgen)[](#l1.540)
@@ -766,7 +837,7 @@ class ErrorReportingTest(unittest.TestCa parser = create_parser() parser.setContentHandler(ContentHandler()) # do nothing source = InputSource()
source.setByteStream(StringIO("<foo bar foobar>")) #ill-formed[](#l1.545)
source.setByteStream(BytesIO(b"<foo bar foobar>")) #ill-formed[](#l1.546) name = "a file name"[](#l1.547) source.setSystemId(name)[](#l1.548) try:[](#l1.549)
@@ -857,7 +928,9 @@ class XmlReaderTest(XmlTestBase): def test_main(): run_unittest(MakeParserTest, SaxutilsTest,
XmlgenTest,[](#l1.554)
StringXmlgenTest,[](#l1.555)
BytesXmlgenTest,[](#l1.556)
WriterXmlgenTest,[](#l1.557) ExpatReaderTest,[](#l1.558) ErrorReportingTest,[](#l1.559) XmlReaderTest)[](#l1.560)
--- a/Lib/xml/sax/saxutils.py +++ b/Lib/xml/sax/saxutils.py @@ -4,18 +4,10 @@ convenience of application and driver wr """ import os, urllib.parse, urllib.request +import io from . import handler from . import xmlreader -# See whether the xmlcharrefreplace error handler is -# supported -try:
- from codecs import xmlcharrefreplace_errors
- _error_handling = "xmlcharrefreplace"
- del xmlcharrefreplace_errors
- def __dict_replace(s, d): """Replace substrings of a string using a dictionary.""" for key, value in d.items(): @@ -76,14 +68,50 @@ def quoteattr(data, entities={}): return data +def _gettextwriter(out, encoding):
wrap a binary writer with TextIOWrapper
- if isinstance(out, io.RawIOBase):
# Keep the original file open when the TextIOWrapper is[](#l2.38)
# destroyed[](#l2.39)
class _wrapper:[](#l2.40)
__class__ = out.__class__[](#l2.41)
def __getattr__(self, name):[](#l2.42)
return getattr(out, name)[](#l2.43)
buffer = _wrapper()[](#l2.44)
buffer.close = lambda: None[](#l2.45)
- else:
# This is to handle passed objects that aren't in the[](#l2.47)
# IOBase hierarchy, but just have a write method[](#l2.48)
buffer = io.BufferedIOBase()[](#l2.49)
buffer.writable = lambda: True[](#l2.50)
buffer.write = out.write[](#l2.51)
try:[](#l2.52)
# TextIOWrapper uses this methods to determine[](#l2.53)
# if BOM (for UTF-16, etc) should be added[](#l2.54)
buffer.seekable = out.seekable[](#l2.55)
buffer.tell = out.tell[](#l2.56)
except AttributeError:[](#l2.57)
pass[](#l2.58)
- return io.TextIOWrapper(buffer, encoding=encoding,
errors='xmlcharrefreplace',[](#l2.60)
newline='\n',[](#l2.61)
write_through=True)[](#l2.62)
+ class XMLGenerator(handler.ContentHandler): def init(self, out=None, encoding="iso-8859-1", short_empty_elements=False):
if out is None:[](#l2.67)
import sys[](#l2.68)
out = sys.stdout[](#l2.69) handler.ContentHandler.__init__(self)[](#l2.70)
self._out = out[](#l2.71)
out = _gettextwriter(out, encoding)[](#l2.72)
self._write = out.write[](#l2.73)
self._flush = out.flush[](#l2.74) self._ns_contexts = [{}] # contains uri -> prefix dicts[](#l2.75) self._current_context = self._ns_contexts[-1][](#l2.76) self._undeclared_ns_maps = [][](#l2.77)
@@ -91,12 +119,6 @@ class XMLGenerator(handler.ContentHandle self._short_empty_elements = short_empty_elements self._pending_start_element = False
- def _write(self, text):
if isinstance(text, str):[](#l2.83)
self._out.write(text)[](#l2.84)
else:[](#l2.85)
self._out.write(text.encode(self._encoding, _error_handling))[](#l2.86)
- def _qname(self, name): """Builds a qualified name from a (ns_url, localname) pair""" if name[0]: @@ -125,6 +147,9 @@ class XMLGenerator(handler.ContentHandle self._write('\n' % self._encoding)
+ def startPrefixMapping(self, prefix, uri): self._ns_contexts.append(self._current_context.copy()) self._current_context[uri] = prefix @@ -157,9 +182,9 @@ class XMLGenerator(handler.ContentHandle for prefix, uri in self._undeclared_ns_maps: if prefix:
self._out.write(' xmlns:%s="%s"' % (prefix, uri))[](#l2.105)
self._write(' xmlns:%s="%s"' % (prefix, uri))[](#l2.106) else:[](#l2.107)
self._out.write(' xmlns="%s"' % uri)[](#l2.108)
self._write(' xmlns="%s"' % uri)[](#l2.109) self._undeclared_ns_maps = [][](#l2.110)
for (name, value) in attrs.items():
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -172,6 +172,8 @@ Core and Builtins Library ------- +- Issue #1470548: XMLGenerator now works with binary output streams. +