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-05-12 19:26:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-cachetools (Old)
 and      /work/SRC/openSUSE:Factory/.python-cachetools.new.1966 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-cachetools"

Tue May 12 19:26:08 2026 rev:33 rq:1352302 version:7.1.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-cachetools/python-cachetools.changes      
2026-05-04 21:17:13.191843144 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-cachetools.new.1966/python-cachetools.changes
    2026-05-12 19:26:17.654156992 +0200
@@ -1,0 +2,8 @@
+Sun May  3 17:51:25 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 7.1.0:
+  * Add type stubs based on the work of the good people at
+    typeshed.
+  * Update unit tests.
+
+-------------------------------------------------------------------

Old:
----
  cachetools-7.0.6.tar.gz

New:
----
  cachetools-7.1.0.tar.gz

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

Other differences:
------------------
++++++ python-cachetools.spec ++++++
--- /var/tmp/diff_new_pack.QGyrmK/_old  2026-05-12 19:26:18.818205236 +0200
+++ /var/tmp/diff_new_pack.QGyrmK/_new  2026-05-12 19:26:18.822205401 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-cachetools
-Version:        7.0.6
+Version:        7.1.0
 Release:        0
 Summary:        Extensible memoizing collections and decorators
 License:        MIT

++++++ cachetools-7.0.6.tar.gz -> cachetools-7.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/CHANGELOG.rst 
new/cachetools-7.1.0/CHANGELOG.rst
--- old/cachetools-7.0.6/CHANGELOG.rst  2026-04-20 20:57:12.000000000 +0200
+++ new/cachetools-7.1.0/CHANGELOG.rst  2026-05-01 23:13:44.000000000 +0200
@@ -1,3 +1,12 @@
+v7.1.0 (2026-05-01)
+===================
+
+- Add type stubs based on the work of the good people at `typeshed
+  <https://github.com/python/typeshed/tree/main/stubs/cachetools/>`__.
+
+- Update unit tests.
+
+
 v7.0.6 (2026-04-20)
 ===================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/PKG-INFO 
new/cachetools-7.1.0/PKG-INFO
--- old/cachetools-7.0.6/PKG-INFO       2026-04-20 20:58:42.338762300 +0200
+++ new/cachetools-7.1.0/PKG-INFO       2026-05-01 23:15:48.482225400 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: cachetools
-Version: 7.0.6
+Version: 7.1.0
 Summary: Extensible memoizing collections and decorators
 Author-email: Thomas Kemmer <[email protected]>
 Maintainer-email: Thomas Kemmer <[email protected]>
@@ -101,11 +101,6 @@
 
   pip install cachetools
 
-Typing stubs for this package are provided by typeshed_ and can be
-installed by running::
-
-  pip install types-cachetools
-
 
 Project Resources
 ------------------------------------------------------------------------
@@ -142,7 +137,6 @@
 .. _cache algorithm: https://en.wikipedia.org/wiki/Cache_algorithms
 
 .. _PyPI: https://pypi.org/project/cachetools/
-.. _typeshed: https://github.com/python/typeshed/
 .. _Documentation: https://cachetools.readthedocs.io/
 .. _Issue tracker: https://github.com/tkem/cachetools/issues/
 .. _Source code: https://github.com/tkem/cachetools/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/README.rst 
new/cachetools-7.1.0/README.rst
--- old/cachetools-7.0.6/README.rst     2026-02-01 19:44:54.000000000 +0100
+++ new/cachetools-7.1.0/README.rst     2026-05-01 23:13:29.000000000 +0200
@@ -72,11 +72,6 @@
 
   pip install cachetools
 
-Typing stubs for this package are provided by typeshed_ and can be
-installed by running::
-
-  pip install types-cachetools
-
 
 Project Resources
 ------------------------------------------------------------------------
@@ -113,7 +108,6 @@
 .. _cache algorithm: https://en.wikipedia.org/wiki/Cache_algorithms
 
 .. _PyPI: https://pypi.org/project/cachetools/
-.. _typeshed: https://github.com/python/typeshed/
 .. _Documentation: https://cachetools.readthedocs.io/
 .. _Issue tracker: https://github.com/tkem/cachetools/issues/
 .. _Source code: https://github.com/tkem/cachetools/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/docs/conf.py 
new/cachetools-7.1.0/docs/conf.py
--- old/cachetools-7.0.6/docs/conf.py   2026-02-01 19:44:54.000000000 +0100
+++ new/cachetools-7.1.0/docs/conf.py   2026-05-01 23:13:29.000000000 +0200
@@ -16,6 +16,7 @@
         full_version = line.partition("=")[2].strip().strip("\"'")
         partial_version = ".".join(full_version.split(".")[:2])
         return full_version, partial_version
+    return (None, None)
 
 
 project = "cachetools"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/pyproject.toml 
new/cachetools-7.1.0/pyproject.toml
--- old/cachetools-7.0.6/pyproject.toml 2026-04-20 20:57:12.000000000 +0200
+++ new/cachetools-7.1.0/pyproject.toml 2026-05-01 23:13:29.000000000 +0200
@@ -53,4 +53,11 @@
 select = ["C", "E", "F", "W", "B", "B950", "I", "N"]
 # F401: imported but unused (submodule shims)
 # E501: line too long (black)
-ignore = ["F401", "E501"]
+# 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/src/cachetools/__init__.py 
new/cachetools-7.1.0/src/cachetools/__init__.py
--- old/cachetools-7.0.6/src/cachetools/__init__.py     2026-04-20 
20:57:12.000000000 +0200
+++ new/cachetools-7.1.0/src/cachetools/__init__.py     2026-05-01 
23:13:29.000000000 +0200
@@ -12,7 +12,7 @@
     "cachedmethod",
 )
 
-__version__ = "7.0.6"
+__version__ = "7.1.0"
 
 import collections
 import collections.abc
@@ -440,6 +440,9 @@
         # be O(1) regardless of cache contents.
         Cache.clear(self)
 
+    def expire(self, time=None):  # pragma: no cover
+        raise NotImplementedError
+
 
 class TTLCache(_TimedCache):
     """LRU Cache implementation with per-item time-to-live (TTL) value."""
@@ -711,6 +714,8 @@
         return value
 
 
