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-06-15 19:39:55
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-cachetools (Old)
 and      /work/SRC/openSUSE:Factory/.python-cachetools.new.1981 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-cachetools"

Mon Jun 15 19:39:55 2026 rev:34 rq:1359221 version:7.1.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-cachetools/python-cachetools.changes      
2026-05-12 19:26:17.654156992 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-cachetools.new.1981/python-cachetools.changes
    2026-06-15 19:41:28.714472919 +0200
@@ -1,0 +2,13 @@
+Sun Jun 14 09:45:30 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 7.1.4:
+  * Minor unit test improvements.
+  * Update build environment.
+  * Minor type stub improvements.
+  * Update build environment.
+  * Minor type stub improvements.
+  * Minor documentation improvements.
+  * Modernize build environment.
+  * Various type stub improvements.
+
+-------------------------------------------------------------------

Old:
----
  cachetools-7.1.0.tar.gz

New:
----
  cachetools-7.1.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-cachetools.spec ++++++
--- /var/tmp/diff_new_pack.guY0n8/_old  2026-06-15 19:41:29.678513316 +0200
+++ /var/tmp/diff_new_pack.guY0n8/_new  2026-06-15 19:41:29.678513316 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-cachetools
-Version:        7.1.0
+Version:        7.1.4
 Release:        0
 Summary:        Extensible memoizing collections and decorators
 License:        MIT

++++++ cachetools-7.1.0.tar.gz -> cachetools-7.1.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/CHANGELOG.rst 
new/cachetools-7.1.4/CHANGELOG.rst
--- old/cachetools-7.1.0/CHANGELOG.rst  2026-05-01 23:13:44.000000000 +0200
+++ new/cachetools-7.1.4/CHANGELOG.rst  2026-05-22 00:35:03.000000000 +0200
@@ -1,3 +1,35 @@
+v7.1.4 (2026-05-22)
+===================
+
+- Minor unit test improvements.
+
+- Update build environment.
+
+
+v7.1.3 (2026-05-18)
+===================
+
+- Minor type stub improvements.
+
+- Update build environment.
+
+
+v7.1.2 (2026-05-16)
+===================
+
+- Minor type stub improvements.
+
+- Minor documentation improvements.
+
+- Modernize build environment.
+
+
+v7.1.1 (2026-05-03)
+===================
+
+- Various type stub improvements.
+
+
 v7.1.0 (2026-05-01)
 ===================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/MANIFEST.in 
new/cachetools-7.1.4/MANIFEST.in
--- old/cachetools-7.1.0/MANIFEST.in    2026-03-09 21:22:39.000000000 +0100
+++ new/cachetools-7.1.4/MANIFEST.in    2026-05-22 00:35:03.000000000 +0200
@@ -1,11 +1,3 @@
-include CHANGELOG.rst
-include LICENSE
-include MANIFEST.in
-include README.rst
-include tox.ini
+prune .github/
+exclude .gitignore
 exclude .readthedocs.yaml
-
-recursive-include docs *
-prune docs/_build
-
-recursive-include tests *.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/PKG-INFO 
new/cachetools-7.1.4/PKG-INFO
--- old/cachetools-7.1.0/PKG-INFO       2026-05-01 23:15:48.482225400 +0200
+++ new/cachetools-7.1.4/PKG-INFO       2026-05-22 00:37:58.447413000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: cachetools
-Version: 7.1.0
+Version: 7.1.4
 Summary: Extensible memoizing collections and decorators
 Author-email: Thomas Kemmer <[email protected]>
 Maintainer-email: Thomas Kemmer <[email protected]>
@@ -46,19 +46,10 @@
    :target: https://codecov.io/gh/tkem/cachetools
    :alt: Test coverage
 
-.. image:: https://img.shields.io/librariesio/sourcerank/pypi/cachetools
-   :target: https://libraries.io/pypi/cachetools
-   :alt: Libraries.io SourceRank
-
 .. image:: https://img.shields.io/github/license/tkem/cachetools
    :target: https://raw.github.com/tkem/cachetools/master/LICENSE
    :alt: License
 
