cachetools 7.0.2__tar.gz → 7.0.4__tar.gz

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 (33) hide show
  1. {cachetools-7.0.2 → cachetools-7.0.4}/CHANGELOG.rst +15 -0
  2. {cachetools-7.0.2/src/cachetools.egg-info → cachetools-7.0.4}/PKG-INFO +1 -1
  3. {cachetools-7.0.2 → cachetools-7.0.4}/docs/index.rst +15 -8
  4. {cachetools-7.0.2 → cachetools-7.0.4}/src/cachetools/__init__.py +3 -3
  5. {cachetools-7.0.2 → cachetools-7.0.4}/src/cachetools/_cachedmethod.py +10 -5
  6. {cachetools-7.0.2 → cachetools-7.0.4/src/cachetools.egg-info}/PKG-INFO +1 -1
  7. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_cachedmethod.py +28 -6
  8. {cachetools-7.0.2 → cachetools-7.0.4}/LICENSE +0 -0
  9. {cachetools-7.0.2 → cachetools-7.0.4}/MANIFEST.in +0 -0
  10. {cachetools-7.0.2 → cachetools-7.0.4}/README.rst +0 -0
  11. {cachetools-7.0.2 → cachetools-7.0.4}/docs/conf.py +0 -0
  12. {cachetools-7.0.2 → cachetools-7.0.4}/pyproject.toml +0 -0
  13. {cachetools-7.0.2 → cachetools-7.0.4}/setup.cfg +0 -0
  14. {cachetools-7.0.2 → cachetools-7.0.4}/src/cachetools/_cached.py +0 -0
  15. {cachetools-7.0.2 → cachetools-7.0.4}/src/cachetools/func.py +0 -0
  16. {cachetools-7.0.2 → cachetools-7.0.4}/src/cachetools/keys.py +0 -0
  17. {cachetools-7.0.2 → cachetools-7.0.4}/src/cachetools.egg-info/SOURCES.txt +0 -0
  18. {cachetools-7.0.2 → cachetools-7.0.4}/src/cachetools.egg-info/dependency_links.txt +0 -0
  19. {cachetools-7.0.2 → cachetools-7.0.4}/src/cachetools.egg-info/top_level.txt +0 -0
  20. {cachetools-7.0.2 → cachetools-7.0.4}/tests/__init__.py +0 -0
  21. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_cache.py +0 -0
  22. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_cached.py +0 -0
  23. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_classmethod.py +0 -0
  24. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_fifo.py +0 -0
  25. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_func.py +0 -0
  26. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_keys.py +0 -0
  27. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_lfu.py +0 -0
  28. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_lru.py +0 -0
  29. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_rr.py +0 -0
  30. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_threading.py +0 -0
  31. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_tlru.py +0 -0
  32. {cachetools-7.0.2 → cachetools-7.0.4}/tests/test_ttl.py +0 -0
  33. {cachetools-7.0.2 → cachetools-7.0.4}/tox.ini +0 -0
@@ -1,3 +1,18 @@
1
+ v7.0.4 (2026-03-08)
2
+ ===================
3
+
4
+ - Fix and properly document ``@cachedmethod.cache_key`` behavior.
5
+
6
+ - Minor documentation improvements.
7
+
8
+
9
+ v7.0.3 (2026-03-05)
10
+ ===================
11
+
12
+ - Fix ``DeprecationWarning`` when creating an autospec mock with
13
+ ``@cachedmethod`` decorations.
14
+
15
+
1
16
  v7.0.2 (2026-03-02)
2
17
  ===================
3
18
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cachetools
3
- Version: 7.0.2
3
+ Version: 7.0.4
4
4
  Summary: Extensible memoizing collections and decorators
5
5
  Author-email: Thomas Kemmer <tkemmer@computer.org>
6
6
  Maintainer-email: Thomas Kemmer <tkemmer@computer.org>
@@ -370,13 +370,10 @@ often called with the same arguments:
370
370
  with urllib.request.urlopen(url) as s:
371
371
  return s.read()
372
372
 
373
- # make sure access to cache is synchronized
373
+ # remove (pop) an individual cached PEP from the cache
374
+ key = get_pep.cache_key(42)
374
375
  with get_pep.cache_lock:
375
- get_pep.cache.clear()
376
-
377
- # always use the key function for accessing cache items
378
- with get_pep.cache_lock:
379
- get_pep.cache.pop(get_pep.cache_key(42), None)
376
+ get_pep.cache.pop(key, None)
380
377
 
381
378
  For the common use case of clearing or invalidating the cache, the
382
379
  decorator also provides a :func:`cache_clear()` function which
