cachetools 6.2.5__tar.gz → 7.0.0__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.
- {cachetools-6.2.5 → cachetools-7.0.0}/CHANGELOG.rst +38 -0
- {cachetools-6.2.5/src/cachetools.egg-info → cachetools-7.0.0}/PKG-INFO +2 -3
- {cachetools-6.2.5 → cachetools-7.0.0}/docs/index.rst +84 -61
- {cachetools-6.2.5 → cachetools-7.0.0}/pyproject.toml +1 -2
- {cachetools-6.2.5 → cachetools-7.0.0}/src/cachetools/__init__.py +23 -15
- {cachetools-6.2.5 → cachetools-7.0.0}/src/cachetools/_cached.py +10 -1
- cachetools-7.0.0/src/cachetools/_cachedmethod.py +410 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/src/cachetools/func.py +3 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/src/cachetools/keys.py +7 -4
- {cachetools-6.2.5 → cachetools-7.0.0/src/cachetools.egg-info}/PKG-INFO +2 -3
- {cachetools-6.2.5 → cachetools-7.0.0}/src/cachetools.egg-info/SOURCES.txt +1 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/__init__.py +33 -2
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_cached.py +1 -35
- cachetools-7.0.0/tests/test_cachedmethod.py +675 -0
- cachetools-7.0.0/tests/test_classmethod.py +151 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_keys.py +1 -1
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_threading.py +21 -8
- cachetools-6.2.5/src/cachetools/_cachedmethod.py +0 -128
- cachetools-6.2.5/tests/test_cachedmethod.py +0 -434
- {cachetools-6.2.5 → cachetools-7.0.0}/LICENSE +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/MANIFEST.in +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/README.rst +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/docs/conf.py +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/setup.cfg +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/src/cachetools.egg-info/dependency_links.txt +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/src/cachetools.egg-info/top_level.txt +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_cache.py +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_fifo.py +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_func.py +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_lfu.py +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_lru.py +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_rr.py +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_tlru.py +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tests/test_ttl.py +0 -0
- {cachetools-6.2.5 → cachetools-7.0.0}/tox.ini +0 -0
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
v7.0.0 (2026-02-01)
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
- Require Python 3.10 or later (breaking change).
|
|
5
|
+
|
|
6
|
+
- Drop support for passing ``info`` as fourth positional parameter to
|
|
7
|
+
``@cached`` (breaking change).
|
|
8
|
+
|
|
9
|
+
- Drop support for ``cache(self)`` returning ``None`` with
|
|
10
|
+
``@cachedmethod`` (breaking change).
|
|
11
|
+
|
|
12
|
+
- Convert the ``@cachedmethod`` wrappers to descriptors, deprecating
|
|
13
|
+
its use with class methods and instances that do not provide a
|
|
14
|
+
mutable ``__dict__`` attribute (potentially breaking change).
|
|
15
|
+
|
|
16
|
+
- Convert the previously undocumented ``@cachedmethod`` attributes
|
|
17
|
+
(``cache``, ``cache_lock``, etc.) to properties for instance
|
|
18
|
+
methods, providing official support and documentation (potentially
|
|
19
|
+
breaking change).
|
|
20
|
+
|
|
21
|
+
- Add an optional ``info`` parameter to the ``@cachedmethod``
|
|
22
|
+
decorator for reporting per-instance cache statistics. Note that
|
|
23
|
+
this requires the instance's ``__dict__`` attribute to be a mutable
|
|
24
|
+
mapping.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
v6.2.6 (2026-01-27)
|
|
28
|
+
===================
|
|
29
|
+
|
|
30
|
+
- Improve typedkey performance.
|
|
31
|
+
|
|
32
|
+
- Minor documentation improvements.
|
|
33
|
+
|
|
34
|
+
- Minor testing improvements.
|
|
35
|
+
|
|
36
|
+
- Minor code readability improvements.
|
|
37
|
+
|
|
38
|
+
|
|
1
39
|
v6.2.5 (2026-01-25)
|
|
2
40
|
===================
|
|
3
41
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cachetools
|
|
3
|
-
Version:
|
|
3
|
+
Version: 7.0.0
|
|
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>
|
|
@@ -11,14 +11,13 @@ Classifier: Intended Audience :: Developers
|
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Programming Language :: Python
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.14
|
|
20
19
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
22
21
|
Description-Content-Type: text/x-rst
|
|
23
22
|
License-File: LICENSE
|
|
24
23
|
Dynamic: license-file
|
|
@@ -26,6 +26,7 @@ method calls.
|
|
|
26
26
|
from unittest import mock
|
|
27
27
|
urllib = mock.MagicMock()
|
|
28
28
|
|
|
29
|
+
import threading
|
|
29
30
|
import time
|
|
30
31
|
|
|
31
32
|
|
|
@@ -35,11 +36,11 @@ Cache implementations
|
|
|
35
36
|
This module provides several classes implementing caches using
|
|
36
37
|
different cache algorithms. All these classes derive from class
|
|
37
38
|
:class:`Cache`, which in turn derives from
|
|
38
|
-
:class:`collections.MutableMapping`, and provide :attr:`maxsize`
|
|
39
|
-
:attr:`currsize` properties to retrieve the maximum and current
|
|
40
|
-
of the cache. When a cache is full, :meth:`Cache.__setitem__()`
|
|
41
|
-
:meth:`self.popitem()` repeatedly until there is enough room for
|
|
42
|
-
item to be added.
|
|
39
|
+
:class:`collections.abc.MutableMapping`, and provide :attr:`maxsize`
|
|
40
|
+
and :attr:`currsize` properties to retrieve the maximum and current
|
|
41
|
+
size of the cache. When a cache is full, :meth:`Cache.__setitem__()`
|
|
42
|
+
calls :meth:`self.popitem()` repeatedly until there is enough room for
|
|
43
|
+
the item to be added.
|
|
43
44
|
|
|
44
45
|
.. note::
|
|
45
46
|
|
|
@@ -53,8 +54,9 @@ returns the size of a given `value`. The default implementation of
|
|
|
53
54
|
:meth:`getsizeof` returns :const:`1` irrespective of its argument,
|
|
54
55
|
making the cache's size equal to the number of its items, or
|
|
55
56
|
`len(cache)`. For convenience, all cache classes accept an optional
|
|
56
|
-
named constructor parameter `getsizeof`, which may specify a
|
|
57
|
-
|
|
57
|
+
named constructor parameter `getsizeof`, which may specify a callable
|
|
58
|
+
``getsizeof(value) -> int`` used to retrieve the size of an item's
|
|
59
|
+
value.
|
|
58
60
|
|
|
59
61
|
The values of a :class:`Cache` are mutable by default, as are e.g. the
|
|
60
62
|
values of a :class:`dict`. It is the user's responsibility to take
|
|
@@ -214,7 +216,6 @@ all cache implementations call :meth:`popitem` to evict items from the
|
|
|
214
216
|
cache, this can be achieved by overriding this method in a subclass:
|
|
215
217
|
|
|
216
218
|
.. doctest::
|
|
217
|
-
:pyversion: >= 3
|
|
218
219
|
|
|
219
220
|
>>> class MyCache(LRUCache):
|
|
220
221
|
... def popitem(self):
|
|
@@ -236,7 +237,6 @@ pairs. By overriding :meth:`expire`, a subclass will be able to track
|
|
|
236
237
|
expired items:
|
|
237
238
|
|
|
238
239
|
.. doctest::
|
|
239
|
-
:pyversion: >= 3
|
|
240
240
|
|
|
241
241
|
>>> class ExpCache(TTLCache):
|
|
242
242
|
... def expire(self, time=None):
|
|
@@ -259,7 +259,6 @@ method which is called by :meth:`Cache.__getitem__` if the requested
|
|
|
259
259
|
key is not found:
|
|
260
260
|
|
|
261
261
|
.. doctest::
|
|
262
|
-
:pyversion: >= 3
|
|
263
262
|
|
|
264
263
|
>>> class PepStore(LRUCache):
|
|
265
264
|
... def __missing__(self, key):
|
|
@@ -363,10 +362,8 @@ often called with the same arguments:
|
|
|
363
362
|
|
|
364
363
|
.. testcode::
|
|
365
364
|
|
|
366
|
-
from threading import Lock
|
|
367
|
-
|
|
368
365
|
# 640K should be enough for anyone...
|
|
369
|
-
@cached(cache=LRUCache(maxsize=640*1024, getsizeof=len), lock=Lock())
|
|
366
|
+
@cached(cache=LRUCache(maxsize=640*1024, getsizeof=len), lock=threading.Lock())
|
|
370
367
|
def get_pep(num):
|
|
371
368
|
'Retrieve text of a Python Enhancement Proposal'
|
|
372
369
|
url = 'http://www.python.org/dev/peps/pep-%04d/' % num
|
|
@@ -401,7 +398,6 @@ often called with the same arguments:
|
|
|
401
398
|
to be enabled explicitly.
|
|
402
399
|
|
|
403
400
|
.. doctest::
|
|
404
|
-
:pyversion: >= 3
|
|
405
401
|
|
|
406
402
|
>>> @cached(cache=LRUCache(maxsize=32), info=True)
|
|
407
403
|
... def get_pep(num):
|
|
@@ -495,7 +491,6 @@ often called with the same arguments:
|
|
|
495
491
|
invocations, with separately cached results:
|
|
496
492
|
|
|
497
493
|
.. doctest::
|
|
498
|
-
:pyversion: >= 3
|
|
499
494
|
|
|
500
495
|
>>> @cached(LRUCache(maxsize=100))
|
|
501
496
|
... def foo(a=1):
|
|
@@ -515,7 +510,6 @@ often called with the same arguments:
|
|
|
515
510
|
be introduced to avoid ambiguities, e.g.:
|
|
516
511
|
|
|
517
512
|
.. doctest::
|
|
518
|
-
:pyversion: >= 3
|
|
519
513
|
|
|
520
514
|
>>> def foo(a=1):
|
|
521
515
|
... _foo(a)
|
|
@@ -531,17 +525,16 @@ often called with the same arguments:
|
|
|
531
525
|
>>> foo(a=1)
|
|
532
526
|
|
|
533
527
|
|
|
534
|
-
.. decorator:: cachedmethod(cache, key=cachetools.keys.methodkey, lock=None, condition=None)
|
|
528
|
+
.. decorator:: cachedmethod(cache, key=cachetools.keys.methodkey, lock=None, condition=None, info=False)
|
|
535
529
|
|
|
536
|
-
Decorator to wrap
|
|
537
|
-
|
|
530
|
+
Decorator to wrap an instance method with a memoizing callable that
|
|
531
|
+
saves results in a cache.
|
|
538
532
|
|
|
539
533
|
The main difference between this and the :func:`cached` function
|
|
540
534
|
decorator is that `cache`, `lock` and `condition` are not passed
|
|
541
|
-
objects, but functions. Those will be called with :const:`self`
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
respective instance or class.
|
|
535
|
+
objects, but functions. Those will be called with :const:`self` as
|
|
536
|
+
their sole argument to retrieve a valid cache, lock, or condition
|
|
537
|
+
object for the respective instance.
|
|
545
538
|
|
|
546
539
|
.. note::
|
|
547
540
|
|
|
@@ -550,55 +543,63 @@ often called with the same arguments:
|
|
|
550
543
|
the user's responsibility to handle concurrent calls to the
|
|
551
544
|
underlying wrapped method in a multithreaded environment.
|
|
552
545
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
546
|
+
Similarly to the :func:`cached` function decorator, the `cache`,
|
|
547
|
+
`key`, `lock` and `condition` parameters are also available as
|
|
548
|
+
:attr:`cache`, :attr:`cache_key`, :attr:`cache_lock` and
|
|
549
|
+
:attr:`cache_condition` attributes of the wrapped instance method.
|
|
550
|
+
A :func:`cache_clear()` function will also be provided, as well as
|
|
551
|
+
an optional :func:`cache_info()` function reporting per-instance
|
|
552
|
+
cache statistics.
|
|
558
553
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
You may provide a different `key` function,
|
|
565
|
-
e.g. :func:`cachetools.keys.hashkey`, if you need :const:`self` to
|
|
566
|
-
be part of the cache key.
|
|
554
|
+
Also, mostly for efficiency, this decorator requires that the
|
|
555
|
+
:attr:`__dict__` attribute on each instance be a mutable mapping.
|
|
556
|
+
This means it will not work with some types, such as metaclasses,
|
|
557
|
+
and those that specify :attr:`__slots__` without including
|
|
558
|
+
:attr:`__dict__` as one of the defined slots.
|
|
567
559
|
|
|
568
560
|
One advantage of :func:`cachedmethod` over the :func:`cached`
|
|
569
561
|
function decorator is that cache properties such as `maxsize` can
|
|
570
562
|
be set at runtime:
|
|
571
563
|
|
|
572
|
-
..
|
|
564
|
+
.. doctest::
|
|
573
565
|
|
|
574
|
-
|
|
575
|
-
|
|
566
|
+
>>> class CachedPEPs:
|
|
567
|
+
... def __init__(self, cachesize):
|
|
568
|
+
... self.cache = LRUCache(maxsize=cachesize)
|
|
569
|
+
... self.lock = threading.Lock()
|
|
570
|
+
...
|
|
571
|
+
... @cachedmethod(lambda self: self.cache, lock=lambda self: self.lock, info=True)
|
|
572
|
+
... def get(self, num):
|
|
573
|
+
... """Retrieve text of a Python Enhancement Proposal"""
|
|
574
|
+
... url = 'http://www.python.org/dev/peps/pep-%04d/' % num
|
|
575
|
+
... with urllib.request.urlopen(url) as s:
|
|
576
|
+
... return s.read()
|
|
577
|
+
|
|
578
|
+
>>> peps = CachedPEPs(cachesize=32)
|
|
579
|
+
>>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:
|
|
580
|
+
... pep = peps.get(n)
|
|
576
581
|
|
|
577
|
-
|
|
582
|
+
>>> peps.get.cache_info()
|
|
583
|
+
CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)
|
|
578
584
|
|
|
579
|
-
|
|
580
|
-
self.cache = LRUCache(maxsize=cachesize)
|
|
581
|
-
self.lock = Lock()
|
|
585
|
+
>>> peps.get.cache_clear()
|
|
582
586
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
"""Retrieve text of a Python Enhancement Proposal"""
|
|
586
|
-
url = 'http://www.python.org/dev/peps/pep-%04d/' % num
|
|
587
|
-
with urllib.request.urlopen(url) as s:
|
|
588
|
-
return s.read()
|
|
589
|
-
|
|
590
|
-
peps = CachedPEPs(cachesize=10)
|
|
591
|
-
print("PEP #1: %s" % peps.get(1))
|
|
587
|
+
>>> peps.get.cache_info()
|
|
588
|
+
CacheInfo(hits=0, misses=0, maxsize=32, currsize=0)
|
|
592
589
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
590
|
+
The `key` function will be called as `key(self, *args, **kwargs)`
|
|
591
|
+
to retrieve a suitable cache key. Note that the default `key`
|
|
592
|
+
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.
|
|
596
595
|
|
|
597
|
-
|
|
596
|
+
You may provide a different `key` function,
|
|
597
|
+
e.g. :func:`cachetools.keys.hashkey`, if you need :const:`self` to
|
|
598
|
+
be part of the cache key.
|
|
598
599
|
|
|
599
600
|
When using a shared cache for multiple methods, be aware that
|
|
600
601
|
different cache keys must be created for each method even when
|
|
601
|
-
function arguments are the same, just as with the
|
|
602
|
+
function arguments are the same, just as with the :func:`cached`
|
|
602
603
|
decorator:
|
|
603
604
|
|
|
604
605
|
.. testcode::
|
|
@@ -641,11 +642,33 @@ often called with the same arguments:
|
|
|
641
642
|
to create distinct cache keys, to avoid issues with
|
|
642
643
|
:func:`methodkey` skipping its initial `self` argument.
|
|
643
644
|
|
|
644
|
-
..
|
|
645
|
+
.. versionchanged:: 7.0
|
|
646
|
+
|
|
647
|
+
Added the `info` option for reporting per-instance cache
|
|
648
|
+
statistics.
|
|
649
|
+
|
|
650
|
+
:func:`cachedmethod` attributes (:attr:`cache`, :attr:`cache_lock`,
|
|
651
|
+
etc.) are now implemented as properties for instance methods, and
|
|
652
|
+
are finally officially supported.
|
|
653
|
+
|
|
654
|
+
Require :attr:`__dict__` to be a mutable mapping to support
|
|
655
|
+
per-instance :func:`cache_info()`.
|
|
656
|
+
|
|
657
|
+
Returning :const:`None` from `cache(self)` is no longer supported.
|
|
658
|
+
|
|
659
|
+
.. deprecated:: 7.0
|
|
660
|
+
|
|
661
|
+
Using :func:`cachedmethod` with :func:`classmethod` is deprecated,
|
|
662
|
+
and support will be removed in the next major version. This is
|
|
663
|
+
mostly due to the fact that chaining descriptors, i.e. using
|
|
664
|
+
descriptors with :func:`classmethod`, was deprecated in Python 3.11
|
|
665
|
+
and removed in Python 3.13. When using :func:`cache_info()`, an
|
|
666
|
+
instance method is already required.
|
|
645
667
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
668
|
+
Using :func:`cachedmethod` with an instance that does not provide a
|
|
669
|
+
mutable :attr:`__dict__` attribute is deprecated, and may inflict a
|
|
670
|
+
noticeable performance penalty. When using :func:`cache_info()`,
|
|
671
|
+
:attr:`__dict__` already has to be a mutable mapping.
|
|
649
672
|
|
|
650
673
|
|
|
651
674
|
*****************************************************************
|
|
@@ -15,14 +15,13 @@ maintainers = [
|
|
|
15
15
|
readme = "README.rst"
|
|
16
16
|
license = "MIT"
|
|
17
17
|
license-files = ["LICENSE"]
|
|
18
|
-
requires-python = ">= 3.
|
|
18
|
+
requires-python = ">= 3.10"
|
|
19
19
|
classifiers = [
|
|
20
20
|
"Development Status :: 5 - Production/Stable",
|
|
21
21
|
"Intended Audience :: Developers",
|
|
22
22
|
"Operating System :: OS Independent",
|
|
23
23
|
"Programming Language :: Python",
|
|
24
24
|
"Programming Language :: Python :: 3",
|
|
25
|
-
"Programming Language :: Python :: 3.9",
|
|
26
25
|
"Programming Language :: Python :: 3.10",
|
|
27
26
|
"Programming Language :: Python :: 3.11",
|
|
28
27
|
"Programming Language :: Python :: 3.12",
|
|
@@ -12,7 +12,7 @@ __all__ = (
|
|
|
12
12
|
"cachedmethod",
|
|
13
13
|
)
|
|
14
14
|
|
|
15
|
-
__version__ = "
|
|
15
|
+
__version__ = "7.0.0"
|
|
16
16
|
|
|
17
17
|
import collections
|
|
18
18
|
import collections.abc
|
|
@@ -23,8 +23,13 @@ import time
|
|
|
23
23
|
|
|
24
24
|
from . import keys
|
|
25
25
|
|
|
26
|
+
# Typing stubs for this package are provided by typeshed:
|
|
27
|
+
# https://github.com/python/typeshed/tree/main/stubs/cachetools
|
|
28
|
+
|
|
26
29
|
|
|
27
30
|
class _DefaultSize:
|
|
31
|
+
"""A minimal "fake" dict that returns a constant size 1 for any key."""
|
|
32
|
+
|
|
28
33
|
__slots__ = ()
|
|
29
34
|
|
|
30
35
|
def __getitem__(self, _key):
|
|
@@ -540,6 +545,8 @@ class TTLCache(_TimedCache):
|
|
|
540
545
|
class TLRUCache(_TimedCache):
|
|
541
546
|
"""Time aware Least Recently Used (TLRU) cache implementation."""
|
|
542
547
|
|
|
548
|
+
__HEAP_CLEANUP_FACTOR = 2 # clean up the heap if size > N * len(items)
|
|
549
|
+
|
|
543
550
|
@functools.total_ordering
|
|
544
551
|
class _Item:
|
|
545
552
|
__slots__ = ("key", "expires", "removed")
|
|
@@ -625,7 +632,7 @@ class TLRUCache(_TimedCache):
|
|
|
625
632
|
items = self.__items
|
|
626
633
|
order = self.__order
|
|
627
634
|
# clean up the heap if too many items are marked as removed
|
|
628
|
-
if len(order) > len(items) *
|
|
635
|
+
if len(order) > len(items) * self.__HEAP_CLEANUP_FACTOR:
|
|
629
636
|
self.__order = order = [item for item in order if not item.removed]
|
|
630
637
|
heapq.heapify(order)
|
|
631
638
|
expired = []
|
|
@@ -671,17 +678,6 @@ def cached(cache, key=keys.hashkey, lock=None, condition=None, info=False):
|
|
|
671
678
|
"""
|
|
672
679
|
from ._cached import _wrapper
|
|
673
680
|
|
|
674
|
-
if isinstance(condition, bool):
|
|
675
|
-
from warnings import warn
|
|
676
|
-
|
|
677
|
-
warn(
|
|
678
|
-
"passing `info` as positional parameter is deprecated",
|
|
679
|
-
DeprecationWarning,
|
|
680
|
-
stacklevel=2,
|
|
681
|
-
)
|
|
682
|
-
info = condition
|
|
683
|
-
condition = None
|
|
684
|
-
|
|
685
681
|
def decorator(func):
|
|
686
682
|
if info:
|
|
687
683
|
if isinstance(cache, Cache):
|
|
@@ -706,7 +702,7 @@ def cached(cache, key=keys.hashkey, lock=None, condition=None, info=False):
|
|
|
706
702
|
return decorator
|
|
707
703
|
|
|
708
704
|
|
|
709
|
-
def cachedmethod(cache, key=keys.methodkey, lock=None, condition=None):
|
|
705
|
+
def cachedmethod(cache, key=keys.methodkey, lock=None, condition=None, info=False):
|
|
710
706
|
"""Decorator to wrap a class or instance method with a memoizing
|
|
711
707
|
callable that saves results in a cache.
|
|
712
708
|
|
|
@@ -714,6 +710,18 @@ def cachedmethod(cache, key=keys.methodkey, lock=None, condition=None):
|
|
|
714
710
|
from ._cachedmethod import _wrapper
|
|
715
711
|
|
|
716
712
|
def decorator(method):
|
|
717
|
-
|
|
713
|
+
if info:
|
|
714
|
+
|
|
715
|
+
def make_info(cache, hits, misses):
|
|
716
|
+
if isinstance(cache, Cache):
|
|
717
|
+
return _CacheInfo(hits, misses, cache.maxsize, cache.currsize)
|
|
718
|
+
elif isinstance(cache, collections.abc.Mapping):
|
|
719
|
+
return _CacheInfo(hits, misses, None, len(cache))
|
|
720
|
+
else:
|
|
721
|
+
raise TypeError("cache(self) must return a mutable mapping")
|
|
722
|
+
|
|
723
|
+
return _wrapper(method, cache, key, lock, condition, info=make_info)
|
|
724
|
+
else:
|
|
725
|
+
return _wrapper(method, cache, key, lock, condition)
|
|
718
726
|
|
|
719
727
|
return decorator
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
"""Function decorator helpers."""
|
|
2
2
|
|
|
3
|
+
__all__ = ()
|
|
4
|
+
|
|
3
5
|
import functools
|
|
4
6
|
|
|
7
|
+
# At least for now, the implementation prefers clarity and performance
|
|
8
|
+
# over ease of maintenance, thus providing separate wrappers for
|
|
9
|
+
# all valid combinations of decorator parameters lock, condition and
|
|
10
|
+
# info.
|
|
11
|
+
|
|
5
12
|
|
|
6
13
|
def _condition_info(func, cache, key, lock, cond, info):
|
|
7
14
|
hits = misses = 0
|
|
@@ -178,7 +185,9 @@ def _locked(func, cache, key, lock):
|
|
|
178
185
|
v = func(*args, **kwargs)
|
|
179
186
|
with lock:
|
|
180
187
|
try:
|
|
181
|
-
#
|
|
188
|
+
# In case of a race condition, i.e. if another thread
|
|
189
|
+
# stored a value for this key while we were calling
|
|
190
|
+
# func(), prefer the cached value.
|
|
182
191
|
return cache.setdefault(k, v)
|
|
183
192
|
except ValueError:
|
|
184
193
|
return v # value too large
|