cpython/Lib/importlib/metadata/zipp.py
2019-03-25 22:23:55 -04:00

110 lines
No EOL
2.6 KiB
Python

"""
>>> root = Path(getfixture('zipfile_abcde'))
>>> a, b = root.iterdir()
>>> a
Path('abcde.zip', 'a.txt')
>>> b
Path('abcde.zip', 'b/')
>>> b.name
'b'
>>> c = b / 'c.txt'
>>> c
Path('abcde.zip', 'b/c.txt')
>>> c.name
'c.txt'
>>> c.read_text()
'content of c'
>>> c.exists()
True
>>> (b / 'missing.txt').exists()
False
>>> str(c)
'abcde.zip/b/c.txt'
"""
from __future__ import division
import io
import sys
import posixpath
import zipfile
import operator
import functools
__metaclass__ = type
class Path:
__repr = '{self.__class__.__name__}({self.root.filename!r}, {self.at!r})'
def __init__(self, root, at=''):
self.root = root if isinstance(root, zipfile.ZipFile) \
else zipfile.ZipFile(self._pathlib_compat(root))
self.at = at
@staticmethod
def _pathlib_compat(path):
"""
For path-like objects, convert to a filename for compatibility
on Python 3.6.1 and earlier.
"""
try:
return path.__fspath__()
except AttributeError:
return str(path)
@property
def open(self):
return functools.partial(self.root.open, self.at)
@property
def name(self):
return posixpath.basename(self.at.rstrip('/'))
def read_text(self, *args, **kwargs):
with self.open() as strm:
return io.TextIOWrapper(strm, *args, **kwargs).read()
def read_bytes(self):
with self.open() as strm:
return strm.read()
def _is_child(self, path):
return posixpath.dirname(path.at.rstrip('/')) == self.at.rstrip('/')
def _next(self, at):
return Path(self.root, at)
def is_dir(self):
return not self.at or self.at.endswith('/')
def is_file(self):
return not self.is_dir()
def exists(self):
return self.at in self.root.namelist()
def iterdir(self):
if not self.is_dir():
raise ValueError("Can't listdir a file")
names = map(operator.attrgetter('filename'), self.root.infolist())
subs = map(self._next, names)
return filter(self._is_child, subs)
def __str__(self):
return posixpath.join(self.root.filename, self.at)
def __repr__(self):
return self.__repr.format(self=self)
def __truediv__(self, add):
add = self._pathlib_compat(add)
next = posixpath.join(self.at, add)
next_dir = posixpath.join(self.at, add, '')
names = self.root.namelist()
return self._next(
next_dir if next not in names and next_dir in names else next
)
if sys.version_info < (3,):
__div__ = __truediv__