py2docfx 0.1.22.dev2258230__py3-none-any.whl → 0.1.22.dev2270449__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. py2docfx/docfx_yaml/process_doctree.py +3 -23
  2. py2docfx/docfx_yaml/translator.py +6 -35
  3. py2docfx/docfx_yaml/type_mapping.py +102 -0
  4. py2docfx/venv/basevenv/Lib/site-packages/certifi/__init__.py +1 -1
  5. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/default.py +8 -9
  6. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/imds.py +7 -3
  7. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/managed_identity.py +7 -1
  8. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/shared_cache.py +2 -2
  9. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/interactive.py +2 -2
  10. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/msal_managed_identity_client.py +1 -1
  11. py2docfx/venv/venv1/Lib/site-packages/azure/identity/_version.py +1 -1
  12. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/default.py +8 -9
  13. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/imds.py +7 -3
  14. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/managed_identity.py +7 -1
  15. py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/shared_cache.py +2 -2
  16. py2docfx/venv/venv1/Lib/site-packages/cachetools/__init__.py +96 -122
  17. py2docfx/venv/venv1/Lib/site-packages/cachetools/{_decorators.py → _cached.py} +106 -13
  18. py2docfx/venv/venv1/Lib/site-packages/cachetools/_cachedmethod.py +128 -0
  19. py2docfx/venv/venv1/Lib/site-packages/cachetools/func.py +5 -25
  20. py2docfx/venv/venv1/Lib/site-packages/certifi/__init__.py +1 -1
  21. py2docfx/venv/venv1/Lib/site-packages/cryptography/__about__.py +1 -1
  22. py2docfx/venv/venv1/Lib/site-packages/google/api_core/client_options.py +9 -2
  23. py2docfx/venv/venv1/Lib/site-packages/google/api_core/general_helpers.py +36 -0
  24. py2docfx/venv/venv1/Lib/site-packages/google/api_core/grpc_helpers.py +10 -7
  25. py2docfx/venv/venv1/Lib/site-packages/google/api_core/grpc_helpers_async.py +8 -3
  26. py2docfx/venv/venv1/Lib/site-packages/google/api_core/operations_v1/transports/base.py +13 -7
  27. py2docfx/venv/venv1/Lib/site-packages/google/api_core/operations_v1/transports/rest.py +19 -12
  28. py2docfx/venv/venv1/Lib/site-packages/google/api_core/operations_v1/transports/rest_asyncio.py +21 -0
  29. py2docfx/venv/venv1/Lib/site-packages/google/api_core/version.py +1 -1
  30. py2docfx/venv/venv1/Lib/site-packages/google/auth/_default.py +66 -12
  31. py2docfx/venv/venv1/Lib/site-packages/google/auth/_default_async.py +16 -10
  32. py2docfx/venv/venv1/Lib/site-packages/google/auth/_helpers.py +41 -0
  33. py2docfx/venv/venv1/Lib/site-packages/google/auth/compute_engine/credentials.py +67 -6
  34. py2docfx/venv/venv1/Lib/site-packages/google/auth/credentials.py +161 -18
  35. py2docfx/venv/venv1/Lib/site-packages/google/auth/environment_vars.py +4 -0
  36. py2docfx/venv/venv1/Lib/site-packages/google/auth/external_account.py +33 -10
  37. py2docfx/venv/venv1/Lib/site-packages/google/auth/external_account_authorized_user.py +24 -1
  38. py2docfx/venv/venv1/Lib/site-packages/google/auth/identity_pool.py +25 -1
  39. py2docfx/venv/venv1/Lib/site-packages/google/auth/impersonated_credentials.py +57 -9
  40. py2docfx/venv/venv1/Lib/site-packages/google/auth/pluggable.py +25 -1
  41. py2docfx/venv/venv1/Lib/site-packages/google/auth/version.py +1 -1
  42. py2docfx/venv/venv1/Lib/site-packages/google/oauth2/_client.py +117 -0
  43. py2docfx/venv/venv1/Lib/site-packages/google/oauth2/service_account.py +39 -4
  44. {py2docfx-0.1.22.dev2258230.dist-info → py2docfx-0.1.22.dev2270449.dist-info}/METADATA +1 -1
  45. {py2docfx-0.1.22.dev2258230.dist-info → py2docfx-0.1.22.dev2270449.dist-info}/RECORD +47 -45
  46. {py2docfx-0.1.22.dev2258230.dist-info → py2docfx-0.1.22.dev2270449.dist-info}/WHEEL +0 -0
  47. {py2docfx-0.1.22.dev2258230.dist-info → py2docfx-0.1.22.dev2270449.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,6 @@ __all__ = (
5
5
  "FIFOCache",
6
6
  "LFUCache",
7
7
  "LRUCache",
8
- "MRUCache",
9
8
  "RRCache",
10
9
  "TLRUCache",
11
10
  "TTLCache",
@@ -13,7 +12,7 @@ __all__ = (
13
12
  "cachedmethod",
14
13
  )
15
14
 
16
- __version__ = "5.5.2"
15
+ __version__ = "6.2.0"
17
16
 
18
17
  import collections
19
18
  import collections.abc
@@ -23,7 +22,6 @@ import random
23
22
  import time
24
23
 
25
24
  from . import keys
26
- from ._decorators import _cached_wrapper
27
25
 
28
26
 
29
27
  class _DefaultSize:
@@ -172,32 +170,78 @@ class FIFOCache(Cache):
172
170
  class LFUCache(Cache):
173
171
  """Least Frequently Used (LFU) cache implementation."""
174
172
 
173
+ class _Link:
174
+ __slots__ = ("count", "keys", "next", "prev")
175
+
176
+ def __init__(self, count):
177
+ self.count = count
178
+ self.keys = set()
179
+
180
+ def unlink(self):
181
+ next = self.next
182
+ prev = self.prev
183
+ prev.next = next
184
+ next.prev = prev
185
+
175
186
  def __init__(self, maxsize, getsizeof=None):
176
187
  Cache.__init__(self, maxsize, getsizeof)
177
- self.__counter = collections.Counter()
188
+ self.__root = root = LFUCache._Link(0) # sentinel
189
+ root.prev = root.next = root
190
+ self.__links = {}
178
191
 
179
192
  def __getitem__(self, key, cache_getitem=Cache.__getitem__):
180
193
  value = cache_getitem(self, key)
181
194
  if key in self: # __missing__ may not store item
182
- self.__counter[key] -= 1
195
+ self.__touch(key)
183
196
  return value
184
197
 
185
198
  def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
186
199
  cache_setitem(self, key, value)
187
- self.__counter[key] -= 1
200
+ if key in self.__links:
201
+ return self.__touch(key)
202
+ root = self.__root
203
+ link = root.next
204
+ if link.count != 1:
205
+ link = LFUCache._Link(1)
206
+ link.next = root.next
207
+ root.next = link.next.prev = link
208
+ link.prev = root
209
+ link.keys.add(key)
210
+ self.__links[key] = link
188
211
 
189
212
  def __delitem__(self, key, cache_delitem=Cache.__delitem__):
190
213
  cache_delitem(self, key)
191
- del self.__counter[key]
214
+ link = self.__links.pop(key)
215
+ link.keys.remove(key)
216
+ if not link.keys:
217
+ link.unlink()
192
218
 
193
219
  def popitem(self):
194
220
  """Remove and return the `(key, value)` pair least frequently used."""
195
- try:
196
- ((key, _),) = self.__counter.most_common(1)
197
- except ValueError:
221
+ root = self.__root
222
+ curr = root.next
223
+ if curr is root:
198
224
  raise KeyError("%s is empty" % type(self).__name__) from None
199
- else:
200
- return (key, self.pop(key))
225
+ key = next(iter(curr.keys)) # remove an arbitrary element
226
+ return (key, self.pop(key))
227
+
228
+ def __touch(self, key):
229
+ """Increment use count"""
230
+ link = self.__links[key]
231
+ curr = link.next
232
+ if curr.count != link.count + 1:
233
+ if len(link.keys) == 1:
234
+ link.count += 1
235
+ return
236
+ curr = LFUCache._Link(link.count + 1)
237
+ curr.next = link.next
238
+ link.next = curr.next.prev = curr
239
+ curr.prev = link
240
+ curr.keys.add(key)
241
+ link.keys.remove(key)
242
+ if not link.keys:
243
+ link.unlink()
244
+ self.__links[key] = curr
201
245
 
202
246
 
203
247
  class LRUCache(Cache):
@@ -210,12 +254,12 @@ class LRUCache(Cache):
210
254
  def __getitem__(self, key, cache_getitem=Cache.__getitem__):
211
255
  value = cache_getitem(self, key)
212
256
  if key in self: # __missing__ may not store item
213
- self.__update(key)
257
+ self.__touch(key)
214
258
  return value
215
259
 
216
260
  def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
217
261
  cache_setitem(self, key, value)
218
- self.__update(key)
262
+ self.__touch(key)
219
263
 
220
264
  def __delitem__(self, key, cache_delitem=Cache.__delitem__):
221
265
  cache_delitem(self, key)
@@ -230,70 +274,47 @@ class LRUCache(Cache):
230
274
  else:
231
275
  return (key, self.pop(key))
232
276
 
233
- def __update(self, key):
277
+ def __touch(self, key):
278
+ """Mark as recently used"""
234
279
  try:
235
280
  self.__order.move_to_end(key)
236
281
  except KeyError:
237
282
  self.__order[key] = None
238
283
 
239
284
 
240
- class MRUCache(Cache):
241
- """Most Recently Used (MRU) cache implementation."""
242
-
243
- def __init__(self, maxsize, getsizeof=None):
244
- from warnings import warn
245
-
246
- warn("MRUCache is deprecated", DeprecationWarning, stacklevel=2)
247
-
248
- Cache.__init__(self, maxsize, getsizeof)
249
- self.__order = collections.OrderedDict()
250
-
251
- def __getitem__(self, key, cache_getitem=Cache.__getitem__):
252
- value = cache_getitem(self, key)
253
- if key in self: # __missing__ may not store item
254
- self.__update(key)
255
- return value
256
-
257
- def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
258
- cache_setitem(self, key, value)
259
- self.__update(key)
260
-
261
- def __delitem__(self, key, cache_delitem=Cache.__delitem__):
262
- cache_delitem(self, key)
263
- del self.__order[key]
264
-
265
- def popitem(self):
266
- """Remove and return the `(key, value)` pair most recently used."""
267
- try:
268
- key = next(iter(self.__order))
269
- except StopIteration:
270
- raise KeyError("%s is empty" % type(self).__name__) from None
271
- else:
272
- return (key, self.pop(key))
273
-
274
- def __update(self, key):
275
- try:
276
- self.__order.move_to_end(key, last=False)
277
- except KeyError:
278
- self.__order[key] = None
279
-
280
-
281
285
  class RRCache(Cache):
282
286
  """Random Replacement (RR) cache implementation."""
283
287
 
284
288
  def __init__(self, maxsize, choice=random.choice, getsizeof=None):
285
289
  Cache.__init__(self, maxsize, getsizeof)
286
290
  self.__choice = choice
291
+ self.__index = {}
292
+ self.__keys = []
287
293
 
288
294
  @property
289
295
  def choice(self):
290
296
  """The `choice` function used by the cache."""
291
297
  return self.__choice
292
298
 
299
+ def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
300
+ cache_setitem(self, key, value)
301
+ if key not in self.__index:
302
+ self.__index[key] = len(self.__keys)
303
+ self.__keys.append(key)
304
+
305
+ def __delitem__(self, key, cache_delitem=Cache.__delitem__):
306
+ cache_delitem(self, key)
307
+ index = self.__index.pop(key)
308
+ if index != len(self.__keys) - 1:
309
+ last = self.__keys[-1]
310
+ self.__keys[index] = last
311
+ self.__index[last] = index
312
+ self.__keys.pop()
313
+
293
314
  def popitem(self):
294
315
  """Remove and return a random `(key, value)` pair."""
295
316
  try:
296
- key = self.__choice(list(self))
317
+ key = self.__choice(self.__keys)
297
318
  except IndexError:
298
319
  raise KeyError("%s is empty" % type(self).__name__) from None
299
320
  else:
@@ -636,11 +657,23 @@ _CacheInfo = collections.namedtuple(
636
657
  )
637
658
 
638
659
 
639
- def cached(cache, key=keys.hashkey, lock=None, info=False):
660
+ def cached(cache, key=keys.hashkey, lock=None, condition=None, info=False):
640
661
  """Decorator to wrap a function with a memoizing callable that saves
641
662
  results in a cache.
642
663
 
643
664
  """
665
+ from ._cached import _wrapper
666
+
667
+ if isinstance(condition, bool):
668
+ from warnings import warn
669
+
670
+ warn(
671
+ "passing `info` as positional parameter is deprecated",
672
+ DeprecationWarning,
673
+ stacklevel=2,
674
+ )
675
+ info = condition
676
+ condition = None
644
677
 
645
678
  def decorator(func):
646
679
  if info:
@@ -659,80 +692,21 @@ def cached(cache, key=keys.hashkey, lock=None, info=False):
659
692
  def make_info(hits, misses):
660
693
  return _CacheInfo(hits, misses, 0, 0)
661
694
 
662
- wrapper = _cached_wrapper(func, cache, key, lock, make_info)
695
+ return _wrapper(func, cache, key, lock, condition, info=make_info)
663
696
  else:
664
- wrapper = _cached_wrapper(func, cache, key, lock, None)
665
-
666
- wrapper.cache = cache
667
- wrapper.cache_key = key
668
- wrapper.cache_lock = lock
669
-
670
- return functools.update_wrapper(wrapper, func)
697
+ return _wrapper(func, cache, key, lock, condition)
671
698
 
672
699
  return decorator
673
700
 
674
701
 
675
- def cachedmethod(cache, key=keys.methodkey, lock=None):
702
+ def cachedmethod(cache, key=keys.methodkey, lock=None, condition=None):
676
703
  """Decorator to wrap a class or instance method with a memoizing
677
704
  callable that saves results in a cache.
678
705
 
679
706
  """
707
+ from ._cachedmethod import _wrapper
680
708
 
681
709
  def decorator(method):
682
- if lock is None:
683
-
684
- def wrapper(self, *args, **kwargs):
685
- c = cache(self)
686
- if c is None:
687
- return method(self, *args, **kwargs)
688
- k = key(self, *args, **kwargs)
689
- try:
690
- return c[k]
691
- except KeyError:
692
- pass # key not found
693
- v = method(self, *args, **kwargs)
694
- try:
695
- c[k] = v
696
- except ValueError:
697
- pass # value too large
698
- return v
699
-
700
- def clear(self):
701
- c = cache(self)
702
- if c is not None:
703
- c.clear()
704
-
705
- else:
706
-
707
- def wrapper(self, *args, **kwargs):
708
- c = cache(self)
709
- if c is None:
710
- return method(self, *args, **kwargs)
711
- k = key(self, *args, **kwargs)
712
- try:
713
- with lock(self):
714
- return c[k]
715
- except KeyError:
716
- pass # key not found
717
- v = method(self, *args, **kwargs)
718
- # in case of a race, prefer the item already in the cache
719
- try:
720
- with lock(self):
721
- return c.setdefault(k, v)
722
- except ValueError:
723
- return v # value too large
724
-
725
- def clear(self):
726
- c = cache(self)
727
- if c is not None:
728
- with lock(self):
729
- c.clear()
730
-
731
- wrapper.cache = cache
732
- wrapper.cache_key = key
733
- wrapper.cache_lock = lock
734
- wrapper.cache_clear = clear
735
-
736
- return functools.update_wrapper(wrapper, method)
710
+ return _wrapper(method, cache, key, lock, condition)
737
711
 
738
712
  return decorator
@@ -1,7 +1,53 @@
1
- """Extensible memoizing decorator helpers."""
1
+ """Function decorator helpers."""
2
2
 
3
+ import functools
3
4
 
4
- def _cached_locked_info(func, cache, key, lock, info):
5
+
6
+ def _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
+
50
+ def _locked_info(func, cache, key, lock, info):
5
51
  hits = misses = 0
6
52
 
7
53
  def wrapper(*args, **kwargs):
@@ -37,7 +83,7 @@ def _cached_locked_info(func, cache, key, lock, info):
37
83
  return wrapper
38
84
 
39
85
 
40
- def _cached_unlocked_info(func, cache, key, info):
86
+ def _unlocked_info(func, cache, key, info):
41
87
  hits = misses = 0
42
88
 
43
89
  def wrapper(*args, **kwargs):
@@ -83,7 +129,40 @@ def _uncached_info(func, info):
83
129
  return wrapper
84
130
 
85
131
 
86
- def _cached_locked(func, cache, key, lock):
132
+ def _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
+
165
+ def _locked(func, cache, key, lock):
87
166
  def wrapper(*args, **kwargs):
88
167
  k = key(*args, **kwargs)
89
168
  with lock:
@@ -107,7 +186,7 @@ def _cached_locked(func, cache, key, lock):
107
186
  return wrapper
108
187
 
109
188
 
110
- def _cached_unlocked(func, cache, key):
189
+ def _unlocked(func, cache, key):
111
190
  def wrapper(*args, **kwargs):
112
191
  k = key(*args, **kwargs)
113
192
  try:
@@ -133,20 +212,34 @@ def _uncached(func):
133
212
  return wrapper
134
213
 
135
214
 
136
- def _cached_wrapper(func, cache, key, lock, info):
215
+ def _wrapper(func, cache, key, lock=None, cond=None, info=None):
137
216
  if info is not None:
138
217
  if cache is None:
139
218
  wrapper = _uncached_info(func, info)
140
- elif lock is None:
141
- wrapper = _cached_unlocked_info(func, cache, key, 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)
142
225
  else:
143
- wrapper = _cached_locked_info(func, cache, key, lock, info)
226
+ wrapper = _unlocked_info(func, cache, key, info)
144
227
  else:
145
228
  if cache is None:
146
229
  wrapper = _uncached(func)
147
- elif lock is None:
148
- wrapper = _cached_unlocked(func, cache, key)
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)
149
236
  else:
150
- wrapper = _cached_locked(func, cache, key, lock)
237
+ wrapper = _unlocked(func, cache, key)
151
238
  wrapper.cache_info = None
152
- return wrapper
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)
@@ -0,0 +1,128 @@
1
+ """Method decorator helpers."""
2
+
3
+ import functools
4
+ import weakref
5
+
6
+
7
+ def warn_cache_none():
8
+ from warnings import warn
9
+
10
+ warn(
11
+ "returning `None` from `cache(self)` is deprecated",
12
+ DeprecationWarning,
13
+ stacklevel=3,
14
+ )
15
+
16
+
17
+ def _condition(method, cache, key, lock, cond):
18
+ pending = weakref.WeakKeyDictionary()
19
+
20
+ def wrapper(self, *args, **kwargs):
21
+ c = cache(self)
22
+ if c is None:
23
+ warn_cache_none()
24
+ return method(self, *args, **kwargs)
25
+ k = key(self, *args, **kwargs)
26
+ with lock(self):
27
+ p = pending.setdefault(self, set())
28
+ cond(self).wait_for(lambda: k not in p)
29
+ try:
30
+ return c[k]
31
+ except KeyError:
32
+ p.add(k)
33
+ try:
34
+ v = method(self, *args, **kwargs)
35
+ with lock(self):
36
+ try:
37
+ c[k] = v
38
+ except ValueError:
39
+ pass # value too large
40
+ return v
41
+ finally:
42
+ with lock(self):
43
+ pending[self].remove(k)
44
+ cond(self).notify_all()
45
+
46
+ def cache_clear(self):
47
+ c = cache(self)
48
+ if c is not None:
49
+ with lock(self):
50
+ c.clear()
51
+
52
+ wrapper.cache_clear = cache_clear
53
+ return wrapper
54
+
55
+
56
+ def _locked(method, cache, key, lock):
57
+ def wrapper(self, *args, **kwargs):
58
+ c = cache(self)
59
+ if c is None:
60
+ warn_cache_none()
61
+ return method(self, *args, **kwargs)
62
+ k = key(self, *args, **kwargs)
63
+ with lock(self):
64
+ try:
65
+ return c[k]
66
+ except KeyError:
67
+ pass # key not found
68
+ v = method(self, *args, **kwargs)
69
+ # in case of a race, prefer the item already in the cache
70
+ with lock(self):
71
+ try:
72
+ return c.setdefault(k, v)
73
+ except ValueError:
74
+ return v # value too large
75
+
76
+ def cache_clear(self):
77
+ c = cache(self)
78
+ if c is not None:
79
+ with lock(self):
80
+ c.clear()
81
+
82
+ wrapper.cache_clear = cache_clear
83
+ return wrapper
84
+
85
+
86
+ def _unlocked(method, cache, key):
87
+ def wrapper(self, *args, **kwargs):
88
+ c = cache(self)
89
+ if c is None:
90
+ warn_cache_none()
91
+ return method(self, *args, **kwargs)
92
+ k = key(self, *args, **kwargs)
93
+ try:
94
+ return c[k]
95
+ except KeyError:
96
+ pass # key not found
97
+ v = method(self, *args, **kwargs)
98
+ try:
99
+ c[k] = v
100
+ except ValueError:
101
+ pass # value too large
102
+ return v
103
+
104
+ def cache_clear(self):
105
+ c = cache(self)
106
+ if c is not None:
107
+ c.clear()
108
+
109
+ wrapper.cache_clear = cache_clear
110
+ return wrapper
111
+
112
+
113
+ def _wrapper(method, cache, key, lock=None, cond=None):
114
+ if cond is not None and lock is not None:
115
+ wrapper = _condition(method, cache, key, lock, cond)
116
+ elif cond is not None:
117
+ wrapper = _condition(method, cache, key, cond, cond)
118
+ elif lock is not None:
119
+ wrapper = _locked(method, cache, key, lock)
120
+ else:
121
+ wrapper = _unlocked(method, cache, key)
122
+
123
+ wrapper.cache = cache
124
+ wrapper.cache_key = key
125
+ wrapper.cache_lock = lock if lock is not None else cond
126
+ wrapper.cache_condition = cond
127
+
128
+ return functools.update_wrapper(wrapper, method)
@@ -1,17 +1,14 @@
1
1
  """`functools.lru_cache` compatible memoizing function decorators."""
