core: add ZipPath encapsulating compressed zip files

this way you don't have to unpack it first and can work as if it's a 'virtual' directory

related: https://github.com/karlicoss/HPI/issues/20
This commit is contained in:
Dima Gerasimov 2022-04-14 08:31:17 +01:00
parent 444ec1c450
commit 95cd3b9289
3 changed files with 145 additions and 50 deletions

View file

@ -1,6 +1,8 @@
"""
Various helpers for compression
"""
from __future__ import annotations
import pathlib
from pathlib import Path
from typing import Union, IO
@ -107,9 +109,44 @@ open = kopen # TODO deprecate
# meh
# TODO ideally switch to ZipPath or smth similar?
# nothing else supports subpath properly anyway
def kexists(path: PathIsh, subpath: str) -> bool:
try:
kopen(path, subpath)
return True
except Exception:
return False
import zipfile
class ZipPath(zipfile.Path):
def absolute(self) -> ZipPath:
return ZipPath(Path(self.root.filename).absolute(), self.at)
def exists(self) -> bool:
if self.at == '':
# special case, the base class returns False in this case for some reason
return Path(self.root.filename).exists()
return super().exists()
def rglob(self, glob: str) -> Sequence[ZipPath]:
# note: not 100% sure about the correctness, but seem fine?
# Path.match() matches from the right, so need to
rpaths = [p for p in self.root.namelist() if p.startswith(self.at)]
rpaths = [p for p in rpaths if Path(p).match(glob)]
return [ZipPath(self.root, p) for p in rpaths]
def relative_to(self, other: ZipPath) -> Path:
assert self.root == other.root, (self.root, other.root)
return Path(self.at).relative_to(Path(other.at))
@property
def __class__(self):
return Path
def __eq__(self, other) -> bool:
# hmm, super class doesn't seem to treat as equals unless they are the same object
if not isinstance(other, ZipPath):
return False
return self.root.filename == other.root.filename and self.at == other.at