1
+ import datetime as dt
1
2
import pickle # noqa: S403
2
3
from typing import Iterable , Iterator
3
4
@@ -21,7 +22,7 @@ def id(self) -> IdType:
21
22
return f"{ self .__class__ .__name__ } ({ self .wrapped .id } )"
22
23
23
24
@property
24
- def wrapped (self ) -> CacheInterface :
25
+ def wrapped (self ) -> CacheInterface [ KeyType , ValueType ] :
25
26
return self ._wrapped
26
27
27
28
@property
@@ -82,3 +83,53 @@ def __setitem__(self, key: KeyType, value: ValueType) -> None:
82
83
83
84
def set_many (self , items : Iterable [tuple [KeyType , ValueType ]]) -> None :
84
85
return super ().set_many ((key , self ._encode (value )) for key , value in items ) # type: ignore
86
+
87
+
88
+ class ExpirationWrapper (BaseWrapper [KeyType , ValueType ]):
89
+ def __init__ (
90
+ self ,
91
+ wrapped : CacheInterface [KeyType , tuple [dt .datetime , ValueType ]],
92
+ lifespan = dt .timedelta (days = 1 ),
93
+ ) -> None :
94
+ super ().__init__ (wrapped ) # type: ignore
95
+ self ._lifespan = lifespan
96
+
97
+ @property
98
+ def wrapped (self ) -> CacheInterface [KeyType , tuple [dt .datetime , ValueType ]]:
99
+ return self ._wrapped # type: ignore
100
+
101
+ @property
102
+ def lifespan (self ) -> dt .timedelta :
103
+ return self ._lifespan
104
+
105
+ @property
106
+ def _now (self ) -> dt .datetime :
107
+ return dt .datetime .now (dt .UTC )
108
+
109
+ def _check_item (self , key : KeyType ) -> bool :
110
+ expiration_time , _ = self .wrapped [key ]
111
+ if expiration_time < self ._now :
112
+ del self .wrapped [key ]
113
+ return False
114
+ return True
115
+
116
+ def __len__ (self ) -> int :
117
+ # TODO: This is very inefficient.
118
+ # Need to store expiration_time in a separate cache, but will need a way to clone cache for that.
119
+ return sum (int (self ._check_item (key )) for key in self .wrapped ) # type: ignore
120
+
121
+ def __iter__ (self ) -> Iterable [KeyType ]:
122
+ for key in self .wrapped : # type: ignore
123
+ if self ._check_item (key ):
124
+ yield key
125
+
126
+ def __setitem__ (self , key : KeyType , value : ValueType ) -> None :
127
+ self .wrapped [key ] = self ._now + self .lifespan , value
128
+
129
+ def __getitem__ (self , key : KeyType ) -> ValueType :
130
+ if self ._check_item (key ):
131
+ return self .wrapped [key ][1 ]
132
+ raise KeyError (key )
133
+
134
+ def __contains__ (self , key : KeyType ) -> bool :
135
+ return super ().__contains__ (key ) and self ._check_item (key )
0 commit comments