+# note that the runtime __name__ is "CacheInfo", as in stdlib:
+# https://github.com/python/cpython/blob/3.14/Lib/functools.py#L520
 _CacheInfo = collections.namedtuple(
     "CacheInfo", ["hits", "misses", "maxsize", "currsize"]
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/src/cachetools/__init__.pyi 
new/cachetools-7.1.0/src/cachetools/__init__.pyi
--- old/cachetools-7.0.6/src/cachetools/__init__.pyi    1970-01-01 
01:00:00.000000000 +0100
+++ new/cachetools-7.1.0/src/cachetools/__init__.pyi    2026-05-01 
23:13:29.000000000 +0200
@@ -0,0 +1,213 @@
+import random
+from collections.abc import Callable, Iterator, MutableMapping, Sequence
+from contextlib import AbstractContextManager
+from typing import (
+    Any,
+    Final,
+    Generic,
+    Literal,
+    NamedTuple,
+    Protocol,
+    TypeVar,
+    overload,
+    type_check_only,
+)
+
+__all__: Final = (
+    "Cache",
+    "FIFOCache",
+    "LFUCache",
+    "LRUCache",
+    "RRCache",
+    "TLRUCache",
+    "TTLCache",
+    "cached",
+    "cachedmethod",
+)
+__version__: str
+
+_KT = TypeVar("_KT")
+_VT = TypeVar("_VT")
+_TT = TypeVar("_TT", default=float)
+_T = TypeVar("_T")
+_R = TypeVar("_R")
+_KT2 = TypeVar("_KT2")
+_VT2 = TypeVar("_VT2")
+
+class Cache(MutableMapping[_KT, _VT]):
+    def __init__(
+        self, maxsize: float, getsizeof: Callable[[_VT], float] | None = None
+    ) -> None: ...
+    def __getitem__(self, key: _KT) -> _VT: ...
+    def __setitem__(self, key: _KT, value: _VT) -> None: ...
+    def __delitem__(self, key: _KT) -> None: ...
+    def __missing__(self, key: _KT) -> _VT: ...
+    def __iter__(self) -> Iterator[_KT]: ...
+    def __len__(self) -> int: ...
+    @overload
+    def pop(self, key: _KT) -> _VT: ...
+    @overload
+    def pop(self, key: _KT, default: _VT | _T) -> _VT | _T: ...
+    def setdefault(self, key: _KT, default: _VT | None = None) -> _VT: ...
+    @property
+    def maxsize(self) -> float: ...
+    @property
+    def currsize(self) -> float: ...
+    @staticmethod
+    def getsizeof(value: _VT) -> float: ...
+
+class FIFOCache(Cache[_KT, _VT]): ...
+class LFUCache(Cache[_KT, _VT]): ...
+class LRUCache(Cache[_KT, _VT]): ...
+
+class RRCache(Cache[_KT, _VT]):
+    def __init__(
+        self,
+        maxsize: float,
+        choice: Callable[[Sequence[_KT]], _KT] = random.choice,
+        getsizeof: Callable[[_VT], float] | None = None,
+    ) -> None: ...
+    @property
+    def choice(self) -> Callable[[Sequence[_KT]], _KT]: ...
+
+class _TimedCache(Cache[_KT, _VT], Generic[_KT, _VT, _TT]):
+    def __init__(
+        self,
+        maxsize: float,
+        timer: Callable[[], _TT],
+        getsizeof: Callable[[_VT], float] | None = None,
+    ) -> None: ...
+
+    class _Timer(AbstractContextManager[_T]):
+        def __init__(self, timer: Callable[[], _T]) -> None: ...
+        def __call__(self) -> _T: ...
+        def __enter__(self) -> _T: ...
+        def __exit__(self, *exc: object) -> None: ...
+        def __getattr__(self, name: str) -> Any: ...
+
+    @property
+    def timer(self) -> _Timer[_TT]: ...
+
+class TTLCache(_TimedCache[_KT, _VT, _TT]):
+    @overload
+    def __init__(
+        self: TTLCache[_KT2, _VT2, float],
+        maxsize: float,
+        ttl: float,
+        *,
+        getsizeof: Callable[[_VT2], float] | None = None,
+    ) -> None: ...
+    @overload
+    def __init__(
+        self,
+        maxsize: float,
+        ttl: Any,  # FIXME: must be "addable" to _TT
+        timer: Callable[[], _TT],
+        getsizeof: Callable[[_VT], float] | None = None,
+    ) -> None: ...
+    @property
+    def ttl(self) -> Any: ...
+    def expire(self, time: _TT | None = None) -> list[tuple[_KT, _VT]]: ...
+
+class TLRUCache(_TimedCache[_KT, _VT, _TT]):
+    @overload
+    def __init__(
+        self: TLRUCache[_KT2, _VT2, float],
+        maxsize: float,
+        ttu: Callable[[_KT2, _VT2, float], float],
+        *,
+        getsizeof: Callable[[_VT2], float] | None = None,
+    ) -> None: ...
+    @overload
+    def __init__(
+        self,
+        maxsize: float,
+        ttu: Callable[[_KT, _VT, _TT], _TT],
+        timer: Callable[[], _TT],
+        getsizeof: Callable[[_VT], float] | None = None,
+    ) -> None: ...
+    @property
+    def ttu(self) -> Callable[[_KT, _VT, _TT], _TT]: ...
+    def expire(self, time: _TT | None = None) -> list[tuple[_KT, _VT]]: ...
+
+class _CacheInfo(NamedTuple):
+    hits: int
+    misses: int
+    maxsize: float | None
+    currsize: float
+
+@type_check_only
+class _AbstractCondition(AbstractContextManager[Any], Protocol):
+    # implementation and unit tests do not use plain wait() and notify()
+    def wait(self, timeout: float | None = None) -> bool: ...
+    def wait_for(
+        self, predicate: Callable[[], _T], timeout: float | None = None
+    ) -> _T: ...
+    def notify(self, n: int = 1) -> None: ...
+    def notify_all(self) -> None: ...
+
+@type_check_only
+class _cached_wrapper(Generic[_R]):
+    __wrapped__: Callable[..., _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 cache_clear(self) -> None: ...
+
+@type_check_only
+class _cached_wrapper_info(_cached_wrapper[_R]):
+    def cache_info(self) -> _CacheInfo: ...
+
+@overload
+def cached(
+    cache: MutableMapping[_KT, Any] | None,
+    key: Callable[..., _KT] = ...,
+    lock: AbstractContextManager[Any] | None = None,
+    condition: _AbstractCondition | None = None,
+    info: Literal[True] = ...,
+) -> Callable[[Callable[..., _R]], _cached_wrapper_info[_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]]: ...
+
+@type_check_only
+class _cachedmethod_wrapper(Generic[_R]):
+    __wrapped__: Callable[..., _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 cache_clear(self) -> None: ...
+
+@type_check_only
+class _cachedmethod_wrapper_info(_cachedmethod_wrapper[_R]):
+    def cache_info(self) -> _CacheInfo: ...
+
+@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[True] = ...,
+) -> Callable[[Callable[..., _R]], _cachedmethod_wrapper_info[_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]]: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/src/cachetools/_cachedmethod.py 
new/cachetools-7.1.0/src/cachetools/_cachedmethod.py
--- old/cachetools-7.0.6/src/cachetools/_cachedmethod.py        2026-03-09 
21:27:23.000000000 +0100
+++ new/cachetools-7.1.0/src/cachetools/_cachedmethod.py        2026-05-01 
23:13:29.000000000 +0200
@@ -80,7 +80,7 @@
             )
 
     def __get__(self, obj, objtype=None):
-        wrapper = self.Wrapper(obj)
+        wrapper = self.Wrapper(obj)  # type: ignore
         if obj is None:
             # Return the wrapper itself without modification when accessed
             # through the class to support class-level introspection, such
@@ -411,9 +411,11 @@
             wrapper = _unlocked(method, cache, key)
 
     # backward-compatible properties for deprecated @classmethod use
-    wrapper.cache = cache
-    wrapper.cache_key = key
-    wrapper.cache_lock = lock if lock is not None else cond
-    wrapper.cache_condition = cond
-
-    return functools.update_wrapper(wrapper, method)
+    wrapper.cache = cache  # type: ignore
+    wrapper.cache_key = key  # type: ignore
+    wrapper.cache_lock = lock if lock is not None else cond  # type: ignore
+    wrapper.cache_condition = cond  # type: ignore
+
+    # functools.update_wrapper() will not accept descriptor (decorator) as 
wrapper
+    # https://github.com/python/typeshed/issues/9846
+    return functools.update_wrapper(wrapper, method)  # type: ignore
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/src/cachetools/func.py 
new/cachetools-7.1.0/src/cachetools/func.py
--- old/cachetools-7.0.6/src/cachetools/func.py 2026-02-01 19:44:54.000000000 
+0100
+++ new/cachetools-7.1.0/src/cachetools/func.py 2026-05-01 23:13:29.000000000 
+0200
@@ -18,7 +18,7 @@
         TTLCache.__init__(self, math.inf, ttl, timer)
 
     @property
-    def maxsize(self):
+    def maxsize(self):  # type: ignore
         return None
 
 
@@ -29,7 +29,7 @@
         # using a condition variable
         key = keys.typedkey if typed else keys.hashkey
         wrapper = cached(cache=cache, key=key, condition=Condition(), 
info=True)(func)
-        wrapper.cache_parameters = lambda: {"maxsize": maxsize, "typed": typed}
+        wrapper.cache_parameters = lambda: {"maxsize": maxsize, "typed": 
typed}  # type: ignore
         return wrapper
 
     return decorator
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/src/cachetools/func.pyi 
new/cachetools-7.1.0/src/cachetools/func.pyi
--- old/cachetools-7.0.6/src/cachetools/func.pyi        1970-01-01 
01:00:00.000000000 +0100
+++ new/cachetools-7.1.0/src/cachetools/func.pyi        2026-05-01 
23:13:29.000000000 +0200
@@ -0,0 +1,70 @@
+from collections.abc import Callable, Sequence
+from typing import Any, Final, Generic, TypeVar, overload, type_check_only
+
+from . import _CacheInfo
+
+__all__: Final = ("fifo_cache", "lfu_cache", "lru_cache", "rr_cache", 
"ttl_cache")
+
+_T = TypeVar("_T")
+_R = TypeVar("_R")
+
+@type_check_only
+class _cachetools_cache_wrapper(Generic[_R]):
+    __wrapped__: Callable[..., _R]
+    __name__: str
+    __doc__: str | None
+    def __call__(self, /, *args: Any, **kwargs: Any) -> _R: ...
+    def cache_info(self) -> _CacheInfo: ...
+    def cache_clear(self) -> None: ...
+    def cache_parameters(self) -> dict[str, Any]: ...
+
+@overload
+def fifo_cache(
+    maxsize: int | None = 128, typed: bool = False
+) -> Callable[[Callable[..., _R]], _cachetools_cache_wrapper[_R]]: ...
+@overload
+def fifo_cache(
+    maxsize: Callable[..., _R], typed: bool = False
+) -> _cachetools_cache_wrapper[_R]: ...
+@overload
+def lfu_cache(
+    maxsize: int | None = 128, typed: bool = False
+) -> Callable[[Callable[..., _R]], _cachetools_cache_wrapper[_R]]: ...
+@overload
+def lfu_cache(
+    maxsize: Callable[..., _R], typed: bool = False
+) -> _cachetools_cache_wrapper[_R]: ...
+@overload
+def lru_cache(
+    maxsize: int | None = 128, typed: bool = False
+) -> Callable[[Callable[..., _R]], _cachetools_cache_wrapper[_R]]: ...
+@overload
+def lru_cache(
+    maxsize: Callable[..., _R], typed: bool = False
+) -> _cachetools_cache_wrapper[_R]: ...
+@overload
+def rr_cache(
+    maxsize: int | None = 128,
+    choice: Callable[[Sequence[_T]], _T] = ...,
+    typed: bool = False,
+) -> Callable[[Callable[..., _R]], _cachetools_cache_wrapper[_R]]: ...
+@overload
+def rr_cache(
+    maxsize: Callable[..., _R],
+    choice: Callable[[Sequence[_T]], _T] = ...,
+    typed: bool = False,
+) -> _cachetools_cache_wrapper[_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]]: ...
+@overload
+def ttl_cache(
+    maxsize: Callable[..., _R],
+    ttl: Any = 600,
+    timer: Callable[[], _T] = ...,
+    typed: bool = False,
+) -> _cachetools_cache_wrapper[_R]: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/src/cachetools/keys.pyi 
new/cachetools-7.1.0/src/cachetools/keys.pyi
--- old/cachetools-7.0.6/src/cachetools/keys.pyi        1970-01-01 
01:00:00.000000000 +0100
+++ new/cachetools-7.1.0/src/cachetools/keys.pyi        2026-05-01 
23:13:29.000000000 +0200
@@ -0,0 +1,14 @@
+from _typeshed import Unused
+from collections.abc import Hashable
+from typing import Final
+
+__all__: Final = ("hashkey", "methodkey", "typedkey", "typedmethodkey")
+
+def hashkey(*args: Hashable, **kwargs: Hashable) -> tuple[Hashable, ...]: ...
+def methodkey(
+    self: Unused, /, *args: Hashable, **kwargs: Hashable
+) -> tuple[Hashable, ...]: ...
+def typedkey(*args: Hashable, **kwargs: Hashable) -> tuple[Hashable, ...]: ...
+def typedmethodkey(
+    self: Unused, /, *args: Hashable, **kwargs: Hashable
+) -> tuple[Hashable, ...]: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/src/cachetools.egg-info/PKG-INFO 
new/cachetools-7.1.0/src/cachetools.egg-info/PKG-INFO
--- old/cachetools-7.0.6/src/cachetools.egg-info/PKG-INFO       2026-04-20 
20:58:42.000000000 +0200
+++ new/cachetools-7.1.0/src/cachetools.egg-info/PKG-INFO       2026-05-01 
23:15:48.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: cachetools
-Version: 7.0.6
+Version: 7.1.0
 Summary: Extensible memoizing collections and decorators
 Author-email: Thomas Kemmer <[email protected]>
 Maintainer-email: Thomas Kemmer <[email protected]>
