From 5a92d75549ab5fe9a6b711500b15db79effae4fe Mon Sep 17 00:00:00 2001 From: Jonathan Gossage Date: Sat, 3 Nov 2018 13:41:19 -0600 Subject: [PATCH 1/6] Add support for LexicalHandler class and documentation. --- Doc/library/xml.sax.handler.rst | 63 ++++++++++++++-- Lib/test/test_sax.py | 126 +++++++++++++++++++++++++++++++- Lib/xml/sax/expatreader.py | 2 + Lib/xml/sax/handler.py | 69 +++++++++++++++-- 4 files changed, 244 insertions(+), 16 deletions(-) diff --git a/Doc/library/xml.sax.handler.rst b/Doc/library/xml.sax.handler.rst index ae0877ca90db07..adb86a4d960a22 100644 --- a/Doc/library/xml.sax.handler.rst +++ b/Doc/library/xml.sax.handler.rst @@ -11,12 +11,12 @@ -------------- -The SAX API defines four kinds of handlers: content handlers, DTD handlers, -error handlers, and entity resolvers. Applications normally only need to -implement those interfaces whose events they are interested in; they can -implement the interfaces in a single object or in multiple objects. Handler -implementations should inherit from the base classes provided in the module -:mod:`xml.sax.handler`, so that all methods get default implementations. +The SAX API defines five kinds of handlers: content handlers, DTD handlers, +error handlers, entity resolvers and lexical handlers. Applications normally +only need to implement those interfaces whose events they are interested in; +they can implement the interfaces in a single object or in multiple objects. +Handler implementations should inherit from the base classes provided in the +module:mod:`xml.sax.handler`, so that all methods get default implementations. .. class:: ContentHandler @@ -47,6 +47,12 @@ implementations should inherit from the base classes provided in the module application. The methods of this object control whether errors are immediately converted to exceptions or are handled in some other way. + +.. class:: LexicalHandler + + Interface used by the parser to represent low freqency events which may not + be of interest to many applications. + In addition to these classes, :mod:`xml.sax.handler` provides symbolic constants for the feature and property names. @@ -114,7 +120,7 @@ for the feature and property names. .. data:: property_lexical_handler | value: ``"http://xml.org/sax/properties/lexical-handler"`` - | data type: xml.sax.sax2lib.LexicalHandler (not supported in Python 2) + | data type: xml.sax.handler.LexicalHandler (not supported in Python 2) | description: An optional extension handler for lexical events like comments. | access: read/write @@ -413,3 +419,46 @@ the passed-in exception object. information will continue to be passed to the application. Raising an exception in this method will cause parsing to end. + +.. _lexical-handler-objects: + +LexicalHandler Objects +---------------------- +Optional SAX2 handler for lexical events. + +This handler is used to obtain Lexical information about an XML +document. Lexical information includes information describing the +document encoding used, XML comments embedded in the document as +well as section boundaries for the DTD and for any CDATA sections. +The lexical handlers are used in the same manner as content handlers. + +Set the LexicalHandler of an XMLReader by using the setProperty method +with the property identifier +'http://xml.org/sax/handlers/LexicalHandler'. + + +.. method:: LexicalHandler.xmlDecl(version, encoding, standalone) + Reports an XML declaration or the default values used if no XML + declaration was provided. + +.. method:: LexicalHandler.comment(content) + Reports a comment anywhere in the document (including the DTD and + outside the document element). + +.. method:: LexicalHandler.startDTD(name, public_id, system_id) + Reports the start of the DTD declarations if the document has an + associated DTD. + +.. method:: LexicalHandler.endDTD() + Reports the end of DTD declaration. + +.. method:: LexicalHandler.startCDATA() + Reports the start of a CDATA marked section. + + The contents of the CDATA marked section will be reported through + the characters handler. + + .. method:: LexicalHandler.endCDATA() + Reports the end of a CDATA marked section. + + \ No newline at end of file diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py index 3044960a0ed165..844d12a18bf375 100644 --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -13,7 +13,8 @@ from xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \ XMLFilterBase, prepare_input_source from xml.sax.expatreader import create_parser -from xml.sax.handler import feature_namespaces, feature_external_ges +from xml.sax.handler import feature_namespaces, feature_external_ges, \ + LexicalHandler, ErrorHandler from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl from io import BytesIO, StringIO import codecs @@ -1311,6 +1312,125 @@ def test_nsattrs_wattr(self): self.assertEqual(attrs.getQNameByName((ns_uri, "attr")), "ns:attr") +class LexicalHandlerTest(unittest.TestCase): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.parser = None + + self.specified_version = '1.0' + self.specified_encoding = 'UTF-8' + self.specified_doctype = 'wish' + self.specified_entity_names = ('nbsp', 'source', 'target') + self.specified_comment = ('Comment in a DTD', + 'Really! You think so?') + self.test_data = StringIO() + self.test_data.write('\n'. + format(self.specified_version, + self.specified_encoding)) + self.test_data.write('\n'. + format(self.specified_comment[0])) + self.test_data.write('\n'. + format(self.specified_doctype)) + self.test_data.write('\n') + self.test_data.write('\n') + self.test_data.write('\n') + self.test_data.write('\n') + self.test_data.write('\n') + self.test_data.write('\n'. + format(self.specified_entity_names[0])) + self.test_data.write('\n'. + format(self.specified_entity_names[1])) + self.test_data.write('\n'. + format(self.specified_entity_names[2])) + self.test_data.write(']>\n') + self.test_data.write('<{}>'.format(self.specified_doctype)) + self.test_data.write('Aristotle\n') + self.test_data.write('Alexander\n') + self.test_data.write('Supplication\n') + self.test_data.write('Teach me patience!\n') + self.test_data.write('\n'. + format(self.specified_entity_names[1], + self.specified_entity_names[0], + self.specified_entity_names[2])) + self.test_data.write('\n'.format(self.specified_comment[1])) + self.test_data.write('\n'.format(self.specified_doctype)) + self.test_data.seek(0) + + # Data received from handlers - to be validated + self.version = None + self.encoding = None + self.standalone = None + self.doctype = None + self.publicID = None + self.systemID = None + self.end_of_dtd = False + self.comments = [] + + def test_handlers(self): + class TestLexicalHandler(LexicalHandler): + def __init__(self, test_harness, *args, **kwargs): + super().__init__(*args, **kwargs) + self.test_harness = test_harness + + def xmlDecl(self, version, encoding, standalone): + self.test_harness.version = version + self.test_harness.encoding = encoding + self.test_harness.standalone = standalone + + def startDTD(self, doctype, publicID, systemID): + self.test_harness.doctype = doctype + self.test_harness.publicID = publicID + self.test_harness.systemID = systemID + + def endDTD(self): + self.test_harness.end_of_dtd = True + + def comment(self, text): + self.test_harness.comments.append(text) + + class TestErrorHandler(ErrorHandler): + def __init__(self, test_harness, *args, **kwargs): + super().__init__(*args, **kwargs) + self.test_harness = test_harness + + def fatalError(self, exception): + code = self.test_harness.parser.\ + getProperty('http://xml.org/sax/properties/xml-string') + print('Exception: {} - Code being parsed: {}'. + format(exception.__repr__(), code)) + self.test_harness.test_data.seek(0) + test_data = self.test_harness.test_data.getvalue().split('\n') + i = 0 + print('Test data') + for i in range(len(test_data) - 1): + print('{} - {}'.format(i + 1, test_data[i])) + raise exception + + self.parser = create_parser() + self.parser.setContentHandler(ContentHandler()) + self.parser.setProperty( + 'http://xml.org/sax/properties/lexical-handler', + TestLexicalHandler(self)) + source = InputSource() + source.setCharacterStream(self.test_data) + self.parser.setErrorHandler(TestErrorHandler(self)) + self.parser.parse(source) + self.assertEqual(self.version, self.specified_version) + self.assertEqual(self.encoding, self.specified_encoding) + self.assertIsNotNone(self.standalone) + self.assertEqual(self.doctype, self.specified_doctype) + self.assertIsNone(self.publicID) + self.assertIsNone(self.systemID) + self.assertTrue(self.end_of_dtd) + for i in range(1): + self.assertEqual(len(self.comments), + len(self.specified_comment)) + self.assertEqual(' {} '.format(self.specified_comment[i]), + self.comments[i]) + + def test_main(): run_unittest(MakeParserTest, ParseTest, @@ -1323,7 +1443,9 @@ def test_main(): StreamReaderWriterXmlgenTest, ExpatReaderTest, ErrorReportingTest, - XmlReaderTest) + XmlReaderTest, + LexicalHandlerTest) + if __name__ == "__main__": test_main() diff --git a/Lib/xml/sax/expatreader.py b/Lib/xml/sax/expatreader.py index 5066ffc2fa51f0..853c872223ca88 100644 --- a/Lib/xml/sax/expatreader.py +++ b/Lib/xml/sax/expatreader.py @@ -266,12 +266,14 @@ def _reset_lex_handler_prop(self): parser.EndCdataSectionHandler = None parser.StartDoctypeDeclHandler = None parser.EndDoctypeDeclHandler = None + parser.XmlDeclHandler = None else: parser.CommentHandler = lex.comment parser.StartCdataSectionHandler = lex.startCDATA parser.EndCdataSectionHandler = lex.endCDATA parser.StartDoctypeDeclHandler = self.start_doctype_decl parser.EndDoctypeDeclHandler = lex.endDTD + parser.XmlDeclHandler = lex.xmlDecl def reset(self): if self._namespaces: diff --git a/Lib/xml/sax/handler.py b/Lib/xml/sax/handler.py index 481733d2cbe6e5..9dd5a4f11cf370 100644 --- a/Lib/xml/sax/handler.py +++ b/Lib/xml/sax/handler.py @@ -11,11 +11,12 @@ version = '2.0beta' -#============================================================================ +# ============================================================================ # # HANDLER INTERFACES # -#============================================================================ +# ============================================================================ + # ===== ERRORHANDLER ===== @@ -225,7 +226,7 @@ class EntityResolver: implementing this interface, then register the object with your Parser, the parser will call the method in your object to resolve all external entities. Note that DefaultHandler implements - this interface with the default behaviour.""" + this interface with the default behavior.""" def resolveEntity(self, publicId, systemId): """Resolve the system identifier of an entity and return either @@ -234,11 +235,11 @@ def resolveEntity(self, publicId, systemId): return systemId -#============================================================================ +# ============================================================================ # # CORE FEATURES # -#============================================================================ +# ============================================================================ feature_namespaces = "http://xml.org/sax/features/namespaces" # true: Perform Namespace processing (default). @@ -285,11 +286,11 @@ def resolveEntity(self, publicId, systemId): feature_external_pes] -#============================================================================ +# ============================================================================ # # CORE PROPERTIES # -#============================================================================ +# ============================================================================ property_lexical_handler = "http://xml.org/sax/properties/lexical-handler" # data type: xml.sax.sax2lib.LexicalHandler @@ -340,3 +341,57 @@ def resolveEntity(self, publicId, systemId): property_xml_string, property_encoding, property_interning_dict] + + +class LexicalHandler: + """Optional SAX2 handler for lexical events. + + This handler is used to obtain lexical information about an XML + document, that is, information about how the document was encoded + (as opposed to what it contains, which is reported to the + ContentHandler), such as comments and CDATA marked section + boundaries. + + To set the LexicalHandler of an XMLReader, use the setProperty + method with the property identifier + 'http://xml.org/sax/handlers/LexicalHandler'.""" + + def xmlDecl(self, version, encoding, standalone): + """Reports the contents of the XML declaration. + + version is the XML version of the document. + encoding is the character encoding used to read the document. + standalone indicates that no default attribute values are + declared and no external entities are declared. + """ + + def comment(self, content): + """Reports a comment anywhere in the document (including the + DTD and outside the document element). + + content is a string that holds the contents of the comment.""" + + def startDTD(self, name, public_id, system_id): + """Report the start of the DTD declarations, if the document + has an associated DTD. + + A startEntity event will be reported before declaration events + from the external DTD subset are reported, and this can be + used to infer from which subset DTD declarations derive. + + name is the name of the document element type, public_id the + public identifier of the DTD (or None if none were supplied) + and system_id the system identfier of the external subset (or + None if none were supplied).""" + + def endDTD(self): + "Signals the end of DTD declarations." + + def startCDATA(self): + """Reports the beginning of a CDATA marked section. + + The contents of the CDATA marked section will be reported + through the characters event.""" + + def endCDATA(self): + "Reports the end of a CDATA marked section." From 9a2d3d15192c5cecc030c30daeaf48ff2ac19866 Mon Sep 17 00:00:00 2001 From: Jonathan Gossage Date: Sat, 3 Nov 2018 21:23:32 -0600 Subject: [PATCH 2/6] Add testing CDATA handlers. --- Doc/library/xml.sax.handler.rst | 8 +- Lib/test/test_sax.py | 85 ++++++++++++++----- .../2018-11-03-21-21-32.bpo-35018.z1vnri.rst | 4 + 3 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-11-03-21-21-32.bpo-35018.z1vnri.rst diff --git a/Doc/library/xml.sax.handler.rst b/Doc/library/xml.sax.handler.rst index adb86a4d960a22..5605c3f98b1c2f 100644 --- a/Doc/library/xml.sax.handler.rst +++ b/Doc/library/xml.sax.handler.rst @@ -438,27 +438,33 @@ with the property identifier .. method:: LexicalHandler.xmlDecl(version, encoding, standalone) + Reports an XML declaration or the default values used if no XML declaration was provided. .. method:: LexicalHandler.comment(content) + Reports a comment anywhere in the document (including the DTD and outside the document element). .. method:: LexicalHandler.startDTD(name, public_id, system_id) + Reports the start of the DTD declarations if the document has an associated DTD. .. method:: LexicalHandler.endDTD() + Reports the end of DTD declaration. .. method:: LexicalHandler.startCDATA() + Reports the start of a CDATA marked section. The contents of the CDATA marked section will be reported through the characters handler. - .. method:: LexicalHandler.endCDATA() +.. method:: LexicalHandler.endCDATA() + Reports the end of a CDATA marked section. \ No newline at end of file diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py index 4d050475f34314..868b5be794eaef 100644 --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -5,6 +5,7 @@ SAXException, SAXReaderNotAvailable, SAXParseException import unittest from unittest import mock +from Lib.pickle import FALSE try: make_parser() except SAXReaderNotAvailable: @@ -1418,24 +1419,6 @@ def endDTD(self): def comment(self, text): self.test_harness.comments.append(text) - class TestErrorHandler(ErrorHandler): - def __init__(self, test_harness, *args, **kwargs): - super().__init__(*args, **kwargs) - self.test_harness = test_harness - - def fatalError(self, exception): - code = self.test_harness.parser.\ - getProperty('http://xml.org/sax/properties/xml-string') - print('Exception: {} - Code being parsed: {}'. - format(exception.__repr__(), code)) - self.test_harness.test_data.seek(0) - test_data = self.test_harness.test_data.getvalue().split('\n') - i = 0 - print('Test data') - for i in range(len(test_data) - 1): - print('{} - {}'.format(i + 1, test_data[i])) - raise exception - self.parser = create_parser() self.parser.setContentHandler(ContentHandler()) self.parser.setProperty( @@ -1443,7 +1426,6 @@ def fatalError(self, exception): TestLexicalHandler(self)) source = InputSource() source.setCharacterStream(self.test_data) - self.parser.setErrorHandler(TestErrorHandler(self)) self.parser.parse(source) self.assertEqual(self.version, self.specified_version) self.assertEqual(self.encoding, self.specified_encoding) @@ -1459,6 +1441,68 @@ def fatalError(self, exception): self.comments[i]) +class CDATAHandlerTest(): + """This is implemented as a separate class since CDATA sections in XML + cannot appear within elements defined within a DTD. Hence this test does + not use a DTD.""" + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.parser = None + self.specified_chars = [] + self.specified_chars.append(('Parseable character data', False)) + self.specified_chars.append(('<> &% - assorted other XML junk.', True)) + self.char_index = 0 # Used to index specified results within handlers + self.test_data = StringIO() + self.test_data.write('\n') + self.test_data.write('\n') + self.test_data.write('{}\n'.format(self.specified_chars[0])) + self.test_data.write('\n') + self.test_data.write('\n') + self.test_data.write('{}\n'.format(self.specified_chars[1])) + self.test_data.write('\n') + self.test_data.write('\n') + self.test_data.seek(0) + + # Data received from handlers - to be validated + self.chardata = [] + self.in_cdata = False + + def test_handlers(self): + class TestLexicalHandler(LexicalHandler): + def __init__(self, test_harness, *args, **kwargs): + super().__init__(*args, **kwargs) + self.test_harness = test_harness + + def startCDATA(self): + self.test_harness.in_cdata = True + + def endCDATA(self): + self.test_harness.in_cdata = False + + class TestCharHandler(ContentHandler): + def __init__(self, test_harness, *args, **kwargs): + super().__init__(*args, **kwargs) + self.test_harness = test_harness + + def characters(self, content): + t = self.specified_chars[self.char_index] + self.test_harness.assertEqual(t[0], content) + self.asertEqual(t[1], self.test_harness.in_cdata) + self.test_harness.char_index += 1 + + self.parser = create_parser() + self.parser.setContentHandler(TestCharHandler(self)) + self.parser.setProperty( + 'http://xml.org/sax/properties/lexical-handler', + TestLexicalHandler(self)) + source = InputSource() + source.setCharacterStream(self.test_data) + self.parser.parse(source) + + self.assertFalse(self.in_cdata) + self.assertEqual(self.char_index, 2) + + def test_main(): run_unittest(MakeParserTest, ParseTest, @@ -1472,7 +1516,8 @@ def test_main(): ExpatReaderTest, ErrorReportingTest, XmlReaderTest, - LexicalHandlerTest) + LexicalHandlerTest, + CDATAHandlerTest) if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Library/2018-11-03-21-21-32.bpo-35018.z1vnri.rst b/Misc/NEWS.d/next/Library/2018-11-03-21-21-32.bpo-35018.z1vnri.rst new file mode 100644 index 00000000000000..7c7c9f7eba60b0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-11-03-21-21-32.bpo-35018.z1vnri.rst @@ -0,0 +1,4 @@ +Add the LexicalHandler class that is present in other SAX XML +implementations. The plumbing is already supported by Ptyhon so this simply +adds the poecelain that makes it easy for users of the Python Sax parser to +handle lexical events. From 69ae816dda9ec0a3da376e2550b1583587fdd261 Mon Sep 17 00:00:00 2001 From: Jonathan Gossage Date: Sun, 4 Nov 2018 20:49:45 -0600 Subject: [PATCH 3/6] Fix whitespace problem. --- Doc/library/xml.sax.handler.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/xml.sax.handler.rst b/Doc/library/xml.sax.handler.rst index 5605c3f98b1c2f..def46752ee5559 100644 --- a/Doc/library/xml.sax.handler.rst +++ b/Doc/library/xml.sax.handler.rst @@ -464,7 +464,7 @@ with the property identifier the characters handler. .. method:: LexicalHandler.endCDATA() - + Reports the end of a CDATA marked section. \ No newline at end of file From d7d4d30aed769d0e0fa64abf9140e4f95b9fe370 Mon Sep 17 00:00:00 2001 From: Jonathan Gossage Date: Sun, 4 Nov 2018 21:56:32 -0600 Subject: [PATCH 4/6] Fix CDATAHandlerTest - was not tested because of missing super class in test class definition. --- Lib/test/test_sax.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py index 868b5be794eaef..24230564b8c1e7 100644 --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -1441,7 +1441,7 @@ def comment(self, text): self.comments[i]) -class CDATAHandlerTest(): +class CDATAHandlerTest(unittest.TestCase): """This is implemented as a separate class since CDATA sections in XML cannot appear within elements defined within a DTD. Hence this test does not use a DTD.""" @@ -1455,10 +1455,10 @@ def __init__(self, *args, **kwargs): self.test_data = StringIO() self.test_data.write('\n') self.test_data.write('\n') - self.test_data.write('{}\n'.format(self.specified_chars[0])) + self.test_data.write('{}\n'.format(self.specified_chars[0][0])) self.test_data.write('\n') self.test_data.write('\n') - self.test_data.write('{}\n'.format(self.specified_chars[1])) + self.test_data.write('\n'.format(self.specified_chars[1][0])) self.test_data.write('\n') self.test_data.write('\n') self.test_data.seek(0) @@ -1485,10 +1485,11 @@ def __init__(self, test_harness, *args, **kwargs): self.test_harness = test_harness def characters(self, content): - t = self.specified_chars[self.char_index] - self.test_harness.assertEqual(t[0], content) - self.asertEqual(t[1], self.test_harness.in_cdata) - self.test_harness.char_index += 1 + if content != '\n': + t = self.test_harness.specified_chars[self.test_harness.char_index] + self.test_harness.assertEqual(t[0], content) + self.test_harness.assertEqual(t[1], self.test_harness.in_cdata) + self.test_harness.char_index += 1 self.parser = create_parser() self.parser.setContentHandler(TestCharHandler(self)) From db60cb573a13a9f012fd201ef86de99e62e25c5d Mon Sep 17 00:00:00 2001 From: Jonathan Gossage Date: Sun, 4 Nov 2018 22:45:56 -0600 Subject: [PATCH 5/6] Fix long-standing typo in xml.sax.handler.rst. --- Doc/library/xml.sax.handler.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/xml.sax.handler.rst b/Doc/library/xml.sax.handler.rst index def46752ee5559..c369e877c87b8c 100644 --- a/Doc/library/xml.sax.handler.rst +++ b/Doc/library/xml.sax.handler.rst @@ -16,7 +16,7 @@ error handlers, entity resolvers and lexical handlers. Applications normally only need to implement those interfaces whose events they are interested in; they can implement the interfaces in a single object or in multiple objects. Handler implementations should inherit from the base classes provided in the -module:mod:`xml.sax.handler`, so that all methods get default implementations. +module :mod:`xml.sax.handler`, so that all methods get default implementations. .. class:: ContentHandler From d8dc65ec064f917a6ef0e13f687599077c239247 Mon Sep 17 00:00:00 2001 From: Jonathan Gossage Date: Thu, 8 Nov 2018 11:00:24 -0600 Subject: [PATCH 6/6] Fix areas suggested by review comments. --- Lib/test/test_sax.py | 5 ++--- Lib/xml/sax/handler.py | 22 +++++++++---------- .../2018-11-03-21-21-32.bpo-35018.z1vnri.rst | 4 ++-- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py index 24230564b8c1e7..8f5b7007a81ceb 100644 --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -5,7 +5,6 @@ SAXException, SAXReaderNotAvailable, SAXParseException import unittest from unittest import mock -from Lib.pickle import FALSE try: make_parser() except SAXReaderNotAvailable: @@ -14,8 +13,8 @@ from xml.sax.saxutils import XMLGenerator, escape, unescape, quoteattr, \ XMLFilterBase, prepare_input_source from xml.sax.expatreader import create_parser -from xml.sax.handler import feature_namespaces, feature_external_ges, \ - LexicalHandler, ErrorHandler +from xml.sax.handler import (feature_namespaces, feature_external_ges, + LexicalHandler) from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl from io import BytesIO, StringIO import codecs diff --git a/Lib/xml/sax/handler.py b/Lib/xml/sax/handler.py index 9dd5a4f11cf370..fbfcb871439fb3 100644 --- a/Lib/xml/sax/handler.py +++ b/Lib/xml/sax/handler.py @@ -11,14 +11,14 @@ version = '2.0beta' -# ============================================================================ +#============================================================================ # # HANDLER INTERFACES # -# ============================================================================ +#============================================================================ -# ===== ERRORHANDLER ===== +#===== ERRORHANDLER ===== class ErrorHandler: """Basic interface for SAX error handlers. @@ -204,7 +204,7 @@ def skippedEntity(self, name): properties.""" -# ===== DTDHandler ===== +#===== DTDHandler ===== class DTDHandler: """Handle DTD events. @@ -219,14 +219,14 @@ def unparsedEntityDecl(self, name, publicId, systemId, ndata): "Handle an unparsed entity declaration event." -# ===== ENTITYRESOLVER ===== +#===== ENTITYRESOLVER ===== class EntityResolver: """Basic interface for resolving entities. If you create an object implementing this interface, then register the object with your Parser, the parser will call the method in your object to resolve all external entities. Note that DefaultHandler implements - this interface with the default behavior.""" + this interface with the default behaviour.""" def resolveEntity(self, publicId, systemId): """Resolve the system identifier of an entity and return either @@ -235,11 +235,11 @@ def resolveEntity(self, publicId, systemId): return systemId -# ============================================================================ +#============================================================================ # # CORE FEATURES # -# ============================================================================ +#============================================================================ feature_namespaces = "http://xml.org/sax/features/namespaces" # true: Perform Namespace processing (default). @@ -286,11 +286,11 @@ def resolveEntity(self, publicId, systemId): feature_external_pes] -# ============================================================================ +#============================================================================ # # CORE PROPERTIES # -# ============================================================================ +#============================================================================ property_lexical_handler = "http://xml.org/sax/properties/lexical-handler" # data type: xml.sax.sax2lib.LexicalHandler @@ -394,4 +394,4 @@ def startCDATA(self): through the characters event.""" def endCDATA(self): - "Reports the end of a CDATA marked section." + """Reports the end of a CDATA marked section.""" diff --git a/Misc/NEWS.d/next/Library/2018-11-03-21-21-32.bpo-35018.z1vnri.rst b/Misc/NEWS.d/next/Library/2018-11-03-21-21-32.bpo-35018.z1vnri.rst index 7c7c9f7eba60b0..a3d2be80f2b2d0 100644 --- a/Misc/NEWS.d/next/Library/2018-11-03-21-21-32.bpo-35018.z1vnri.rst +++ b/Misc/NEWS.d/next/Library/2018-11-03-21-21-32.bpo-35018.z1vnri.rst @@ -1,4 +1,4 @@ Add the LexicalHandler class that is present in other SAX XML -implementations. The plumbing is already supported by Ptyhon so this simply -adds the poecelain that makes it easy for users of the Python Sax parser to +implementations. The plumbing is already supported by Python so this simply +adds the porcelain that makes it easy for users of the Python Sax parser to handle lexical events.