2
2
 
3
- __all__ = ("fifo_cache", "lfu_cache", "lru_cache", "mru_cache", "rr_cache", "ttl_cache")
3
+ __all__ = ("fifo_cache", "lfu_cache", "lru_cache", "rr_cache", "ttl_cache")
4
4
 
5
+ import functools
5
6
  import math
6
7
  import random
7
8
  import time
9
+ from threading import Condition
8
10
 
9
- try:
10
- from threading import RLock
11
- except ImportError: # pragma: no cover
12
- from dummy_threading import RLock
13
-
14
- from . import FIFOCache, LFUCache, LRUCache, MRUCache, RRCache, TTLCache
11
+ from . import FIFOCache, LFUCache, LRUCache, RRCache, TTLCache
15
12
  from . import cached
16
13
  from . import keys
17
14
 
@@ -28,7 +25,7 @@ class _UnboundTTLCache(TTLCache):
28
25
  def _cache(cache, maxsize, typed):
29
26
  def decorator(func):
30
27
  key = keys.typedkey if typed else keys.hashkey
31
- wrapper = cached(cache=cache, key=key, lock=RLock(), info=True)(func)
28
+ wrapper = cached(cache=cache, key=key, condition=Condition(), info=True)(func)
32
29
  wrapper.cache_parameters = lambda: {"maxsize": maxsize, "typed": typed}
