-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
gh-101438: Avoid reference cycle in ElementTree.iterparse. #114269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
2119f17
8fabc7c
1ae917e
05baaad
307b375
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -99,6 +99,7 @@ | |
| import collections | ||
| import collections.abc | ||
| import contextlib | ||
| import weakref | ||
|
|
||
| from . import ElementPath | ||
|
|
||
|
|
@@ -1223,13 +1224,14 @@ def iterparse(source, events=None, parser=None): | |
| # parser argument of iterparse is removed, this can be killed. | ||
| pullparser = XMLPullParser(events=events, _parser=parser) | ||
|
|
||
| def iterator(source): | ||
| if not hasattr(source, "read"): | ||
| source = open(source, "rb") | ||
| close_source = True | ||
| else: | ||
| close_source = False | ||
|
|
||
| def iterator(source): | ||
| 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 | ||
|
|
@@ -1239,18 +1241,22 @@ def iterator(source): | |
| pullparser.feed(data) | ||
| root = pullparser._close_and_return_root() | ||
| yield from pullparser.read_events() | ||
| it.root = root | ||
| if it := wr(): | ||
| it.root = root | ||
| finally: | ||
| if close_source: | ||
| source.close() | ||
|
|
||
| class IterParseIterator(collections.abc.Iterator): | ||
| __next__ = iterator(source).__next__ | ||
| it = IterParseIterator() | ||
| it.root = None | ||
| del iterator, IterParseIterator | ||
|
|
||
| next(it) | ||
| def __del__(self): | ||
| if close_source: | ||
| source.close() | ||
|
|
||
| it = IterParseIterator() | ||
| wr = weakref.ref(it) | ||
| del IterParseIterator | ||
|
Comment on lines
+1258
to
+1260
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am curious, why previously both
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also noticed that
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you are right about the I don't think the |
||
| return it | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Avoid reference cycle in ElementTree.iterparse. The iterator returned by | ||
| ``ElementTree.iterparse`` may hold on to a file descriptor. The reference | ||
| cycle prevented prompt clean-up of the file decsriptor if the returned | ||
| iterator was not exhausted. |
Uh oh!
There was an error while loading. Please reload this page.