-.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
-   :target: https://github.com/psf/black
-   :alt: Code style: black
-
-
 This module provides various memoizing collections and decorators,
 including variants of the Python Standard Library's `@lru_cache`_
 function decorator.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/README.rst 
new/cachetools-7.1.4/README.rst
--- old/cachetools-7.1.0/README.rst     2026-05-01 23:13:29.000000000 +0200
+++ new/cachetools-7.1.4/README.rst     2026-05-17 21:35:51.000000000 +0200
@@ -17,19 +17,10 @@
    :target: https://codecov.io/gh/tkem/cachetools
    :alt: Test coverage
 
-.. image:: https://img.shields.io/librariesio/sourcerank/pypi/cachetools
-   :target: https://libraries.io/pypi/cachetools
-   :alt: Libraries.io SourceRank
-
 .. image:: https://img.shields.io/github/license/tkem/cachetools
    :target: https://raw.github.com/tkem/cachetools/master/LICENSE
    :alt: License
 
-.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
-   :target: https://github.com/psf/black
-   :alt: Code style: black
-
-
 This module provides various memoizing collections and decorators,
 including variants of the Python Standard Library's `@lru_cache`_
 function decorator.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/docs/index.rst 
new/cachetools-7.1.4/docs/index.rst
--- old/cachetools-7.1.0/docs/index.rst 2026-03-09 21:21:03.000000000 +0100
+++ new/cachetools-7.1.4/docs/index.rst 2026-05-17 21:35:51.000000000 +0200
@@ -88,6 +88,10 @@
    This class evicts items in the order they were added to make space
    when necessary.
 
+   Updating a cache item via :meth:`FIFOCache.__setitem__` will act
+   like a re-insertion, i.e. deleting the item followed by an insert,
+   and therefore will reset the item's position in the cache.
+
 .. autoclass:: LFUCache(maxsize, getsizeof=None)
    :members: popitem
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/pyproject.toml 
new/cachetools-7.1.4/pyproject.toml
--- old/cachetools-7.1.0/pyproject.toml 2026-05-01 23:13:29.000000000 +0200
+++ new/cachetools-7.1.4/pyproject.toml 2026-05-22 00:35:03.000000000 +0200
@@ -1,5 +1,5 @@
 [build-system]
-requires = ["setuptools >= 61.0.0", "wheel"]
+requires = ["setuptools >= 80", "setuptools-scm >= 8.2"]
 build-backend = "setuptools.build_meta"
 
 [project]
@@ -47,17 +47,8 @@
 [tool.setuptools.dynamic]
 version = {attr = "cachetools.__version__"}
 
-[tool.flake8]
-max-line-length = 80
-exclude = [".git", ".tox", "build"]
-select = ["C", "E", "F", "W", "B", "B950", "I", "N"]
-# F401: imported but unused (submodule shims)
-# E501: line too long (black)
-# E704: multiple statements on one line (typehints)
-ignore = ["F401", "E501", "E704"]
-
 [tool.pyright]
 typeCheckingMode = "standard"
-reportFunctionMemberAccess = false
-reportOptionalContextManager = false
-reportOptionalMemberAccess = false
\ No newline at end of file
+reportFunctionMemberAccess = "information"
+reportOptionalContextManager = "warning"
+reportOptionalMemberAccess = "warning"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/src/cachetools/__init__.py 
new/cachetools-7.1.4/src/cachetools/__init__.py
--- old/cachetools-7.1.0/src/cachetools/__init__.py     2026-05-01 
23:13:29.000000000 +0200
+++ new/cachetools-7.1.4/src/cachetools/__init__.py     2026-05-22 
00:35:03.000000000 +0200
@@ -12,7 +12,7 @@
     "cachedmethod",
 )
 
-__version__ = "7.1.0"
+__version__ = "7.1.4"
 
 import collections
 import collections.abc
@@ -23,9 +23,6 @@
 
 from . import keys
 
