wfexs_backend.utils.zipfile_path#

Module Contents#

Classes#

CompleteDirs

A ZipFile subclass that ensures that implied directories are always included in the namelist.

FastLookup

ZipFile subclass to ensure implicit dirs exist and are resolved rapidly.

ZipfilePath

A pathlib-compatible interface for zip files.

Functions#

_parents

Given a path with elements separated by posixpath.sep, generate all parents of that path.

_ancestry

Given a path with elements separated by posixpath.sep, generate all elements of that path

_difference

Return items in minuend not in subtrahend, retaining order with O(1) lookup.

path_relative_to

Data#

_dedupe

Deduplicate an iterable in original order

API#

wfexs_backend.utils.zipfile_path._parents(path: str) Iterator[str]#

Given a path with elements separated by posixpath.sep, generate all parents of that path.

>>> list(_parents('b/d'))
['b']
>>> list(_parents('/b/d/'))
['/b']
>>> list(_parents('b/d/f/'))
['b/d', 'b']
>>> list(_parents('b'))
[]
>>> list(_parents(''))
[]
wfexs_backend.utils.zipfile_path._ancestry(path: str) Iterator[str]#

Given a path with elements separated by posixpath.sep, generate all elements of that path

>>> list(_ancestry('b/d'))
['b/d', 'b']
>>> list(_ancestry('/b/d/'))
['/b/d', '/b']
>>> list(_ancestry('b/d/f/'))
['b/d/f', 'b/d', 'b']
>>> list(_ancestry('b'))
['b']
>>> list(_ancestry(''))
[]
wfexs_backend.utils.zipfile_path._dedupe = None#

Deduplicate an iterable in original order

wfexs_backend.utils.zipfile_path._difference(minuend: Iterable[str], subtrahend: Iterable[str]) Iterator[str]#

Return items in minuend not in subtrahend, retaining order with O(1) lookup.

class wfexs_backend.utils.zipfile_path.CompleteDirs(file, mode='r', compression=ZIP_STORED, allowZip64=True, compresslevel=None, *, strict_timestamps=True, metadata_encoding=None)#

Bases: zipfile.ZipFile

A ZipFile subclass that ensures that implied directories are always included in the namelist.

Initialization

Open the ZIP file with mode read ‘r’, write ‘w’, exclusive create ‘x’, or append ‘a’.

static _implied_dirs(names: Sequence[str]) Mapping[str, str | None]#
namelist() List[str]#
_name_set() Set[str]#
resolve_dir(name: str) str#

If the name represents a directory, return that name as a directory (with the trailing slash).

getinfo(name: str) zipfile.ZipInfo#

Supplement getinfo for implied dirs.

classmethod make(source: CompleteDirs | zipfile.ZipFile | str | os.PathLike[str]) wfexs_backend.utils.zipfile_path.CompleteDirs#

Given a source (filename or zipfile), return an appropriate CompleteDirs subclass.

class wfexs_backend.utils.zipfile_path.FastLookup(file, mode='r', compression=ZIP_STORED, allowZip64=True, compresslevel=None, *, strict_timestamps=True, metadata_encoding=None)#

Bases: wfexs_backend.utils.zipfile_path.CompleteDirs

ZipFile subclass to ensure implicit dirs exist and are resolved rapidly.

Initialization

Open the ZIP file with mode read ‘r’, write ‘w’, exclusive create ‘x’, or append ‘a’.

namelist() List[str]#
_name_set() Set[str]#
wfexs_backend.utils.zipfile_path.path_relative_to(path: pathlib.Path, other: pathlib.Path, *extra: str | os.PathLike[str]) str#
class wfexs_backend.utils.zipfile_path.ZipfilePath(root: str | CompleteDirs | os.PathLike[str] | zipfile.ZipFile, at: str = '')#

Bases: pathlib.Path

A pathlib-compatible interface for zip files.

Consider a zip file with this structure:

.
├── a.txt
└── b
    ├── c.txt
    └── d
        └── e.txt
>>> data = io.BytesIO()
>>> zf = zipfile.ZipFile(data, 'w')
>>> 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 = 'mem/abcde.zip'

Path accepts the zipfile object itself or a filename

>>> root = Path(zf)

From there, several path operations are available.

Directory iteration (including the zip file itself):

>>> a, b = root.iterdir()
>>> a
Path('mem/abcde.zip', 'a.txt')
>>> b
Path('mem/abcde.zip', 'b/')

name property:

>>> b.name
'b'

join with divide operator:

>>> c = b / 'c.txt'
>>> c
Path('mem/abcde.zip', 'b/c.txt')
>>> c.name
'c.txt'

Read text:

>>> c.read_text()
'content of c'

existence:

>>> c.exists()
True
>>> (b / 'missing.txt').exists()
False

Coercion to string:

>>> 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'

Initialization

Construct a Path from a ZipFile or filename.

Note: When the source is an existing ZipFile object, its type (__class__) will be mutated to a specialized type. If the caller wishes to retain the original type, the caller should either create a separate ZipFile object or pass a filename.

__repr = '{self.__class__.__name__}({self._root.filename!r}, {self._at!r})'#
__new__(*args: Any, **kwargs: Any) wfexs_backend.utils.zipfile_path.ZipfilePath#
open(mode: str = 'r', pwd: bytes | None = None, buffering: int = -1, encoding: str | None = None, newline: str | None = None) IO[str] | IO[bytes]#

Open this entry as text or binary following the semantics of pathlib.Path.open() by passing arguments through to io.TextIOWrapper().

property name: str#
property filename: pathlib.Path#
read_text(*args: Any, **kwargs: Any) str#
read_bytes() bytes#
_is_child(path: wfexs_backend.utils.zipfile_path.ZipfilePath) bool#
_next(at: str) wfexs_backend.utils.zipfile_path.ZipfilePath#
is_dir(*, follow_symlinks: bool = False) bool#
is_file(*, follow_symlinks: bool = False) bool#
exists(*, follow_symlinks: bool = False) bool#
iterdir() Generator[ZipfilePath, None, None]#
__str__() str#
__repr__() str#
joinpath(*other: str | os.PathLike[str]) wfexs_backend.utils.zipfile_path.ZipfilePath#
__truediv__ = None#
property parent: wfexs_backend.utils.zipfile_path.ZipfilePath#
property zip_root: zipfile.ZipFile#
relative_to(other: str | os.PathLike[str], *_deprecated: str | os.PathLike[str], walk_up: bool = False) pathlib.Path#
resolve(strict: bool = False) wfexs_backend.utils.zipfile_path.ZipfilePath#
_extract_member(member: zipfile.ZipInfo | str, targetpath: str | os.PathLike[str], pwd: bytes | None = None, preserve_attrs: bool = True, aggresive_attrs: bool = False) str#

Method partially borrowed from python 3.12

copy_to(dest: pathlib.Path, preserve_attrs: bool = True, aggresive_attrs: bool = False) None#
with_name(name: str | os.PathLike[str]) wfexs_backend.utils.zipfile_path.ZipfilePath#