@@ -101,11 +101,6 @@
 
   pip install cachetools
 
-Typing stubs for this package are provided by typeshed_ and can be
-installed by running::
-
-  pip install types-cachetools
-
 
 Project Resources
 ------------------------------------------------------------------------
@@ -142,7 +137,6 @@
 .. _cache algorithm: https://en.wikipedia.org/wiki/Cache_algorithms
 
 .. _PyPI: https://pypi.org/project/cachetools/
-.. _typeshed: https://github.com/python/typeshed/
 .. _Documentation: https://cachetools.readthedocs.io/
 .. _Issue tracker: https://github.com/tkem/cachetools/issues/
 .. _Source code: https://github.com/tkem/cachetools/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/src/cachetools.egg-info/SOURCES.txt 
new/cachetools-7.1.0/src/cachetools.egg-info/SOURCES.txt
--- old/cachetools-7.0.6/src/cachetools.egg-info/SOURCES.txt    2026-04-20 
20:58:42.000000000 +0200
+++ new/cachetools-7.1.0/src/cachetools.egg-info/SOURCES.txt    2026-05-01 
23:15:48.000000000 +0200
@@ -7,10 +7,14 @@
 docs/conf.py
 docs/index.rst
 src/cachetools/__init__.py
+src/cachetools/__init__.pyi
 src/cachetools/_cached.py
 src/cachetools/_cachedmethod.py
 src/cachetools/func.py
