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