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

49 statements  

« prev     ^ index     » next       coverage.py v7.7.1, created at 2025-03-27 22:31 -0700

1from collections.abc import Iterator 

2from datetime import timedelta 

3from typing import Any, cast, override 

4 

5from valkey import Valkey 

6 

7from ..blob import BytesBlob, StrBlob 

8from . import BlobDictBase 

9 

10 

11class ValkeyBlobDict(BlobDictBase): 

12 def __init__( 

13 self, 

14 *, 

15 ttl: timedelta | None = None, 

16 str_blob_only: bool = False, 

17 ) -> None: 

18 super().__init__() 

19 

20 self.__r: Valkey = Valkey( 

21 decode_responses=True, 

22 ) 

23 

24 self.__ttl_ms: int | None = int(ttl.total_seconds() * 1_000) if ttl else None 

25 

26 self.__str_blob_only: bool = str_blob_only 

27 

28 @override 

29 def __len__(self) -> int: 

30 return cast("int", self.__r.dbsize()) 

31 

32 @override 

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

34 return cast("int", self.__r.exists(key)) == 1 

35 

36 @override 

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

38 response: Any = self.__r.get(key) 

39 if not response: 

40 return default 

41 

42 s: str = cast("str", response) 

43 return ( 

44 StrBlob(s) if self.__str_blob_only 

45 else BytesBlob.from_b64_str(s) 

46 ) 

47 

48 @override 

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

50 for key in self.__r.scan_iter(_type="STRING"): 

51 yield cast("str", key) 

52 

53 @override 

54 def clear(self) -> None: 

55 self.__r.flushdb() 

56 

57 @override 

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

59 if response := self.get(key): 

60 self.__r.delete(key) 

61 return response 

62 

63 return default 

64 

65 @override 

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

67 number_deleted: int = cast("int", self.__r.delete(key)) 

68 if number_deleted == 0: 

69 raise KeyError 

70 

71 __BAD_BLOB_CLASS_ERROR_MESSAGE: str = "Must specify blob of type `StrBlob`" 

72 

73 @override 

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

75 if self.__str_blob_only and not isinstance(blob, StrBlob): 

76 raise TypeError(self.__BAD_BLOB_CLASS_ERROR_MESSAGE) 

77 

78 self.__r.set( 

79 key, 

80 ( 

81 cast("StrBlob", blob).as_str() if self.__str_blob_only 

82 else blob.as_b64_str() 

83 ), 

84 px=self.__ttl_ms, 

85 )