cachetools 6.2.6__tar.gz → 7.0.1__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.6 → cachetools-7.0.1}/CHANGELOG.rst +34 -0
- {cachetools-6.2.6/src/cachetools.egg-info → cachetools-7.0.1}/PKG-INFO +2 -3
- {cachetools-6.2.6 → cachetools-7.0.1}/docs/index.rst +76 -54
- {cachetools-6.2.6 → cachetools-7.0.1}/pyproject.toml +1 -2
- {cachetools-6.2.6 → cachetools-7.0.1}/src/cachetools/__init__.py +20 -14
- {cachetools-6.2.6 → cachetools-7.0.1}/src/cachetools/_cached.py +10 -1
- cachetools-7.0.1/src/cachetools/_cachedmethod.py +410 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/src/cachetools/keys.py +1 -1
- {cachetools-6.2.6 → cachetools-7.0.1/src/cachetools.egg-info}/PKG-INFO +2 -3
- {cachetools-6.2.6 → cachetools-7.0.1}/src/cachetools.egg-info/SOURCES.txt +1 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/__init__.py +28 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_cached.py +1 -35
- cachetools-7.0.1/tests/test_cachedmethod.py +675 -0
- cachetools-7.0.1/tests/test_classmethod.py +151 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_keys.py +1 -1
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_rr.py +5 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_threading.py +21 -8
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_tlru.py +33 -3
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_ttl.py +14 -0
- cachetools-6.2.6/src/cachetools/_cachedmethod.py +0 -128
- cachetools-6.2.6/tests/test_cachedmethod.py +0 -434
- {cachetools-6.2.6 → cachetools-7.0.1}/LICENSE +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/MANIFEST.in +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/README.rst +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/docs/conf.py +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/setup.cfg +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/src/cachetools/func.py +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/src/cachetools.egg-info/dependency_links.txt +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/src/cachetools.egg-info/top_level.txt +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_cache.py +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_fifo.py +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_func.py +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_lfu.py +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/tests/test_lru.py +0 -0
- {cachetools-6.2.6 → cachetools-7.0.1}/tox.ini +0 -0
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
v7.0.1 (2026-02-10)
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
- Various test improvements.
|
|
5
|
+
|
|
6
|
+
- Update Copilot Instructions.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
v7.0.0 (2026-02-01)
|
|
10
|
+
===================
|
|
11
|
+
|
|
12
|
+
- Require Python 3.10 or later (breaking change).
|
|
13
|
+
|
|
14
|
+
- Drop support for passing ``info`` as fourth positional parameter to
|
|
15
|
+
``@cached`` (breaking change).
|
|
16
|
+
|
|
17
|
+
- Drop support for ``cache(self)`` returning ``None`` with
|
|
18
|
+
``@cachedmethod`` (breaking change).
|
|
19
|
+
|
|
20
|
+
- Convert the ``@cachedmethod`` wrappers to descriptors, deprecating
|
|
21
|
+
its use with class methods and instances that do not provide a
|
|
22
|
+
mutable ``__dict__`` attribute (potentially breaking change).
|
|
23
|
+
|
|
24
|
+
- Convert the previously undocumented ``@cachedmethod`` attributes
|
|
25
|
+
(``cache``, ``cache_lock``, etc.) to properties for instance
|
|
26
|
+
methods, providing official support and documentation (potentially
|
|
27
|
+
breaking change).
|
|
28
|
+
|
|
29
|
+
- Add an optional ``info`` parameter to the ``@cachedmethod``
|
|
30
|
+
decorator for reporting per-instance cache statistics. Note that
|
|
31
|
+
this requires the instance's ``__dict__`` attribute to be a mutable
|
|
32
|
+
mapping.
|
|
33
|
+
|
|
34
|
+
|
|
1
35
|
v6.2.6 (2026-01-27)
|
|
2
36
|
===================
|
|
3
37
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cachetools
|
|
3
|
-
Version:
|
|
3
|
+
Version: 7.0.1
|
|
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
|
|
|
@@ -215,7 +216,6 @@ all cache implementations call :meth:`popitem` to evict items from the
|
|
|
215
216
|
cache, this can be achieved by overriding this method in a subclass:
|
|
216
217
|
|
|
217
218
|
.. doctest::
|
|
218
|
-
:pyversion: >= 3
|
|
219
219
|
|
|
220
220
|
>>> class MyCache(LRUCache):
|
|
221
221
|
... def popitem(self):
|
|
@@ -237,7 +237,6 @@ pairs. By overriding :meth:`expire`, a subclass will be able to track
|
|
|
237
237
|
expired items:
|
|
238
238
|
|
|
239
239
|
.. doctest::
|
|
240
|
-
:pyversion: >= 3
|
|
241
240
|
|
|
242
241
|
>>> class ExpCache(TTLCache):
|
|
243
242
|
... def expire(self, time=None):
|
|
@@ -260,7 +259,6 @@ method which is called by :meth:`Cache.__getitem__` if the requested
|
|
|
260
259
|
key is not found:
|
|
261
260
|
|
|
262
261
|
.. doctest::
|
|
263
|
-
:pyversion: >= 3
|
|
264
262
|
|
|
265
263
|
>>> class PepStore(LRUCache):
|
|
266
264
|
... def __missing__(self, key):
|
|
@@ -364,10 +362,8 @@ often called with the same arguments:
|
|
|
364
362
|
|
|
365
363
|
.. testcode::
|
|
366
364
|
|
|
367
|
-
from threading import Lock
|
|
368
|
-
|
|
369
365
|
# 640K should be enough for anyone...
|
|
370
|
-
@cached(cache=LRUCache(maxsize=640*1024, getsizeof=len), lock=Lock())
|
|
366
|
+
@cached(cache=LRUCache(maxsize=640*1024, getsizeof=len), lock=threading.Lock())
|
|
371
367
|
def get_pep(num):
|
|
372
368
|
'Retrieve text of a Python Enhancement Proposal'
|
|
373
369
|
url = 'http://www.python.org/dev/peps/pep-%04d/' % num
|
|
@@ -402,7 +398,6 @@ often called with the same arguments:
|
|
|
402
398
|
to be enabled explicitly.
|
|
403
399
|
|
|
404
400
|
.. doctest::
|
|
405
|
-
:pyversion: >= 3
|
|
406
401
|
|
|
407
402
|
>>> @cached(cache=LRUCache(maxsize=32), info=True)
|
|
408
403
|
... def get_pep(num):
|
|
@@ -496,7 +491,6 @@ often called with the same arguments:
|
|
|
496
491
|
invocations, with separately cached results:
|
|
497
492
|
|
|
498
493
|
.. doctest::
|
|
499
|
-
:pyversion: >= 3
|
|
500
494
|
|
|
501
495
|
>>> @cached(LRUCache(maxsize=100))
|
|
502
496
|
... def foo(a=1):
|
|
@@ -516,7 +510,6 @@ often called with the same arguments:
|
|
|
516
510
|
be introduced to avoid ambiguities, e.g.:
|
|
517
511
|
|
|
518
512
|
.. doctest::
|
|
519
|
-
:pyversion: >= 3
|
|
520
513
|
|
|
521
514
|
>>> def foo(a=1):
|
|
522
515
|
... _foo(a)
|
|
@@ -532,17 +525,16 @@ often called with the same arguments:
|
|
|
532
525
|
>>> foo(a=1)
|
|
533
526
|
|
|
534
527
|
|
|
535
|
-
.. 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)
|
|
536
529
|
|
|
537
|
-
Decorator to wrap
|
|
538
|
-
|
|
530
|
+
Decorator to wrap an instance method with a memoizing callable that
|
|
531
|
+
saves results in a cache.
|
|
539
532
|
|
|
540
533
|
The main difference between this and the :func:`cached` function
|
|
541
534
|
decorator is that `cache`, `lock` and `condition` are not passed
|
|
542
|
-
objects, but functions. Those will be called with :const:`self`
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
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.
|
|
546
538
|
|
|
547
539
|
.. note::
|
|
548
540
|
|
|
@@ -551,55 +543,63 @@ often called with the same arguments:
|
|
|
551
543
|
the user's responsibility to handle concurrent calls to the
|
|
552
544
|
underlying wrapped method in a multithreaded environment.
|
|
553
545
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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.
|
|
559
553
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
You may provide a different `key` function,
|
|
566
|
-
e.g. :func:`cachetools.keys.hashkey`, if you need :const:`self` to
|
|
567
|
-
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.
|
|
568
559
|
|
|
569
560
|
One advantage of :func:`cachedmethod` over the :func:`cached`
|
|
570
561
|
function decorator is that cache properties such as `maxsize` can
|
|
571
562
|
be set at runtime:
|
|
572
563
|
|
|
573
|
-
..
|
|
564
|
+
.. doctest::
|
|
574
565
|
|
|
575
|
-
|
|
576
|
-
|
|
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)
|
|
577
581
|
|
|
578
|
-
|
|
582
|
+
>>> peps.get.cache_info()
|
|
583
|
+
CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)
|
|
579
584
|
|
|
580
|
-
|
|
581
|
-
self.cache = LRUCache(maxsize=cachesize)
|
|
582
|
-
self.lock = Lock()
|
|
585
|
+
>>> peps.get.cache_clear()
|
|
583
586
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
"""Retrieve text of a Python Enhancement Proposal"""
|
|
587
|
-
url = 'http://www.python.org/dev/peps/pep-%04d/' % num
|
|
588
|
-
with urllib.request.urlopen(url) as s:
|
|
589
|
-
return s.read()
|
|
590
|
-
|
|
591
|
-
peps = CachedPEPs(cachesize=10)
|
|
592
|
-
print("PEP #1: %s" % peps.get(1))
|
|
587
|
+
>>> peps.get.cache_info()
|
|
588
|
+
CacheInfo(hits=0, misses=0, maxsize=32, currsize=0)
|
|
593
589
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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.
|
|
597
595
|
|
|
598
|
-
|
|
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.
|
|
599
599
|
|
|
600
600
|
When using a shared cache for multiple methods, be aware that
|
|
601
601
|
different cache keys must be created for each method even when
|
|
602
|
-
function arguments are the same, just as with the
|
|
602
|
+
function arguments are the same, just as with the :func:`cached`
|
|
603
603
|
decorator:
|
|
604
604
|
|
|
605
605
|
.. testcode::
|
|
@@ -642,11 +642,33 @@ often called with the same arguments:
|
|
|
642
642
|
to create distinct cache keys, to avoid issues with
|
|
643
643
|
:func:`methodkey` skipping its initial `self` argument.
|
|
644
644
|
|
|
645
|
-
..
|
|
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.
|
|
646
667
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
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.
|
|
650
672
|
|
|
651
673
|
|
|
652
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.1"
|
|
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):
|
|
@@ -673,17 +678,6 @@ def cached(cache, key=keys.hashkey, lock=None, condition=None, info=False):
|
|
|
673
678
|
"""
|
|
674
679
|
from ._cached import _wrapper
|
|
675
680
|
|
|
676
|
-
if isinstance(condition, bool):
|
|
677
|
-
from warnings import warn
|
|
678
|
-
|
|
679
|
-
warn(
|
|
680
|
-
"passing `info` as positional parameter is deprecated",
|
|
681
|
-
DeprecationWarning,
|
|
682
|
-
stacklevel=2,
|
|
683
|
-
)
|
|
684
|
-
info = condition
|
|
685
|
-
condition = None
|
|
686
|
-
|
|
687
681
|
def decorator(func):
|
|
688
682
|
if info:
|
|
689
683
|
if isinstance(cache, Cache):
|
|
@@ -708,7 +702,7 @@ def cached(cache, key=keys.hashkey, lock=None, condition=None, info=False):
|
|
|
708
702
|
return decorator
|
|
709
703
|
|
|
710
704
|
|
|
711
|
-
def cachedmethod(cache, key=keys.methodkey, lock=None, condition=None):
|
|
705
|
+
def cachedmethod(cache, key=keys.methodkey, lock=None, condition=None, info=False):
|
|
712
706
|
"""Decorator to wrap a class or instance method with a memoizing
|
|
713
707
|
callable that saves results in a cache.
|
|
714
708
|
|
|
@@ -716,6 +710,18 @@ def cachedmethod(cache, key=keys.methodkey, lock=None, condition=None):
|
|
|
716
710
|
from ._cachedmethod import _wrapper
|
|
717
711
|
|
|
718
712
|
def decorator(method):
|
|
719
|
-
|
|
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)
|
|
720
726
|
|
|
721
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
|