44from abc import ABC , abstractmethod
55from collections import OrderedDict , defaultdict
66from enum import Enum
7- from typing import List
7+ from typing import List , Sequence , Union
88
99from redis .typing import KeyT , ResponseT
1010
11- DEFAULT_EVICTION_POLICY = "lru"
1211
12+ class EvictionPolicy (Enum ):
13+ LRU = "lru"
14+ LFU = "lfu"
15+ RANDOM = "random"
1316
14- DEFAULT_BLACKLIST = [
17+
18+ DEFAULT_EVICTION_POLICY = EvictionPolicy .LRU
19+
20+ DEFAULT_DENY_LIST = [
1521 "BF.CARD" ,
1622 "BF.DEBUG" ,
1723 "BF.EXISTS" ,
7177 "TTL" ,
7278]
7379
74-
75- DEFAULT_WHITELIST = [
80+ DEFAULT_ALLOW_LIST = [
7681 "BITCOUNT" ,
7782 "BITFIELD_RO" ,
7883 "BITPOS" ,
155160_ACCESS_COUNT = "access_count"
156161
157162
158- class EvictionPolicy (Enum ):
159- LRU = "lru"
160- LFU = "lfu"
161- RANDOM = "random"
162-
163-
164163class AbstractCache (ABC ):
165164 """
166165 An abstract base class for client caching implementations.
167166 If you want to implement your own cache you must support these methods.
168167 """
169168
170169 @abstractmethod
171- def set (self , command : str , response : ResponseT , keys_in_command : List [KeyT ]):
170+ def set (
171+ self ,
172+ command : Union [str , Sequence [str ]],
173+ response : ResponseT ,
174+ keys_in_command : List [KeyT ],
175+ ):
172176 pass
173177
174178 @abstractmethod
175- def get (self , command : str ) -> ResponseT :
179+ def get (self , command : Union [ str , Sequence [ str ]] ) -> ResponseT :
176180 pass
177181
178182 @abstractmethod
179- def delete_command (self , command : str ):
183+ def delete_command (self , command : Union [ str , Sequence [ str ]] ):
180184 pass
181185
182186 @abstractmethod
183- def delete_many (self , commands ):
187+ def delete_commands (self , commands : List [ Union [ str , Sequence [ str ]]] ):
184188 pass
185189
186190 @abstractmethod
@@ -215,7 +219,6 @@ def __init__(
215219 max_size : int = 10000 ,
216220 ttl : int = 0 ,
217221 eviction_policy : EvictionPolicy = DEFAULT_EVICTION_POLICY ,
218- ** kwargs ,
219222 ):
220223 self .max_size = max_size
221224 self .ttl = ttl
@@ -224,12 +227,17 @@ def __init__(
224227 self .key_commands_map = defaultdict (set )
225228 self .commands_ttl_list = []
226229
227- def set (self , command : str , response : ResponseT , keys_in_command : List [KeyT ]):
230+ def set (
231+ self ,
232+ command : Union [str , Sequence [str ]],
233+ response : ResponseT ,
234+ keys_in_command : List [KeyT ],
235+ ):
228236 """
229237 Set a redis command and its response in the cache.
230238
231239 Args:
232- command (str): The redis command.
240+ command (Union[ str, Sequence[str]] ): The redis command.
233241 response (ResponseT): The response associated with the command.
234242 keys_in_command (List[KeyT]): The list of keys used in the command.
235243 """
@@ -244,12 +252,12 @@ def set(self, command: str, response: ResponseT, keys_in_command: List[KeyT]):
244252 self ._update_key_commands_map (keys_in_command , command )
245253 self .commands_ttl_list .append (command )
246254
247- def get (self , command : str ) -> ResponseT :
255+ def get (self , command : Union [ str , Sequence [ str ]] ) -> ResponseT :
248256 """
249257 Get the response for a redis command from the cache.
250258
251259 Args:
252- command (str): The redis command.
260+ command (Union[ str, Sequence[str]] ): The redis command.
253261
254262 Returns:
255263 ResponseT: The response associated with the command, or None if the command is not in the cache. # noqa
@@ -261,34 +269,42 @@ def get(self, command: str) -> ResponseT:
261269 self ._update_access (command )
262270 return copy .deepcopy (self .cache [command ]["response" ])
263271
264- def delete_command (self , command : str ):
272+ def delete_command (self , command : Union [ str , Sequence [ str ]] ):
265273 """
266274 Delete a redis command and its metadata from the cache.
267275
268276 Args:
269- command (str): The redis command to be deleted.
277+ command (Union[ str, Sequence[str]] ): The redis command to be deleted.
270278 """
271279 if command in self .cache :
272280 keys_in_command = self .cache [command ].get ("keys" )
273281 self ._del_key_commands_map (keys_in_command , command )
274282 self .commands_ttl_list .remove (command )
275283 del self .cache [command ]
276284
277- def delete_many (self , commands ):
278- pass
285+ def delete_commands (self , commands : List [Union [str , Sequence [str ]]]):
286+ """
287+ Delete multiple commands and their metadata from the cache.
288+
289+ Args:
290+ commands (List[Union[str, Sequence[str]]]): The list of commands to be
291+ deleted.
292+ """
293+ for command in commands :
294+ self .delete_command (command )
279295
280296 def flush (self ):
281297 """Clear the entire cache, removing all redis commands and metadata."""
282298 self .cache .clear ()
283299 self .key_commands_map .clear ()
284300 self .commands_ttl_list = []
285301
286- def _is_expired (self , command : str ) -> bool :
302+ def _is_expired (self , command : Union [ str , Sequence [ str ]] ) -> bool :
287303 """
288304 Check if a redis command has expired based on its time-to-live.
289305
290306 Args:
291- command (str): The redis command.
307+ command (Union[ str, Sequence[str]] ): The redis command.
292308
293309 Returns:
294310 bool: True if the command has expired, False otherwise.
@@ -297,56 +313,60 @@ def _is_expired(self, command: str) -> bool:
297313 return False
298314 return time .monotonic () - self .cache [command ]["ctime" ] > self .ttl
299315
300- def _update_access (self , command : str ):
316+ def _update_access (self , command : Union [ str , Sequence [ str ]] ):
301317 """
302318 Update the access information for a redis command based on the eviction policy.
303319
304320 Args:
305- command (str): The redis command.
321+ command (Union[ str, Sequence[str]] ): The redis command.
306322 """
307- if self .eviction_policy == EvictionPolicy .LRU . value :
323+ if self .eviction_policy == EvictionPolicy .LRU :
308324 self .cache .move_to_end (command )
309- elif self .eviction_policy == EvictionPolicy .LFU . value :
325+ elif self .eviction_policy == EvictionPolicy .LFU :
310326 self .cache [command ]["access_count" ] = (
311327 self .cache .get (command , {}).get ("access_count" , 0 ) + 1
312328 )
313329 self .cache .move_to_end (command )
314- elif self .eviction_policy == EvictionPolicy .RANDOM . value :
330+ elif self .eviction_policy == EvictionPolicy .RANDOM :
315331 pass # Random eviction doesn't require updates
316332
317333 def _evict (self ):
318334 """Evict a redis command from the cache based on the eviction policy."""
319335 if self ._is_expired (self .commands_ttl_list [0 ]):
320336 self .delete_command (self .commands_ttl_list [0 ])
321- elif self .eviction_policy == EvictionPolicy .LRU . value :
337+ elif self .eviction_policy == EvictionPolicy .LRU :
322338 self .cache .popitem (last = False )
323- elif self .eviction_policy == EvictionPolicy .LFU . value :
339+ elif self .eviction_policy == EvictionPolicy .LFU :
324340 min_access_command = min (
325341 self .cache , key = lambda k : self .cache [k ].get ("access_count" , 0 )
326342 )
327343 self .cache .pop (min_access_command )
328- elif self .eviction_policy == EvictionPolicy .RANDOM . value :
344+ elif self .eviction_policy == EvictionPolicy .RANDOM :
329345 random_command = random .choice (list (self .cache .keys ()))
330346 self .cache .pop (random_command )
331347
332- def _update_key_commands_map (self , keys : List [KeyT ], command : str ):
348+ def _update_key_commands_map (
349+ self , keys : List [KeyT ], command : Union [str , Sequence [str ]]
350+ ):
333351 """
334352 Update the key_commands_map with command that uses the keys.
335353
336354 Args:
337355 keys (List[KeyT]): The list of keys used in the command.
338- command (str): The redis command.
356+ command (Union[ str, Sequence[str]] ): The redis command.
339357 """
340358 for key in keys :
341359 self .key_commands_map [key ].add (command )
342360
343- def _del_key_commands_map (self , keys : List [KeyT ], command : str ):
361+ def _del_key_commands_map (
362+ self , keys : List [KeyT ], command : Union [str , Sequence [str ]]
363+ ):
344364 """
345365 Remove a redis command from the key_commands_map.
346366
347367 Args:
348368 keys (List[KeyT]): The list of keys used in the redis command.
349- command (str): The redis command.
369+ command (Union[ str, Sequence[str]] ): The redis command.
350370 """
351371 for key in keys :
352372 self .key_commands_map [key ].remove (command )
0 commit comments