-# Typing stubs for this package are provided by typeshed:
-# https://github.com/python/typeshed/tree/main/stubs/cachetools
-
 
 class _DefaultSize:
     """A minimal "fake" dict that returns a constant size 1 for any key."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/src/cachetools/__init__.pyi 
new/cachetools-7.1.4/src/cachetools/__init__.pyi
--- old/cachetools-7.1.0/src/cachetools/__init__.pyi    2026-05-01 
23:13:29.000000000 +0200
+++ new/cachetools-7.1.4/src/cachetools/__init__.pyi    2026-05-17 
21:35:51.000000000 +0200
@@ -3,10 +3,12 @@
 from contextlib import AbstractContextManager
 from typing import (
     Any,
+    Concatenate,
     Final,
     Generic,
     Literal,
     NamedTuple,
+    ParamSpec,
     Protocol,
     TypeVar,
     overload,
@@ -26,11 +28,12 @@
 )
 __version__: str
 
+_P = ParamSpec("_P")
+_R = TypeVar("_R")
+_T = TypeVar("_T")
 _KT = TypeVar("_KT")
 _VT = TypeVar("_VT")
 _TT = TypeVar("_TT", default=float)
-_T = TypeVar("_T")
-_R = TypeVar("_R")
 _KT2 = TypeVar("_KT2")
 _VT2 = TypeVar("_VT2")
 
@@ -147,19 +150,19 @@
     def notify_all(self) -> None: ...
 
 @type_check_only
-class _cached_wrapper(Generic[_R]):
-    __wrapped__: Callable[..., _R]
+class _cached_wrapper(Generic[_P, _R]):
+    __wrapped__: Callable[_P, _R]
     __name__: str
     __doc__: str | None
     cache: MutableMapping[Any, Any] | None
     cache_key: Callable[..., Any] = ...
     cache_lock: AbstractContextManager[Any] | None = None
     cache_condition: _AbstractCondition | None = None
-    def __call__(self, /, *args: Any, **kwargs: Any) -> _R: ...
+    def __call__(self, /, *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
     def cache_clear(self) -> None: ...
 
 @type_check_only
-class _cached_wrapper_info(_cached_wrapper[_R]):
+class _cached_wrapper_info(_cached_wrapper[_P, _R]):
     def cache_info(self) -> _CacheInfo: ...
 
 @overload
@@ -168,31 +171,47 @@
     key: Callable[..., _KT] = ...,
     lock: AbstractContextManager[Any] | None = None,
     condition: _AbstractCondition | None = None,
-    info: Literal[True] = ...,
-) -> Callable[[Callable[..., _R]], _cached_wrapper_info[_R]]: ...
+    info: Literal[False] = ...,
+) -> Callable[[Callable[_P, _R]], _cached_wrapper[_P, _R]]: ...
 @overload
 def cached(
     cache: MutableMapping[_KT, Any] | None,
     key: Callable[..., _KT] = ...,
     lock: AbstractContextManager[Any] | None = None,
     condition: _AbstractCondition | None = None,
-    info: Literal[False] = ...,
-) -> Callable[[Callable[..., _R]], _cached_wrapper[_R]]: ...
+    *,
+    info: Literal[True],
+) -> Callable[[Callable[_P, _R]], _cached_wrapper_info[_P, _R]]: ...
+@overload
+def cached(
+    cache: MutableMapping[_KT, Any] | None,
+    key: Callable[..., _KT],
+    lock: AbstractContextManager[Any] | None,
+    condition: _AbstractCondition | None,
+    info: Literal[True],
+) -> Callable[[Callable[_P, _R]], _cached_wrapper_info[_P, _R]]: ...
 
 @type_check_only
-class _cachedmethod_wrapper(Generic[_R]):
-    __wrapped__: Callable[..., _R]
+class _cachedmethod_wrapper(Generic[_P, _R]):
+    __wrapped__: Callable[Concatenate[Any, _P], _R]
     __name__: str
     __doc__: str | None
-    cache: MutableMapping[Any, Any] | None
+    cache: MutableMapping[Any, Any]
     cache_key: Callable[..., Any] = ...
     cache_lock: AbstractContextManager[Any] | None = None
     cache_condition: _AbstractCondition | None = None
-    def __call__(self, /, *args: Any, **kwargs: Any) -> _R: ...
+    def __set_name__(self, owner: type, name: str) -> None: ...
+    def __get__(
+        self, obj: Any, objtype: type | None = None
+    ) -> _cachedmethod_wrapper[_P, _R]: ...
+    def __call__(self, /, *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
     def cache_clear(self) -> None: ...
 
 @type_check_only
-class _cachedmethod_wrapper_info(_cachedmethod_wrapper[_R]):
+class _cachedmethod_wrapper_info(_cachedmethod_wrapper[_P, _R]):
+    def __get__(
+        self, obj: Any, objtype: type | None = None
+    ) -> _cachedmethod_wrapper_info[_P, _R]: ...
     def cache_info(self) -> _CacheInfo: ...
 
 @overload
@@ -201,13 +220,26 @@
     key: Callable[..., _KT] = ...,
     lock: Callable[[Any], AbstractContextManager[Any]] | None = None,
     condition: Callable[[Any], _AbstractCondition] | None = None,
-    info: Literal[True] = ...,
-) -> Callable[[Callable[..., _R]], _cachedmethod_wrapper_info[_R]]: ...
+    info: Literal[False] = ...,
+) -> Callable[[Callable[Concatenate[Any, _P], _R]], _cachedmethod_wrapper[_P, 
_R]]: ...
 @overload
 def cachedmethod(
     cache: Callable[[Any], MutableMapping[_KT, Any]],
     key: Callable[..., _KT] = ...,
     lock: Callable[[Any], AbstractContextManager[Any]] | None = None,
     condition: Callable[[Any], _AbstractCondition] | None = None,
-    info: Literal[False] = ...,
-) -> Callable[[Callable[..., _R]], _cachedmethod_wrapper[_R]]: ...
+    *,
+    info: Literal[True],
+) -> Callable[
+    [Callable[Concatenate[Any, _P], _R]], _cachedmethod_wrapper_info[_P, _R]
+]: ...
+@overload
+def cachedmethod(
+    cache: Callable[[Any], MutableMapping[_KT, Any]],
+    key: Callable[..., _KT],
+    lock: Callable[[Any], AbstractContextManager[Any]] | None,
+    condition: Callable[[Any], _AbstractCondition] | None,
+    info: Literal[True],
+) -> Callable[
+    [Callable[Concatenate[Any, _P], _R]], _cachedmethod_wrapper_info[_P, _R]
+]: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/src/cachetools/func.py 
new/cachetools-7.1.4/src/cachetools/func.py
--- old/cachetools-7.1.0/src/cachetools/func.py 2026-05-01 23:13:29.000000000 
+0200
+++ new/cachetools-7.1.4/src/cachetools/func.py 2026-05-17 21:35:51.000000000 
+0200
@@ -2,7 +2,6 @@
 
 __all__ = ("fifo_cache", "lfu_cache", "lru_cache", "rr_cache", "ttl_cache")
 
-import functools
 import math
 import random
 import time
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/src/cachetools/func.pyi 
new/cachetools-7.1.4/src/cachetools/func.pyi
--- old/cachetools-7.1.0/src/cachetools/func.pyi        2026-05-01 
23:13:29.000000000 +0200
+++ new/cachetools-7.1.4/src/cachetools/func.pyi        2026-05-18 
20:09:02.000000000 +0200
@@ -1,19 +1,20 @@
 from collections.abc import Callable, Sequence
-from typing import Any, Final, Generic, TypeVar, overload, type_check_only
+from typing import Any, Final, Generic, ParamSpec, TypeVar, overload, 
type_check_only
 
 from . import _CacheInfo
 
 __all__: Final = ("fifo_cache", "lfu_cache", "lru_cache", "rr_cache", 
"ttl_cache")
 
+_P = ParamSpec("_P")
 _T = TypeVar("_T")
 _R = TypeVar("_R")
 
 @type_check_only
-class _cachetools_cache_wrapper(Generic[_R]):
-    __wrapped__: Callable[..., _R]
+class _cachetools_cache_wrapper(Generic[_P, _R]):
+    __wrapped__: Callable[_P, _R]
     __name__: str
     __doc__: str | None
-    def __call__(self, /, *args: Any, **kwargs: Any) -> _R: ...
+    def __call__(self, /, *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
     def cache_info(self) -> _CacheInfo: ...
     def cache_clear(self) -> None: ...
     def cache_parameters(self) -> dict[str, Any]: ...
@@ -21,50 +22,50 @@
 @overload
 def fifo_cache(
     maxsize: int | None = 128, typed: bool = False
-) -> Callable[[Callable[..., _R]], _cachetools_cache_wrapper[_R]]: ...
+) -> Callable[[Callable[_P, _R]], _cachetools_cache_wrapper[_P, _R]]: ...
 @overload
 def fifo_cache(
-    maxsize: Callable[..., _R], typed: bool = False
-) -> _cachetools_cache_wrapper[_R]: ...
+    maxsize: Callable[_P, _R], typed: bool = False
+) -> _cachetools_cache_wrapper[_P, _R]: ...
 @overload
 def lfu_cache(
     maxsize: int | None = 128, typed: bool = False
-) -> Callable[[Callable[..., _R]], _cachetools_cache_wrapper[_R]]: ...
+) -> Callable[[Callable[_P, _R]], _cachetools_cache_wrapper[_P, _R]]: ...
 @overload
 def lfu_cache(
-    maxsize: Callable[..., _R], typed: bool = False
-) -> _cachetools_cache_wrapper[_R]: ...
+    maxsize: Callable[_P, _R], typed: bool = False
+) -> _cachetools_cache_wrapper[_P, _R]: ...
 @overload
 def lru_cache(
     maxsize: int | None = 128, typed: bool = False
-) -> Callable[[Callable[..., _R]], _cachetools_cache_wrapper[_R]]: ...
+) -> Callable[[Callable[_P, _R]], _cachetools_cache_wrapper[_P, _R]]: ...
 @overload
 def lru_cache(
-    maxsize: Callable[..., _R], typed: bool = False
-) -> _cachetools_cache_wrapper[_R]: ...
+    maxsize: Callable[_P, _R], typed: bool = False
+) -> _cachetools_cache_wrapper[_P, _R]: ...
 @overload
 def rr_cache(
     maxsize: int | None = 128,
     choice: Callable[[Sequence[_T]], _T] = ...,
     typed: bool = False,
-) -> Callable[[Callable[..., _R]], _cachetools_cache_wrapper[_R]]: ...
+) -> Callable[[Callable[_P, _R]], _cachetools_cache_wrapper[_P, _R]]: ...
 @overload
 def rr_cache(
-    maxsize: Callable[..., _R],
+    maxsize: Callable[_P, _R],
     choice: Callable[[Sequence[_T]], _T] = ...,
     typed: bool = False,
-) -> _cachetools_cache_wrapper[_R]: ...
+) -> _cachetools_cache_wrapper[_P, _R]: ...
 @overload
 def ttl_cache(
     maxsize: int | None = 128,
     ttl: Any = 600,
     timer: Callable[[], _T] = ...,
     typed: bool = False,
-) -> Callable[[Callable[..., _R]], _cachetools_cache_wrapper[_R]]: ...
+) -> Callable[[Callable[_P, _R]], _cachetools_cache_wrapper[_P, _R]]: ...
 @overload
 def ttl_cache(
-    maxsize: Callable[..., _R],
+    maxsize: Callable[_P, _R],
     ttl: Any = 600,
     timer: Callable[[], _T] = ...,
     typed: bool = False,
-) -> _cachetools_cache_wrapper[_R]: ...
+) -> _cachetools_cache_wrapper[_P, _R]: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/src/cachetools.egg-info/PKG-INFO 
new/cachetools-7.1.4/src/cachetools.egg-info/PKG-INFO
--- old/cachetools-7.1.0/src/cachetools.egg-info/PKG-INFO       2026-05-01 
23:15:48.000000000 +0200
+++ new/cachetools-7.1.4/src/cachetools.egg-info/PKG-INFO       2026-05-22 
00:37:58.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: cachetools
-Version: 7.1.0
+Version: 7.1.4
 Summary: Extensible memoizing collections and decorators
 Author-email: Thomas Kemmer <[email protected]>
 Maintainer-email: Thomas Kemmer <[email protected]>
@@ -46,19 +46,10 @@
    :target: https://codecov.io/gh/tkem/cachetools
    :alt: Test coverage
 
-.. image:: https://img.shields.io/librariesio/sourcerank/pypi/cachetools
-   :target: https://libraries.io/pypi/cachetools
-   :alt: Libraries.io SourceRank
-
 .. image:: https://img.shields.io/github/license/tkem/cachetools
    :target: https://raw.github.com/tkem/cachetools/master/LICENSE
    :alt: License
 
-.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
-   :target: https://github.com/psf/black
-   :alt: Code style: black
-
-
 This module provides various memoizing collections and decorators,
 including variants of the Python Standard Library's `@lru_cache`_
 function decorator.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/tests/__init__.py 
new/cachetools-7.1.4/tests/__init__.py
--- old/cachetools-7.1.0/tests/__init__.py      2026-05-01 23:13:29.000000000 
+0200
+++ new/cachetools-7.1.4/tests/__init__.py      2026-05-17 21:35:51.000000000 
+0200
@@ -1,5 +1,5 @@
 from collections.abc import Container, Iterable
-from typing import Any, Protocol, TypeAlias, no_type_check
+from typing import Any, Protocol
 
 import cachetools
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/tests/test_cached.py 
new/cachetools-7.1.4/tests/test_cached.py
--- old/cachetools-7.1.0/tests/test_cached.py   2026-05-01 23:13:29.000000000 
+0200
+++ new/cachetools-7.1.4/tests/test_cached.py   2026-05-17 21:35:51.000000000 
+0200
@@ -1,5 +1,4 @@
 import unittest
-import warnings
 
 import cachetools
 import cachetools.keys
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/tests/test_cachedmethod.py 
new/cachetools-7.1.4/tests/test_cachedmethod.py
--- old/cachetools-7.1.0/tests/test_cachedmethod.py     2026-05-01 
23:13:29.000000000 +0200
+++ new/cachetools-7.1.4/tests/test_cachedmethod.py     2026-05-17 
21:35:51.000000000 +0200
@@ -517,7 +517,6 @@
 
 
 class CacheMethodTest(unittest.TestCase, MethodDecoratorTestMixin):
-
     def cache(self, minsize, **kwargs):
         return Cache(maxsize=minsize, **kwargs)
 
@@ -636,13 +635,11 @@
 
 
 class DictMethodTest(unittest.TestCase, MethodDecoratorTestMixin):
-
     def cache(self, minsize, **_kwargs):
         return dict()
 
 
 class WeakRefMethodTest(unittest.TestCase):
-
     def test_weakref(self):
         import fractions
         import gc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/tests/test_threading.py 
new/cachetools-7.1.4/tests/test_threading.py
--- old/cachetools-7.1.0/tests/test_threading.py        2026-05-01 
23:13:29.000000000 +0200
+++ new/cachetools-7.1.4/tests/test_threading.py        2026-05-22 
00:35:03.000000000 +0200
@@ -1,7 +1,6 @@
 import threading
 import time
 import unittest
-from os import environ
 from typing import Any
 
 from cachetools import LRUCache, cached, cachedmethod
@@ -17,31 +16,50 @@
     return count
 
 
[email protected](environ.get("THREADING_TESTS", False), "THREADING_TESTS 
not set")
-class ThreadingTest(unittest.TestCase):
+@cached(cache=LRUCache(1), lock=threading.Lock(), info=True)
+def locked_func():
+    global count
+    time.sleep(1.0)
+    count += 1
+    return 42
+
 
+class ThreadingTest(unittest.TestCase):
     NTHREADS = 10
 
+    TIMEOUT = 10
+
     cache: LRUCache[Any, int] = LRUCache(1)
 
     cond = threading.Condition()
 
+    lock = threading.Lock()
+
     count = 0
 
     @cachedmethod(
         cache=lambda self: self.cache, condition=lambda self: self.cond, 
info=True
     )
-    def meth(self):
+    def method(self):
+        time.sleep(1.0)
+        self.count += 1
+        return 42
+
+    @cachedmethod(cache=lambda self: self.cache, lock=lambda self: self.lock, 
info=True)
+    def locked_method(self):
         time.sleep(1.0)
         self.count += 1
         return 42
 
     def test_cached_stampede(self):
+        global count
+        count = 0
         threads = [threading.Thread(target=func) for i in range(0, 
self.NTHREADS)]
         for t in threads:
             t.start()
         for t in threads:
-            t.join()
+            t.join(timeout=self.TIMEOUT)
+            self.assertFalse(t.is_alive())
 
         self.assertEqual(count, 1)
 
@@ -50,14 +68,59 @@
         self.assertEqual(info.misses, 1)
 
     def test_cachedmethod_stampede(self):
-        threads = [threading.Thread(target=self.meth) for i in range(0, 
self.NTHREADS)]
+        self.cache = LRUCache(1)
+        self.count = 0
+        threads = [
+            threading.Thread(target=self.method) for i in range(0, 
self.NTHREADS)
+        ]
         for t in threads:
             t.start()
         for t in threads:
-            t.join()
+            t.join(timeout=self.TIMEOUT)
+            self.assertFalse(t.is_alive())
 
         self.assertEqual(self.count, 1)
 
-        info = self.meth.cache_info()
+        info = self.method.cache_info()
         self.assertEqual(info.hits, self.NTHREADS - 1)
         self.assertEqual(info.misses, 1)
+
+    def test_cached_locked(self):
+        global count
+        count = 0
+        threads = [
+            threading.Thread(target=locked_func) for i in range(0, 
self.NTHREADS)
+        ]
+        for t in threads:
+            t.start()
+        for t in threads:
+            t.join(timeout=self.TIMEOUT)
+            self.assertFalse(t.is_alive())
+
+        # Without condition/stampede prevention, func is called by multiple
+        # threads, but all return the same cached value (42).
+        self.assertGreaterEqual(count, 1)
+
+        info = locked_func.cache_info()
+        self.assertEqual(info.hits + info.misses, self.NTHREADS)
+        self.assertGreaterEqual(info.misses, 1)
+
+    def test_cachedmethod_locked(self):
+        self.cache = LRUCache(1)
+        self.count = 0
+        threads = [
+            threading.Thread(target=self.locked_method) for i in range(0, 
self.NTHREADS)
+        ]
+        for t in threads:
+            t.start()
+        for t in threads:
+            t.join(timeout=self.TIMEOUT)
+            self.assertFalse(t.is_alive())
+
+        # Multiple threads may compute the value, but setdefault ensures
+        # the first cached result wins and all return 42.
+        self.assertGreaterEqual(self.count, 1)
+
+        info = self.locked_method.cache_info()
+        self.assertEqual(info.hits + info.misses, self.NTHREADS)
+        self.assertGreaterEqual(info.misses, 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.1.0/tox.ini new/cachetools-7.1.4/tox.ini
--- old/cachetools-7.1.0/tox.ini        2026-05-01 23:13:29.000000000 +0200
+++ new/cachetools-7.1.4/tox.ini        2026-05-22 00:35:03.000000000 +0200
@@ -1,22 +1,13 @@
 [tox]
-envlist = check-manifest,docs,doctest,flake8,pyright,py
+envlist = py,docs,doctest,ruff,ruff-format,pyright
 
 [testenv]
 deps =
     pytest
     pytest-cov
-setenv =
-    THREADING_TESTS = 1
 commands =
     py.test --basetemp={envtmpdir} --cov=cachetools --cov-report term-missing 
{posargs}
 
-[testenv:check-manifest]
-deps =
-    check-manifest
-commands =
-    check-manifest
-skip_install = true
-
 [testenv:docs]
 deps =
      sphinx
@@ -29,15 +20,18 @@
 commands =
      sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs 
{envtmpdir}/doctest
 
-[testenv:flake8]
+[testenv:ruff]
+deps =
+    ruff
+commands =
+    ruff check {posargs}
+skip_install = true
+
+[testenv:ruff-format]
 deps =
-    flake8
-    flake8-black
-    flake8-bugbear
-    flake8-import-order
-    flake8-pyproject
+    ruff
 commands =
-    flake8
+    ruff format --diff -q {posargs}
 skip_install = true
 
 [testenv:pyright]

Reply via email to