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

190 statements  

1"""Function decorator helpers.""" 

2 

3import functools 

4 

5 

6def _condition_info(func, cache, key, lock, cond, info): 

7 hits = misses = 0 

8 pending = set() 

9 

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() 

34 

35 def cache_clear(): 

36 nonlocal hits, misses 

37 with lock: 

38 cache.clear() 

39 hits = misses = 0 

40 

41 def cache_info(): 

42 with lock: 

43 return info(hits, misses) 

44 

45 wrapper.cache_clear = cache_clear 

46 wrapper.cache_info = cache_info 

47 return wrapper 

48 

49 

50def _locked_info(func, cache, key, lock, info): 

51 hits = misses = 0 

52 

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 

72 

73 def cache_clear(): 

74 nonlocal hits, misses 

75 with lock: 

76 cache.clear() 

77 hits = misses = 0 

78 

79 def cache_info(): 

80 with lock: 

81 return info(hits, misses) 

82 

83 wrapper.cache_clear = cache_clear 

84 wrapper.cache_info = cache_info 

85 return wrapper 

86 

87 

88def _unlocked_info(func, cache, key, info): 

89 hits = misses = 0 

90 

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 

106 

107 def cache_clear(): 

108 nonlocal hits, misses 

109 cache.clear() 

110 hits = misses = 0 

111 

112 def cache_info(): 

113 return info(hits, misses) 

114 

115 wrapper.cache_clear = cache_clear 

116 wrapper.cache_info = cache_info 

117 return wrapper 

118 

119 

120def _uncached_info(func, info): 

121 misses = 0 

122 

123 def wrapper(*args, **kwargs): 

124 nonlocal misses 

125 misses += 1 

126 return func(*args, **kwargs) 

127 

128 def cache_clear(): 

129 nonlocal misses 

130 misses = 0 

131 

132 wrapper.cache_clear = cache_clear 

133 wrapper.cache_info = lambda: info(0, misses) 

134 return wrapper 

135 

136 

137def _condition(func, cache, key, lock, cond): 

138 pending = set() 

139 

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() 

161 

162 def cache_clear(): 

163 with lock: 

164 cache.clear() 

165 

166 wrapper.cache_clear = cache_clear 

167 return wrapper 

168 

169 

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 

185 

186 def cache_clear(): 

187 with lock: 

188 cache.clear() 

189 

190 wrapper.cache_clear = cache_clear 

191 return wrapper 

192 

193 

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 

207 

208 wrapper.cache_clear = lambda: cache.clear() 

209 return wrapper 

210 

211 

212def _uncached(func): 

213 def wrapper(*args, **kwargs): 

214 return func(*args, **kwargs) 

215 

216 wrapper.cache_clear = lambda: None 

217 return wrapper 

218 

219 

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 

244 

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 

249 

250 return functools.update_wrapper(wrapper, func)