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, prefer the item already in the cache 

67 return cache.setdefault(k, v) 

68 except ValueError: 

69 return v # value too large 

70 

71 def cache_clear(): 

72 nonlocal hits, misses 

73 with lock: 

74 cache.clear() 

75 hits = misses = 0 

76 

77 def cache_info(): 

78 with lock: 

79 return info(hits, misses) 

80 

81 wrapper.cache_clear = cache_clear 

82 wrapper.cache_info = cache_info 

83 return wrapper 

84 

85 

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

87 hits = misses = 0 

88 

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

90 nonlocal hits, misses 

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

92 try: 

93 result = cache[k] 

94 hits += 1 

95 return result 

96 except KeyError: 

97 misses += 1 

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

99 try: 

100 cache[k] = v 

101 except ValueError: 

102 pass # value too large 

103 return v 

104 

105 def cache_clear(): 

106 nonlocal hits, misses 

107 cache.clear() 

108 hits = misses = 0 

109 

110 wrapper.cache_clear = cache_clear 

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

112 return wrapper 

113 

114 

115def _uncached_info(func, info): 

116 misses = 0 

117 

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

119 nonlocal misses 

120 misses += 1 

121 return func(*args, **kwargs) 

122 

123 def cache_clear(): 

124 nonlocal misses 

125 misses = 0 

126 

127 wrapper.cache_clear = cache_clear 

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

129 return wrapper 

130 

131 

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

133 pending = set() 

134 

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

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

137 with lock: 

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

139 try: 

140 result = cache[k] 

141 return result 

142 except KeyError: 

143 pending.add(k) 

144 try: 

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

146 with lock: 

147 try: 

148 cache[k] = v 

149 except ValueError: 

150 pass # value too large 

151 return v 

152 finally: 

153 with lock: 

154 pending.remove(k) 

155 cond.notify_all() 

156 

157 def cache_clear(): 

158 with lock: 

159 cache.clear() 

160 

161 wrapper.cache_clear = cache_clear 

162 return wrapper 

163 

164 

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

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

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

168 with lock: 

169 try: 

170 return cache[k] 

171 except KeyError: 

172 pass # key not found 

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

174 with lock: 

175 try: 

176 # in case of a race, prefer the item already in the cache 

177 return cache.setdefault(k, v) 

178 except ValueError: 

179 return v # value too large 

180 

181 def cache_clear(): 

182 with lock: 

183 cache.clear() 

184 

185 wrapper.cache_clear = cache_clear 

186 return wrapper 

187 

188 

189def _unlocked(func, cache, key): 

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

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

192 try: 

193 return cache[k] 

194 except KeyError: 

195 pass # key not found 

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

197 try: 

198 cache[k] = v 

199 except ValueError: 

200 pass # value too large 

201 return v 

202 

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

204 return wrapper 

205 

206 

207def _uncached(func): 

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

209 return func(*args, **kwargs) 

210 

211 wrapper.cache_clear = lambda: None 

212 return wrapper 

213 

214 

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

216 if info is not None: 

217 if cache is None: 

218 wrapper = _uncached_info(func, info) 

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

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

221 elif cond is not None: 

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

223 elif lock is not None: 

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

225 else: 

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

227 else: 

228 if cache is None: 

229 wrapper = _uncached(func) 

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

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

232 elif cond is not None: 

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

234 elif lock is not None: 

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

236 else: 

237 wrapper = _unlocked(func, cache, key) 

238 wrapper.cache_info = None 

239 

240 wrapper.cache = cache 

241 wrapper.cache_key = key 

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

243 wrapper.cache_condition = cond 

244 

245 return functools.update_wrapper(wrapper, func)