Coverage for src/blob_dict/blob/__init__.py: 0%

40 statements  

« prev     ^ index     » next       coverage.py v7.8.1, created at 2025-05-21 20:53 -0700

1from __future__ import annotations 

2 

3from base64 import b64decode, b64encode 

4from pathlib import Path 

5from typing import Any, Self, override 

6 

7from simple_zstd import compress, decompress 

8 

9 

10class BytesBlob: 

11 def __init__(self, blob: bytes) -> None: 

12 super().__init__() 

13 

14 self._blob_bytes: bytes = blob 

15 

16 def as_blob( 

17 self, 

18 blob_class: type[BytesBlob], 

19 blob_class_args: dict[str, Any] | None = None, 

20 ) -> BytesBlob: 

21 return blob_class(self._blob_bytes, **(blob_class_args or {})) 

22 

23 def as_bytes(self, *, compression: bool = False) -> bytes: 

24 return compress(self._blob_bytes) if compression else self._blob_bytes 

25 

26 @staticmethod 

27 def from_bytes(b: bytes, *, compression: bool = False) -> BytesBlob: 

28 return BytesBlob(decompress(b) if compression else b) 

29 

30 @staticmethod 

31 def from_b64_str(s: str) -> BytesBlob: 

32 return BytesBlob(b64decode(s)) 

33 

34 def as_b64_str(self) -> str: 

35 return b64encode(self._blob_bytes).decode("ascii") 

36 

37 def __repr__(self) -> str: 

38 return f"{self.__class__.__name__}({self.as_bytes().__repr__()})" 

39 

40 @classmethod 

41 def load(cls: type[Self], f: Path | str) -> Self: 

42 return cls(Path(f).expanduser().read_bytes()) 

43 

44 def dump(self, f: Path | str) -> None: 

45 Path(f).expanduser().write_bytes(self.as_bytes()) 

46 

47 

48class StrBlob(BytesBlob): 

49 def __init__(self, blob: bytes | str) -> None: 

50 if isinstance(blob, str): 

51 blob = blob.encode() 

52 

53 super().__init__(blob) 

54 

55 def as_str(self) -> str: 

56 return self._blob_bytes.decode() 

57 

58 def __str__(self) -> str: 

59 return self.as_str() 

60 

61 @override 

62 def __repr__(self) -> str: 

63 return f"{self.__class__.__name__}({self.as_str().__repr__()})"