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-09-29 17:46:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-cachetools (Old) and /work/SRC/openSUSE:Factory/.python-cachetools.new.383539 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-cachetools" Tue Sep 29 17:46:05 2026 rev:36 rq:1380844 version:7.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-cachetools/python-cachetools.changes 2026-08-06 16:17:54.971468357 +0200 +++ /work/SRC/openSUSE:Factory/.python-cachetools.new.383539/python-cachetools.changes 2026-09-29 17:46:30.918029004 +0200 @@ -1,0 +2,11 @@ +Sat Sep 26 21:36:27 UTC 2026 - Dirk Müller <[email protected]> + +- update to 7.2.0: + * Deprecate use of cache=None to suppress caching with the + @cached decorator. + * Add support for Python 3.15. + * Minor test improvements. + * Minor documentation updates. + * Reject negative maxsize in Cache.__init__. + +------------------------------------------------------------------- Old: ---- cachetools-7.1.7.tar.gz New: ---- cachetools-7.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-cachetools.spec ++++++ --- /var/tmp/diff_new_pack.mDY1EN/_old 2026-09-29 17:46:31.740063393 +0200 +++ /var/tmp/diff_new_pack.mDY1EN/_new 2026-09-29 17:46:31.742063476 +0200 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-cachetools -Version: 7.1.7 +Version: 7.2.0 Release: 0 Summary: Extensible memoizing collections and decorators License: MIT ++++++ cachetools-7.1.7.tar.gz -> cachetools-7.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.7/CHANGELOG.rst new/cachetools-7.2.0/CHANGELOG.rst --- old/cachetools-7.1.7/CHANGELOG.rst 2026-08-01 23:18:35.000000000 +0200 +++ new/cachetools-7.2.0/CHANGELOG.rst 2026-09-16 22:47:28.948641800 +0200 @@ -1,3 +1,22 @@ +v7.2.0 (2026-09-16) +=================== + +- Deprecate use of ``cache=None`` to suppress caching with the + ``@cached`` decorator. + +- Add support for Python 3.15. + +- Minor test improvements. + +- Minor documentation updates. + + +v7.1.8 (2026-08-31) +=================== + +- Reject negative ``maxsize`` in ``Cache.__init__``. + + v7.1.7 (2026-08-01) =================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.7/PKG-INFO new/cachetools-7.2.0/PKG-INFO --- old/cachetools-7.1.7/PKG-INFO 2026-08-01 23:19:52.379794600 +0200 +++ new/cachetools-7.2.0/PKG-INFO 2026-09-16 22:48:16.718563000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: cachetools -Version: 7.1.7 +Version: 7.2.0 Summary: Extensible memoizing collections and decorators Author-email: Thomas Kemmer <[email protected]> Maintainer-email: Thomas Kemmer <[email protected]> @@ -21,6 +21,7 @@ Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: 3.15 Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.10 Description-Content-Type: text/x-rst diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.7/docs/index.rst new/cachetools-7.2.0/docs/index.rst --- old/cachetools-7.1.7/docs/index.rst 2026-06-29 21:13:44.000000000 +0200 +++ new/cachetools-7.2.0/docs/index.rst 2026-09-16 22:47:28.949642000 +0200 @@ -42,12 +42,6 @@ calls :meth:`self.popitem()` repeatedly until there is enough room for the item to be added. -.. note:: - - Please be aware that `maxsize` must be a positive number. If you - really want your cache to grow without bounds, use - :const:`math.inf` or something similar. - In general, a cache's size is the total size of its item's values. Therefore, :class:`Cache` provides a :meth:`getsizeof` method, which returns the size of a given `value`. The default implementation of @@ -267,7 +261,7 @@ >>> class PepStore(LRUCache): ... def __missing__(self, key): ... """Retrieve text of a Python Enhancement Proposal""" - ... url = 'http://www.python.org/dev/peps/pep-%04d/' % key + ... url = 'https://peps.python.org/pep-%04d/' % key ... with urllib.request.urlopen(url) as s: ... pep = s.read() ... self[key] = pep # store text in cache @@ -370,7 +364,7 @@ @cached(cache=LRUCache(maxsize=640*1024, getsizeof=len), lock=threading.Lock()) def get_pep(num): 'Retrieve text of a Python Enhancement Proposal' - url = 'http://www.python.org/dev/peps/pep-%04d/' % num + url = 'https://peps.python.org/pep-%04d/' % num with urllib.request.urlopen(url) as s: return s.read() @@ -402,7 +396,7 @@ >>> @cached(cache=LRUCache(maxsize=32), info=True) ... def get_pep(num): - ... url = 'http://www.python.org/dev/peps/pep-%04d/' % num + ... url = 'https://peps.python.org/pep-%04d/' % num ... with urllib.request.urlopen(url) as s: ... return s.read() @@ -457,7 +451,7 @@ @cached(cache=LRUCache(maxsize=10), info=True) def _get_pep_wrapped(num): - url = "http://www.python.org/dev/peps/pep-%04d/" % num + url = "https://peps.python.org/pep-%04d/" % num try: with urllib.request.urlopen(url) as s: return s.read() @@ -525,6 +519,13 @@ >>> foo(1) >>> foo(a=1) + .. deprecated:: 7.2 + + Passing :const:`None` as `cache` parameter is deprecated, and + support will be removed in the next major version. This is + mainly for consistency with :func:`cachedmethod`, which no + longer supports returning :const:`None` from `cache(self)`. + .. decorator:: cachedmethod(cache, key=cachetools.keys.methodkey, lock=None, condition=None, info=False) @@ -572,7 +573,7 @@ ... @cachedmethod(lambda self: self.cache, lock=lambda self: self.lock, info=True) ... def get(self, num): ... """Retrieve text of a Python Enhancement Proposal""" - ... url = 'http://www.python.org/dev/peps/pep-%04d/' % num + ... url = 'https://peps.python.org/pep-%04d/' % num ... with urllib.request.urlopen(url) as s: ... return s.read() @@ -626,7 +627,7 @@ @cachedmethod(lambda self: self.cache, key=partial(methodkey, method='pep')) def get_pep(self, num): """Retrieve text of a Python Enhancement Proposal""" - url = 'http://www.python.org/dev/peps/pep-%04d/' % num + url = 'https://peps.python.org/pep-%04d/' % num with urllib.request.urlopen(url) as s: return s.read() @@ -655,31 +656,33 @@ .. versionchanged:: 7.0 - Added the `info` option for reporting per-instance cache - statistics. + Added the `info` option for reporting per-instance cache + statistics. - :func:`cachedmethod` attributes (:attr:`cache`, :attr:`cache_lock`, - etc.) are now implemented as properties for instance methods, and - are finally officially supported. + :func:`cachedmethod` attributes (:attr:`cache`, + :attr:`cache_lock`, etc.) are now implemented as properties for + instance methods, and are finally officially supported. - Require :attr:`__dict__` to be a mutable mapping to support - per-instance :func:`cache_info()`. + Require :attr:`__dict__` to be a mutable mapping to support + per-instance :func:`cache_info()`. - Returning :const:`None` from `cache(self)` is no longer supported. + Returning :const:`None` from `cache(self)` is no longer supported. .. deprecated:: 7.0 - Using :func:`cachedmethod` with :func:`classmethod` is deprecated, - and support will be removed in the next major version. This is - mostly due to the fact that chaining descriptors, i.e. using - descriptors with :func:`classmethod`, was deprecated in Python 3.11 - and removed in Python 3.13. When using :func:`cache_info()`, an - instance method is already required. - - Using :func:`cachedmethod` with an instance that does not provide a - mutable :attr:`__dict__` attribute is deprecated, and may inflict a - noticeable performance penalty. When using :func:`cache_info()`, - :attr:`__dict__` already has to be a mutable mapping. + Using :func:`cachedmethod` with :func:`classmethod` is + deprecated, and support will be removed in the next major + version. This is mostly due to the fact that chaining + descriptors, i.e. using descriptors with :func:`classmethod`, + was deprecated in Python 3.11 and removed in Python 3.13. When + using :func:`cache_info()`, an instance method is already + required. + + Using :func:`cachedmethod` with an instance that does not + provide a mutable :attr:`__dict__` attribute is deprecated, and + may inflict a noticeable performance penalty. When using + :func:`cache_info()`, :attr:`__dict__` already has to be a + mutable mapping. ***************************************************************** @@ -823,7 +826,7 @@ .. _cache algorithm: https://en.wikipedia.org/wiki/Cache_algorithms .. _cache stampede: https://en.wikipedia.org/wiki/Cache_stampede .. _condition variable: https://docs.python.org/3/library/threading.html#condition-objects -.. _context manager: https://docs.python.org/dev/glossary.html#term-context-manager -.. _mapping: https://docs.python.org/dev/glossary.html#term-mapping -.. _mutable: https://docs.python.org/dev/glossary.html#term-mutable +.. _context manager: https://docs.python.org/3/glossary.html#term-context-manager +.. _mapping: https://docs.python.org/3/glossary.html#term-mapping +.. _mutable: https://docs.python.org/3/glossary.html#term-mutable .. _thread-safe: https://en.wikipedia.org/wiki/Thread_safety diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.7/pyproject.toml new/cachetools-7.2.0/pyproject.toml --- old/cachetools-7.1.7/pyproject.toml 2026-07-24 00:43:17.000000000 +0200 +++ new/cachetools-7.2.0/pyproject.toml 2026-09-16 22:47:28.949642000 +0200 @@ -27,6 +27,7 @@ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Topic :: Software Development :: Libraries :: Python Modules", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.7/src/cachetools/__init__.py new/cachetools-7.2.0/src/cachetools/__init__.py --- old/cachetools-7.1.7/src/cachetools/__init__.py 2026-08-01 23:18:35.000000000 +0200 +++ new/cachetools-7.2.0/src/cachetools/__init__.py 2026-09-16 22:47:28.949642000 +0200 @@ -12,7 +12,7 @@ "cachedmethod", ) -__version__ = "7.1.7" +__version__ = "7.2.0" import collections import collections.abc @@ -50,6 +50,8 @@ __size = _DefaultSize() def __init__(self, maxsize, getsizeof=None): + if maxsize < 0: + raise ValueError("maxsize must be non-negative") if getsizeof: self.getsizeof = getsizeof if self.getsizeof is not Cache.getsizeof: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.7/src/cachetools/_cached.py new/cachetools-7.2.0/src/cachetools/_cached.py --- old/cachetools-7.1.7/src/cachetools/_cached.py 2026-05-17 21:35:51.000000000 +0200 +++ new/cachetools-7.2.0/src/cachetools/_cached.py 2026-09-16 22:47:28.949642000 +0200 @@ -3,6 +3,7 @@ __all__ = () import functools +import warnings # At least for now, the implementation prefers clarity and performance # over ease of maintenance, thus providing separate wrappers for @@ -227,6 +228,13 @@ def _wrapper(func, cache, key, lock=None, cond=None, info=None): + if cache is None: + warnings.warn( + "@cachetools.cached(cache=None) is deprecated", + DeprecationWarning, + stacklevel=3, + ) + if info is not None: if cache is None: wrapper = _uncached_info(func, info) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.7/src/cachetools.egg-info/PKG-INFO new/cachetools-7.2.0/src/cachetools.egg-info/PKG-INFO --- old/cachetools-7.1.7/src/cachetools.egg-info/PKG-INFO 2026-08-01 23:19:52.000000000 +0200 +++ new/cachetools-7.2.0/src/cachetools.egg-info/PKG-INFO 2026-09-16 22:48:16.697077500 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: cachetools -Version: 7.1.7 +Version: 7.2.0 Summary: Extensible memoizing collections and decorators Author-email: Thomas Kemmer <[email protected]> Maintainer-email: Thomas Kemmer <[email protected]> @@ -21,6 +21,7 @@ Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: 3.15 Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.10 Description-Content-Type: text/x-rst diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.7/tests/__init__.py new/cachetools-7.2.0/tests/__init__.py --- old/cachetools-7.1.7/tests/__init__.py 2026-08-01 23:18:35.000000000 +0200 +++ new/cachetools-7.2.0/tests/__init__.py 2026-09-03 22:43:48.021188000 +0200 @@ -1,3 +1,4 @@ +import math from collections.abc import Container, Iterable from typing import Any, Protocol @@ -41,6 +42,29 @@ self.assertEqual(1, cache.getsizeof(0)) self.assertTrue(repr(cache).startswith(cache.__class__.__name__)) + def test_maxsize_negative(self): + with self.assertRaises(ValueError): + self.Cache(maxsize=-1) + + with self.assertRaises(ValueError): + self.Cache(maxsize=-math.inf) + + def test_maxsize_zero(self): + cache = self.Cache(maxsize=0) + + self.assertEqual(0, cache.maxsize) + with self.assertRaises(ValueError): + cache[1] = 1 + self.assertEqual(0, len(cache)) + self.assertEqual(0, cache.currsize) + + def test_maxsize_infinite(self): + cache = self.Cache(maxsize=math.inf) + + cache.update((i, i) for i in range(100)) + self.assertEqual(100, len(cache)) + self.assertEqual(100, cache.currsize) + def test_insert(self): cache = self.Cache(maxsize=2) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.7/tests/test_cached.py new/cachetools-7.2.0/tests/test_cached.py --- old/cachetools-7.1.7/tests/test_cached.py 2026-07-24 00:43:17.000000000 +0200 +++ new/cachetools-7.2.0/tests/test_cached.py 2026-09-16 22:47:28.949642000 +0200 @@ -1,4 +1,5 @@ import unittest +import warnings import cachetools import cachetools.keys @@ -17,6 +18,9 @@ self.count = 0 return self.count + def error_func(self, *args, **kwargs): + raise ValueError("test error") + def test_decorator(self): cache = self.cache(2) wrapper = cachetools.cached(cache)(self.func) @@ -86,7 +90,7 @@ self.assertEqual(wrapper(1), 1) self.assertEqual(lock.count, 5) - def test_decorator_condition(self): + def test_decorator_cond(self): cache = self.cache(2) lock = cond = CountedCondition() wrapper = cachetools.cached(cache, condition=cond)(self.func) @@ -105,7 +109,7 @@ self.assertEqual(cond.wait_count, 3) self.assertEqual(cond.notify_count, 2) - def test_decorator_lock_condition(self): + def test_decorator_lock_cond(self): cache = self.cache(2) lock = CountedLock() cond = CountedCondition() @@ -125,6 +129,26 @@ self.assertEqual(cond.wait_count, 3) self.assertEqual(cond.notify_count, 2) + def test_decorator_cond_error(self): + cache = self.cache(2) + lock = cond = CountedCondition() + wrapper = cachetools.cached(cache, condition=cond)(self.error_func) + + with self.assertRaises(ValueError): + wrapper(0) + self.assertEqual(len(cache), 0) + self.assertEqual(lock.count, 2) + self.assertEqual(cond.wait_count, 1) + self.assertEqual(cond.notify_count, 1) + + # verify pending set is cleaned up, otherwise this might deadlock + with self.assertRaises(ValueError): + wrapper(0) + self.assertEqual(len(cache), 0) + self.assertEqual(lock.count, 4) + self.assertEqual(cond.wait_count, 2) + self.assertEqual(cond.notify_count, 2) + def test_decorator_wrapped(self): cache = self.cache(2) wrapper = cachetools.cached(cache)(self.func) @@ -158,7 +182,7 @@ self.assertIs(wrapper.cache_lock, lock) self.assertIs(wrapper.cache_condition, None) - def test_decorator_attributes_condition(self): + def test_decorator_attributes_cond(self): cache = self.cache(2) lock = cond = CountedCondition() wrapper = cachetools.cached(cache, condition=cond)(self.func) @@ -187,7 +211,7 @@ self.assertEqual(len(cache), 0) self.assertEqual(lock.count, 3) - def test_decorator_clear_condition(self): + def test_decorator_clear_cond(self): cache = self.cache(2) lock = cond = CountedCondition() wrapper = cachetools.cached(cache, condition=cond)(self.func) @@ -241,7 +265,7 @@ self.assertEqual(wrapper.cache_info(), (0, 0, 2, 0)) self.assertEqual(lock.count, 11) - def test_decorator_condition_info(self): + def test_decorator_cond_info(self): cache = self.cache(2) lock = cond = CountedCondition() wrapper = cachetools.cached(cache, condition=cond, info=True)(self.func) @@ -265,7 +289,7 @@ self.assertEqual(wrapper.cache_info(), (0, 0, 2, 0)) self.assertEqual(lock.count, 13) - def test_decorator_lock_condition_info(self): + def test_decorator_lock_cond_info(self): cache = self.cache(2) lock = CountedLock() cond = CountedCondition() @@ -310,7 +334,7 @@ self.assertEqual(len(cache), 0) self.assertEqual(lock.count, 2) - def test_zero_size_cache_decorator_condition(self): + def test_zero_size_cache_decorator_cond(self): cache = self.cache(0) lock = cond = CountedCondition() wrapper = cachetools.cached(cache, condition=cond)(self.func) @@ -342,6 +366,20 @@ self.assertEqual(wrapper.cache_info(), (0, 1, 0, 0)) self.assertEqual(lock.count, 4) + def test_zero_size_cache_decorator_cond_info(self): + cache = self.cache(0) + lock = cond = CountedCondition() + wrapper = cachetools.cached(cache, condition=cond, info=True)(self.func) + + self.assertEqual(len(cache), 0) + self.assertEqual(wrapper.cache_info(), (0, 0, 0, 0)) + self.assertEqual(lock.count, 1) + self.assertEqual(wrapper(0), 0) + self.assertEqual(len(cache), 0) + self.assertEqual(lock.count, 4) + self.assertEqual(wrapper.cache_info(), (0, 1, 0, 0)) + self.assertEqual(lock.count, 5) + class DictWrapperTest(unittest.TestCase, DecoratorTestMixin): def cache(self, minsize): @@ -367,26 +405,34 @@ return args + tuple(kwargs.items()) def test_decorator(self): - wrapper = cachetools.cached(None)(self.func) + with warnings.catch_warnings(record=True) as w: + wrapper = cachetools.cached(None)(self.func) + self.assertIs(w[0].category, DeprecationWarning) self.assertEqual(wrapper(0), (0,)) self.assertEqual(wrapper(1), (1,)) self.assertEqual(wrapper(1, foo="bar"), (1, ("foo", "bar"))) def test_decorator_attributes(self): - wrapper = cachetools.cached(None)(self.func) + with warnings.catch_warnings(record=True) as w: + wrapper = cachetools.cached(None)(self.func) + self.assertIs(w[0].category, DeprecationWarning) self.assertIs(wrapper.cache, None) self.assertIs(wrapper.cache_key, cachetools.keys.hashkey) self.assertIs(wrapper.cache_lock, None) def test_decorator_clear(self): - wrapper = cachetools.cached(None)(self.func) + with warnings.catch_warnings(record=True) as w: + wrapper = cachetools.cached(None)(self.func) + self.assertIs(w[0].category, DeprecationWarning) wrapper.cache_clear() # no-op def test_decorator_info(self): - wrapper = cachetools.cached(None, info=True)(self.func) + with warnings.catch_warnings(record=True) as w: + wrapper = cachetools.cached(None, info=True)(self.func) + self.assertIs(w[0].category, DeprecationWarning) self.assertEqual(wrapper.cache_info(), (0, 0, 0, 0)) self.assertEqual(wrapper(0), (0,)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachetools-7.1.7/tests/test_lfu.py new/cachetools-7.2.0/tests/test_lfu.py --- old/cachetools-7.1.7/tests/test_lfu.py 2026-06-29 21:13:44.000000000 +0200 +++ new/cachetools-7.2.0/tests/test_lfu.py 2026-09-16 22:47:28.949642000 +0200 @@ -31,6 +31,27 @@ self.assertEqual(cache[1], 1) self.assertEqual(cache[4], 4) + def test_lfu_tie(self): + cache = LFUCache[int, int](maxsize=3) + + cache[1] = 1 + cache[1] + cache[2] = 2 + cache[3] = 3 + cache[4] = 4 + + self.assertEqual(len(cache), 3) + self.assertIn(1, cache) + self.assertIn(4, cache) + self.assertTrue(2 in cache or 3 in cache) + self.assertTrue(2 not in cache or 3 not in cache) + + cache[5] = 5 + self.assertEqual(len(cache), 3) + self.assertIn(1, cache) + self.assertIn(5, cache) + self.assertTrue(2 in cache or 3 in cache or 4 in cache) + def test_lfu_getsizeof(self): cache = LFUCache[int, int](maxsize=3, getsizeof=lambda x: x)
