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-08-06 16:17:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-cachetools (Old) and /work/SRC/openSUSE:Factory/.python-cachetools.new.16738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-cachetools" Thu Aug 6 16:17:52 2026 rev:35 rq:1369592 version:7.1.7 Changes: -------- --- /work/SRC/openSUSE:Factory/python-cachetools/python-cachetools.changes 2026-06-15 19:41:28.714472919 +0200 +++ /work/SRC/openSUSE:Factory/.python-cachetools.new.16738/python-cachetools.changes 2026-08-06 16:17:54.971468357 +0200 @@ -1,0 +2,12 @@ +Tue Aug 4 21:14:43 UTC 2026 - Dirk Müller <[email protected]> + +- update to 7.1.7: + * Improve Cache.__setitem__ behavior when replacing an existing + cache item with a larger value. + * Update CI environment. + * Minor style improvements to keep ruff happy. + * Fix TLRUCache silently keeping stale values on expired + overwrites. + * Reject negative cache item getsizeof values. + +------------------------------------------------------------------- Old: ---- cachetools-7.1.4.tar.gz New: ---- cachetools-7.1.7.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-cachetools.spec ++++++ --- /var/tmp/diff_new_pack.Vg86Bt/_old 2026-08-06 16:17:55.599490335 +0200 +++ /var/tmp/diff_new_pack.Vg86Bt/_new 2026-08-06 16:17:55.603490475 +0200 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-cachetools -Version: 7.1.4 +Version: 7.1.7 Release: 0 Summary: Extensible memoizing collections and decorators License: MIT ++++++ cachetools-7.1.4.tar.gz -> cachetools-7.1.7.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/CHANGELOG.rst new/cachetools-7.1.7/CHANGELOG.rst --- old/cachetools-7.1.4/CHANGELOG.rst 2026-05-22 00:35:03.000000000 +0200 +++ new/cachetools-7.1.7/CHANGELOG.rst 2026-08-01 23:18:35.000000000 +0200 @@ -1,3 +1,29 @@ +v7.1.7 (2026-08-01) +=================== + +- Improve ``Cache.__setitem__`` behavior when replacing an existing + cache item with a larger value. + +- Update CI environment. + + +v7.1.6 (2026-07-24) +=================== + +- Minor style improvements to keep ``ruff`` happy. + + +v7.1.5 (2026-07-23) +=================== + +- Fix ``TLRUCache`` silently keeping stale values on expired + overwrites. + +- Reject negative cache item ``getsizeof`` values. + +- Update build environment. + + v7.1.4 (2026-05-22) =================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/PKG-INFO new/cachetools-7.1.7/PKG-INFO --- old/cachetools-7.1.4/PKG-INFO 2026-05-22 00:37:58.447413000 +0200 +++ new/cachetools-7.1.7/PKG-INFO 2026-08-01 23:19:52.379794600 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: cachetools -Version: 7.1.4 +Version: 7.1.7 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.1.4/docs/conf.py new/cachetools-7.1.7/docs/conf.py --- old/cachetools-7.1.4/docs/conf.py 2026-05-17 21:35:51.000000000 +0200 +++ new/cachetools-7.1.7/docs/conf.py 2026-07-24 00:43:17.000000000 +0200 @@ -1,27 +1,9 @@ -import pathlib -import sys - -src_directory = (pathlib.Path(__file__).parent.parent / "src").resolve() -sys.path.insert(0, str(src_directory)) - - -# Extract the current version from the source. -def get_version(): - """Get the version and release from the source code.""" - - text = (src_directory / "cachetools/__init__.py").read_text() - for line in text.splitlines(): - if not line.strip().startswith("__version__"): - continue - full_version = line.partition("=")[2].strip().strip("\"'") - partial_version = ".".join(full_version.split(".")[:2]) - return full_version, partial_version - return (None, None) - +import importlib.metadata project = "cachetools" copyright = "2014-2026 Thomas Kemmer" -release, version = get_version() +release = importlib.metadata.version(project) +version = ".".join(release.split(".")[:2]) extensions = [ "sphinx.ext.autodoc", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/pyproject.toml new/cachetools-7.1.7/pyproject.toml --- old/cachetools-7.1.4/pyproject.toml 2026-05-22 00:35:03.000000000 +0200 +++ new/cachetools-7.1.7/pyproject.toml 2026-07-24 00:43:17.000000000 +0200 @@ -52,3 +52,6 @@ reportFunctionMemberAccess = "information" reportOptionalContextManager = "warning" reportOptionalMemberAccess = "warning" + +[tool.ruff.lint] +ignore = ["DTZ005", "UP031"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/src/cachetools/__init__.py new/cachetools-7.1.7/src/cachetools/__init__.py --- old/cachetools-7.1.4/src/cachetools/__init__.py 2026-05-22 00:35:03.000000000 +0200 +++ new/cachetools-7.1.7/src/cachetools/__init__.py 2026-08-01 23:18:35.000000000 +0200 @@ -12,7 +12,7 @@ "cachedmethod", ) -__version__ = "7.1.4" +__version__ = "7.1.7" import collections import collections.abc @@ -53,8 +53,8 @@ if getsizeof: self.getsizeof = getsizeof if self.getsizeof is not Cache.getsizeof: - self.__size = dict() - self.__data = dict() + self.__size = {} + self.__data = {} self.__currsize = 0 self.__maxsize = maxsize @@ -75,15 +75,20 @@ def __setitem__(self, key, value): maxsize = self.__maxsize size = self.getsizeof(value) + if size < 0: + raise ValueError("value size must be non-negative") if size > maxsize: raise ValueError("value too large") - if key not in self.__data or self.__size[key] < size: - while self.__currsize + size > maxsize: + if key not in self.__data: + diffsize = size + while self.__currsize + diffsize > maxsize: self.popitem() - if key in self.__data: - diffsize = size - self.__size[key] else: - diffsize = size + diffsize = size - self.__size[key] + while self.__currsize + diffsize > maxsize: + self.popitem() + if key not in self.__data: + diffsize = size self.__data[key] = value self.__size[key] = size self.__currsize += diffsize @@ -445,7 +450,7 @@ """LRU Cache implementation with per-item time-to-live (TTL) value.""" class _Link: - __slots__ = ("key", "expires", "next", "prev") + __slots__ = ("expires", "key", "next", "prev") def __init__(self, key=None, expires=None): self.key = key @@ -589,7 +594,7 @@ @functools.total_ordering class _Item: - __slots__ = ("key", "expires", "removed") + __slots__ = ("expires", "key", "removed") def __init__(self, key=None, expires=None): self.key = key @@ -627,10 +632,12 @@ def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): with self.timer as time: + self.expire(time) expires = self.__ttu(key, value, time) if not (time < expires): - return # skip expired items - self.expire(time) + # updating an existing item with an already expired + # one should remove the existing item + return self.__delitem(key) cache_setitem(self, key, value) # removing an existing item would break the heap structure, so # only mark it as removed for now @@ -710,6 +717,14 @@ self.__items.move_to_end(key) return value + def __delitem(self, key, cache_delitem=Cache.__delitem__): + try: + self.__items.pop(key).removed = True + except KeyError: + pass + else: + cache_delitem(self, key) + # note that the runtime __name__ is "CacheInfo", as in stdlib: # https://github.com/python/cpython/blob/3.14/Lib/functools.py#L520 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/src/cachetools/func.py new/cachetools-7.1.7/src/cachetools/func.py --- old/cachetools-7.1.4/src/cachetools/func.py 2026-05-17 21:35:51.000000000 +0200 +++ new/cachetools-7.1.7/src/cachetools/func.py 2026-07-24 00:43:17.000000000 +0200 @@ -7,9 +7,7 @@ import time from threading import Condition -from . import FIFOCache, LFUCache, LRUCache, RRCache, TTLCache -from . import cached -from . import keys +from . import FIFOCache, LFUCache, LRUCache, RRCache, TTLCache, cached, keys class _UnboundTTLCache(TTLCache): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/src/cachetools/keys.pyi new/cachetools-7.1.7/src/cachetools/keys.pyi --- old/cachetools-7.1.4/src/cachetools/keys.pyi 2026-05-17 21:35:51.000000000 +0200 +++ new/cachetools-7.1.7/src/cachetools/keys.pyi 2026-07-24 00:43:17.000000000 +0200 @@ -1,7 +1,8 @@ -from _typeshed import Unused from collections.abc import Hashable from typing import Final +from _typeshed import Unused + __all__: Final = ("hashkey", "methodkey", "typedkey", "typedmethodkey") def hashkey(*args: Hashable, **kwargs: Hashable) -> tuple[Hashable, ...]: ... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/src/cachetools.egg-info/PKG-INFO new/cachetools-7.1.7/src/cachetools.egg-info/PKG-INFO --- old/cachetools-7.1.4/src/cachetools.egg-info/PKG-INFO 2026-05-22 00:37:58.000000000 +0200 +++ new/cachetools-7.1.7/src/cachetools.egg-info/PKG-INFO 2026-08-01 23:19:52.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: cachetools -Version: 7.1.4 +Version: 7.1.7 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.1.4/tests/__init__.py new/cachetools-7.1.7/tests/__init__.py --- old/cachetools-7.1.4/tests/__init__.py 2026-05-17 21:35:51.000000000 +0200 +++ new/cachetools-7.1.7/tests/__init__.py 2026-08-01 23:18:35.000000000 +0200 @@ -284,6 +284,56 @@ def test_getsizeof_param(self): self._test_getsizeof(self.Cache(maxsize=3, getsizeof=lambda x: x)) + def test_getsizeof_replace_grow(self): + cache = self.Cache(maxsize=10, getsizeof=lambda x: x) + + cache[3] = 3 + cache[4] = 4 + self.assertEqual(2, len(cache)) + self.assertEqual(7, cache.currsize) + + # growing an existing entry must only reserve the additional size + cache[4] = 7 + self.assertEqual(2, len(cache)) + self.assertEqual(10, cache.currsize) + self.assertEqual(3, cache[3]) + self.assertEqual(7, cache[4]) + + def test_getsizeof_replace_same_size(self): + cache = self.Cache(maxsize=10, getsizeof=lambda x: x) + + cache[3] = 3 + cache[4] = 4 + self.assertEqual(7, cache.currsize) + + cache[4] = 4 + self.assertEqual(2, len(cache)) + self.assertEqual(7, cache.currsize) + self.assertEqual(3, cache[3]) + self.assertEqual(4, cache[4]) + + def test_getsizeof_replace_shrink(self): + cache = self.Cache(maxsize=10, getsizeof=lambda x: x) + + cache[3] = 3 + cache[4] = 4 + self.assertEqual(7, cache.currsize) + + cache[4] = 1 + self.assertEqual(2, len(cache)) + self.assertEqual(4, cache.currsize) + self.assertEqual(3, cache[3]) + self.assertEqual(1, cache[4]) + + def test_getsizeof_negative(self): + cache = self.Cache(maxsize=3, getsizeof=lambda x: -1) + + with self.assertRaises(ValueError): + cache[1] = 1 + + self.assertEqual(0, len(cache)) + self.assertEqual(0, cache.currsize) + def test_getsizeof_subclass(self): class Cache(self.Cache): @staticmethod diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/tests/test_cached.py new/cachetools-7.1.7/tests/test_cached.py --- old/cachetools-7.1.4/tests/test_cached.py 2026-05-17 21:35:51.000000000 +0200 +++ new/cachetools-7.1.7/tests/test_cached.py 2026-07-24 00:43:17.000000000 +0200 @@ -345,7 +345,7 @@ class DictWrapperTest(unittest.TestCase, DecoratorTestMixin): def cache(self, minsize): - return dict() + return {} def test_decorator_info(self): cache = self.cache(2) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/tests/test_cachedmethod.py new/cachetools-7.1.7/tests/test_cachedmethod.py --- old/cachetools-7.1.4/tests/test_cachedmethod.py 2026-05-17 21:35:51.000000000 +0200 +++ new/cachetools-7.1.7/tests/test_cachedmethod.py 2026-07-24 00:43:17.000000000 +0200 @@ -2,7 +2,6 @@ import unittest.mock import warnings - from cachetools import Cache, cachedmethod, keys from . import CountedCondition, CountedLock, _TestCaseProtocol @@ -636,7 +635,7 @@ class DictMethodTest(unittest.TestCase, MethodDecoratorTestMixin): def cache(self, minsize, **_kwargs): - return dict() + return {} class WeakRefMethodTest(unittest.TestCase): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/tests/test_func.py new/cachetools-7.1.7/tests/test_func.py --- old/cachetools-7.1.4/tests/test_func.py 2026-05-17 21:35:51.000000000 +0200 +++ new/cachetools-7.1.7/tests/test_func.py 2026-07-24 00:43:17.000000000 +0200 @@ -1,5 +1,6 @@ import unittest -from typing import Any, Callable +from collections.abc import Callable +from typing import Any import cachetools.func diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/tests/test_threading.py new/cachetools-7.1.7/tests/test_threading.py --- old/cachetools-7.1.4/tests/test_threading.py 2026-05-22 00:35:03.000000000 +0200 +++ new/cachetools-7.1.7/tests/test_threading.py 2026-07-24 00:43:17.000000000 +0200 @@ -54,7 +54,7 @@ def test_cached_stampede(self): global count count = 0 - threads = [threading.Thread(target=func) for i in range(0, self.NTHREADS)] + threads = [threading.Thread(target=func) for i in range(self.NTHREADS)] for t in threads: t.start() for t in threads: @@ -70,9 +70,7 @@ def test_cachedmethod_stampede(self): self.cache = LRUCache(1) self.count = 0 - threads = [ - threading.Thread(target=self.method) for i in range(0, self.NTHREADS) - ] + threads = [threading.Thread(target=self.method) for i in range(self.NTHREADS)] for t in threads: t.start() for t in threads: @@ -88,9 +86,7 @@ def test_cached_locked(self): global count count = 0 - threads = [ - threading.Thread(target=locked_func) for i in range(0, self.NTHREADS) - ] + threads = [threading.Thread(target=locked_func) for i in range(self.NTHREADS)] for t in threads: t.start() for t in threads: @@ -109,7 +105,7 @@ self.cache = LRUCache(1) self.count = 0 threads = [ - threading.Thread(target=self.locked_method) for i in range(0, self.NTHREADS) + threading.Thread(target=self.locked_method) for i in range(self.NTHREADS) ] for t in threads: t.start() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/tests/test_tlru.py new/cachetools-7.1.7/tests/test_tlru.py --- old/cachetools-7.1.4/tests/test_tlru.py 2026-05-17 21:35:51.000000000 +0200 +++ new/cachetools-7.1.7/tests/test_tlru.py 2026-07-23 01:46:46.000000000 +0200 @@ -144,6 +144,26 @@ self.assertEqual(cache[4], 4) self.assertEqual(cache[5], 5) + def test_overwrite_existing_with_expired(self): + # Overwriting an existing key with an already-expired value must not + # silently retain the previous value: the assignment cannot store the + # new (dead-on-arrival) value, so the key has to be evicted instead. + def ttu(_k, value, t): + return t + value + + cache = TLRUCache[int, int, int](maxsize=2, ttu=ttu, timer=Timer()) + cache[1] = 5 + self.assertEqual(cache[1], 5) + self.assertEqual(len(cache), 1) + self.assertEqual(cache.currsize, 1) + + cache[1] = 0 # ttu -> t, i.e. not (t < t): immediately expired + self.assertNotIn(1, cache) + self.assertIsNone(cache.get(1)) + self.assertEqual(len(cache), 0) + self.assertEqual(cache.currsize, 0) + self.assertEqual(set(cache), set()) + def test_ttu_expire(self): def ttu(_k, _v, t): return t + 3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.4/tox.ini new/cachetools-7.1.7/tox.ini --- old/cachetools-7.1.4/tox.ini 2026-05-22 00:35:03.000000000 +0200 +++ new/cachetools-7.1.7/tox.ini 2026-07-24 00:43:17.000000000 +0200 @@ -1,5 +1,5 @@ [tox] -envlist = py,docs,doctest,ruff,ruff-format,pyright +envlist = py,docs,doctest,pyright,ruff,ruff-format [testenv] deps = @@ -20,23 +20,20 @@ commands = sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs {envtmpdir}/doctest +[testenv:pyright] +deps = + pyright +commands = + pyright {posargs} + [testenv:ruff] deps = ruff commands = ruff check {posargs} -skip_install = true [testenv:ruff-format] deps = ruff commands = ruff format --diff -q {posargs} -skip_install = true - -[testenv:pyright] -deps = - pyright -commands = - pyright {posargs} -skip_install = true
