Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/cachetools/_cached.py: 48%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Function decorator helpers."""
3import functools
6def _condition_info(func, cache, key, lock, cond, info):
7 hits = misses = 0
8 pending = set()
10 def wrapper(*args, **kwargs):
11 nonlocal hits, misses
12 k = key(*args, **kwargs)
13 with lock:
14 cond.wait_for(lambda: k not in pending)
15 try:
16 result = cache[k]
17 hits += 1
18 return result
19 except KeyError:
20 pending.add(k)
21 misses += 1
22 try:
23 v = func(*args, **kwargs)
24 with lock:
25 try:
26 cache[k] = v
27 except ValueError:
28 pass # value too large
29 return v
30 finally:
31 with lock:
32 pending.remove(k)
33 cond.notify_all()
35 def cache_clear():
36 nonlocal hits, misses
37 with lock:
38 cache.clear()
39 hits = misses = 0
41 def cache_info():
42 with lock:
43 return info(hits, misses)
45 wrapper.cache_clear = cache_clear
46 wrapper.cache_info = cache_info
47 return wrapper
50def _locked_info(func, cache, key, lock, info):
51 hits = misses = 0
53 def wrapper(*args, **kwargs):
54 nonlocal hits, misses
55 k = key(*args, **kwargs)
56 with lock:
57 try:
58 result = cache[k]
59 hits += 1
60 return result
61 except KeyError:
62 misses += 1
63 v = func(*args, **kwargs)
64 with lock:
65 try:
66 # In case of a race condition, i.e. if another thread
67 # stored a value for this key while we were calling
68 # func(), prefer the cached value.
69 return cache.setdefault(k, v)
70 except ValueError:
71 return v # value too large
73 def cache_clear():
74 nonlocal hits, misses
75 with lock:
76 cache.clear()
77 hits = misses = 0
79 def cache_info():
80 with lock:
81 return info(hits, misses)
83 wrapper.cache_clear = cache_clear
84 wrapper.cache_info = cache_info
85 return wrapper
88def _unlocked_info(func, cache, key, info):
89 hits = misses = 0
91 def wrapper(*args, **kwargs):
92 nonlocal hits, misses
93 k = key(*args, **kwargs)
94 try:
95 result = cache[k]
96 hits += 1
97 return result
98 except KeyError:
99 misses += 1
100 v = func(*args, **kwargs)
101 try:
102 cache[k] = v
103 except ValueError:
104 pass # value too large
105 return v
107 def cache_clear():
108 nonlocal hits, misses
109 cache.clear()
110 hits = misses = 0
112 def cache_info():
113 return info(hits, misses)
115 wrapper.cache_clear = cache_clear
116 wrapper.cache_info = cache_info
117 return wrapper
120def _uncached_info(func, info):
121 misses = 0
123 def wrapper(*args, **kwargs):
124 nonlocal misses
125 misses += 1
126 return func(*args, **kwargs)
128 def cache_clear():
129 nonlocal misses
130 misses = 0
132 wrapper.cache_clear = cache_clear
133 wrapper.cache_info = lambda: info(0, misses)
134 return wrapper
137def _condition(func, cache, key, lock, cond):
138 pending = set()
140 def wrapper(*args, **kwargs):
141 k = key(*args, **kwargs)
142 with lock:
143 cond.wait_for(lambda: k not in pending)
144 try:
145 result = cache[k]
146 return result
147 except KeyError:
148 pending.add(k)
149 try:
150 v = func(*args, **kwargs)
151 with lock:
152 try:
153 cache[k] = v
154 except ValueError:
155 pass # value too large
156 return v
157 finally:
158 with lock:
159 pending.remove(k)
160 cond.notify_all()
162 def cache_clear():
163 with lock:
164 cache.clear()
166 wrapper.cache_clear = cache_clear
167 return wrapper
170def _locked(func, cache, key, lock):
171 def wrapper(*args, **kwargs):
172 k = key(*args, **kwargs)
173 with lock:
174 try:
175 return cache[k]
176 except KeyError:
177 pass # key not found
178 v = func(*args, **kwargs)
179 with lock:
180 try:
181 # possible race condition: see above
182 return cache.setdefault(k, v)
183 except ValueError:
184 return v # value too large
186 def cache_clear():
187 with lock:
188 cache.clear()
190 wrapper.cache_clear = cache_clear
191 return wrapper
194def _unlocked(func, cache, key):
195 def wrapper(*args, **kwargs):
196 k = key(*args, **kwargs)
197 try:
198 return cache[k]
199 except KeyError:
200 pass # key not found
201 v = func(*args, **kwargs)
202 try:
203 cache[k] = v
204 except ValueError:
205 pass # value too large
206 return v
208 wrapper.cache_clear = lambda: cache.clear()
209 return wrapper
212def _uncached(func):
213 def wrapper(*args, **kwargs):
214 return func(*args, **kwargs)
216 wrapper.cache_clear = lambda: None
217 return wrapper
220def _wrapper(func, cache, key, lock=None, cond=None, info=None):
221 if info is not None:
222 if cache is None:
223 wrapper = _uncached_info(func, info)
224 elif cond is not None and lock is not None:
225 wrapper = _condition_info(func, cache, key, lock, cond, info)
226 elif cond is not None:
227 wrapper = _condition_info(func, cache, key, cond, cond, info)
228 elif lock is not None:
229 wrapper = _locked_info(func, cache, key, lock, info)
230 else:
231 wrapper = _unlocked_info(func, cache, key, info)
232 else:
233 if cache is None:
234 wrapper = _uncached(func)
235 elif cond is not None and lock is not None:
236 wrapper = _condition(func, cache, key, lock, cond)
237 elif cond is not None:
238 wrapper = _condition(func, cache, key, cond, cond)
239 elif lock is not None:
240 wrapper = _locked(func, cache, key, lock)
241 else:
242 wrapper = _unlocked(func, cache, key)
243 wrapper.cache_info = None
245 wrapper.cache = cache
246 wrapper.cache_key = key
247 wrapper.cache_lock = lock if lock is not None else cond
248 wrapper.cache_condition = cond
250 return functools.update_wrapper(wrapper, func)