@@ -582,6 +579,15 @@ often called with the same arguments:
582
579
  >>> peps.get.cache_info()
583
580
  CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)
584
581
 
582
+ >>> # remove an individual cached PEP from the cache
583
+ >>> key = peps.get.cache_key(320)
584
+ >>> with peps.get.cache_lock:
585
+ ... del peps.get.cache[key]
586
+
587
+ >>> peps.get.cache_info()
588
+ CacheInfo(hits=3, misses=8, maxsize=32, currsize=7)
589
+
590
+ >>> # remove all cached PEPs and clear cache info
585
591
  >>> peps.get.cache_clear()
586
592
 
587
593
  >>> peps.get.cache_info()
@@ -590,8 +596,9 @@ often called with the same arguments:
590
596
  The `key` function will be called as `key(self, *args, **kwargs)`
591
597
  to retrieve a suitable cache key. Note that the default `key`
592
598
  function, :func:`cachetools.keys.methodkey`, ignores its first
593
- argument, i.e. :const:`self`. This has mostly historical reasons,
594
- but also ensures that :const:`self` does not have to be hashable.
599
+ implicit argument, i.e. :const:`self`. This has mostly historical
600
+ reasons, but also ensures that :const:`self` does not have to be
601
+ hashable.
595
602
 
596
603
  You may provide a different `key` function,
597
604
  e.g. :func:`cachetools.keys.hashkey`, if you need :const:`self` to
@@ -12,7 +12,7 @@ __all__ = (
12
12
  "cachedmethod",
13
13
  )
14
14
 
15
- __version__ = "7.0.2"
15
+ __version__ = "7.0.4"
16
16
 
17
17
  import collections
18
18
  import collections.abc
@@ -748,8 +748,8 @@ def cached(cache, key=keys.hashkey, lock=None, condition=None, info=False):
748
748
 
749
749
 
750
750
  def cachedmethod(cache, key=keys.methodkey, lock=None, condition=None, info=False):
751
- """Decorator to wrap a class or instance method with a memoizing
752
- callable that saves results in a cache.
751
+ """Decorator to wrap a method with a memoizing callable that saves
752
+ results in a cache.
753
753
 
