Repository navigation
ZipFile.extractall fails if zipfile.Path object is created based on the ZipFile object #101566
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Feb 4, 2023 - addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
on Feb 4, 2023 @serhiy-storchaka, @Yhg1s, @gpshead as zipfile experts.
- added3.11only security fixesonly security fixes3.10 (EOL)end of lifeend of life3.12only security fixesonly security fixes
on Feb 4, 2023 This issue occurs because of the optimizations / tradeoffs made in attempting to extend an open file object. Here's what's going on:
zipfile.Pathneeds to be able to infer directories when there are none in the zipfile (i.e. the presence ofdata/test.txtimplies the presence ofdata/even though it's not explicitly a member of the zipfile).- To accomplish this goal, the CompleteDirs wraps the original zipfile.
- Due to challenges with the lifecycle of a zipfile (which may have been created in memory or exist on disk as an open file), wrapping a Zipfile in a Path actually mutates its class, giving the original Zipfile object the CompleteDirs behavior.
- In
extractall, it's assumed that every item in thenamelistis also a member, but withCompleteDirs, that's no longer true.
This report is the first I've seen that this (admittedly impure) behavior has caused any trouble.
I agree that at the very least, it's worthwhile documenting these limitations.
I did try to track down the origins of the change that led to this regression in behavior. I took a brief look at the readme for zipp, the forward/backport, and it doesn't mention any changes for Python 3.10 (now updated to reflect new findings).
Okay. I see the change occurred in ebbe803, bpo-40564/#84744. That bug pretty thoroughly describes the thought process and the tradeoffs considered.
I can think of a few ways to address the issue.
- document it as unsupported behavior
- document it as unsupported behavior, but provide a mechanism to restore the original object
- add support for zipfile.Zipfile to be lenient to dirs not present
- add support to CompleteDirs to return a virtual member info for an implied dir
- CompleteDirs to override extractall to bypass the issue
I'm leaning toward (3) or (4). (4) has an advantage over all of the other options in that, if it can be implemented, it provides better compatibility for more use cases (not just ZipFile.extractall).
In jaraco/zipp#90, I've drafted a patch implementing option 4, to be released as zipp 3.12.1. I'd like to get some feedback on the concept before porting that to cpython.
Reacted by Gregory P. Smith2 remaining items
- added 3 commits that reference this issue
on Feb 20, 2023 This issue was closed back in Feb.
Bug report
The following code works fine with Python 3.8 and 3.9 but starts failing with Python 3.10.
It seems that
zipfile.Pathcreates an entry in thezipfile.ZipFileobject that does not exist in the underlying file and therefore makeszipfile.ZipFile.extractallfail.Your environment
Working version:
Failing versions:
3.10.9:
and 3.11.0
If this is the expected new behavior I think the documentation for 3.10 should mention this breaking change and the
zipfile.Pathdocumentation might need an entry about this problem.The
zipfile.Pathobject is used in the original code to check if the "data/" directory exists in the zip file.Linked PRs