Rewrite cache decorator to reference args by name

`@cache.delete('user', 'user_id')` is easier to read and understand than
`@cache.delete('user', key_from_args=[1])`. This will become even more
apparent if we have to start doing stuff like `key_from_args=[1, 5]`,
which is a lot more opaque than just saying
`'service_id', 'template_id'`.

It does make the implementation a bit more complex, but I’m not too
worried about that because:
- the tests are solid
- it’s nicely encapsulated
This commit is contained in:
Chris Hill-Scott
2018-04-19 10:23:21 +01:00
parent 6c8fea1ee8
commit 6101e5da43
5 changed files with 65 additions and 41 deletions

View File

@@ -1,27 +1,51 @@
import json
from contextlib import suppress
from datetime import timedelta
from functools import wraps
from inspect import signature
TTL = int(timedelta(hours=24).total_seconds())
def _make_key(prefix, args, key_from_args):
def _get_argument(argument_name, args, kwargs, client_method):
if key_from_args is None:
key_from_args = [0]
with suppress(KeyError):
return kwargs[argument_name]
with suppress(ValueError):
return args[list(signature(client_method).parameters).index(argument_name) - 1]
raise TypeError("{}() takes no argument called '{}'".format(
client_method.__name__, argument_name
))
def list_of_strings(list_of_stuff):
return list(map(str, filter(None, list_of_stuff)))
def _make_key(prefix, key_from_args, local_variables):
return '-'.join(
[prefix] + [args[index] for index in key_from_args]
[
local_variables['prefix']
] + list_of_strings(
_get_argument(
argument_name,
local_variables['args'],
local_variables['kwargs'],
local_variables['client_method']
) for argument_name in key_from_args
)
)
def set(prefix, key_from_args=None):
def set(prefix, *key_from_args):
def _set(client_method):
@wraps(client_method)
def new_client_method(client_instance, *args, **kwargs):
redis_key = _make_key(prefix, args, key_from_args)
redis_key = _make_key(prefix, key_from_args, locals())
cached = client_instance.redis_client.get(redis_key)
if cached:
return json.loads(cached.decode('utf-8'))
@@ -37,13 +61,13 @@ def set(prefix, key_from_args=None):
return _set
def delete(prefix, key_from_args=None):
def delete(prefix, *key_from_args):
def _delete(client_method):
@wraps(client_method)
def new_client_method(client_instance, *args, **kwargs):
redis_key = _make_key(prefix, args, key_from_args)
redis_key = _make_key(prefix, key_from_args, locals())
client_instance.redis_client.delete(redis_key)
return client_method(client_instance, *args, **kwargs)