Closes #7334: close source files on ElementTree.parse and iterparse (partial backport of issue #10093 from 3.2).
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
index d89fd3b..19862e2 100644
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -642,17 +642,23 @@
# @exception ParseError If the parser fails to parse the document.
def parse(self, source, parser=None):
+ close_source = False
if not hasattr(source, "read"):
source = open(source, "rb")
- if not parser:
- parser = XMLParser(target=TreeBuilder())
- while 1:
- data = source.read(65536)
- if not data:
- break
- parser.feed(data)
- self._root = parser.close()
- return self._root
+ close_source = True
+ try:
+ if not parser:
+ parser = XMLParser(target=TreeBuilder())
+ while 1:
+ data = source.read(65536)
+ if not data:
+ break
+ parser.feed(data)
+ self._root = parser.close()
+ return self._root
+ finally:
+ if close_source:
+ source.close()
##
# Creates a tree iterator for the root element. The iterator loops
@@ -1189,16 +1195,19 @@
# @return A (event, elem) iterator.
def iterparse(source, events=None, parser=None):
+ close_source = False
if not hasattr(source, "read"):
source = open(source, "rb")
+ close_source = True
if not parser:
parser = XMLParser(target=TreeBuilder())
- return _IterParseIterator(source, events, parser)
+ return _IterParseIterator(source, events, parser, close_source)
class _IterParseIterator(object):
- def __init__(self, source, events, parser):
+ def __init__(self, source, events, parser, close_source=False):
self._file = source
+ self._close_file = close_source
self._events = []
self._index = 0
self.root = self._root = None
@@ -1249,6 +1258,8 @@
except IndexError:
if self._parser is None:
self.root = self._root
+ if self._close_file:
+ self._file.close()
raise StopIteration
# load event buffer
del self._events[:]
diff --git a/Misc/NEWS b/Misc/NEWS
index 9223433..86042f2 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -71,6 +71,8 @@
Library
-------
+- Issue #7334: close source files on ElementTree.parse and iterparse.
+
- Issue #13232: logging: Improved logging of exceptions in the presence of
multiple encodings.
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c
index 4311ba2..c368e14 100644
--- a/Modules/_elementtree.c
+++ b/Modules/_elementtree.c
@@ -2915,19 +2915,25 @@
"class ElementTree(ET.ElementTree):\n" /* public */
" def parse(self, source, parser=None):\n"
+ " close_source = False\n"
" if not hasattr(source, 'read'):\n"
" source = open(source, 'rb')\n"
- " if parser is not None:\n"
- " while 1:\n"
- " data = source.read(65536)\n"
- " if not data:\n"
- " break\n"
- " parser.feed(data)\n"
- " self._root = parser.close()\n"
- " else:\n"
- " parser = cElementTree.XMLParser()\n"
- " self._root = parser._parse(source)\n"
- " return self._root\n"
+ " close_source = False\n"
+ " try:\n"
+ " if parser is not None:\n"
+ " while 1:\n"
+ " data = source.read(65536)\n"
+ " if not data:\n"
+ " break\n"
+ " parser.feed(data)\n"
+ " self._root = parser.close()\n"
+ " else:\n"
+ " parser = cElementTree.XMLParser()\n"
+ " self._root = parser._parse(source)\n"
+ " return self._root\n"
+ " finally:\n"
+ " if close_source:\n"
+ " source.close()\n"
"cElementTree.ElementTree = ElementTree\n"
"def iter(node, tag=None):\n" /* helper */
@@ -2957,8 +2963,10 @@
"class iterparse(object):\n"
" root = None\n"
" def __init__(self, file, events=None):\n"
+ " self._close_file = False\n"
" if not hasattr(file, 'read'):\n"
" file = open(file, 'rb')\n"
+ " self._close_file = True\n"
" self._file = file\n"
" self._events = []\n"
" self._index = 0\n"
@@ -2973,6 +2981,8 @@
" except IndexError:\n"
" if self._parser is None:\n"
" self.root = self._root\n"
+ " if self._close_file:\n"
+ " self._file.close()\n"
" raise StopIteration\n"
" # load event buffer\n"
" del self._events[:]\n"