Coverage for tarjinja/zip.py: 92%
40 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-05 14:24 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-05 14:24 +0000
1import datetime
2import time
3import zipfile
4from collections.abc import Generator
5from logging import getLogger
7from .iface import Input, Output
9log = getLogger(__name__)
12class ZipInput(Input):
13 def __init__(self, ifn: str, **kwargs):
14 super().__init__(ifn)
15 self.zf = zipfile.ZipFile(ifn)
16 self.encoding = "utf-8"
17 self.ZIP_UNIX_SYSTEM = 3
19 def walk(self) -> Generator[tuple[str, int, float], None, None]:
20 for zinfo in self.zf.infolist():
21 if zinfo.is_dir(): 21 ↛ 22line 21 didn't jump to line 22 because the condition on line 21 was never true
22 continue
23 ts = datetime.datetime(*zinfo.date_time)
24 mode = 0o644
25 if zinfo.create_system == self.ZIP_UNIX_SYSTEM: 25 ↛ 27line 25 didn't jump to line 27 because the condition on line 25 was always true
26 mode = zinfo.external_attr >> 16
27 yield zinfo.filename, mode, ts.timestamp()
29 def readfile(self, fn: str) -> str:
30 return self.zf.read(fn).decode(self.encoding)
33class ZipOutput(Output):
34 def __init__(self, ofn: str, **kwargs):
35 super().__init__(ofn)
36 self.zf = zipfile.ZipFile(ofn, "w")
37 self.encoding = "utf-8"
38 self.compress_type = zipfile.ZIP_DEFLATED
40 def writefile(self, fn: str, content: str, mode: int, ts: float | None = None):
41 zinfo = zipfile.ZipInfo(fn, time.localtime(ts))
42 zinfo.compress_type = self.compress_type
43 zinfo.external_attr = mode << 16
44 if ts is not None: 44 ↛ 54line 44 didn't jump to line 54 because the condition on line 44 was always true
45 tm = time.localtime(ts)
46 zinfo.date_time = (
47 tm.tm_year,
48 tm.tm_mon,
49 tm.tm_mday,
50 tm.tm_hour,
51 tm.tm_min,
52 tm.tm_sec,
53 )
54 self.zf.writestr(zinfo, content)
56 def finish(self):
57 self.zf.close()