Coverage for src/blob_dict/dict/multi_replica.py: 0%

64 statements  

« prev     ^ index     » next       coverage.py v7.8.1, created at 2025-05-23 02:51 -0700

1from collections.abc import Iterator 

2from typing import Any, Literal, override 

3 

4from ..blob import BytesBlob 

5from . import BlobDictBase 

6 

7 

8class MultiReplicaBlobDict(BlobDictBase): 

9 def __init__( 

10 self, 

11 replica_dicts: dict[str, BlobDictBase], 

12 ) -> None: 

13 super().__init__() 

14 

15 self.__replica_dicts: dict[str, BlobDictBase] = replica_dicts 

16 self.__primary_dict: BlobDictBase = next(iter(replica_dicts.values())) 

17 

18 @override 

19 def __len__(self) -> int: 

20 return len(self.__primary_dict) 

21 

22 def len( 

23 self, 

24 *, 

25 replica_name: str | None = None, 

26 ) -> int: 

27 return len( 

28 self.__replica_dicts[replica_name] if replica_name 

29 else self.__primary_dict, 

30 ) 

31 

32 @override 

33 def __contains__(self, key: Any) -> bool: 

34 return self.contains(str(key)) 

35 

36 def contains( 

37 self, 

38 key: str, 

39 *, 

40 replica_names: set[str] | None = None, 

41 ) -> bool: 

42 return any( 

43 key in self.__replica_dicts[replica_name] 

44 for replica_name in ( 

45 self.__replica_dicts.keys() if replica_names is None 

46 else replica_names 

47 ) 

48 ) 

49 

50 @override 

51 def get[T: Any]( 

52 self, 

53 key: str, 

54 /, 

55 default: BytesBlob | T = None, 

56 *, 

57 replica_names: set[str] | None = None, 

58 ) -> BytesBlob | T: 

59 for replica_name in ( 

60 self.__replica_dicts.keys() if replica_names is None 

61 else replica_names 

62 ): 

63 replica_dict: BlobDictBase = self.__replica_dicts[replica_name] 

64 blob: BytesBlob | None 

65 if blob := replica_dict.get(key): 

66 return blob 

67 

68 return default 

69 

70 @override 

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

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

73 if blob is None: 

74 raise KeyError 

75 

76 return blob 

77 

78 @override 

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

80 yield from ( 

81 key for key in self.__primary_dict 

82 ) 

83 

84 def iter( 

85 self, 

86 *, 

87 replica_name: str | None = None, 

88 ) -> Iterator[str]: 

89 yield from ( 

90 key for key in ( 

91 self.__replica_dicts[replica_name] if replica_name 

92 else self.__primary_dict 

93 ) 

94 ) 

95 

96 @override 

97 def clear( 

98 self, 

99 *, 

100 replica_names: set[str] | None = None, 

101 ) -> None: 

102 for replica_name in ( 

103 self.__replica_dicts.keys() if replica_names is None 

104 else replica_names 

105 ): 

106 replica_dict: BlobDictBase = self.__replica_dicts[replica_name] 

107 replica_dict.clear() 

108 

109 @override 

110 def pop[T: Any]( 

111 self, 

112 key: str, 

113 /, 

114 default: BytesBlob | T | Literal["__DEFAULT"] = "__DEFAULT", 

115 *, 

116 replica_names: set[str] | None = None, 

117 ) -> BytesBlob | T: 

118 final_blob: BytesBlob | None = None 

119 for replica_name in ( 

120 self.__replica_dicts.keys() if replica_names is None 

121 else replica_names 

122 ): 

123 replica_dict: BlobDictBase = self.__replica_dicts[replica_name] 

124 if (blob := replica_dict.pop(key, None)) and not final_blob: 

125 final_blob = blob 

126 

127 if final_blob: 

128 return final_blob 

129 

130 if default == "__DEFAULT": 

131 raise KeyError 

132 

133 return default 

134 

135 @override 

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

137 if key not in self: 

138 raise KeyError 

139 

140 self.pop(key) 

141 

142 @override 

143 def __setitem__( 

144 self, 

145 key: str, 

146 blob: BytesBlob, 

147 /, 

148 *, 

149 replica_names: set[str] | None = None, 

150 ) -> None: 

151 for replica_name in ( 

152 self.__replica_dicts.keys() if replica_names is None 

153 else replica_names 

154 ): 

155 replica_dict: BlobDictBase = self.__replica_dicts[replica_name] 

156 replica_dict[key] = blob