Skip to content

Commit 1808a57

Browse files
committed
feat: Adds option in memoize to ignore args
1 parent 9e1b157 commit 1808a57

File tree

2 files changed

+61
-13
lines changed

2 files changed

+61
-13
lines changed

flask_caching/__init__.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@
4242

4343

4444
def wants_args(f):
45-
"""Check if the function wants any arguments
46-
"""
45+
"""Check if the function wants any arguments"""
4746

4847
argspec = inspect.getfullargspec(f)
4948

@@ -299,7 +298,7 @@ def cached(
299298
hash_method=hashlib.md5,
300299
cache_none=False,
301300
make_cache_key=None,
302-
source_check=None
301+
source_check=None,
303302
):
304303
"""Decorator. Use this to cache a function. By default the cache key
305304
is `view/request.path`. You are able to use this decorator with any
@@ -417,8 +416,9 @@ def decorated_function(*args, **kwargs):
417416
if make_cache_key is not None and callable(make_cache_key):
418417
cache_key = make_cache_key(*args, **kwargs)
419418
else:
420-
cache_key = _make_cache_key(args, kwargs, use_request=True)
421-
419+
cache_key = _make_cache_key(
420+
args, kwargs, use_request=True
421+
)
422422

423423
if (
424424
callable(forced_update)
@@ -535,14 +535,17 @@ def _make_cache_key(args, kwargs, use_request):
535535
if use_request:
536536
cache_key = key_prefix % request.path
537537
else:
538-
cache_key = key_prefix % url_for(f.__name__, **kwargs)
538+
cache_key = key_prefix % url_for(
539+
f.__name__, **kwargs
540+
)
539541
else:
540542
cache_key = key_prefix
541543

542544
if source_check and callable(f):
543545
func_source_code = inspect.getsource(f)
544546
func_source_hash = hash_method(
545-
func_source_code.encode("utf-8"))
547+
func_source_code.encode("utf-8")
548+
)
546549
func_source_hash = str(func_source_hash.hexdigest())
547550

548551
cache_key += func_source_hash
@@ -572,6 +575,7 @@ def _memoize_version(
572575
delete=False,
573576
timeout=None,
574577
forced_update=False,
578+
args_to_ignore=None,
575579
):
576580
"""Updates the hash version associated with a memoized function or
577581
method.
@@ -580,6 +584,10 @@ def _memoize_version(
580584
version_key = self._memvname(fname)
581585
fetch_keys = [version_key]
582586

587+
args_to_ignore = args_to_ignore or []
588+
if "self" in args_to_ignore:
589+
instance_fname = None
590+
583591
if instance_fname:
584592
instance_version_key = self._memvname(instance_fname)
585593
fetch_keys.append(instance_version_key)
@@ -633,14 +641,20 @@ def _memoize_make_cache_key(
633641
timeout=None,
634642
forced_update=False,
635643
hash_method=hashlib.md5,
636-
source_check=False
644+
source_check=False,
645+
args_to_ignore=None,
637646
):
638647
"""Function used to create the cache_key for memoized functions."""
639648

640649
def make_cache_key(f, *args, **kwargs):
641650
_timeout = getattr(timeout, "cache_timeout", timeout)
642651
fname, version_data = self._memoize_version(
643-
f, args=args, kwargs=kwargs, timeout=_timeout, forced_update=forced_update
652+
f,
653+
args=args,
654+
kwargs=kwargs,
655+
timeout=_timeout,
656+
forced_update=forced_update,
657+
args_to_ignore=args_to_ignore,
644658
)
645659

646660
#: this should have to be after version_data, so that it
@@ -649,7 +663,7 @@ def make_cache_key(f, *args, **kwargs):
649663

650664
if callable(f):
651665
keyargs, keykwargs = self._memoize_kwargs_to_args(
652-
f, *args, **kwargs
666+
f, *args, **kwargs, args_to_ignore=args_to_ignore
653667
)
654668
else:
655669
keyargs, keykwargs = args, kwargs
@@ -680,6 +694,7 @@ def _memoize_kwargs_to_args(self, f, *args, **kwargs):
680694
#: 1, b=2 is equivilant to a=1, b=2, etc.
681695
new_args = []
682696
arg_num = 0
697+
args_to_ignore = kwargs.pop("args_to_ignore", None) or []
683698

684699
# If the function uses VAR_KEYWORD type of parameters,
685700
# we need to pass these further
@@ -689,7 +704,10 @@ def _memoize_kwargs_to_args(self, f, *args, **kwargs):
689704

690705
for i in range(args_len):
691706
arg_default = get_arg_default(f, i)
692-
if i == 0 and arg_names[i] in ("self", "cls"):
707+
if arg_names[i] in args_to_ignore:
708+
arg = None
709+
arg_num += 1
710+
elif i == 0 and arg_names[i] in ("self", "cls"):
693711
#: use the id func of the class instance
694712
#: this supports instance methods for
695713
#: the memoized functions, giving more
@@ -769,7 +787,8 @@ def memoize(
769787
response_filter=None,
770788
hash_method=hashlib.md5,
771789
cache_none=False,
772-
source_check=None
790+
source_check=None,
791+
args_to_ignore=None,
773792
):
774793
"""Use this to cache the result of a function, taking its arguments
775794
into account in the cache key.
@@ -847,9 +866,17 @@ def big_foo(a, b):
847866
formed with the function's source code hash in
848867
addition to other parameters that may be included
849868
in the formation of the key.
869+
:param args_to_ignore: List of arguments that will be ignored while
870+
generating the cache key. Default to None.
871+
This means that those arguments may change
872+
without affecting the cache value that will be
873+
returned.
850874
851875
.. versionadded:: 0.5
852876
params ``make_name``, ``unless``
877+
878+
.. versionadded:: 1.10
879+
params ``args_to_ignore``
853880
"""
854881

855882
def memoize(f):
@@ -928,7 +955,8 @@ def decorated_function(*args, **kwargs):
928955
timeout=decorated_function,
929956
forced_update=forced_update,
930957
hash_method=hash_method,
931-
source_check=source_check
958+
source_check=source_check,
959+
args_to_ignore=args_to_ignore,
932960
)
933961
decorated_function.delete_memoized = lambda: self.delete_memoized(f)
934962

tests/test_memoize.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,3 +760,23 @@ def big_foo(a, b):
760760
third_try = big_foo(5, 2)
761761

762762
assert third_try == first_try
763+
764+
765+
def test_memoize_ignore_args(app, cache):
766+
with app.test_request_context():
767+
@cache.memoize(50, args_to_ignore=["b"])
768+
def big_foo(a, b):
769+
return a + b + random.randrange(0, 100000)
770+
771+
result = big_foo(5, 2)
772+
assert big_foo(5, 3) == result
773+
774+
775+
def test_memoize_method_ignore_self_arg(app, cache):
776+
with app.test_request_context():
777+
class Foo(object):
778+
@cache.memoize(50, args_to_ignore=["self"])
779+
def big_foo(self, a, b):
780+
return a + b + random.randrange(0, 100000)
781+
782+
assert Foo().big_foo(5, 2) == Foo().big_foo(5, 2)

0 commit comments

Comments
 (0)