754
754
  """
755
755
  from ._cachedmethod import _wrapper
@@ -48,7 +48,7 @@ class _WrapperBase:
48
48
 
49
49
  @property
50
50
  def cache_key(self):
51
- return self.__key
51
+ return functools.partial(self.__key, self._obj)
52
52
 
53
53
  @property
54
54
  def cache_lock(self):
@@ -77,7 +77,12 @@ class _DescriptorBase:
77
77
 
78
78
  def __get__(self, obj, objtype=None):
79
79
  wrapper = self.Wrapper(obj)
80
- if self.__attrname is not None:
80
+ if obj is None:
81
+ # Return the wrapper itself without modification when accessed
82
+ # through the class to support class-level introspection, such
83
+ # as for mocking with autospec=True in unittest.mock.
84
+ pass
85
+ elif self.__attrname is not None:
81
86
  # replace descriptor instance with wrapper in instance dict
82
87
  try:
83
88
  # In case of a race condition where another thread already replaced
@@ -148,7 +153,7 @@ def _condition_info(method, cache, key, lock, cond, info):
148
153
  cache = self.cache
149
154
  lock = self.cache_lock
150
155
  cond = self.cache_condition
151
- key = self.cache_key(self._obj, *args, **kwargs)
156
+ key = self.cache_key(*args, **kwargs)
152
157
 
153
158
  with lock:
154
159
  cond.wait_for(lambda: key not in self.__pending)
@@ -194,7 +199,7 @@ def _locked_info(method, cache, key, lock, info):
194
199
  def __call__(self, *args, **kwargs):
195
200
  cache = self.cache
196
201
  lock = self.cache_lock
197
- key = self.cache_key(self._obj, *args, **kwargs)
202
+ key = self.cache_key(*args, **kwargs)
198
203
  with lock:
199
204
  try:
200
205
  result = cache[key]
@@ -233,7 +238,7 @@ def _unlocked_info(method, cache, key, info):
233
238
 
234
239
  def __call__(self, *args, **kwargs):
235
240
  cache = self.cache
236
- key = self.cache_key(self._obj, *args, **kwargs)
241
+ key = self.cache_key(*args, **kwargs)
237
242
  try:
238
243
  result = cache[key]
239
244
  self.__hits += 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cachetools
3
- Version: 7.0.2
3
+ Version: 7.0.4
4
4
  Summary: Extensible memoizing collections and decorators
5
5
  Author-email: Thomas Kemmer <tkemmer@computer.org>
6
6
  Maintainer-email: Thomas Kemmer <tkemmer@computer.org>
@@ -1,4 +1,5 @@
1
1
  import unittest
2
+ import unittest.mock
2
3
  import warnings
3
4
 
4
5
 
@@ -369,24 +370,26 @@ class MethodDecoratorTestMixin:
369
370
  cached = Cached(cache)
370
371
 
371
372
  self.assertIs(cached.get.cache, cache)
372
- self.assertIs(cached.get.cache_key, keys.methodkey)
373
373
  self.assertIs(cached.get.cache_lock, None)
374
374
  self.assertIs(cached.get.cache_condition, None)
375
+ self.assertEqual(cached.get.cache_key(42), keys.methodkey(cached, 42))
375
376
 
376
377
  self.assertIs(cached.get_lock.cache, cache)
377
- self.assertIs(cached.get_lock.cache_key, keys.methodkey)
378
378
  self.assertIs(cached.get_lock.cache_lock, cached.lock)
379
379
  self.assertIs(cached.get_lock.cache_condition, None)
380
+ self.assertEqual(cached.get_lock.cache_key(42), keys.methodkey(cached, 42))
380
381
 
381
382
  self.assertIs(cached.get_cond.cache, cache)
382
- self.assertIs(cached.get_cond.cache_key, keys.methodkey)
383
383
  self.assertIs(cached.get_cond.cache_lock, cached.cond)
384
384
  self.assertIs(cached.get_cond.cache_condition, cached.cond)
385
+ self.assertEqual(cached.get_cond.cache_key(42), keys.methodkey(cached, 42))
385
386
 
386
387
  self.assertIs(cached.get_lock_cond_info.cache, cache)
387
- self.assertIs(cached.get_lock_cond_info.cache_key, keys.methodkey)
388
388
  self.assertIs(cached.get_lock_cond_info.cache_lock, cached.lock)
389
389
  self.assertIs(cached.get_lock_cond_info.cache_condition, cached.cond)
390
+ self.assertEqual(
391
+ cached.get_lock_cond_info.cache_key(42), keys.methodkey(cached, 42)
392
+ )
390
393
 
391
394
  def test_decorator_clear(self):
392
395
  cache = self.cache(2)
@@ -602,15 +605,25 @@ class CacheMethodTest(unittest.TestCase, MethodDecoratorTestMixin):
602
605
  self.assertEqual(cached1.get_info.cache_info(), (0, 0, 2, 0))
603
606
  self.assertEqual(cached2.get_info.cache_info(), (0, 0, 2, 0))
604
607
 
608
+ # hits/misses are counted by instance
605
609
  self.assertEqual(cached1.get_info(0), 0)
606
-
607
610
  self.assertEqual(cached1.get_info.cache_info(), (0, 1, 2, 1))
608
611
  self.assertEqual(cached2.get_info.cache_info(), (0, 0, 2, 1))
609
612
 
613
+ # default methodkey discards "self", so results will be shared
614
+ # across instances
610
615
  self.assertEqual(cached2.get_info(0), 0)
611
-
612
616
  self.assertEqual(cached1.get_info.cache_info(), (0, 1, 2, 1))
613
617
  self.assertEqual(cached2.get_info.cache_info(), (1, 0, 2, 1))
618
+ self.assertEqual(cached1.get_info(0), 0)
619
+ self.assertEqual(cached1.get_info.cache_info(), (1, 1, 2, 1))
620
+ self.assertEqual(cached2.get_info.cache_info(), (1, 0, 2, 1))
621
+ self.assertEqual(cached1.get_info(1), 1)
622
+ self.assertEqual(cached1.get_info.cache_info(), (1, 2, 2, 2))
623
+ self.assertEqual(cached2.get_info.cache_info(), (1, 0, 2, 2))
624
+ self.assertEqual(cached2.get_info(1), 1)
625
+ self.assertEqual(cached1.get_info.cache_info(), (1, 2, 2, 2))
626
+ self.assertEqual(cached2.get_info.cache_info(), (2, 0, 2, 2))
614
627
 
615
628
  def test_value_too_large(self):
616
629
  cache = self.cache(1, getsizeof=lambda x: x)
@@ -673,3 +686,12 @@ class NoneMethodTest(unittest.TestCase):
673
686
 
674
687
  with self.assertRaises(TypeError):
675
688
  wrapper.cache_info()
689
+
690
+
691
+ class AutospecTest(unittest.TestCase):
692
+ def test_autospec_no_warnings(self):
693
+
694
+ with warnings.catch_warnings(record=True) as w:
695
+ warnings.simplefilter("always")
696
+ unittest.mock.create_autospec(Cached, instance=True)
697
+ self.assertEqual(len(w), 0)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes