diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2022-03-07 02:31:52 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-07 02:31:52 -0800 |
commit | 8acbb93c0763fa53b5959fe05d86ba275c9e8a5b (patch) | |
tree | 8090672c0d9f70c2a9c3193b3fe8f547e5ac86fc | |
parent | ee18df425209cfa4f394b57220177c168fc3a1da (diff) | |
download | cpython-git-8acbb93c0763fa53b5959fe05d86ba275c9e8a5b.tar.gz |
bpo-43292: Fix file leak in `ET.iterparse()` when not exhausted (GH-31696)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
(cherry picked from commit 496c428de3318c9c5770937491b71dc3d3f18a6a)
Co-authored-by: Jacob Walls <jacobtylerwalls@gmail.com>
-rw-r--r-- | Lib/test/test_xml_etree.py | 8 | ||||
-rw-r--r-- | Lib/xml/etree/ElementTree.py | 16 | ||||
-rw-r--r-- | Misc/ACKS | 1 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2022-03-05-09-43-53.bpo-25707.gTlclP.rst | 2 |
4 files changed, 20 insertions, 7 deletions
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index c5292b5e9e..5a34d848b3 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -658,6 +658,14 @@ class ElementTreeTest(unittest.TestCase): 'junk after document element: line 1, column 12') del cm, it + # Not exhausting the iterator still closes the resource (bpo-43292) + with warnings_helper.check_no_resource_warning(self): + it = iterparse(TESTFN) + del it + + with self.assertRaises(FileNotFoundError): + iterparse("nonexistent") + def test_writefile(self): elem = ET.Element("tag") elem.text = "text" diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index e9409fd29a..07be8609b8 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1248,8 +1248,14 @@ def iterparse(source, events=None, parser=None): # Use the internal, undocumented _parser argument for now; When the # parser argument of iterparse is removed, this can be killed. pullparser = XMLPullParser(events=events, _parser=parser) - def iterator(): + + def iterator(source): + close_source = False try: + if not hasattr(source, "read"): + source = open(source, "rb") + close_source = True + yield None while True: yield from pullparser.read_events() # load event buffer @@ -1265,16 +1271,12 @@ def iterparse(source, events=None, parser=None): source.close() class IterParseIterator(collections.abc.Iterator): - __next__ = iterator().__next__ + __next__ = iterator(source).__next__ it = IterParseIterator() it.root = None del iterator, IterParseIterator - close_source = False - if not hasattr(source, "read"): - source = open(source, "rb") - close_source = True - + next(it) return it @@ -1870,6 +1870,7 @@ Wojtek Walczak Charles Waldman Richard Walker Larry Wall +Jacob Walls Kevin Walzer Rodrigo Steinmuller Wanderley Dingyuan Wang diff --git a/Misc/NEWS.d/next/Library/2022-03-05-09-43-53.bpo-25707.gTlclP.rst b/Misc/NEWS.d/next/Library/2022-03-05-09-43-53.bpo-25707.gTlclP.rst new file mode 100644 index 0000000000..a59f0a7657 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-03-05-09-43-53.bpo-25707.gTlclP.rst @@ -0,0 +1,2 @@ +Fixed a file leak in :func:`xml.etree.ElementTree.iterparse` when the +iterator is not exhausted. Patch by Jacob Walls. |