+src/cachetools/func.pyi
 src/cachetools/keys.py
+src/cachetools/keys.pyi
+src/cachetools/py.typed
 src/cachetools.egg-info/PKG-INFO
 src/cachetools.egg-info/SOURCES.txt
 src/cachetools.egg-info/dependency_links.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/__init__.py 
new/cachetools-7.1.0/tests/__init__.py
--- old/cachetools-7.0.6/tests/__init__.py      2026-04-20 20:25:01.000000000 
+0200
+++ new/cachetools-7.1.0/tests/__init__.py      2026-05-01 23:13:29.000000000 
+0200
@@ -1,8 +1,35 @@
-import unittest
+from collections.abc import Container, Iterable
+from typing import Any, Protocol, TypeAlias, no_type_check
 
+import cachetools
 
-class CacheTestMixin:
-    Cache = None
+
+class _TestCaseProtocol(Protocol):
+    def assertEqual(self, first: Any, second: Any, msg: Any = None) -> None: 
...
+    def assertNotEqual(self, first: Any, second: Any, msg: Any = None) -> 
None: ...
+    def assertTrue(self, expr: Any, msg: Any = None) -> None: ...
+    def assertFalse(self, expr: Any, msg: Any = None) -> None: ...
+    def assertIs(self, expr1: object, expr2: object, msg: Any = None) -> None: 
...
+    def assertIsNot(self, expr1: object, expr2: object, msg: Any = None) -> 
None: ...
+    def assertIsNone(self, obj: object, msg: Any = None) -> None: ...
+
+    def assertIn(
+        self, member: Any, container: Iterable[Any] | Container[Any], msg: Any 
= None
+    ) -> None: ...
+
+    def assertNotIn(
+        self, member: Any, container: Iterable[Any] | Container[Any], msg: Any 
= None
+    ) -> None: ...
+
+    def assertRaises(self, expected_exception: type[BaseException]) -> Any: ...
+
+    def assertRaisesRegex(
+        self, expected_exception: type[BaseException], expected_regex: str
+    ) -> Any: ...
+
+
+class CacheTestMixin(_TestCaseProtocol):
+    Cache: type[cachetools.Cache]
 
     def test_defaults(self):
         cache = self.Cache(maxsize=1)
@@ -112,13 +139,11 @@
     def test_popitem_exception_context(self):
         # since Python 3.7, MutableMapping.popitem() suppresses
         # exception context as implementation detail
-        exception = None
-        try:
+        with self.assertRaises(KeyError) as cm:
             self.Cache(maxsize=2).popitem()
-        except Exception as e:
-            exception = e
-        self.assertIsNone(exception.__cause__)
-        self.assertTrue(exception.__suppress_context__)
+        e = cm.exception
+        self.assertIsNone(e.__cause__)
+        self.assertTrue(e.__suppress_context__)
 
     def test_missing(self):
         class DefaultCache(self.Cache):
@@ -261,7 +286,8 @@
 
     def test_getsizeof_subclass(self):
         class Cache(self.Cache):
-            def getsizeof(self, value):
+            @staticmethod
+            def getsizeof(value):
                 return value
 
         self._test_getsizeof(Cache(maxsize=3))
@@ -372,12 +398,20 @@
         self.wait_count = 0
         self.notify_count = 0
 
-    # only wait_for() and notify_all() are used in the cache tests,
-    # calling wait() or notify() will fail intentionally
+    # only wait_for() and notify_all() are currently used, but wait()
+    # and notify() are also required according to the docs...
+
+    def wait(self, timeout=None):
+        self.wait_count += 1
+        return True
 
