Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-cachetools for
openSUSE:Factory checked in at 2026-03-17 19:02:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-cachetools (Old)
and /work/SRC/openSUSE:Factory/.python-cachetools.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-cachetools"
Tue Mar 17 19:02:03 2026 rev:31 rq:1339019 version:7.0.5
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-cachetools/python-cachetools.changes
2026-02-17 16:38:58.838434445 +0100
+++
/work/SRC/openSUSE:Factory/.python-cachetools.new.8177/python-cachetools.changes
2026-03-17 19:02:04.742672490 +0100
@@ -1,0 +2,12 @@
+Sat Mar 14 21:59:01 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 7.0.5:
+ * Minor @cachedmethod performance improvements.
+ * Fix and properly document @cachedmethod.cache_key behavior.
+ * Minor documentation improvements.
+ * Fix DeprecationWarning when creating an autospec mock with
+ @cachedmethod decorations.
+ * Provide more efficient clear() implementation for all support
+ Cache classes (courtesy Josep Pon Farreny).
+
+-------------------------------------------------------------------
Old:
----
cachetools-7.0.1.tar.gz
New:
----
cachetools-7.0.5.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-cachetools.spec ++++++
--- /var/tmp/diff_new_pack.80Fq3v/_old 2026-03-17 19:02:06.706753032 +0100
+++ /var/tmp/diff_new_pack.80Fq3v/_new 2026-03-17 19:02:06.722753688 +0100
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-cachetools
-Version: 7.0.1
+Version: 7.0.5
Release: 0
Summary: Extensible memoizing collections and decorators
License: MIT
++++++ cachetools-7.0.1.tar.gz -> cachetools-7.0.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/CHANGELOG.rst
new/cachetools-7.0.5/CHANGELOG.rst
--- old/cachetools-7.0.1/CHANGELOG.rst 2026-02-10 23:12:18.000000000 +0100
+++ new/cachetools-7.0.5/CHANGELOG.rst 2026-03-09 21:27:23.000000000 +0100
@@ -1,3 +1,31 @@
+v7.0.5 (2026-03-09)
+===================
+
+- Minor ``@cachedmethod`` performance improvements.
+
+
+v7.0.4 (2026-03-08)
+===================
+
+- Fix and properly document ``@cachedmethod.cache_key`` behavior.
+
+- Minor documentation improvements.
+
+
+v7.0.3 (2026-03-05)
+===================
+
+- Fix ``DeprecationWarning`` when creating an autospec mock with
+ ``@cachedmethod`` decorations.
+
+
+v7.0.2 (2026-03-02)
+===================
+
+- Provide more efficient ``clear()`` implementation for all support
+ Cache classes (courtesy Josep Pon Farreny).
+
+
v7.0.1 (2026-02-10)
===================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/PKG-INFO
new/cachetools-7.0.5/PKG-INFO
--- old/cachetools-7.0.1/PKG-INFO 2026-02-10 23:23:51.343722300 +0100
+++ new/cachetools-7.0.5/PKG-INFO 2026-03-09 21:51:16.601176500 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: cachetools
-Version: 7.0.1
+Version: 7.0.5
Summary: Extensible memoizing collections and decorators
Author-email: Thomas Kemmer <[email protected]>
Maintainer-email: Thomas Kemmer <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/docs/index.rst
new/cachetools-7.0.5/docs/index.rst
--- old/cachetools-7.0.1/docs/index.rst 2026-02-01 19:54:12.000000000 +0100
+++ new/cachetools-7.0.5/docs/index.rst 2026-03-09 21:21:03.000000000 +0100
@@ -370,13 +370,10 @@
with urllib.request.urlopen(url) as s:
return s.read()
- # make sure access to cache is synchronized
+ # remove (pop) an individual cached PEP from the cache
+ key = get_pep.cache_key(42)
with get_pep.cache_lock:
- get_pep.cache.clear()
-
- # always use the key function for accessing cache items
- with get_pep.cache_lock:
- get_pep.cache.pop(get_pep.cache_key(42), None)
+ get_pep.cache.pop(key, None)
For the common use case of clearing or invalidating the cache, the
decorator also provides a :func:`cache_clear()` function which
@@ -582,6 +579,15 @@
>>> peps.get.cache_info()
CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)
+ >>> # remove an individual cached PEP from the cache
+ >>> key = peps.get.cache_key(320)
+ >>> with peps.get.cache_lock:
+ ... del peps.get.cache[key]
+
+ >>> peps.get.cache_info()
+ CacheInfo(hits=3, misses=8, maxsize=32, currsize=7)
+
+ >>> # remove all cached PEPs and clear cache info
>>> peps.get.cache_clear()
>>> peps.get.cache_info()
@@ -590,8 +596,9 @@
The `key` function will be called as `key(self, *args, **kwargs)`
to retrieve a suitable cache key. Note that the default `key`
function, :func:`cachetools.keys.methodkey`, ignores its first
- argument, i.e. :const:`self`. This has mostly historical reasons,
- but also ensures that :const:`self` does not have to be hashable.
+ implicit argument, i.e. :const:`self`. This has mostly historical
+ reasons, but also ensures that :const:`self` does not have to be
+ hashable.
You may provide a different `key` function,
e.g. :func:`cachetools.keys.hashkey`, if you need :const:`self` to
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/src/cachetools/__init__.py
new/cachetools-7.0.5/src/cachetools/__init__.py
--- old/cachetools-7.0.1/src/cachetools/__init__.py 2026-02-10
23:12:18.000000000 +0100
+++ new/cachetools-7.0.5/src/cachetools/__init__.py 2026-03-09
21:27:23.000000000 +0100
@@ -12,7 +12,7 @@
"cachedmethod",
)
-__version__ = "7.0.1"
+__version__ = "7.0.5"
import collections
import collections.abc
@@ -41,6 +41,9 @@
def pop(self, _key):
return 1
+ def clear(self):
+ pass
+
class Cache(collections.abc.MutableMapping):
"""Mutable mapping to serve as a simple cache or cache base class."""
@@ -134,6 +137,17 @@
self[key] = value = default
return value
+ # Although the MutableMapping.clear() default implementation works
+ # perfectly well, it calls popitem() in a loop until the cache is
+ # empty, resulting in O(n) complexity. For large caches, this
+ # becomes a significant performance bottleneck, so we provide an
+ # optimized version for each Cache subclass.
+
+ def clear(self):
+ self.__data.clear()
+ self.__size.clear()
+ self.__currsize = 0
+
@property
def maxsize(self):
"""The maximum size of the cache."""
@@ -177,6 +191,10 @@
else:
return (key, self.pop(key))
+ def clear(self):
+ Cache.clear(self)
+ self.__order.clear()
+
class LFUCache(Cache):
"""Least Frequently Used (LFU) cache implementation."""
@@ -237,6 +255,12 @@
key = next(iter(curr.keys)) # remove an arbitrary element
return (key, self.pop(key))
+ def clear(self):
+ Cache.clear(self)
+ root = self.__root
+ root.prev = root.next = root
+ self.__links.clear()
+
def __touch(self, key):
"""Increment use count"""
link = self.__links[key]
@@ -286,6 +310,10 @@
else:
return (key, self.pop(key))
+ def clear(self):
+ Cache.clear(self)
+ self.__order.clear()
+
def __touch(self, key):
"""Mark as recently used"""
try:
@@ -332,6 +360,11 @@
else:
return (key, self.pop(key))
+ def clear(self):
+ Cache.clear(self)
+ self.__index.clear()
+ del self.__keys[:]
+
class _TimedCache(Cache):
"""Base class for time aware cache implementations."""
@@ -389,11 +422,6 @@
"""The timer function used by the cache."""
return self.__timer
- def clear(self):
- with self.__timer as time:
- self.expire(time)
- Cache.clear(self)
-
def get(self, *args, **kwargs):
with self.__timer:
return Cache.get(self, *args, **kwargs)
@@ -406,6 +434,12 @@
with self.__timer:
return Cache.setdefault(self, *args, **kwargs)
+ def clear(self):
+ # Subclasses must override to also reset their own time-tracking
+ # structures; we do not call expire() here since clear() should
+ # be O(1) regardless of cache contents.
+ Cache.clear(self)
+
class TTLCache(_TimedCache):
"""LRU Cache implementation with per-item time-to-live (TTL) value."""
@@ -536,6 +570,12 @@
else:
return (key, self.pop(key))
+ def clear(self):
+ _TimedCache.clear(self)
+ root = self.__root
+ root.prev = root.next = root
+ self.__links.clear()
+
def __getlink(self, key):
value = self.__links[key]
self.__links.move_to_end(key)
@@ -660,6 +700,11 @@
else:
return (key, self.pop(key))
+ def clear(self):
+ _TimedCache.clear(self)
+ self.__items.clear()
+ del self.__order[:]
+
def __getitem(self, key):
value = self.__items[key]
self.__items.move_to_end(key)
@@ -703,8 +748,8 @@
def cachedmethod(cache, key=keys.methodkey, lock=None, condition=None,
info=False):
- """Decorator to wrap a class or instance method with a memoizing
- callable that saves results in a cache.
+ """Decorator to wrap a method with a memoizing callable that saves
+ results in a cache.
"""
from ._cachedmethod import _wrapper
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/src/cachetools/_cachedmethod.py
new/cachetools-7.0.5/src/cachetools/_cachedmethod.py
--- old/cachetools-7.0.1/src/cachetools/_cachedmethod.py 2026-02-02
18:55:59.000000000 +0100
+++ new/cachetools-7.0.5/src/cachetools/_cachedmethod.py 2026-03-09
21:27:23.000000000 +0100
@@ -23,6 +23,10 @@
)
+def _none(_):
+ return None
+
+
class _WrapperBase:
"""Wrapper base class providing default implementations for properties."""
@@ -32,9 +36,9 @@
functools.update_wrapper(self, method)
self._obj = obj # protected
self.__cache = cache
- self.__key = key
- self.__lock = lock
- self.__cond = cond
+ self.__key = functools.partial(key, obj)
+ self.__lock = lock if lock is not None else _none
+ self.__cond = cond if cond is not None else _none
def __call__(self, *args, **kwargs):
raise NotImplementedError() # pragma: no cover
@@ -48,15 +52,15 @@
@property
def cache_key(self):
- return self.__key
+ return self.__key # self._obj passed via functools.partial
@property
def cache_lock(self):
- return None if self.__lock is None else self.__lock(self._obj)
+ return self.__lock(self._obj)
@property
def cache_condition(self):
- return None if self.__cond is None else self.__cond(self._obj)
+ return self.__cond(self._obj)
class _DescriptorBase:
@@ -77,7 +81,12 @@
def __get__(self, obj, objtype=None):
wrapper = self.Wrapper(obj)
- if self.__attrname is not None:
+ if obj is None:
+ # Return the wrapper itself without modification when accessed
+ # through the class to support class-level introspection, such
+ # as for mocking with autospec=True in unittest.mock.
+ pass
+ elif self.__attrname is not None:
# replace descriptor instance with wrapper in instance dict
try:
# In case of a race condition where another thread already
replaced
@@ -148,7 +157,7 @@
cache = self.cache
lock = self.cache_lock
cond = self.cache_condition
- key = self.cache_key(self._obj, *args, **kwargs)
+ key = self.cache_key(*args, **kwargs)
with lock:
cond.wait_for(lambda: key not in self.__pending)
@@ -194,7 +203,7 @@
def __call__(self, *args, **kwargs):
cache = self.cache
lock = self.cache_lock
- key = self.cache_key(self._obj, *args, **kwargs)
+ key = self.cache_key(*args, **kwargs)
with lock:
try:
result = cache[key]
@@ -233,7 +242,7 @@
def __call__(self, *args, **kwargs):
cache = self.cache
- key = self.cache_key(self._obj, *args, **kwargs)
+ key = self.cache_key(*args, **kwargs)
try:
result = cache[key]
self.__hits += 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/src/cachetools.egg-info/PKG-INFO
new/cachetools-7.0.5/src/cachetools.egg-info/PKG-INFO
--- old/cachetools-7.0.1/src/cachetools.egg-info/PKG-INFO 2026-02-10
23:23:51.000000000 +0100
+++ new/cachetools-7.0.5/src/cachetools.egg-info/PKG-INFO 2026-03-09
21:51:16.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: cachetools
-Version: 7.0.1
+Version: 7.0.5
Summary: Extensible memoizing collections and decorators
Author-email: Thomas Kemmer <[email protected]>
Maintainer-email: Thomas Kemmer <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/tests/__init__.py
new/cachetools-7.0.5/tests/__init__.py
--- old/cachetools-7.0.1/tests/__init__.py 2026-02-01 19:54:12.000000000
+0100
+++ new/cachetools-7.0.5/tests/__init__.py 2026-03-09 21:21:03.000000000
+0100
@@ -266,6 +266,57 @@
self._test_getsizeof(Cache(maxsize=3))
+ def test_clear(self):
+ cache = self.Cache(maxsize=2)
+ cache.update({1: 1, 2: 2})
+
+ self.assertEqual(2, len(cache))
+ self.assertEqual(2, cache.currsize)
+
+ cache.clear()
+
+ self.assertEqual(0, len(cache))
+ self.assertEqual(0, cache.currsize)
+ self.assertNotIn(1, cache)
+ self.assertNotIn(2, cache)
+
+ # verify cache can be reused after clear
+ cache[3] = 3
+ cache[4] = 4
+ self.assertEqual(2, len(cache))
+ self.assertEqual(3, cache[3])
+ self.assertEqual(4, cache[4])
+
+ # verify eviction still works after clear
+ cache[5] = 5
+ self.assertEqual(2, len(cache))
+ self.assertIn(5, cache)
+
+ def test_clear_empty(self):
+ cache = self.Cache(maxsize=2)
+ cache.clear() # should not raise
+ self.assertEqual(0, len(cache))
+ self.assertEqual(0, cache.currsize)
+
+ def test_clear_getsizeof(self):
+ cache = self.Cache(maxsize=10, getsizeof=lambda x: x)
+ cache[1] = 1
+ cache[2] = 2
+ cache[3] = 3
+
+ self.assertEqual(3, len(cache))
+ self.assertEqual(6, cache.currsize)
+
+ cache.clear()
+
+ self.assertEqual(0, len(cache))
+ self.assertEqual(0, cache.currsize)
+
+ # verify cache can be reused with getsizeof after clear
+ cache[4] = 4
+ self.assertEqual(1, len(cache))
+ self.assertEqual(4, cache.currsize)
+
def test_pickle(self):
import pickle
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/tests/test_cachedmethod.py
new/cachetools-7.0.5/tests/test_cachedmethod.py
--- old/cachetools-7.0.1/tests/test_cachedmethod.py 2026-02-01
19:54:12.000000000 +0100
+++ new/cachetools-7.0.5/tests/test_cachedmethod.py 2026-03-09
21:21:03.000000000 +0100
@@ -1,4 +1,5 @@
import unittest
+import unittest.mock
import warnings
@@ -369,24 +370,26 @@
cached = Cached(cache)
self.assertIs(cached.get.cache, cache)
- self.assertIs(cached.get.cache_key, keys.methodkey)
self.assertIs(cached.get.cache_lock, None)
self.assertIs(cached.get.cache_condition, None)
+ self.assertEqual(cached.get.cache_key(42), keys.methodkey(cached, 42))
self.assertIs(cached.get_lock.cache, cache)
- self.assertIs(cached.get_lock.cache_key, keys.methodkey)
self.assertIs(cached.get_lock.cache_lock, cached.lock)
self.assertIs(cached.get_lock.cache_condition, None)
+ self.assertEqual(cached.get_lock.cache_key(42), keys.methodkey(cached,
42))
self.assertIs(cached.get_cond.cache, cache)
- self.assertIs(cached.get_cond.cache_key, keys.methodkey)
self.assertIs(cached.get_cond.cache_lock, cached.cond)
self.assertIs(cached.get_cond.cache_condition, cached.cond)
+ self.assertEqual(cached.get_cond.cache_key(42), keys.methodkey(cached,
42))
self.assertIs(cached.get_lock_cond_info.cache, cache)
- self.assertIs(cached.get_lock_cond_info.cache_key, keys.methodkey)
self.assertIs(cached.get_lock_cond_info.cache_lock, cached.lock)
self.assertIs(cached.get_lock_cond_info.cache_condition, cached.cond)
+ self.assertEqual(
+ cached.get_lock_cond_info.cache_key(42), keys.methodkey(cached, 42)
+ )
def test_decorator_clear(self):
cache = self.cache(2)
@@ -602,15 +605,25 @@
self.assertEqual(cached1.get_info.cache_info(), (0, 0, 2, 0))
self.assertEqual(cached2.get_info.cache_info(), (0, 0, 2, 0))
+ # hits/misses are counted by instance
self.assertEqual(cached1.get_info(0), 0)
-
self.assertEqual(cached1.get_info.cache_info(), (0, 1, 2, 1))
self.assertEqual(cached2.get_info.cache_info(), (0, 0, 2, 1))
+ # default methodkey discards "self", so results will be shared
+ # across instances
self.assertEqual(cached2.get_info(0), 0)
-
self.assertEqual(cached1.get_info.cache_info(), (0, 1, 2, 1))
self.assertEqual(cached2.get_info.cache_info(), (1, 0, 2, 1))
+ self.assertEqual(cached1.get_info(0), 0)
+ self.assertEqual(cached1.get_info.cache_info(), (1, 1, 2, 1))
+ self.assertEqual(cached2.get_info.cache_info(), (1, 0, 2, 1))
+ self.assertEqual(cached1.get_info(1), 1)
+ self.assertEqual(cached1.get_info.cache_info(), (1, 2, 2, 2))
+ self.assertEqual(cached2.get_info.cache_info(), (1, 0, 2, 2))
+ self.assertEqual(cached2.get_info(1), 1)
+ self.assertEqual(cached1.get_info.cache_info(), (1, 2, 2, 2))
+ self.assertEqual(cached2.get_info.cache_info(), (2, 0, 2, 2))
def test_value_too_large(self):
cache = self.cache(1, getsizeof=lambda x: x)
@@ -673,3 +686,12 @@
with self.assertRaises(TypeError):
wrapper.cache_info()
+
+
+class AutospecTest(unittest.TestCase):
+ def test_autospec_no_warnings(self):
+
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("always")
+ unittest.mock.create_autospec(Cached, instance=True)
+ self.assertEqual(len(w), 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/tests/test_lfu.py
new/cachetools-7.0.5/tests/test_lfu.py
--- old/cachetools-7.0.1/tests/test_lfu.py 2026-02-01 19:44:54.000000000
+0100
+++ new/cachetools-7.0.5/tests/test_lfu.py 2026-03-09 21:21:03.000000000
+0100
@@ -64,3 +64,27 @@
self.assertEqual(cache[1], "updated")
self.assertIn(3, cache)
self.assertNotIn(2, cache)
+
+ def test_lfu_clear(self):
+ cache = LFUCache(maxsize=2)
+
+ cache[1] = 1
+ cache[1] # increment frequency
+ cache[1] # increment frequency again
+ cache[2] = 2
+
+ cache.clear()
+
+ self.assertEqual(0, len(cache))
+ self.assertEqual(0, cache.currsize)
+
+ # verify LFU frequency tracking is reset after clear
+ cache[3] = 3
+ cache[4] = 4
+ cache[3] # access 3 to increment frequency
+ cache[5] = 5 # should evict 4 (least frequently used)
+
+ self.assertEqual(2, len(cache))
+ self.assertIn(3, cache)
+ self.assertIn(5, cache)
+ self.assertNotIn(4, cache)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/tests/test_lru.py
new/cachetools-7.0.5/tests/test_lru.py
--- old/cachetools-7.0.1/tests/test_lru.py 2026-02-01 19:44:54.000000000
+0100
+++ new/cachetools-7.0.5/tests/test_lru.py 2026-03-09 21:21:03.000000000
+0100
@@ -66,3 +66,24 @@
self.assertEqual(cache[1], "updated")
self.assertIn(3, cache)
self.assertNotIn(2, cache)
+
+ def test_lru_clear(self):
+ cache = LRUCache(maxsize=2)
+
+ cache[1] = 1
+ cache[2] = 2
+ cache.clear()
+
+ self.assertEqual(0, len(cache))
+ self.assertEqual(0, cache.currsize)
+
+ # verify LRU order is reset after clear
+ cache[3] = 3
+ cache[4] = 4
+ cache[3] # access 3 to make it most recently used
+ cache[5] = 5 # should evict 4 (least recently used)
+
+ self.assertEqual(2, len(cache))
+ self.assertIn(3, cache)
+ self.assertIn(5, cache)
+ self.assertNotIn(4, cache)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/tests/test_tlru.py
new/cachetools-7.0.5/tests/test_tlru.py
--- old/cachetools-7.0.1/tests/test_tlru.py 2026-02-10 23:12:18.000000000
+0100
+++ new/cachetools-7.0.5/tests/test_tlru.py 2026-03-09 21:21:03.000000000
+0100
@@ -299,3 +299,31 @@
expired = cache.expire()
self.assertEqual(4, len(expired))
self.assertEqual(0, len(cache))
+
+ def test_tlru_clear(self):
+ cache = TLRUCache(maxsize=2, ttu=lambda k, v, t: t + 2, timer=Timer())
+
+ cache[1] = 1
+ cache[2] = 2
+ cache.clear()
+
+ self.assertEqual(0, len(cache))
+ self.assertEqual(0, cache.currsize)
+
+ # verify LRU eviction order is reset after clear
+ cache[3] = 3
+ cache[4] = 4
+ cache[3] # access 3 to make it most recently used
+ cache[5] = 5 # should evict 4 (least recently used)
+
+ self.assertEqual(2, len(cache))
+ self.assertIn(3, cache)
+ self.assertIn(5, cache)
+ self.assertNotIn(4, cache)
+
+ # verify TLRU expiry still works after clear
+ cache[42] = 42
+ cache.timer.tick()
+ cache.timer.tick()
+ cache.timer.tick() # past TTL
+ self.assertNotIn(42, cache)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cachetools-7.0.1/tests/test_ttl.py
new/cachetools-7.0.5/tests/test_ttl.py
--- old/cachetools-7.0.1/tests/test_ttl.py 2026-02-10 23:12:18.000000000
+0100
+++ new/cachetools-7.0.5/tests/test_ttl.py 2026-03-09 21:21:03.000000000
+0100
@@ -215,3 +215,31 @@
items = cache.expire(datetime.now() + timedelta(days=1))
self.assertEqual([(1, 1)], list(items))
self.assertEqual(0, len(cache))
+
+ def test_ttl_clear(self):
+ cache = TTLCache(maxsize=2, ttl=2, timer=Timer())
+
+ cache[1] = 1
+ cache[2] = 2
+ cache.clear()
+
+ self.assertEqual(0, len(cache))
+ self.assertEqual(0, cache.currsize)
+
+ # verify LRU eviction order is reset after clear
+ cache[3] = 3
+ cache[4] = 4
+ cache[3] # access 3 to make it most recently used
+ cache[5] = 5 # should evict 4 (least recently used)
+
+ self.assertEqual(2, len(cache))
+ self.assertIn(3, cache)
+ self.assertIn(5, cache)
+ self.assertNotIn(4, cache)
+
+ # verify TTL expiry still works after clear
+ cache[42] = 42
+ cache.timer.tick()
+ cache.timer.tick()
+ cache.timer.tick() # past TTL
+ self.assertNotIn(42, cache)