summaryrefslogtreecommitdiffstats
path: root/Lib/xml/sax
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-05-05 08:04:57 (GMT)
committerGitHub <noreply@github.com>2017-05-05 08:04:57 (GMT)
commit0fe870f3f95ba883b2b06bc0d814bdab8d53df98 (patch)
treefd94539649980663fdcf0e89ac84dfd7d0ebaada /Lib/xml/sax
parent39b73dd5131ce205dcee3b9e24ba0fc28934d79c (diff)
downloadcpython-0fe870f3f95ba883b2b06bc0d814bdab8d53df98.zip
cpython-0fe870f3f95ba883b2b06bc0d814bdab8d53df98.tar.gz
cpython-0fe870f3f95ba883b2b06bc0d814bdab8d53df98.tar.bz2
bpo-30264: ExpatParser closes the source on error (#1451) (#1474)
ExpatParser.parse() of xml.sax.xmlreader now always closes the source: close the file object or the urllib object if source is a string (not an open file-like object). The change fixes a ResourceWarning on parsing error. Add test_parse_close_source() unit test. (cherry picked from commit ef9c0e732fc50aefbdd7c5a80e04e14b31684e66)
Diffstat (limited to 'Lib/xml/sax')
-rw-r--r--Lib/xml/sax/expatreader.py33
1 files changed, 22 insertions, 11 deletions
diff --git a/Lib/xml/sax/expatreader.py b/Lib/xml/sax/expatreader.py
index 98b5ca9..421358f 100644
--- a/Lib/xml/sax/expatreader.py
+++ b/Lib/xml/sax/expatreader.py
@@ -105,9 +105,16 @@ class ExpatParser(xmlreader.IncrementalParser, xmlreader.Locator):
source = saxutils.prepare_input_source(source)
self._source = source
- self.reset()
- self._cont_handler.setDocumentLocator(ExpatLocator(self))
- xmlreader.IncrementalParser.parse(self, source)
+ try:
+ self.reset()
+ self._cont_handler.setDocumentLocator(ExpatLocator(self))
+ xmlreader.IncrementalParser.parse(self, source)
+ except:
+ # bpo-30264: Close the source on error to not leak resources:
+ # xml.sax.parse() doesn't give access to the underlying parser
+ # to the caller
+ self._close_source()
+ raise
def prepareParser(self, source):
if source.getSystemId() is not None:
@@ -213,6 +220,17 @@ class ExpatParser(xmlreader.IncrementalParser, xmlreader.Locator):
# FIXME: when to invoke error()?
self._err_handler.fatalError(exc)
+ def _close_source(self):
+ source = self._source
+ try:
+ file = source.getCharacterStream()
+ if file is not None:
+ file.close()
+ finally:
+ file = source.getByteStream()
+ if file is not None:
+ file.close()
+
def close(self):
if (self._entity_stack or self._parser is None or
isinstance(self._parser, _ClosedParser)):
@@ -232,14 +250,7 @@ class ExpatParser(xmlreader.IncrementalParser, xmlreader.Locator):
parser.ErrorColumnNumber = self._parser.ErrorColumnNumber
parser.ErrorLineNumber = self._parser.ErrorLineNumber
self._parser = parser
- try:
- file = self._source.getCharacterStream()
- if file is not None:
- file.close()
- finally:
- file = self._source.getByteStream()
- if file is not None:
- file.close()
+ self._close_source()
def _reset_cont_handler(self):
self._parser.ProcessingInstructionHandler = \