From c22fc7d1baeba5454f6bb5d10f89cffd71764dbe Mon Sep 17 00:00:00 2001 From: Thomas Kemmer Date: Sun, 18 Aug 2024 19:04:39 +0200 Subject: [PATCH] Fix #292, fix #205, fix #103: TTLCache.expire() returns iterable of expired (key, value) pairs. --- src/cachetools/__init__.py | 12 ++++++++---- tests/test_ttl.py | 19 ++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/cachetools/__init__.py b/src/cachetools/__init__.py index 5a9a042..6471a85 100644 --- a/src/cachetools/__init__.py +++ b/src/cachetools/__init__.py @@ -26,7 +26,6 @@ class _DefaultSize: - __slots__ = () def __getitem__(self, _): @@ -378,7 +377,6 @@ class TTLCache(_TimedCache): """LRU Cache implementation with per-item time-to-live (TTL) value.""" class _Link: - __slots__ = ("key", "expires", "next", "prev") def __init__(self, key=None, expires=None): @@ -469,19 +467,26 @@ def ttl(self): return self.__ttl def expire(self, time=None): - """Remove expired items from the cache.""" + """Remove expired items from the cache and return an iterable of the + expired `(key, value)` pairs. + + """ if time is None: time = self.timer() root = self.__root curr = root.next links = self.__links + expired = [] cache_delitem = Cache.__delitem__ + cache_getitem = Cache.__getitem__ while curr is not root and not (time < curr.expires): + expired.append((curr.key, cache_getitem(self, curr.key))) cache_delitem(self, curr.key) del links[curr.key] next = curr.next curr.unlink() curr = next + return expired def popitem(self): """Remove and return the `(key, value)` pair least recently used that @@ -508,7 +513,6 @@ class TLRUCache(_TimedCache): @functools.total_ordering class _Item: - __slots__ = ("key", "expires", "removed") def __init__(self, key=None, expires=None): diff --git a/tests/test_ttl.py b/tests/test_ttl.py index 9a33cc5..957b360 100644 --- a/tests/test_ttl.py +++ b/tests/test_ttl.py @@ -26,7 +26,6 @@ def __init__(self, maxsize, ttl=math.inf, **kwargs): class TTLCacheTest(unittest.TestCase, CacheTestMixin): - Cache = TTLTestCache def test_ttl(self): @@ -132,28 +131,32 @@ def test_ttl_expire(self): self.assertEqual(2, cache[2]) self.assertEqual(3, cache[3]) - cache.expire() + items = cache.expire() + self.assertEqual(set(), set(items)) self.assertEqual({1, 2, 3}, set(cache)) self.assertEqual(3, len(cache)) self.assertEqual(1, cache[1]) self.assertEqual(2, cache[2]) self.assertEqual(3, cache[3]) - cache.expire(3) + items = cache.expire(3) + self.assertEqual({(1, 1)}, set(items)) self.assertEqual({2, 3}, set(cache)) self.assertEqual(2, len(cache)) self.assertNotIn(1, cache) self.assertEqual(2, cache[2]) self.assertEqual(3, cache[3]) - cache.expire(4) + items = cache.expire(4) + self.assertEqual({(2, 2)}, set(items)) self.assertEqual({3}, set(cache)) self.assertEqual(1, len(cache)) self.assertNotIn(1, cache) self.assertNotIn(2, cache) self.assertEqual(3, cache[3]) - cache.expire(5) + items = cache.expire(5) + self.assertEqual({(3, 3)}, set(items)) self.assertEqual(set(), set(cache)) self.assertEqual(0, len(cache)) self.assertNotIn(1, cache) @@ -192,7 +195,9 @@ def test_ttl_datetime(self): cache[1] = 1 self.assertEqual(1, len(cache)) - cache.expire(datetime.now()) + items = cache.expire(datetime.now()) + self.assertEqual([], list(items)) self.assertEqual(1, len(cache)) - cache.expire(datetime.now() + timedelta(days=1)) + items = cache.expire(datetime.now() + timedelta(days=1)) + self.assertEqual([(1, 1)], list(items)) self.assertEqual(0, len(cache))