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

188 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 wrapper.cache_clear = cache_clear 

113 wrapper.cache_info = lambda: info(hits, misses) 

114 return wrapper 

115 

116 

117def _uncached_info(func, info): 

118 misses = 0 

119 

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

121 nonlocal misses 

122 misses += 1 

123 return func(*args, **kwargs) 

124 

125 def cache_clear(): 

126 nonlocal misses 

127 misses = 0 

128 

129 wrapper.cache_clear = cache_clear 

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

131 return wrapper 

132 

133 

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

135 pending = set() 

136 

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

138 k = key(*args, **kwargs) 

139 with lock: 

140 cond.wait_for(lambda: k not in pending) 

141 try: 

142 result = cache[k] 

143 return result 

144 except KeyError: 

145 pending.add(k) 

146 try: 

147 v = func(*args, **kwargs) 

148 with lock: 

149 try: 

150 cache[k] = v 

151 except ValueError: 

152 pass # value too large 

153 return v 

154 finally: 

155 with lock: 

156 pending.remove(k) 

157 cond.notify_all() 

158 

159 def cache_clear(): 

160 with lock: 

161 cache.clear() 

162 

163 wrapper.cache_clear = cache_clear 

164 return wrapper 

165 

166 

167def _locked(func, cache, key, lock): 

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

169 k = key(*args, **kwargs) 

170 with lock: 

171 try: 

172 return cache[k] 

173 except KeyError: 

174 pass # key not found 

175 v = func(*args, **kwargs) 

176 with lock: 

177 try: 

178 # possible race condition: see above 

179 return cache.setdefault(k, v) 

180 except ValueError: 

181 return v # value too large 

182 

183 def cache_clear(): 

184 with lock: 

185 cache.clear() 

186 

187 wrapper.cache_clear = cache_clear 

188 return wrapper 

189 

190 

191def _unlocked(func, cache, key): 

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

193 k = key(*args, **kwargs) 

194 try: 

195 return cache[k] 

196 except KeyError: 

197 pass # key not found 

198 v = func(*args, **kwargs) 

199 try: 

200 cache[k] = v 

201 except ValueError: 

202 pass # value too large 

203 return v 

204 

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

206 return wrapper 

207 

208 

209def _uncached(func): 

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

211 return func(*args, **kwargs) 

212 

213 wrapper.cache_clear = lambda: None 

214 return wrapper 

215 

216 

217def _wrapper(func, cache, key, lock=None, cond=None, info=None): 

218 if info is not None: 

219 if cache is None: 

220 wrapper = _uncached_info(func, info) 

221 elif cond is not None and lock is not None: 

222 wrapper = _condition_info(func, cache, key, lock, cond, info) 

223 elif cond is not None: 

224 wrapper = _condition_info(func, cache, key, cond, cond, info) 

225 elif lock is not None: 

226 wrapper = _locked_info(func, cache, key, lock, info) 

227 else: 

228 wrapper = _unlocked_info(func, cache, key, info) 

229 else: 

230 if cache is None: 

231 wrapper = _uncached(func) 

232 elif cond is not None and lock is not None: 

233 wrapper = _condition(func, cache, key, lock, cond) 

234 elif cond is not None: 

235 wrapper = _condition(func, cache, key, cond, cond) 

236 elif lock is not None: 

237 wrapper = _locked(func, cache, key, lock) 

238 else: 

239 wrapper = _unlocked(func, cache, key) 

240 wrapper.cache_info = None 

241 

242 wrapper.cache = cache 

243 wrapper.cache_key = key 

244 wrapper.cache_lock = lock if lock is not None else cond 

245 wrapper.cache_condition = cond 

246 

247 return functools.update_wrapper(wrapper, func)