33
30
  return wrapper
34
31
 
@@ -77,23 +74,6 @@ def lru_cache(maxsize=128, typed=False):
77
74
  return _cache(LRUCache(maxsize), maxsize, typed)
78
75
 
79
76
 
80
- def mru_cache(maxsize=128, typed=False):
81
- """Decorator to wrap a function with a memoizing callable that saves
82
- up to `maxsize` results based on a Most Recently Used (MRU)
83
- algorithm.
84
- """
85
- from warnings import warn
86
-
87
- warn("@mru_cache is deprecated", DeprecationWarning, stacklevel=2)
88
-
89
- if maxsize is None:
90
- return _cache({}, None, typed)
91
- elif callable(maxsize):
92
- return _cache(MRUCache(128), 128, typed)(maxsize)
93
- else:
94
- return _cache(MRUCache(maxsize), maxsize, typed)
95
-
96
-
97
77
  def rr_cache(maxsize=128, choice=random.choice, typed=False):
98
78
  """Decorator to wrap a function with a memoizing callable that saves
99
79
  up to `maxsize` results based on a Random Replacement (RR)
@@ -1,4 +1,4 @@
1
1
  from .core import contents, where
2
2
 
3
3
  __all__ = ["contents", "where"]
4
- __version__ = "2025.08.03"
4
+ __version__ = "2025.10.05"
@@ -10,7 +10,7 @@ __all__ = [
10
10
  "__version__",
11
11
  ]
12
12
 
13
- __version__ = "46.0.1"
13
+ __version__ = "46.0.2"
14
14
 
15
15
 
16
16
  __author__ = "The Python Cryptographic Authority and individual contributors"