Coverage for src/blob_dict/dict/valkey.py: 0%
55 statements
« prev ^ index » next coverage.py v7.8.1, created at 2025-05-21 20:53 -0700
« prev ^ index » next coverage.py v7.8.1, created at 2025-05-21 20:53 -0700
1from collections.abc import Iterator
2from datetime import timedelta
3from typing import Any, cast, override
5from valkey import Valkey
7from ..blob import BytesBlob, StrBlob
8from . import BlobDictBase
11class ValkeyBlobDict(BlobDictBase):
12 def __init__(
13 self,
14 *,
15 ttl: timedelta | None = None,
16 str_blob_only: bool = False,
17 client_kwargs: dict[str, Any] | None = None,
18 ) -> None:
19 super().__init__()
21 self.__client: Valkey = Valkey(
22 **(client_kwargs or {}),
23 decode_responses=True,
24 )
26 self.__ttl_ms: int | None = int(ttl.total_seconds() * 1_000) if ttl else None
28 self.__str_blob_only: bool = str_blob_only
30 @override
31 def __len__(self) -> int:
32 return cast("int", self.__client.dbsize())
34 @override
35 def __contains__(self, key: str) -> bool:
36 return cast("int", self.__client.exists(key)) == 1
38 @override
39 def get(self, key: str, /, default: BytesBlob | None = None) -> BytesBlob | None:
40 response: Any = self.__client.get(key)
41 if not response:
42 return default
44 s: str = cast("str", response)
45 return (
46 StrBlob(s) if self.__str_blob_only
47 else BytesBlob.from_b64_str(s)
48 )
50 @override
51 def __getitem__(self, key: str, /) -> BytesBlob:
52 blob: BytesBlob | None = self.get(key)
53 if blob is None:
54 raise KeyError
56 return blob
58 @override
59 def __iter__(self) -> Iterator[str]:
60 for key in self.__client.scan_iter(_type="STRING"):
61 yield cast("str", key)
63 @override
64 def clear(self) -> None:
65 self.__client.flushdb()
67 @override
68 def pop(self, key: str, /, default: BytesBlob | None = None) -> BytesBlob | None:
69 if response := self.get(key):
70 self.__client.delete(key)
71 return response
73 return default
75 @override
76 def __delitem__(self, key: str, /) -> None:
77 number_deleted: int = cast("int", self.__client.delete(key))
78 if number_deleted == 0:
79 raise KeyError
81 __BAD_BLOB_CLASS_ERROR_MESSAGE: str = "Must specify blob of type `StrBlob`"
83 @override
84 def __setitem__(self, key: str, blob: BytesBlob, /) -> None:
85 if self.__str_blob_only and not isinstance(blob, StrBlob):
86 raise TypeError(self.__BAD_BLOB_CLASS_ERROR_MESSAGE)
88 self.__client.set(
89 key,
90 (
91 cast("StrBlob", blob).as_str() if self.__str_blob_only
92 else blob.as_b64_str()
93 ),
94 px=self.__ttl_ms,
95 )