PK!docci/__init__.pyPK!WLdocci/config.py""" Constants required for lib """ import os BASE_DIR = os.path.dirname(os.path.dirname(__file__)) TEST_DATA_DIR = os.path.join(BASE_DIR, "test_data") PK! docci/file.py""" Utils for file manipulations like extracting file name from path """ import base64 import io import os from dataclasses import dataclass, field from typing import Optional def extract_file_name(path: str) -> str: """ >>> extract_file_name("tests/test_api.py") 'test_api.py' """ return os.path.basename(path) @dataclass class FileAttachment: """ Class for file abstraction """ name: str content: bytes = field(repr=False) @property def name_without_extension(self) -> str: """ >>> FileAttachment("sample.py", b"").name_without_extension 'sample' """ return self.name.rsplit(".", 1)[0] @property def extension(self) -> str: """ >>> FileAttachment("sample.py", b"").extension 'py' """ return self.name.rsplit(".", 1)[-1] @property def content_stream(self) -> io.BytesIO: """Return file attachment content as bytes stream""" return io.BytesIO(self.content) @property def content_base64(self) -> bytes: """Convert content to base64 binary string""" return base64.b64encode(self.content) def save(self, path: Optional[str] = None) -> None: """ Save file to disk """ path = path or self.name with open(path, "wb") as f: f.write(self.content) @classmethod def load(cls, path: str) -> 'FileAttachment': """ Load file from disk """ assert os.path.exists(path), f'No such file: "{path}"' with open(path, "rb") as f: return FileAttachment(extract_file_name(path), f.read()) @classmethod def load_from_base64(cls, base64_str: str, name: str) -> 'FileAttachment': """ Load file from base64 string """ return FileAttachment(name, base64.b64decode(base64_str)) PK!lA## docci/zip.py""" Utils for working with zip archives """ import io from typing import Union, Iterable, Sequence from zipfile import ZipFile from docci.file import FileAttachment def list_zip_files( zip_file: Union[str, io.BytesIO, ZipFile, FileAttachment] ) -> Sequence[FileAttachment]: """ List zip archive files """ def zip_file_generator(zip_file: ZipFile) -> Iterable[FileAttachment]: for filename in zip_file.namelist(): content = zip_file.read(filename) yield FileAttachment(filename, content) if isinstance(zip_file, FileAttachment): zip_file = ZipFile(zip_file.content_stream) if isinstance(zip_file, (str, io.BytesIO)): zip_file = ZipFile(zip_file) return list(zip_file_generator(zip_file)) PK!HڽTUdocci-0.1.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!H]Wdocci-0.1.0.dist-info/METADATAPN0+,qŦH,@T@EVY@/q杝 3ԐA1&r*x6k1c9bb-N=DKYŢ˼d&v- WbK%V@ Ђi᫦s1tĤ 9=>?4R2IqJvg!Du?&&5| )8rʮ1hBow.P wch҂#PK!H3A2Ldocci-0.1.0.dist-info/RECORDuKr0нg%@T]DJbE0 (VghA7zO<~3Ed/ȉv(wX^4QJI}1(k%A]N*#6ɹHYSn4Ր)G,|IB*XXjdbfZ%Wtc2@@diC>ImY*d#`, M}4eq@+K8newZ YxԦYCg'%C.;^_o ߌy'?SSCR`qn~1RF7+VVfPK!docci/__init__.pyPK!WL/docci/config.pyPK! docci/file.pyPK!lA## docci/zip.pyPK!HڽTU, docci-0.1.0.dist-info/WHEELPK!H]W docci-0.1.0.dist-info/METADATAPK!H3A2L docci-0.1.0.dist-info/RECORDPKy