Coverage for src/blob_dict/dict/path/__init__.py: 0%

66 statements  

« prev     ^ index     » next       coverage.py v7.7.0, created at 2025-03-19 01:12 -0700

1import shutil 

2from collections.abc import Iterator 

3from pathlib import Path 

4from typing import override 

5 

6from cloudpathlib import CloudPath 

7 

8from ...blob import BytesBlob 

9from .. import BlobDictBase 

10 

11 

12class LocalPath(Path): 

13 def rmtree(self) -> None: 

14 shutil.rmtree(self) 

15 

16 

17class PathBlobDict(BlobDictBase): 

18 def __init__(self, path: LocalPath | CloudPath) -> None: 

19 super().__init__() 

20 

21 self.__path: LocalPath | CloudPath = path 

22 

23 @override 

24 def create(self) -> None: 

25 self.__path.mkdir( 

26 parents=True, 

27 exist_ok=True, 

28 ) 

29 

30 @override 

31 def delete(self) -> None: 

32 self.__path.rmtree() 

33 

34 @override 

35 def __len__(self) -> int: 

36 return sum(1 for _ in self) 

37 

38 @override 

39 def __contains__(self, key: str) -> bool: 

40 return (self.__path / key).is_file() 

41 

42 @override 

43 def get(self, key: str, default: BytesBlob | None = None) -> BytesBlob | None: 

44 if key not in self: 

45 return default 

46 

47 return BytesBlob((self.__path / key).read_bytes()) 

48 

49 @override 

50 def __getitem__(self, key: str) -> BytesBlob: 

51 blob: BytesBlob | None = self.get(key) 

52 if blob is None: 

53 raise KeyError 

54 

55 return blob 

56 

57 @override 

58 def __iter__(self) -> Iterator[str]: 

59 for root, _, files in self.__path.walk(top_down=False): 

60 for filename in files: 

61 yield str((root / filename).relative_to(self.__path)) 

62 

63 @override 

64 def clear(self) -> None: 

65 for root, dirs, files in self.__path.walk(top_down=False): 

66 for filename in files: 

67 (root / filename).unlink() 

68 for dirname in dirs: 

69 (root / dirname).rmdir() 

70 

71 @override 

72 def pop(self, key: str, default: BytesBlob | None = None) -> BytesBlob | None: 

73 blob: BytesBlob | None = self.get(key) 

74 

75 (self.__path / key).unlink() 

76 

77 return blob 

78 

79 @override 

80 def __delitem__(self, key: str) -> None: 

81 if key not in self: 

82 raise KeyError 

83 

84 (self.__path / key).unlink() 

85 

86 # Skip last one which is self.__path 

87 for parent in (self.__path / key).parents[:-1]: 

88 if next(parent.iterdir(), None) is None: 

89 parent.rmdir() 

90 

91 @override 

92 def __setitem__(self, key: str, blob: BytesBlob) -> None: 

93 (self.__path / key).parent.mkdir( 

94 parents=True, 

95 exist_ok=True, 

96 ) 

97 

98 (self.__path / key).write_bytes(blob.as_bytes())