cachetools 7.0.0__tar.gz → 7.0.2__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-7.0.0 → cachetools-7.0.2}/CHANGELOG.rst +15 -0
- {cachetools-7.0.0/src/cachetools.egg-info → cachetools-7.0.2}/PKG-INFO +1 -1
- {cachetools-7.0.0 → cachetools-7.0.2}/src/cachetools/__init__.py +51 -6
- {cachetools-7.0.0 → cachetools-7.0.2/src/cachetools.egg-info}/PKG-INFO +1 -1
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/__init__.py +51 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_classmethod.py +3 -3
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_keys.py +1 -1
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_lfu.py +24 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_lru.py +21 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_rr.py +5 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_tlru.py +61 -3
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_ttl.py +42 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/LICENSE +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/MANIFEST.in +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/README.rst +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/docs/conf.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/docs/index.rst +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/pyproject.toml +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/setup.cfg +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/src/cachetools/_cached.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/src/cachetools/_cachedmethod.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/src/cachetools/func.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/src/cachetools/keys.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/src/cachetools.egg-info/SOURCES.txt +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/src/cachetools.egg-info/dependency_links.txt +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/src/cachetools.egg-info/top_level.txt +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_cache.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_cached.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_cachedmethod.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_fifo.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_func.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tests/test_threading.py +0 -0
- {cachetools-7.0.0 → cachetools-7.0.2}/tox.ini +0 -0
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
v7.0.2 (2026-03-02)
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
- Provide more efficient ``clear()`` implementation for all support
|
|
5
|
+
Cache classes (courtesy Josep Pon Farreny).
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
v7.0.1 (2026-02-10)
|
|
9
|
+
===================
|
|
10
|
+
|
|
11
|
+
- Various test improvements.
|
|
12
|
+
|
|
13
|
+
- Update Copilot Instructions.
|
|
14
|
+
|
|
15
|
+
|
|
1
16
|
v7.0.0 (2026-02-01)
|
|
2
17
|
===================
|
|
3
18
|
|
|
@@ -12,7 +12,7 @@ __all__ = (
|
|
|
12
12
|
"cachedmethod",
|
|
13
13
|
)
|
|
14
14
|
|
|
15
|
-
__version__ = "7.0.
|
|
15
|
+
__version__ = "7.0.2"
|
|
16
16
|
|
|
17
17
|
import collections
|
|
18
18
|
import collections.abc
|
|
@@ -41,6 +41,9 @@ class _DefaultSize:
|
|
|
41
41
|
def pop(self, _key):
|
|
42
42
|
return 1
|
|
43
43
|
|
|
44
|
+
def clear(self):
|
|
45
|
+
pass
|
|
46
|
+
|
|
44
47
|
|
|
45
48
|
class Cache(collections.abc.MutableMapping):
|
|
46
49
|
"""Mutable mapping to serve as a simple cache or cache base class."""
|
|
@@ -134,6 +137,17 @@ class Cache(collections.abc.MutableMapping):
|
|
|
134
137
|
self[key] = value = default
|
|
135
138
|
return value
|
|
136
139
|
|
|
140
|
+
# Although the MutableMapping.clear() default implementation works
|
|
141
|
+
# perfectly well, it calls popitem() in a loop until the cache is
|
|
142
|
+
# empty, resulting in O(n) complexity. For large caches, this
|
|
143
|
+
# becomes a significant performance bottleneck, so we provide an
|
|
144
|
+
# optimized version for each Cache subclass.
|
|
145
|
+
|
|
146
|
+
def clear(self):
|
|
147
|
+
self.__data.clear()
|
|
148
|
+
self.__size.clear()
|
|
149
|
+
self.__currsize = 0
|
|
150
|
+
|
|
137
151
|
@property
|
|
138
152
|
def maxsize(self):
|
|
139
153
|
"""The maximum size of the cache."""
|
|
@@ -177,6 +191,10 @@ class FIFOCache(Cache):
|
|
|
177
191
|
else:
|
|
178
192
|
return (key, self.pop(key))
|
|
179
193
|
|
|
194
|
+
def clear(self):
|
|
195
|
+
Cache.clear(self)
|
|
196
|
+
self.__order.clear()
|
|
197
|
+
|
|
180
198
|
|
|
181
199
|
class LFUCache(Cache):
|
|
182
200
|
"""Least Frequently Used (LFU) cache implementation."""
|
|
@@ -237,6 +255,12 @@ class LFUCache(Cache):
|
|
|
237
255
|
key = next(iter(curr.keys)) # remove an arbitrary element
|
|
238
256
|
return (key, self.pop(key))
|
|
239
257
|
|
|
258
|
+
def clear(self):
|
|
259
|
+
Cache.clear(self)
|
|
260
|
+
root = self.__root
|
|
261
|
+
root.prev = root.next = root
|
|
262
|
+
self.__links.clear()
|
|
263
|
+
|
|
240
264
|
def __touch(self, key):
|
|
241
265
|
"""Increment use count"""
|
|
242
266
|
link = self.__links[key]
|
|
@@ -286,6 +310,10 @@ class LRUCache(Cache):
|
|
|
286
310
|
else:
|
|
287
311
|
return (key, self.pop(key))
|
|
288
312
|
|
|
313
|
+
def clear(self):
|
|
314
|
+
Cache.clear(self)
|
|
315
|
+
self.__order.clear()
|
|
316
|
+
|
|
289
317
|
def __touch(self, key):
|
|
290
318
|
"""Mark as recently used"""
|
|
291
319
|
try:
|
|
@@ -332,6 +360,11 @@ class RRCache(Cache):
|
|
|
332
360
|
else:
|
|
333
361
|
return (key, self.pop(key))
|
|
334
362
|
|
|
363
|
+
def clear(self):
|
|
364
|
+
Cache.clear(self)
|
|
365
|
+
self.__index.clear()
|
|
366
|
+
del self.__keys[:]
|
|
367
|
+
|
|
335
368
|
|
|
336
369
|
class _TimedCache(Cache):
|
|
337
370
|
"""Base class for time aware cache implementations."""
|
|
@@ -389,11 +422,6 @@ class _TimedCache(Cache):
|
|
|
389
422
|
"""The timer function used by the cache."""
|
|
390
423
|
return self.__timer
|
|
391
424
|
|
|
392
|
-
def clear(self):
|
|
393
|
-
with self.__timer as time:
|
|
394
|
-
self.expire(time)
|
|
395
|
-
Cache.clear(self)
|
|
396
|
-
|
|
397
425
|
def get(self, *args, **kwargs):
|
|
398
426
|
with self.__timer:
|
|
399
427
|
return Cache.get(self, *args, **kwargs)
|
|
@@ -406,6 +434,12 @@ class _TimedCache(Cache):
|
|
|
406
434
|
with self.__timer:
|
|
407
435
|
return Cache.setdefault(self, *args, **kwargs)
|
|
408
436
|
|
|
437
|
+
def clear(self):
|
|
438
|
+
# Subclasses must override to also reset their own time-tracking
|
|
439
|
+
# structures; we do not call expire() here since clear() should
|
|
440
|
+
# be O(1) regardless of cache contents.
|
|
441
|
+
Cache.clear(self)
|
|
442
|
+
|
|
409
443
|
|
|
410
444
|
class TTLCache(_TimedCache):
|
|
411
445
|
"""LRU Cache implementation with per-item time-to-live (TTL) value."""
|
|
@@ -536,6 +570,12 @@ class TTLCache(_TimedCache):
|
|
|
536
570
|
else:
|
|
537
571
|
return (key, self.pop(key))
|
|
538
572
|
|
|
573
|
+
def clear(self):
|
|
574
|
+
_TimedCache.clear(self)
|
|
575
|
+
root = self.__root
|
|
576
|
+
root.prev = root.next = root
|
|
577
|
+
self.__links.clear()
|
|
578
|
+
|
|
539
579
|
def __getlink(self, key):
|
|
540
580
|
value = self.__links[key]
|
|
541
581
|
self.__links.move_to_end(key)
|
|
@@ -660,6 +700,11 @@ class TLRUCache(_TimedCache):
|
|
|
660
700
|
else:
|
|
661
701
|
return (key, self.pop(key))
|
|
662
702
|
|
|
703
|
+
def clear(self):
|
|
704
|
+
_TimedCache.clear(self)
|
|
705
|
+
self.__items.clear()
|
|
706
|
+
del self.__order[:]
|
|
707
|
+
|
|
663
708
|
def __getitem(self, key):
|
|
664
709
|
value = self.__items[key]
|
|
665
710
|
self.__items.move_to_end(key)
|
|
@@ -266,6 +266,57 @@ class CacheTestMixin:
|
|
|
266
266
|
|
|
267
267
|
self._test_getsizeof(Cache(maxsize=3))
|
|
268
268
|
|
|
269
|
+
def test_clear(self):
|
|
270
|
+
cache = self.Cache(maxsize=2)
|
|
271
|
+
cache.update({1: 1, 2: 2})
|
|
272
|
+
|
|
273
|
+
self.assertEqual(2, len(cache))
|
|
274
|
+
self.assertEqual(2, cache.currsize)
|
|
275
|
+
|
|
276
|
+
cache.clear()
|
|
277
|
+
|
|
278
|
+
self.assertEqual(0, len(cache))
|
|
279
|
+
self.assertEqual(0, cache.currsize)
|
|
280
|
+
self.assertNotIn(1, cache)
|
|
281
|
+
self.assertNotIn(2, cache)
|
|
282
|
+
|
|
283
|
+
# verify cache can be reused after clear
|
|
284
|
+
cache[3] = 3
|
|
285
|
+
cache[4] = 4
|
|
286
|
+
self.assertEqual(2, len(cache))
|
|
287
|
+
self.assertEqual(3, cache[3])
|
|
288
|
+
self.assertEqual(4, cache[4])
|
|
289
|
+
|
|
290
|
+
# verify eviction still works after clear
|
|
291
|
+
cache[5] = 5
|
|
292
|
+
self.assertEqual(2, len(cache))
|
|
293
|
+
self.assertIn(5, cache)
|
|
294
|
+
|
|
295
|
+
def test_clear_empty(self):
|
|
296
|
+
cache = self.Cache(maxsize=2)
|
|
297
|
+
cache.clear() # should not raise
|
|
298
|
+
self.assertEqual(0, len(cache))
|
|
299
|
+
self.assertEqual(0, cache.currsize)
|
|
300
|
+
|
|
301
|
+
def test_clear_getsizeof(self):
|
|
302
|
+
cache = self.Cache(maxsize=10, getsizeof=lambda x: x)
|
|
303
|
+
cache[1] = 1
|
|
304
|
+
cache[2] = 2
|
|
305
|
+
cache[3] = 3
|
|
306
|
+
|
|
307
|
+
self.assertEqual(3, len(cache))
|
|
308
|
+
self.assertEqual(6, cache.currsize)
|
|
309
|
+
|
|
310
|
+
cache.clear()
|
|
311
|
+
|
|
312
|
+
self.assertEqual(0, len(cache))
|
|
313
|
+
self.assertEqual(0, cache.currsize)
|
|
314
|
+
|
|
315
|
+
# verify cache can be reused with getsizeof after clear
|
|
316
|
+
cache[4] = 4
|
|
317
|
+
self.assertEqual(1, len(cache))
|
|
318
|
+
self.assertEqual(4, cache.currsize)
|
|
319
|
+
|
|
269
320
|
def test_pickle(self):
|
|
270
321
|
import pickle
|
|
271
322
|
|
|
@@ -75,7 +75,7 @@ class CachedClassMethodTest(unittest.TestCase):
|
|
|
75
75
|
self.assertEqual(Cached.get_typed(0), 1)
|
|
76
76
|
self.assertEqual(len(w), 2)
|
|
77
77
|
self.assertIs(w[0].category, DeprecationWarning)
|
|
78
|
-
self.assertIs(w[
|
|
78
|
+
self.assertIs(w[1].category, DeprecationWarning)
|
|
79
79
|
|
|
80
80
|
with warnings.catch_warnings():
|
|
81
81
|
warnings.simplefilter("ignore")
|
|
@@ -99,7 +99,7 @@ class CachedClassMethodTest(unittest.TestCase):
|
|
|
99
99
|
self.assertEqual(Cached.get_locked(0), 1)
|
|
100
100
|
self.assertEqual(len(w), 2)
|
|
101
101
|
self.assertIs(w[0].category, DeprecationWarning)
|
|
102
|
-
self.assertIs(w[
|
|
102
|
+
self.assertIs(w[1].category, DeprecationWarning)
|
|
103
103
|
|
|
104
104
|
def test_condition(self):
|
|
105
105
|
Cached.cache = LRUCache(2)
|
|
@@ -112,7 +112,7 @@ class CachedClassMethodTest(unittest.TestCase):
|
|
|
112
112
|
self.assertEqual(Cached.get_condition(0), 1)
|
|
113
113
|
self.assertEqual(len(w), 2)
|
|
114
114
|
self.assertIs(w[0].category, DeprecationWarning)
|
|
115
|
-
self.assertIs(w[
|
|
115
|
+
self.assertIs(w[1].category, DeprecationWarning)
|
|
116
116
|
|
|
117
117
|
def test_clear(self):
|
|
118
118
|
Cached.cache = LRUCache(2)
|
|
@@ -34,7 +34,7 @@ class CacheKeysTest(unittest.TestCase):
|
|
|
34
34
|
self.assertNotEqual(key("x", 1, 2, 3, x=0), key("x", 1, 2, 3, x=None))
|
|
35
35
|
self.assertNotEqual(key("x", 1, 2, 3, x=0), key("x", 1, 2, 3, y=0))
|
|
36
36
|
with self.assertRaises(TypeError):
|
|
37
|
-
hash("x",
|
|
37
|
+
hash(key("x", {}))
|
|
38
38
|
# untyped keys compare equal
|
|
39
39
|
self.assertEqual(key("x", 1, 2, 3), key("y", 1.0, 2.0, 3.0))
|
|
40
40
|
self.assertEqual(hash(key("x", 1, 2, 3)), hash(key("y", 1.0, 2.0, 3.0)))
|
|
@@ -64,3 +64,27 @@ class LFUCacheTest(unittest.TestCase, CacheTestMixin):
|
|
|
64
64
|
self.assertEqual(cache[1], "updated")
|
|
65
65
|
self.assertIn(3, cache)
|
|
66
66
|
self.assertNotIn(2, cache)
|
|
67
|
+
|
|
68
|
+
def test_lfu_clear(self):
|
|
69
|
+
cache = LFUCache(maxsize=2)
|
|
70
|
+
|
|
71
|
+
cache[1] = 1
|
|
72
|
+
cache[1] # increment frequency
|
|
73
|
+
cache[1] # increment frequency again
|
|
74
|
+
cache[2] = 2
|
|
75
|
+
|
|
76
|
+
cache.clear()
|
|
77
|
+
|
|
78
|
+
self.assertEqual(0, len(cache))
|
|
79
|
+
self.assertEqual(0, cache.currsize)
|
|
80
|
+
|
|
81
|
+
# verify LFU frequency tracking is reset after clear
|
|
82
|
+
cache[3] = 3
|
|
83
|
+
cache[4] = 4
|
|
84
|
+
cache[3] # access 3 to increment frequency
|
|
85
|
+
cache[5] = 5 # should evict 4 (least frequently used)
|
|
86
|
+
|
|
87
|
+
self.assertEqual(2, len(cache))
|
|
88
|
+
self.assertIn(3, cache)
|
|
89
|
+
self.assertIn(5, cache)
|
|
90
|
+
self.assertNotIn(4, cache)
|
|
@@ -66,3 +66,24 @@ class LRUCacheTest(unittest.TestCase, CacheTestMixin):
|
|
|
66
66
|
self.assertEqual(cache[1], "updated")
|
|
67
67
|
self.assertIn(3, cache)
|
|
68
68
|
self.assertNotIn(2, cache)
|
|
69
|
+
|
|
70
|
+
def test_lru_clear(self):
|
|
71
|
+
cache = LRUCache(maxsize=2)
|
|
72
|
+
|
|
73
|
+
cache[1] = 1
|
|
74
|
+
cache[2] = 2
|
|
75
|
+
cache.clear()
|
|
76
|
+
|
|
77
|
+
self.assertEqual(0, len(cache))
|
|
78
|
+
self.assertEqual(0, cache.currsize)
|
|
79
|
+
|
|
80
|
+
# verify LRU order is reset after clear
|
|
81
|
+
cache[3] = 3
|
|
82
|
+
cache[4] = 4
|
|
83
|
+
cache[3] # access 3 to make it most recently used
|
|
84
|
+
cache[5] = 5 # should evict 4 (least recently used)
|
|
85
|
+
|
|
86
|
+
self.assertEqual(2, len(cache))
|
|
87
|
+
self.assertIn(3, cache)
|
|
88
|
+
self.assertIn(5, cache)
|
|
89
|
+
self.assertNotIn(4, cache)
|
|
@@ -77,6 +77,11 @@ class RRCacheTest(unittest.TestCase, CacheTestMixin):
|
|
|
77
77
|
cache[2] = 2
|
|
78
78
|
with self.assertRaises(ValueError):
|
|
79
79
|
cache[3] = 3
|
|
80
|
+
self.assertEqual(len(cache), 2)
|
|
81
|
+
self.assertEqual(cache.currsize, 2)
|
|
82
|
+
self.assertIn(1, cache)
|
|
83
|
+
self.assertIn(2, cache)
|
|
84
|
+
self.assertNotIn(3, cache)
|
|
80
85
|
|
|
81
86
|
def test_rr_default_choice(self):
|
|
82
87
|
cache = RRCache(maxsize=2)
|
|
@@ -6,6 +6,10 @@ from cachetools import TLRUCache
|
|
|
6
6
|
from . import CacheTestMixin
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
def default_ttu(_key, _value, _time):
|
|
10
|
+
return math.inf
|
|
11
|
+
|
|
12
|
+
|
|
9
13
|
class Timer:
|
|
10
14
|
def __init__(self, auto=False):
|
|
11
15
|
self.auto = auto
|
|
@@ -21,9 +25,6 @@ class Timer:
|
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
class TLRUTestCache(TLRUCache):
|
|
24
|
-
def default_ttu(_key, _value, _time):
|
|
25
|
-
return math.inf
|
|
26
|
-
|
|
27
28
|
def __init__(self, maxsize, ttu=default_ttu, **kwargs):
|
|
28
29
|
TLRUCache.__init__(self, maxsize, ttu, timer=Timer(), **kwargs)
|
|
29
30
|
|
|
@@ -269,3 +270,60 @@ class TLRUCacheTest(unittest.TestCase, CacheTestMixin):
|
|
|
269
270
|
self.assertNotIn(1, cache)
|
|
270
271
|
self.assertNotIn(2, cache)
|
|
271
272
|
self.assertNotIn(3, cache)
|
|
273
|
+
|
|
274
|
+
def test_ttu_heap_cleanup(self):
|
|
275
|
+
cache = TLRUCache(maxsize=4, ttu=lambda k, v, t: t + 1, timer=Timer())
|
|
276
|
+
self.assertEqual(0, cache.timer())
|
|
277
|
+
|
|
278
|
+
cache[1] = 1
|
|
279
|
+
cache[2] = 2
|
|
280
|
+
|
|
281
|
+
# replace items to accumulate removed entries in the internal heap
|
|
282
|
+
for i in range(5):
|
|
283
|
+
cache[1] = 10 + i
|
|
284
|
+
cache[2] = 20 + i
|
|
285
|
+
|
|
286
|
+
# this should compact the internal heap
|
|
287
|
+
expired = cache.expire()
|
|
288
|
+
self.assertEqual([], expired)
|
|
289
|
+
|
|
290
|
+
# verify cache is functional after cleanup
|
|
291
|
+
self.assertEqual(2, len(cache))
|
|
292
|
+
self.assertEqual(14, cache[1])
|
|
293
|
+
self.assertEqual(24, cache[2])
|
|
294
|
+
cache[3] = 3
|
|
295
|
+
cache[4] = 4
|
|
296
|
+
self.assertEqual(4, len(cache))
|
|
297
|
+
|
|
298
|
+
cache.timer.tick()
|
|
299
|
+
expired = cache.expire()
|
|
300
|
+
self.assertEqual(4, len(expired))
|
|
301
|
+
self.assertEqual(0, len(cache))
|
|
302
|
+
|
|
303
|
+
def test_tlru_clear(self):
|
|
304
|
+
cache = TLRUCache(maxsize=2, ttu=lambda k, v, t: t + 2, timer=Timer())
|
|
305
|
+
|
|
306
|
+
cache[1] = 1
|
|
307
|
+
cache[2] = 2
|
|
308
|
+
cache.clear()
|
|
309
|
+
|
|
310
|
+
self.assertEqual(0, len(cache))
|
|
311
|
+
self.assertEqual(0, cache.currsize)
|
|
312
|
+
|
|
313
|
+
# verify LRU eviction order is reset after clear
|
|
314
|
+
cache[3] = 3
|
|
315
|
+
cache[4] = 4
|
|
316
|
+
cache[3] # access 3 to make it most recently used
|
|
317
|
+
cache[5] = 5 # should evict 4 (least recently used)
|
|
318
|
+
|
|
319
|
+
self.assertEqual(2, len(cache))
|
|
320
|
+
self.assertIn(3, cache)
|
|
321
|
+
self.assertIn(5, cache)
|
|
322
|
+
self.assertNotIn(4, cache)
|
|
323
|
+
|
|
324
|
+
# verify TLRU expiry still works after clear
|
|
325
|
+
cache[42] = 42
|
|
326
|
+
cache.timer.tick()
|
|
327
|
+
cache.timer.tick()
|
|
328
|
+
cache.timer.tick() # past TTL
|
|
329
|
+
self.assertNotIn(42, cache)
|
|
@@ -84,6 +84,20 @@ class TTLCacheTest(unittest.TestCase, CacheTestMixin):
|
|
|
84
84
|
self.assertEqual(0, len(cache))
|
|
85
85
|
self.assertEqual(set(), set(cache))
|
|
86
86
|
|
|
87
|
+
def test_ttl_timer(self):
|
|
88
|
+
cache = TTLCache(maxsize=2, ttl=2, timer=Timer())
|
|
89
|
+
self.assertEqual(cache.timer.time, 0)
|
|
90
|
+
self.assertFalse(cache.timer.auto)
|
|
91
|
+
|
|
92
|
+
cache[1] = 1
|
|
93
|
+
cache.timer.tick()
|
|
94
|
+
self.assertEqual(cache.timer.time, 1)
|
|
95
|
+
self.assertEqual(1, cache[1])
|
|
96
|
+
|
|
97
|
+
cache.timer.tick()
|
|
98
|
+
self.assertEqual(cache.timer.time, 2)
|
|
99
|
+
self.assertNotIn(1, cache)
|
|
100
|
+
|
|
87
101
|
def test_ttl_lru(self):
|
|
88
102
|
cache = TTLCache(maxsize=2, ttl=1, timer=Timer())
|
|
89
103
|
|
|
@@ -201,3 +215,31 @@ class TTLCacheTest(unittest.TestCase, CacheTestMixin):
|
|
|
201
215
|
items = cache.expire(datetime.now() + timedelta(days=1))
|
|
202
216
|
self.assertEqual([(1, 1)], list(items))
|
|
203
217
|
self.assertEqual(0, len(cache))
|
|
218
|
+
|
|
219
|
+
def test_ttl_clear(self):
|
|
220
|
+
cache = TTLCache(maxsize=2, ttl=2, timer=Timer())
|
|
221
|
+
|
|
222
|
+
cache[1] = 1
|
|
223
|
+
cache[2] = 2
|
|
224
|
+
cache.clear()
|
|
225
|
+
|
|
226
|
+
self.assertEqual(0, len(cache))
|
|
227
|
+
self.assertEqual(0, cache.currsize)
|
|
228
|
+
|
|
229
|
+
# verify LRU eviction order is reset after clear
|
|
230
|
+
cache[3] = 3
|
|
231
|
+
cache[4] = 4
|
|
232
|
+
cache[3] # access 3 to make it most recently used
|
|
233
|
+
cache[5] = 5 # should evict 4 (least recently used)
|
|
234
|
+
|
|
235
|
+
self.assertEqual(2, len(cache))
|
|
236
|
+
self.assertIn(3, cache)
|
|
237
|
+
self.assertIn(5, cache)
|
|
238
|
+
self.assertNotIn(4, cache)
|
|
239
|
+
|
|
240
|
+
# verify TTL expiry still works after clear
|
|
241
|
+
cache[42] = 42
|
|
242
|
+
cache.timer.tick()
|
|
243
|
+
cache.timer.tick()
|
|
244
|
+
cache.timer.tick() # past TTL
|
|
245
|
+
self.assertNotIn(42, cache)
|
|
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
|
|
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
|