]>
jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/setuptools/_vendor/zipp.py
9 if sys
.version_info
< (3, 7):
10 from collections
import OrderedDict
20 Given a path with elements separated by
21 posixpath.sep, generate all parents of that path.
23 >>> list(_parents('b/d'))
25 >>> list(_parents('/b/d/'))
27 >>> list(_parents('b/d/f/'))
29 >>> list(_parents('b'))
31 >>> list(_parents(''))
34 return itertools
.islice(_ancestry(path
), 1, None)
39 Given a path with elements separated by
40 posixpath.sep, generate all elements of that path
42 >>> list(_ancestry('b/d'))
44 >>> list(_ancestry('/b/d/'))
46 >>> list(_ancestry('b/d/f/'))
48 >>> list(_ancestry('b'))
50 >>> list(_ancestry(''))
53 path
= path
.rstrip(posixpath
.sep
)
54 while path
and path
!= posixpath
.sep
:
56 path
, tail
= posixpath
.split(path
)
59 _dedupe
= OrderedDict
.fromkeys
60 """Deduplicate an iterable in original order"""
63 def _difference(minuend
, subtrahend
):
65 Return items in minuend not in subtrahend, retaining order
68 return itertools
.filterfalse(set(subtrahend
).__contains
__, minuend
)
71 class CompleteDirs(zipfile
.ZipFile
):
73 A ZipFile subclass that ensures that implied directories
74 are always included in the namelist.
78 def _implied_dirs(names
):
79 parents
= itertools
.chain
.from_iterable(map(_parents
, names
))
80 as_dirs
= (p
+ posixpath
.sep
for p
in parents
)
81 return _dedupe(_difference(as_dirs
, names
))
84 names
= super(CompleteDirs
, self
).namelist()
85 return names
+ list(self
._implied
_dirs
(names
))
88 return set(self
.namelist())
90 def resolve_dir(self
, name
):
92 If the name represents a directory, return that name
93 as a directory (with the trailing slash).
95 names
= self
._name
_set
()
97 dir_match
= name
not in names
and dirname
in names
98 return dirname
if dir_match
else name
101 def make(cls
, source
):
103 Given a source (filename or zipfile), return an
104 appropriate CompleteDirs subclass.
106 if isinstance(source
, CompleteDirs
):
109 if not isinstance(source
, zipfile
.ZipFile
):
110 return cls(_pathlib_compat(source
))
112 # Only allow for FastLookup when supplied zipfile is read-only
113 if 'r' not in source
.mode
:
116 source
.__class
__ = cls
120 class FastLookup(CompleteDirs
):
122 ZipFile subclass to ensure implicit
123 dirs exist and are resolved rapidly.
127 with contextlib
.suppress(AttributeError):
129 self
.__names
= super(FastLookup
, self
).namelist()
133 with contextlib
.suppress(AttributeError):
135 self
.__lookup
= super(FastLookup
, self
)._name
_set
()
139 def _pathlib_compat(path
):
141 For path-like objects, convert to a filename for compatibility
142 on Python 3.6.1 and earlier.
145 return path
.__fspath
__()
146 except AttributeError:
152 A pathlib-compatible interface for zip files.
154 Consider a zip file with this structure::
163 >>> data = io.BytesIO()
164 >>> zf = zipfile.ZipFile(data, 'w')
165 >>> zf.writestr('a.txt', 'content of a')
166 >>> zf.writestr('b/c.txt', 'content of c')
167 >>> zf.writestr('b/d/e.txt', 'content of e')
168 >>> zf.filename = 'mem/abcde.zip'
170 Path accepts the zipfile object itself or a filename
174 From there, several path operations are available.
176 Directory iteration (including the zip file itself):
178 >>> a, b = root.iterdir()
180 Path('mem/abcde.zip', 'a.txt')
182 Path('mem/abcde.zip', 'b/')
189 join with divide operator:
193 Path('mem/abcde.zip', 'b/c.txt')
206 >>> (b / 'missing.txt').exists()
212 >>> str(c).replace(os.sep, posixpath.sep)
213 'mem/abcde.zip/b/c.txt'
215 At the root, ``name``, ``filename``, and ``parent``
216 resolve to the zipfile. Note these attributes are not
217 valid and will raise a ``ValueError`` if the zipfile
222 >>> str(root.filename).replace(os.sep, posixpath.sep)
228 __repr
= "{self.__class__.__name__}({self.root.filename!r}, {self.at!r})"
230 def __init__(self
, root
, at
=""):
232 Construct a Path from a ZipFile or filename.
234 Note: When the source is an existing ZipFile object,
235 its type (__class__) will be mutated to a
236 specialized type. If the caller wishes to retain the
237 original type, the caller should either create a
238 separate ZipFile object or pass a filename.
240 self
.root
= FastLookup
.make(root
)
243 def open(self
, mode
='r', *args
, pwd
=None, **kwargs
):
245 Open this entry as text or binary following the semantics
246 of ``pathlib.Path.open()`` by passing arguments through
247 to io.TextIOWrapper().
250 raise IsADirectoryError(self
)
252 if not self
.exists() and zip_mode
== 'r':
253 raise FileNotFoundError(self
)
254 stream
= self
.root
.open(self
.at
, zip_mode
, pwd
=pwd
)
257 raise ValueError("encoding args invalid for binary operation")
259 return io
.TextIOWrapper(stream
, *args
, **kwargs
)
263 return pathlib
.Path(self
.at
).name
or self
.filename
.name
267 return pathlib
.Path(self
.at
).suffix
or self
.filename
.suffix
271 return pathlib
.Path(self
.at
).suffixes
or self
.filename
.suffixes
275 return pathlib
.Path(self
.at
).stem
or self
.filename
.stem
279 return pathlib
.Path(self
.root
.filename
).joinpath(self
.at
)
281 def read_text(self
, *args
, **kwargs
):
282 with self
.open('r', *args
, **kwargs
) as strm
:
285 def read_bytes(self
):
286 with self
.open('rb') as strm
:
289 def _is_child(self
, path
):
290 return posixpath
.dirname(path
.at
.rstrip("/")) == self
.at
.rstrip("/")
293 return self
.__class
__(self
.root
, at
)
296 return not self
.at
or self
.at
.endswith("/")
299 return self
.exists() and not self
.is_dir()
302 return self
.at
in self
.root
._name
_set
()
305 if not self
.is_dir():
306 raise ValueError("Can't listdir a file")
307 subs
= map(self
._next
, self
.root
.namelist())
308 return filter(self
._is
_child
, subs
)
311 return posixpath
.join(self
.root
.filename
, self
.at
)
314 return self
.__repr
.format(self
=self
)
316 def joinpath(self
, *other
):
317 next
= posixpath
.join(self
.at
, *map(_pathlib_compat
, other
))
318 return self
._next
(self
.root
.resolve_dir(next
))
320 __truediv__
= joinpath
325 return self
.filename
.parent
326 parent_at
= posixpath
.dirname(self
.at
.rstrip('/'))
329 return self
._next
(parent_at
)