Skip to content

Commit

Permalink
Fix #292, fix #205, fix #103: TTLCache.expire() returns iterable of e…
Browse files Browse the repository at this point in the history
…xpired (key, value) pairs.
  • Loading branch information
tkem committed Aug 18, 2024
1 parent 990665b commit 5c6b789
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 11 deletions.
11 changes: 7 additions & 4 deletions src/cachetools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@


class _DefaultSize:

__slots__ = ()

def __getitem__(self, _):
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -469,19 +467,25 @@ 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
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
Expand All @@ -508,7 +512,6 @@ class TLRUCache(_TimedCache):

@functools.total_ordering
class _Item:

__slots__ = ("key", "expires", "removed")

def __init__(self, key=None, expires=None):
Expand Down
19 changes: 12 additions & 7 deletions tests/test_ttl.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ def __init__(self, maxsize, ttl=math.inf, **kwargs):


class TTLCacheTest(unittest.TestCase, CacheTestMixin):

Cache = TTLTestCache

def test_ttl(self):
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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))

0 comments on commit 5c6b789

Please sign in to comment.