-    def wait_for(self, predicate):
-        assert callable(predicate)
+    def wait_for(self, predicate, timeout=None):
+        res = predicate()
         self.wait_count += 1
+        return res
+
+    def notify(self, n=1):
+        self.notify_count += 1
 
     def notify_all(self):
         self.notify_count += 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_cached.py 
new/cachetools-7.1.0/tests/test_cached.py
--- old/cachetools-7.0.6/tests/test_cached.py   2026-04-20 20:25:01.000000000 
+0200
+++ new/cachetools-7.1.0/tests/test_cached.py   2026-05-01 23:13:29.000000000 
+0200
@@ -4,10 +4,10 @@
 import cachetools
 import cachetools.keys
 
-from . import CountedCondition, CountedLock
+from . import CountedCondition, CountedLock, _TestCaseProtocol
 
 
-class DecoratorTestMixin:
+class DecoratorTestMixin(_TestCaseProtocol):
     def cache(self, minsize):
         raise NotImplementedError
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_cachedmethod.py 
new/cachetools-7.1.0/tests/test_cachedmethod.py
--- old/cachetools-7.0.6/tests/test_cachedmethod.py     2026-04-20 
20:25:01.000000000 +0200
+++ new/cachetools-7.1.0/tests/test_cachedmethod.py     2026-05-01 
23:13:29.000000000 +0200
@@ -5,7 +5,7 @@
 
 from cachetools import Cache, cachedmethod, keys
 
-from . import CountedCondition, CountedLock
+from . import CountedCondition, CountedLock, _TestCaseProtocol
 
 
 class Cached:
@@ -78,8 +78,8 @@
         raise TypeError("unhashable type")
 
 
-class MethodDecoratorTestMixin:
-    def cache(self, _minsize):
+class MethodDecoratorTestMixin(_TestCaseProtocol):
+    def cache(self, _minsize, **_kwargs):
         raise NotImplementedError
 
     def test_decorator(self):
@@ -358,7 +358,7 @@
         self.assertEqual(len(cache), 0)
         self.assertEqual(cached.get.__wrapped__(cached, 0), 0)
         self.assertEqual(cached.get.__name__, "get")
-        self.assertEqual(cached.get.__doc__.strip(), "docstring")
+        self.assertEqual((cached.get.__doc__ or "").strip(), "docstring")
         self.assertEqual(len(cache), 0)
         self.assertEqual(cached.get(0), 1)
         self.assertEqual(len(cache), 1)
@@ -459,7 +459,7 @@
             def __setitem__(self, _key, _value):
                 raise TypeError("Modification not supported")
 
-            def setdefault(self, _key, _value):
+            def setdefault(self, _key, _value=None):
                 raise TypeError("Modification not supported")
 
         class Immutable:
@@ -502,19 +502,18 @@
                 bar = foo
 
     def test_decorator_no_set_name(self):
-
         class Cached:
             def foo(_self):
                 pass
 
         # __set_name__ currently only asserted with info, since this
         # may also occur with deprecated @classmethod use
-        Cached.bar = cachedmethod(lambda _: self.cache(2), 
info=True)(Cached.foo)
+        Cached.bar = cachedmethod(lambda _: self.cache(2), 
info=True)(Cached.foo)  # type: ignore
 
         cached = Cached()
 
         with self.assertRaises(TypeError):
-            cached.bar()
+            cached.bar()  # type: ignore
 
 
 class CacheMethodTest(unittest.TestCase, MethodDecoratorTestMixin):
@@ -638,7 +637,7 @@
 
 class DictMethodTest(unittest.TestCase, MethodDecoratorTestMixin):
 
-    def cache(self, _minsize):
+    def cache(self, minsize, **_kwargs):
         return dict()
 
 
@@ -649,14 +648,14 @@
         import gc
         import weakref
 
-        # in Python 3.9, `int` does not support weak references even
-        # when subclassed, but Fraction apparently does...
+        # FIXME: in Python 3.9, `int` does not support weak references
+        # even when subclassed, but Fraction apparently does...
         class Int(fractions.Fraction):
-            def __add__(self, other):
+            def __add__(self, other):  # type: ignore
                 return Int(fractions.Fraction.__add__(self, other))
 
         cache = weakref.WeakValueDictionary()
-        cached = Cached(cache, count=Int(0))
+        cached = Cached(cache, count=Int(0))  # type: ignore
 
         self.assertEqual(cached.get(0), 0)
         gc.collect()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_classmethod.py 
new/cachetools-7.1.0/tests/test_classmethod.py
--- old/cachetools-7.0.6/tests/test_classmethod.py      2026-04-20 
20:25:01.000000000 +0200
+++ new/cachetools-7.1.0/tests/test_classmethod.py      2026-05-01 
23:13:29.000000000 +0200
@@ -1,13 +1,13 @@
 import threading
 import unittest
 import warnings
-
+from typing import Any
 
 from cachetools import LRUCache, cachedmethod, keys
 
 
 class Cached:
-    cache = LRUCache(2)
+    cache: LRUCache[Any, int] = LRUCache(2)
     count = 0
     lock = threading.Lock()
     cond = threading.Condition()
@@ -123,7 +123,7 @@
             warnings.simplefilter("ignore")
             self.assertEqual(cached.get(0), 1)
             self.assertEqual(len(Cached.cache), 1)
-            Cached.get.cache_clear(cached)
+            Cached.get.cache_clear(cached)  # type: ignore
             self.assertEqual(len(Cached.cache), 0)
 
     def test_clear_locked(self):
@@ -135,7 +135,7 @@
             warnings.simplefilter("ignore")
             self.assertEqual(cached.get_locked(0), 1)
             self.assertEqual(len(Cached.cache), 1)
-            Cached.get_locked.cache_clear(cached)
+            Cached.get_locked.cache_clear(cached)  # type: ignore
             self.assertEqual(len(Cached.cache), 0)
 
     def test_clear_condition(self):
@@ -147,5 +147,5 @@
             warnings.simplefilter("ignore")
             self.assertEqual(cached.get_condition(0), 1)
             self.assertEqual(len(Cached.cache), 1)
