Skip to content

Commit 27ecbd5

Browse files
miss-islingtonjacobtylerwalls
authored andcommitted
[3.9] bpo-43292: Fix file leak in ET.iterparse() when not exhausted (pythonGH-31696) (pythonGH-31720)
Co-authored-by: Serhiy Storchaka <[email protected]> (cherry picked from commit 496c428) Co-authored-by: Jacob Walls <[email protected]>
1 parent b788a2f commit 27ecbd5

File tree

4 files changed

+20
-7
lines changed

4 files changed

+20
-7
lines changed

Lib/test/test_xml_etree.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,14 @@ def test_iterparse(self):
640640
'junk after document element: line 1, column 12')
641641
del cm, it
642642

643+
# Not exhausting the iterator still closes the resource (bpo-43292)
644+
with support.check_no_resource_warning(self):
645+
it = iterparse(TESTFN)
646+
del it
647+
648+
with self.assertRaises(FileNotFoundError):
649+
iterparse("nonexistent")
650+
643651
def test_writefile(self):
644652
elem = ET.Element("tag")
645653
elem.text = "text"

Lib/xml/etree/ElementTree.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,8 +1248,14 @@ def iterparse(source, events=None, parser=None):
12481248
# Use the internal, undocumented _parser argument for now; When the
12491249
# parser argument of iterparse is removed, this can be killed.
12501250
pullparser = XMLPullParser(events=events, _parser=parser)
1251-
def iterator():
1251+
1252+
def iterator(source):
1253+
close_source = False
12521254
try:
1255+
if not hasattr(source, "read"):
1256+
source = open(source, "rb")
1257+
close_source = True
1258+
yield None
12531259
while True:
12541260
yield from pullparser.read_events()
12551261
# load event buffer
@@ -1265,16 +1271,12 @@ def iterator():
12651271
source.close()
12661272

12671273
class IterParseIterator(collections.abc.Iterator):
1268-
__next__ = iterator().__next__
1274+
__next__ = iterator(source).__next__
12691275
it = IterParseIterator()
12701276
it.root = None
12711277
del iterator, IterParseIterator
12721278

1273-
close_source = False
1274-
if not hasattr(source, "read"):
1275-
source = open(source, "rb")
1276-
close_source = True
1277-
1279+
next(it)
12781280
return it
12791281

12801282

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,6 +1836,7 @@ Wojtek Walczak
18361836
Charles Waldman
18371837
Richard Walker
18381838
Larry Wall
1839+
Jacob Walls
18391840
Kevin Walzer
18401841
Rodrigo Steinmuller Wanderley
18411842
Dingyuan Wang
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed a file leak in :func:`xml.etree.ElementTree.iterparse` when the
2+
iterator is not exhausted. Patch by Jacob Walls.

0 commit comments

Comments
 (0)