From 45fc3ccec60ef937a8aab91a6b272fa6832ee510 Mon Sep 17 00:00:00 2001 From: Daniel Chin Date: Fri, 28 Mar 2025 18:28:26 +0400 Subject: [PATCH 1/4] add caller_with_freshness_threshold --- src/cachier/core.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/cachier/core.py b/src/cachier/core.py index 30fcb80..312c38f 100644 --- a/src/cachier/core.py +++ b/src/cachier/core.py @@ -13,7 +13,7 @@ from collections import OrderedDict from concurrent.futures import ThreadPoolExecutor from datetime import datetime, timedelta -from functools import wraps +from functools import wraps, partial from typing import Any, Optional, Union from warnings import warn @@ -214,8 +214,7 @@ def cachier( def _cachier_decorator(func): core.set_func(func) - @wraps(func) - def func_wrapper(*args, **kwds): + def _call(max_age: timedelta | None, *args, **kwds): nonlocal allow_none _allow_none = _update_with_defaults(allow_none, "allow_none", kwds) # print('Inside general wrapper for {}.'.format(func.__name__)) @@ -260,7 +259,7 @@ def func_wrapper(*args, **kwds): if _allow_none or entry.value is not None: _print("Cached result found.") now = datetime.now() - if now - entry.time <= _stale_after: + if now - entry.time <= min(_stale_after, max_age): _print("And it is fresh!") return entry.value _print("But it is stale... :(") @@ -294,6 +293,8 @@ def func_wrapper(*args, **kwds): _print("No entry found. No current calc. Calling like a boss.") return _calc_entry(core, key, func, args, kwds) + func_wrapper = wraps(func)(partial(_call, None)) + def _clear_cache(): """Clear the cache.""" core.clear_cache() @@ -320,11 +321,15 @@ def _precache_value(*args, value_to_cache, **kwds): # noqa: D417 func, _is_method=core.func_is_method, args=args, kwds=kwds ) return core.precache_value((), kwargs, value_to_cache) - + + def _caller_with_freshness_threshold(max_age: timedelta): + return wraps(func)(partial(_call, max_age)) + func_wrapper.clear_cache = _clear_cache func_wrapper.clear_being_calculated = _clear_being_calculated func_wrapper.cache_dpath = _cache_dpath func_wrapper.precache_value = _precache_value + func_wrapper.caller_with_freshness_threshold = _caller_with_freshness_threshold return func_wrapper return _cachier_decorator From 140fa24e7a4fb8753c4519bd9fea076a59312d05 Mon Sep 17 00:00:00 2001 From: Daniel Chin Date: Fri, 28 Mar 2025 18:41:57 +0400 Subject: [PATCH 2/4] fix type --- src/cachier/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cachier/core.py b/src/cachier/core.py index 312c38f..3a692d7 100644 --- a/src/cachier/core.py +++ b/src/cachier/core.py @@ -214,7 +214,7 @@ def cachier( def _cachier_decorator(func): core.set_func(func) - def _call(max_age: timedelta | None, *args, **kwds): + def _call(max_age: timedelta, *args, **kwds): nonlocal allow_none _allow_none = _update_with_defaults(allow_none, "allow_none", kwds) # print('Inside general wrapper for {}.'.format(func.__name__)) @@ -293,7 +293,7 @@ def _call(max_age: timedelta | None, *args, **kwds): _print("No entry found. No current calc. Calling like a boss.") return _calc_entry(core, key, func, args, kwds) - func_wrapper = wraps(func)(partial(_call, None)) + func_wrapper = wraps(func)(partial(_call, timedelta.max)) def _clear_cache(): """Clear the cache.""" From 8dc89d8834b3fb57a9c43bca7166e9a9eae30d62 Mon Sep 17 00:00:00 2001 From: Daniel Chin Date: Fri, 28 Mar 2025 18:42:03 +0400 Subject: [PATCH 3/4] simple test passed --- tests/test_call_with_freshness_threshold.py | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/test_call_with_freshness_threshold.py diff --git a/tests/test_call_with_freshness_threshold.py b/tests/test_call_with_freshness_threshold.py new file mode 100644 index 0000000..48146f6 --- /dev/null +++ b/tests/test_call_with_freshness_threshold.py @@ -0,0 +1,23 @@ +import time +from datetime import timedelta + +import cachier + +def test_call_with_freshness_threshold(): + @cachier.cachier() + def test_func(a, b): + print('Computing...') + return a + b + + print(f'{test_func(1, 2) = }') + print(f'{test_func(1, 2) = }') + caller_with_freshness_threshold = test_func.caller_with_freshness_threshold( + timedelta(seconds=0.5), + ) + print(f'{caller_with_freshness_threshold(1, 2) = }') + print(f'{time.sleep(1.0) = }') + print(f'{test_func(1, 2) = }') + print(f'{caller_with_freshness_threshold(1, 2) = }') + +if __name__ == '__main__': + test_call_with_freshness_threshold() From 25cc7f5487e37e9d3ec0c038ffcbcaeac69b594e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:52:30 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/cachier/core.py | 10 ++++---- tests/test_call_with_freshness_threshold.py | 26 ++++++++++++--------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/cachier/core.py b/src/cachier/core.py index 3a692d7..e57c772 100644 --- a/src/cachier/core.py +++ b/src/cachier/core.py @@ -13,7 +13,7 @@ from collections import OrderedDict from concurrent.futures import ThreadPoolExecutor from datetime import datetime, timedelta -from functools import wraps, partial +from functools import partial, wraps from typing import Any, Optional, Union from warnings import warn @@ -321,15 +321,17 @@ def _precache_value(*args, value_to_cache, **kwds): # noqa: D417 func, _is_method=core.func_is_method, args=args, kwds=kwds ) return core.precache_value((), kwargs, value_to_cache) - + def _caller_with_freshness_threshold(max_age: timedelta): return wraps(func)(partial(_call, max_age)) - + func_wrapper.clear_cache = _clear_cache func_wrapper.clear_being_calculated = _clear_being_calculated func_wrapper.cache_dpath = _cache_dpath func_wrapper.precache_value = _precache_value - func_wrapper.caller_with_freshness_threshold = _caller_with_freshness_threshold + func_wrapper.caller_with_freshness_threshold = ( + _caller_with_freshness_threshold + ) return func_wrapper return _cachier_decorator diff --git a/tests/test_call_with_freshness_threshold.py b/tests/test_call_with_freshness_threshold.py index 48146f6..e99a7c0 100644 --- a/tests/test_call_with_freshness_threshold.py +++ b/tests/test_call_with_freshness_threshold.py @@ -3,21 +3,25 @@ import cachier + def test_call_with_freshness_threshold(): @cachier.cachier() def test_func(a, b): - print('Computing...') + print("Computing...") return a + b - - print(f'{test_func(1, 2) = }') - print(f'{test_func(1, 2) = }') - caller_with_freshness_threshold = test_func.caller_with_freshness_threshold( - timedelta(seconds=0.5), + + print(f"{test_func(1, 2) = }") + print(f"{test_func(1, 2) = }") + caller_with_freshness_threshold = ( + test_func.caller_with_freshness_threshold( + timedelta(seconds=0.5), + ) ) - print(f'{caller_with_freshness_threshold(1, 2) = }') - print(f'{time.sleep(1.0) = }') - print(f'{test_func(1, 2) = }') - print(f'{caller_with_freshness_threshold(1, 2) = }') + print(f"{caller_with_freshness_threshold(1, 2) = }") + print(f"{time.sleep(1.0) = }") + print(f"{test_func(1, 2) = }") + print(f"{caller_with_freshness_threshold(1, 2) = }") + -if __name__ == '__main__': +if __name__ == "__main__": test_call_with_freshness_threshold()