-            Cached.get_condition.cache_clear(cached)
+            Cached.get_condition.cache_clear(cached)  # type: ignore
             self.assertEqual(len(Cached.cache), 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_fifo.py 
new/cachetools-7.1.0/tests/test_fifo.py
--- old/cachetools-7.0.6/tests/test_fifo.py     2026-04-20 20:25:01.000000000 
+0200
+++ new/cachetools-7.1.0/tests/test_fifo.py     2026-05-01 23:13:29.000000000 
+0200
@@ -9,7 +9,7 @@
     Cache = FIFOCache
 
     def test_fifo(self):
-        cache = FIFOCache(maxsize=2)
+        cache = FIFOCache[int, int](maxsize=2)
 
         cache[1] = 1
         cache[2] = 2
@@ -34,7 +34,7 @@
         self.assertNotIn(3, cache)
 
     def test_fifo_getsizeof(self):
-        cache = FIFOCache(maxsize=3, getsizeof=lambda x: x)
+        cache = FIFOCache[int, int](maxsize=3, getsizeof=lambda x: x)
 
         cache[1] = 1
         cache[2] = 2
@@ -56,7 +56,7 @@
         self.assertEqual(cache[3], 3)
 
     def test_fifo_update_existing(self):
-        cache = FIFOCache(maxsize=2)
+        cache = FIFOCache[int, int | str](maxsize=2)
 
         cache[1] = 1
         cache[2] = 2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_func.py 
new/cachetools-7.1.0/tests/test_func.py
--- old/cachetools-7.0.6/tests/test_func.py     2026-04-20 20:25:01.000000000 
+0200
+++ new/cachetools-7.1.0/tests/test_func.py     2026-05-01 23:13:29.000000000 
+0200
@@ -1,9 +1,14 @@
 import unittest
+from typing import Any, Callable
 
 import cachetools.func
 
+from . import _TestCaseProtocol
+
+
+class DecoratorTestMixin(_TestCaseProtocol):
+    DECORATOR: Callable[..., Any]
 
-class DecoratorTestMixin:
     def decorator(self, maxsize, **kwargs):
         return self.DECORATOR(maxsize, **kwargs)
 
@@ -122,3 +127,18 @@
 
 class TTLDecoratorTest(unittest.TestCase, DecoratorTestMixin):
     DECORATOR = staticmethod(cachetools.func.ttl_cache)
+
+    def test_ttl_datetime(self):
+        from datetime import datetime, timedelta
+
+        cached = self.decorator(maxsize=2, ttl=timedelta(days=1), 
timer=datetime.now)(
+            lambda n: n
+        )
+        self.assertEqual(cached.cache_parameters(), {"maxsize": 2, "typed": 
False})
+        self.assertEqual(cached.cache_info(), (0, 0, 2, 0))
+        self.assertEqual(cached(1), 1)
+        self.assertEqual(cached.cache_info(), (0, 1, 2, 1))
+        self.assertEqual(cached(1), 1)
+        self.assertEqual(cached.cache_info(), (1, 1, 2, 1))
+        self.assertEqual(cached(1.0), 1.0)
+        self.assertEqual(cached.cache_info(), (2, 1, 2, 1))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_lfu.py 
new/cachetools-7.1.0/tests/test_lfu.py
--- old/cachetools-7.0.6/tests/test_lfu.py      2026-04-20 20:25:01.000000000 
+0200
+++ new/cachetools-7.1.0/tests/test_lfu.py      2026-05-01 23:13:29.000000000 
+0200
@@ -9,7 +9,7 @@
     Cache = LFUCache
 
     def test_lfu(self):
-        cache = LFUCache(maxsize=2)
+        cache = LFUCache[int, int](maxsize=2)
 
         cache[1] = 1
         cache[1]
@@ -32,7 +32,7 @@
         self.assertEqual(cache[4], 4)
 
     def test_lfu_getsizeof(self):
-        cache = LFUCache(maxsize=3, getsizeof=lambda x: x)
+        cache = LFUCache[int, int](maxsize=3, getsizeof=lambda x: x)
 
         cache[1] = 1
         cache[2] = 2
@@ -54,7 +54,7 @@
         self.assertEqual(cache[3], 3)
 
     def test_lfu_update_existing(self):
-        cache = LFUCache(maxsize=2)
+        cache = LFUCache[int, int | str](maxsize=2)
 
         cache[1] = 1
         cache[2] = 2
@@ -66,7 +66,7 @@
         self.assertNotIn(2, cache)
 
     def test_lfu_clear(self):
-        cache = LFUCache(maxsize=2)
+        cache = LFUCache[int, int](maxsize=2)
 
         cache[1] = 1
         cache[1]  # increment frequency
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_lru.py 
new/cachetools-7.1.0/tests/test_lru.py
--- old/cachetools-7.0.6/tests/test_lru.py      2026-04-20 20:25:01.000000000 
+0200
+++ new/cachetools-7.1.0/tests/test_lru.py      2026-05-01 23:13:29.000000000 
+0200
@@ -9,7 +9,7 @@
     Cache = LRUCache
 
     def test_lru(self):
-        cache = LRUCache(maxsize=2)
+        cache = LRUCache[int, int](maxsize=2)
 
         cache[1] = 1
         cache[2] = 2
@@ -34,7 +34,7 @@
         self.assertNotIn(2, cache)
 
     def test_lru_getsizeof(self):
-        cache = LRUCache(maxsize=3, getsizeof=lambda x: x)
+        cache = LRUCache[int, int](maxsize=3, getsizeof=lambda x: x)
 
         cache[1] = 1
         cache[2] = 2
@@ -56,7 +56,7 @@
         self.assertEqual(cache[3], 3)
 
     def test_lru_update_existing(self):
-        cache = LRUCache(maxsize=2)
+        cache = LRUCache[int, int | str](maxsize=2)
 
         cache[1] = 1
         cache[2] = 2
@@ -68,7 +68,7 @@
         self.assertNotIn(2, cache)
 
     def test_lru_clear(self):
-        cache = LRUCache(maxsize=2)
+        cache = LRUCache[int, int](maxsize=2)
 
         cache[1] = 1
         cache[2] = 2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_rr.py 
new/cachetools-7.1.0/tests/test_rr.py
--- old/cachetools-7.0.6/tests/test_rr.py       2026-04-20 20:25:01.000000000 
+0200
+++ new/cachetools-7.1.0/tests/test_rr.py       2026-05-01 23:13:29.000000000 
+0200
@@ -10,7 +10,7 @@
     Cache = RRCache
 
     def test_rr(self):
-        cache = RRCache(maxsize=2, choice=min)
+        cache = RRCache[int, int](maxsize=2, choice=min)
         self.assertEqual(min, cache.choice)
 
         cache[1] = 1
@@ -35,7 +35,7 @@
         self.assertNotIn(0, cache)
 
     def test_rr_getsizeof(self):
-        cache = RRCache(maxsize=3, choice=min, getsizeof=lambda x: x)
+        cache = RRCache[int, int](maxsize=3, choice=min, getsizeof=lambda x: x)
 
         cache[1] = 1
         cache[2] = 2
@@ -57,7 +57,7 @@
         self.assertEqual(cache[3], 3)
 
     def test_rr_update_existing(self):
-        cache = RRCache(maxsize=2, choice=min)
+        cache = RRCache[int, int | str](maxsize=2, choice=min)
 
         cache[1] = 1
         cache[2] = 2
@@ -72,7 +72,7 @@
         def bad_choice(seq):
             raise ValueError("test error")
 
-        cache = RRCache(maxsize=2, choice=bad_choice)
+        cache = RRCache[int, int](maxsize=2, choice=bad_choice)
         cache[1] = 1
         cache[2] = 2
         with self.assertRaises(ValueError):
@@ -84,5 +84,5 @@
         self.assertNotIn(3, cache)
 
     def test_rr_default_choice(self):
-        cache = RRCache(maxsize=2)
+        cache = RRCache[int, int](maxsize=2)
         self.assertIs(cache.choice, random.choice)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_threading.py 
new/cachetools-7.1.0/tests/test_threading.py
--- old/cachetools-7.0.6/tests/test_threading.py        2026-04-20 
20:25:01.000000000 +0200
+++ new/cachetools-7.1.0/tests/test_threading.py        2026-05-01 
23:13:29.000000000 +0200
@@ -2,18 +2,19 @@
 import time
 import unittest
 from os import environ
+from typing import Any
 
 from cachetools import LRUCache, cached, cachedmethod
 
+count = 0
+
 
 @cached(cache=LRUCache(1), condition=threading.Condition(), info=True)
 def func():
+    global count
     time.sleep(1.0)
-    if hasattr(func, "count"):
-        func.count += 1
-    else:
-        func.count = 1
-    return func.count
+    count += 1
+    return count
 
 
 @unittest.skipUnless(environ.get("THREADING_TESTS", False), "THREADING_TESTS 
not set")
@@ -21,7 +22,7 @@
 
     NTHREADS = 10
 
-    cache = LRUCache(1)
+    cache: LRUCache[Any, int] = LRUCache(1)
 
     cond = threading.Condition()
 
@@ -42,7 +43,7 @@
         for t in threads:
             t.join()
 
-        self.assertEqual(func.count, 1)
+        self.assertEqual(count, 1)
 
         info = func.cache_info()
         self.assertEqual(info.hits, self.NTHREADS - 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_tlru.py 
new/cachetools-7.1.0/tests/test_tlru.py
--- old/cachetools-7.0.6/tests/test_tlru.py     2026-04-20 20:25:01.000000000 
+0200
+++ new/cachetools-7.1.0/tests/test_tlru.py     2026-05-01 23:13:29.000000000 
+0200
@@ -33,9 +33,11 @@
     Cache = TLRUTestCache
 
     def test_ttu(self):
-        cache = TLRUCache(maxsize=6, ttu=lambda _, v, t: t + v + 1, 
timer=Timer())
+        cache = TLRUCache[int, int, int](
+            maxsize=6, ttu=lambda _, v, t: t + v + 1, timer=Timer()
+        )
         self.assertEqual(0, cache.timer())
-        self.assertEqual(3, cache.ttu(None, 1, 1))
+        self.assertEqual(3, cache.ttu(0, 1, 1))
 
         cache[1] = 1
         self.assertEqual(1, cache[1])
@@ -110,9 +112,12 @@
         self.assertEqual(set(), set(cache))
 
     def test_ttu_lru(self):
-        cache = TLRUCache(maxsize=2, ttu=lambda k, v, t: t + 1, timer=Timer())
+        def ttu(_k, _v, t):
+            return t + 1
+
+        cache = TLRUCache[int, int, int](maxsize=2, ttu=ttu, timer=Timer())
         self.assertEqual(0, cache.timer())
-        self.assertEqual(2, cache.ttu(None, None, 1))
+        self.assertEqual(2, cache.ttu(0, 0, 1))
 
         cache[1] = 1
         cache[2] = 2
@@ -140,7 +145,10 @@
         self.assertEqual(cache[5], 5)
 
     def test_ttu_expire(self):
-        cache = TLRUCache(maxsize=3, ttu=lambda k, v, t: t + 3, timer=Timer())
+        def ttu(_k, _v, t):
+            return t + 3
+
+        cache = TLRUCache[int, int, int](maxsize=3, ttu=ttu, timer=Timer())
         with cache.timer as time:
             self.assertEqual(time, cache.timer())
 
@@ -190,7 +198,9 @@
         self.assertNotIn(3, cache)
 
     def test_ttu_expired(self):
-        cache = TLRUCache(maxsize=1, ttu=lambda k, _, t: t + k, timer=Timer())
+        cache = TLRUCache[int, None, int](
+            maxsize=1, ttu=lambda k, _, t: t + k, timer=Timer()
+        )
         cache[1] = None
         self.assertEqual(cache[1], None)
         self.assertEqual(1, len(cache))
@@ -205,7 +215,9 @@
         self.assertEqual(1, len(cache))
 
     def test_ttu_atomic(self):
-        cache = TLRUCache(maxsize=1, ttu=lambda k, v, t: t + 2, 
timer=Timer(auto=True))
+        cache = TLRUCache[int, int, int](
+            maxsize=1, ttu=lambda k, v, t: t + 2, timer=Timer(auto=True)
+        )
         cache[1] = 1
         self.assertEqual(1, cache[1])
         cache[1] = 1
@@ -219,7 +231,9 @@
         self.assertEqual(0, len(cache))
 
     def test_ttu_tuple_key(self):
-        cache = TLRUCache(maxsize=1, ttu=lambda k, v, t: t + 1, timer=Timer())
+        cache = TLRUCache[tuple[int, ...], int, int](
+            maxsize=1, ttu=lambda k, v, t: t + 1, timer=Timer()
+        )
 
         cache[(1, 2, 3)] = 42
         self.assertEqual(42, cache[(1, 2, 3)])
@@ -229,7 +243,10 @@
         self.assertNotIn((1, 2, 3), cache)
 
     def test_ttu_reverse_insert(self):
-        cache = TLRUCache(maxsize=4, ttu=lambda k, v, t: t + v, timer=Timer())
+        def ttu(_k, v, t):
+            return t + v
+
+        cache = TLRUCache[int, int, int](maxsize=4, ttu=ttu, timer=Timer())
         self.assertEqual(0, cache.timer())
 
         cache[3] = 3
@@ -272,7 +289,10 @@
         self.assertNotIn(3, cache)
 
     def test_ttu_heap_cleanup(self):
-        cache = TLRUCache(maxsize=4, ttu=lambda k, v, t: t + 1, timer=Timer())
+        def ttu(_k, _v, t):
+            return t + 1
+
+        cache = TLRUCache[int, int, int](maxsize=4, ttu=ttu, timer=Timer())
         self.assertEqual(0, cache.timer())
 
         cache[1] = 1
@@ -300,8 +320,28 @@
         self.assertEqual(4, len(expired))
         self.assertEqual(0, len(cache))
 
+    def test_tlru_datetime(self):
+        from datetime import datetime, timedelta
+
+        def ttu(_k, _v, t):
+            return t + timedelta(days=1)
+
+        cache = TLRUCache[int, int, datetime](maxsize=1, ttu=ttu, 
timer=datetime.now)
+
+        cache[1] = 1
+        self.assertEqual(1, len(cache))
+        items = cache.expire(datetime.now())
+        self.assertEqual([], list(items))
+        self.assertEqual(1, len(cache))
+        items = cache.expire(datetime.now() + timedelta(days=1))
+        self.assertEqual([(1, 1)], list(items))
+        self.assertEqual(0, len(cache))
+
     def test_tlru_clear(self):
-        cache = TLRUCache(maxsize=2, ttu=lambda k, v, t: t + 2, timer=Timer())
+        def ttu(_k, _v, t):
+            return t + 2
+
+        cache = TLRUCache[int, int, int](maxsize=2, ttu=ttu, timer=Timer())
 
         cache[1] = 1
         cache[2] = 2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tests/test_ttl.py 
new/cachetools-7.1.0/tests/test_ttl.py
--- old/cachetools-7.0.6/tests/test_ttl.py      2026-04-20 20:25:01.000000000 
+0200
+++ new/cachetools-7.1.0/tests/test_ttl.py      2026-05-01 23:13:29.000000000 
+0200
@@ -29,7 +29,7 @@
     Cache = TTLTestCache
 
     def test_ttl(self):
-        cache = TTLCache(maxsize=2, ttl=2, timer=Timer())
+        cache = TTLCache[int, int, int](maxsize=2, ttl=2, timer=Timer())
         self.assertEqual(0, cache.timer())
         self.assertEqual(2, cache.ttl)
 
@@ -85,7 +85,7 @@
         self.assertEqual(set(), set(cache))
 
     def test_ttl_timer(self):
-        cache = TTLCache(maxsize=2, ttl=2, timer=Timer())
+        cache = TTLCache[int, int, int](maxsize=2, ttl=2, timer=Timer())
         self.assertEqual(cache.timer.time, 0)
         self.assertFalse(cache.timer.auto)
 
@@ -99,7 +99,7 @@
         self.assertNotIn(1, cache)
 
     def test_ttl_lru(self):
-        cache = TTLCache(maxsize=2, ttl=1, timer=Timer())
+        cache = TTLCache[int, int, int](maxsize=2, ttl=1, timer=Timer())
 
         cache[1] = 1
         cache[2] = 2
@@ -127,7 +127,7 @@
         self.assertEqual(cache[5], 5)
 
     def test_ttl_expire(self):
-        cache = TTLCache(maxsize=3, ttl=3, timer=Timer())
+        cache = TTLCache[int, int, int](maxsize=3, ttl=3, timer=Timer())
         with cache.timer as time:
             self.assertEqual(time, cache.timer())
         self.assertEqual(3, cache.ttl)
@@ -178,7 +178,7 @@
         self.assertNotIn(3, cache)
 
     def test_ttl_atomic(self):
-        cache = TTLCache(maxsize=1, ttl=2, timer=Timer(auto=True))
+        cache = TTLCache[int, int, int](maxsize=1, ttl=2, 
timer=Timer(auto=True))
         cache[1] = 1
         self.assertEqual(1, cache[1])
         cache[1] = 1
@@ -192,7 +192,7 @@
         self.assertEqual(0, len(cache))
 
     def test_ttl_tuple_key(self):
-        cache = TTLCache(maxsize=1, ttl=1, timer=Timer())
+        cache = TTLCache[tuple[int, ...], int, int](maxsize=1, ttl=1, 
timer=Timer())
         self.assertEqual(1, cache.ttl)
 
         cache[(1, 2, 3)] = 42
@@ -205,7 +205,9 @@
     def test_ttl_datetime(self):
         from datetime import datetime, timedelta
 
-        cache = TTLCache(maxsize=1, ttl=timedelta(days=1), timer=datetime.now)
+        cache = TTLCache[int, int, datetime](
+            maxsize=1, ttl=timedelta(days=1), timer=datetime.now
+        )
 
         cache[1] = 1
         self.assertEqual(1, len(cache))
@@ -217,7 +219,7 @@
         self.assertEqual(0, len(cache))
 
     def test_ttl_clear(self):
-        cache = TTLCache(maxsize=2, ttl=2, timer=Timer())
+        cache = TTLCache[int, int, int](maxsize=2, ttl=2, timer=Timer())
 
         cache[1] = 1
         cache[2] = 2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cachetools-7.0.6/tox.ini new/cachetools-7.1.0/tox.ini
--- old/cachetools-7.0.6/tox.ini        2026-04-20 20:25:01.000000000 +0200
+++ new/cachetools-7.1.0/tox.ini        2026-05-01 23:13:29.000000000 +0200
@@ -1,5 +1,5 @@
 [tox]
-envlist = check-manifest,docs,doctest,flake8,py
+envlist = check-manifest,docs,doctest,flake8,pyright,py
 
 [testenv]
 deps =
@@ -39,3 +39,10 @@
 commands =
     flake8
 skip_install = true
+
+[testenv:pyright]
+deps =
+    pyright
+commands =
+    pyright {posargs}
+skip_install = true

Reply via email to