You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is about zipfile.Path. The doc says it is compatible to pathlib.Path. But it seems that is not for 100% because it doesn't derive from pathlib.PurePath and can treated as Path-like in all situations.
I was redirected from pandas where I opened an issue about the fact that pandas.read_excel() does accept path-like objects but not zipfile.Path. It was explained to me that zipfile.Path doesn't implement __fspath__ and that is the problem.
As explained in pandas-dev/pandas#49906 (comment), I don't think implementing __fspath__ would help your use case. Basically __fspath__ converts the object to a string. There isn't any string that would make sense to be used by any code (for example, the builtin open()) to operate on a file within a zip file.
The question is, from your viewpoint as Python core developers, how could the situation be improved.
As an example csv.reader() can take pathlib.Path and zipfile.Path objects. Works fine without a workaround.
Maybe zipfile.Path is not intended to act exactly like a pathlib.Path object? If this is the case then you should be more clear and direct about that limitations in the documentation.
Or do you see a way that 3rd-party-libs like pandas can improve theire code to also accept zipfile.Path objects without explicit checking for that edge case via isinstance(obj, zipfile.Path)? I don't know why csv.reader() works in that case.
There's some subtlety (probably a little too much subtlety) in the docstring you link to there. The docstring says that zipfile.Path is "pathlib-compatible" (I.e., has a similar interface to pathlib.Path). It doesn't say that ZipFile is "path-like" (and nor do the docs), which is a term that's usually used to mean "an object that conforms to the os.PathLike interface by implementing the __fspath__ method". Somewhat confusingly, a class called zipfile.Path can be "similar to pathlib.Path" without being "path-like".
FWIW, I'm working towards making zipfile.Path a subclass of PurePath (actually, a subclass of a new AbstractPath class that sits between PurePath and Path). It would allow libraries like pandas to work with zip paths like this (pseudocode):
The "pathlib-compatible" bit of the docstring should be changed to "similar to pathlib.Path" IMHO. Saying it's "compatible" is overselling it, particularly as zip paths aren't path-like!
Reacted by Alex Waygood, Christian Buhtz and Alexandre SCHOEPP
Apologies for triple-posting, I've been thinking about this :)
There isn't any string that would make sense to be used by any code (for example, the builtin open()) to operate on a file within a zip file.
Why not the string representation of the archive member path? The os.PathLike interface definition doesn't say what you can do with the resulting string! Indeed, some functions like os.path.join() and os.path.dirname() call os.fspath() and then apply purely lexical operations on the result. pathlib.PurePath too follows this logic - you can happily open(PureWindowsPath('C:/blah')) from a non-Windows system.
IMHO this points to an overloading of what "path-like" means, that can be remedied by making it more granular. We could introduce "pure" analogues of __fspath__(), os.fspath() and os.PathLike - something like __purepath__(), os.purepath(), os.PurePathLike.
My point is just that built-in open() is going to call os.fspath(zip_path). There's nothing that zip_path.__fspath__ could return that will make open() work. So maybe __fspath__ isn't what's needed to solve this problem.
Reacted by Torsten Wörtwein, Christian Buhtz, Barney Gale and Jason R. Coombs
It is probably more accurate to remove the phrase “pathlib-compatible” from the docs or replace it with something like “pathlib.Path-style” or “pathlib.Path-like”.
I really appreciate that you folks invest so much energy in that topic. Please let me throw another question into the pit.
What was the intention about zipfile.Path. When it is not 100% Path-like than this couldn't be the intention to use a zipfile-path as each other path. But this was how I understood it in the first place.
I describe me use-case here; reading data-files (csv, xlsx) from a path object no matter if it is a regular file (pathlib.Path) or an entry in a zip-archive (zipfile.Path). Are there other use cases you had in mind while designing that zipfile.Path?
When designing zipfile.Path, the main use case was for use in abstracting the results from importlib.metadata and importlib.resources when the packages were present in a zipfile. That is, provide access to paths and files of various resources of a package or a distribution's metadata as files in directories. In particular, for importlib.resources, the Traversable protocol was needed. See #88366 for some discussion around Traversable being PathLike and #96870 exploring why Traversable was created. See also python/importlib_resources#232, where @FFY00 and I are discussing the merits and challenges with honoring pathlike objects in importlib.resources.as_file.
Since zipfile.Path is a Traversable, perhaps all you need to do is use as_file?
FWIW, I'm working towards making zipfile.Path a subclass of PurePath (actually, a subclass of a new AbstractPath class that sits between PurePath and Path). It would allow libraries like pandas to work with zip paths like this (pseudocode):
Wait - if you're using path.open(), why does it need to be cast to a pathlib.Path? zipfile.Path supports .open without any manipulation. In other words, Pandas should be adapted to accept a traversable, and then it will accept zipfile.Path objects and pathlib.Path objects.
If you're looking for an interface more like pathlib's (so including stuff like parents, with_suffix(), exists(), write_text(), glob() and walk()) then pathlib.AbstractPath might be a good option if/when it arrives.
Stumbled upon this discussion while dealing with a similar issue. So, maybe I can contribute a different angle on this.
file = importlib.resources.files("my.module").joinpath("some-file") is the recommended way of loading package resources.
Depending on the way the package is distributed, file can be of type pathlib.Path or zipfile.Path, which have non-compatible interfaces, as discussed in this thread. This inconsistency maybe be a stumbling block for those wishing to use importlib.
Activity
ericvsmith commentedon Nov 27, 2022
As explained in pandas-dev/pandas#49906 (comment), I don't think implementing
__fspath__would help your use case. Basically__fspath__converts the object to a string. There isn't any string that would make sense to be used by any code (for example, the builtinopen()) to operate on a file within a zip file.twoertwein commentedon Nov 27, 2022
It might help to hedge the documentation slightly. Maybe something like:
buhtz commentedon Nov 27, 2022
The question is, from your viewpoint as Python core developers, how could the situation be improved.
As an example
csv.reader()can takepathlib.Pathandzipfile.Pathobjects. Works fine without a workaround.Maybe
zipfile.Pathis not intended to act exactly like apathlib.Pathobject? If this is the case then you should be more clear and direct about that limitations in the documentation.Or do you see a way that 3rd-party-libs like
pandascan improve theire code to also acceptzipfile.Pathobjects without explicit checking for that edge case viaisinstance(obj, zipfile.Path)? I don't know whycsv.reader()works in that case.AlexWaygood commentedon Nov 27, 2022
There's some subtlety (probably a little too much subtlety) in the docstring you link to there. The docstring says that
zipfile.Pathis "pathlib-compatible" (I.e., has a similar interface topathlib.Path). It doesn't say thatZipFileis "path-like" (and nor do the docs), which is a term that's usually used to mean "an object that conforms to theos.PathLikeinterface by implementing the__fspath__method". Somewhat confusingly, a class calledzipfile.Pathcan be "similar topathlib.Path" without being "path-like".Cc. @barneygale, for interest :)
barneygale commentedon Nov 27, 2022
FWIW, I'm working towards making
zipfile.Patha subclass ofPurePath(actually, a subclass of a newAbstractPathclass that sits betweenPurePathandPath). It would allow libraries like pandas to work with zip paths like this (pseudocode):Discussion here: https://discuss.python.org/t/make-pathlib-extensible/3428.
barneygale commentedon Nov 27, 2022
The "pathlib-compatible" bit of the docstring should be changed to "similar to pathlib.Path" IMHO. Saying it's "compatible" is overselling it, particularly as zip paths aren't path-like!
barneygale commentedon Nov 27, 2022
Apologies for triple-posting, I've been thinking about this :)
Why not the string representation of the archive member path? The
os.PathLikeinterface definition doesn't say what you can do with the resulting string! Indeed, some functions likeos.path.join()andos.path.dirname()callos.fspath()and then apply purely lexical operations on the result.pathlib.PurePathtoo follows this logic - you can happilyopen(PureWindowsPath('C:/blah'))from a non-Windows system.IMHO this points to an overloading of what "path-like" means, that can be remedied by making it more granular. We could introduce "pure" analogues of
__fspath__(),os.fspath()andos.PathLike- something like__purepath__(),os.purepath(),os.PurePathLike.ericvsmith commentedon Nov 27, 2022
My point is just that built-in
open()is going to callos.fspath(zip_path). There's nothing thatzip_path.__fspath__could return that will makeopen()work. So maybe__fspath__isn't what's needed to solve this problem.fancidev commentedon Nov 29, 2022
It is probably more accurate to remove the phrase “pathlib-compatible” from the docs or replace it with something like “pathlib.Path-style” or “pathlib.Path-like”.
buhtz commentedon Nov 29, 2022
I really appreciate that you folks invest so much energy in that topic. Please let me throw another question into the pit.
What was the intention about
zipfile.Path. When it is not 100% Path-like than this couldn't be the intention to use a zipfile-path as each other path. But this was how I understood it in the first place.I describe me use-case here; reading data-files (csv, xlsx) from a path object no matter if it is a regular file (
pathlib.Path) or an entry in a zip-archive (zipfile.Path). Are there other use cases you had in mind while designing thatzipfile.Path?jaraco commentedon Feb 5, 2023
When designing
zipfile.Path, the main use case was for use in abstracting the results fromimportlib.metadataandimportlib.resourceswhen the packages were present in a zipfile. That is, provide access to paths and files of various resources of a package or a distribution's metadata as files in directories. In particular, forimportlib.resources, the Traversable protocol was needed. See #88366 for some discussion aroundTraversablebeing PathLike and #96870 exploring why Traversable was created. See also python/importlib_resources#232, where @FFY00 and I are discussing the merits and challenges with honoring pathlike objects inimportlib.resources.as_file.Since
zipfile.Pathis aTraversable, perhaps all you need to do is useas_file?Improvements I'd like to see:
zipfile.Path, perhaps by introducingTraversable.zipfile.PathimplementsTraversable.as_fileas a means to readily get a resource on disk.jaraco commentedon Feb 5, 2023
Wait - if you're using
path.open(), why does it need to be cast to apathlib.Path?zipfile.Pathsupports.openwithout any manipulation. In other words, Pandas should be adapted to accept a traversable, and then it will accept zipfile.Path objects and pathlib.Path objects.barneygale commentedon Feb 5, 2023
Bad example on my part. If you're only interested in the interface
Traversableprovides then sure, you can do:If you're looking for an interface more like pathlib's (so including stuff like
parents,with_suffix(),exists(),write_text(),glob()andwalk()) thenpathlib.AbstractPathmight be a good option if/when it arrives.FFY00 commentedon Feb 5, 2023
I opened GH-101589 to fix the documentation.
If the
Traversableinterface is enough, you can just use it, otherwise, as Jason mentioned, you should useas_fileto get apathlib.Pathinstance.And again, please note that path-like objects are a completely different thing 😅
GH-99818: improve the documentation for zipfile.Path and Traversable (G…
Merge branch 'main' into inlinecomp2
Merge branch 'main' into inlinecomp
Merge branch 'main' into lockfreecp
[3.11] pythonGH-99818: improve the documentation for zipfile.Path and…
hauntsaninja commentedon Feb 25, 2023
I opened backport PRs #102266 and #102267 ; once merged I think we can close this
[3.10] pythonGH-99818: improve the documentation for zipfile.Path and…
[3.10] GH-99818: improve the documentation for zipfile.Path and Trave…
[3.11] GH-99818: improve the documentation for zipfile.Path and Trave…
Stannislav commentedon Jul 21, 2023
Stumbled upon this discussion while dealing with a similar issue. So, maybe I can contribute a different angle on this.
file = importlib.resources.files("my.module").joinpath("some-file")is the recommended way of loading package resources.Depending on the way the package is distributed,
filecan be of typepathlib.Pathorzipfile.Path, which have non-compatible interfaces, as discussed in this thread. This inconsistency maybe be a stumbling block for those wishing to useimportlib.pythonGH-99818: improve the documentation for zipfile.Path and Traver…
pythonGH-99818: improve the documentation for zipfile.Path and Traver…