summaryrefslogtreecommitdiffstats
path: root/Lib/zipfile.py
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2020-10-25 18:45:05 (GMT)
committerGitHub <noreply@github.com>2020-10-25 18:45:05 (GMT)
commitd1a0a960ee493262fb95a0f5b795b5b6d75cecb8 (patch)
tree3c8081133e01ea92dc8e3bdb586757272e018824 /Lib/zipfile.py
parent14cdc215aa952d280c18626005d3aff967901d92 (diff)
downloadcpython-d1a0a960ee493262fb95a0f5b795b5b6d75cecb8.zip
cpython-d1a0a960ee493262fb95a0f5b795b5b6d75cecb8.tar.gz
cpython-d1a0a960ee493262fb95a0f5b795b5b6d75cecb8.tar.bz2
bpo-42043: Add support for zipfile.Path subclasses (#22716)
* bpo-42043: Add support for zipfile.Path inheritance as introduced in zipp 3.2.0. * Add blurb.
Diffstat (limited to 'Lib/zipfile.py')
-rw-r--r--Lib/zipfile.py39
1 files changed, 30 insertions, 9 deletions
diff --git a/Lib/zipfile.py b/Lib/zipfile.py
index da3e40e..e1a50a3 100644
--- a/Lib/zipfile.py
+++ b/Lib/zipfile.py
@@ -16,6 +16,7 @@ import sys
import threading
import time
import contextlib
+import pathlib
try:
import zlib # We may need its compression method
@@ -2210,6 +2211,7 @@ class FastLookup(CompleteDirs):
ZipFile subclass to ensure implicit
dirs exist and are resolved rapidly.
"""
+
def namelist(self):
with contextlib.suppress(AttributeError):
return self.__names
@@ -2241,7 +2243,7 @@ class Path:
>>> zf.writestr('a.txt', 'content of a')
>>> zf.writestr('b/c.txt', 'content of c')
>>> zf.writestr('b/d/e.txt', 'content of e')
- >>> zf.filename = 'abcde.zip'
+ >>> zf.filename = 'mem/abcde.zip'
Path accepts the zipfile object itself or a filename
@@ -2253,9 +2255,9 @@ class Path:
>>> a, b = root.iterdir()
>>> a
- Path('abcde.zip', 'a.txt')
+ Path('mem/abcde.zip', 'a.txt')
>>> b
- Path('abcde.zip', 'b/')
+ Path('mem/abcde.zip', 'b/')
name property:
@@ -2266,7 +2268,7 @@ class Path:
>>> c = b / 'c.txt'
>>> c
- Path('abcde.zip', 'b/c.txt')
+ Path('mem/abcde.zip', 'b/c.txt')
>>> c.name
'c.txt'
@@ -2284,8 +2286,21 @@ class Path:
Coercion to string:
- >>> str(c)
- 'abcde.zip/b/c.txt'
+ >>> import os
+ >>> str(c).replace(os.sep, posixpath.sep)
+ 'mem/abcde.zip/b/c.txt'
+
+ At the root, ``name``, ``filename``, and ``parent``
+ resolve to the zipfile. Note these attributes are not
+ valid and will raise a ``ValueError`` if the zipfile
+ has no filename.
+
+ >>> root.name
+ 'abcde.zip'
+ >>> str(root.filename).replace(os.sep, posixpath.sep)
+ 'mem/abcde.zip'
+ >>> str(root.parent)
+ 'mem'
"""
__repr = "{self.__class__.__name__}({self.root.filename!r}, {self.at!r})"
@@ -2323,7 +2338,11 @@ class Path:
@property
def name(self):
- return posixpath.basename(self.at.rstrip("/"))
+ return pathlib.Path(self.at).name or self.filename.name
+
+ @property
+ def filename(self):
+ return pathlib.Path(self.root.filename).joinpath(self.at)
def read_text(self, *args, **kwargs):
with self.open('r', *args, **kwargs) as strm:
@@ -2337,13 +2356,13 @@ class Path:
return posixpath.dirname(path.at.rstrip("/")) == self.at.rstrip("/")
def _next(self, at):
- return Path(self.root, at)
+ return self.__class__(self.root, at)
def is_dir(self):
return not self.at or self.at.endswith("/")
def is_file(self):
- return not self.is_dir()
+ return self.exists() and not self.is_dir()
def exists(self):
return self.at in self.root._name_set()
@@ -2368,6 +2387,8 @@ class Path:
@property
def parent(self):
+ if not self.at:
+ return self.filename.parent
parent_at = posixpath.dirname(self.at.rstrip('/'))
if parent_at:
parent_at += '/'