Create a gist now

Instantly share code, notes, and snippets.

Cache key generator, can be used for things like dogpile.cache
"""
Based on code of dogpile.cache.util.function_key_generator(...) but adds support for kw.
Related dogpile.cache bug: https://bitbucket.org/zzzeek/dogpile.cache/issue/43/kw-support-in-function_key_generator
Usage:
from dogpile.cache import make_region
my_region = make_region(
function_key_generator=make_key_generator,
).configure(...)
"""
def make_key_generator(namespace, fn, value_mangler=str, arg_blacklist=('self', 'cls')):
"""
Create a cache key generator for function calls of fn.
:param namespace:
Value to prefix all keys with. Useful for differentiating methods with
the same name but in different classes.
:param fn:
Function to create a key generator for.
:param value_mangler:
Each value passed to the function is run through this mangler.
Default: str
:param arg_blacklist:
Iterable of arguments to ignore when creating a key.
Returns a function which can be called with the same arguments as fn but
returns a corresponding key for that call.
Note: Ingores fn(..., *arg, **kw) parameters.
"""
# TODO: Include parent class in name?
# TODO: Handle undefined vararg and kw?
# TODO: Better default value_mangler?
fn_args = inspect.getargspec(fn).args
arg_blacklist = arg_blacklist or []
if namespace is None:
namespace = '%s:%s' % (fn.__module__, fn.__name__)
else:
namespace = '%s:%s|%s' % (fn.__module__, fn.__name__, namespace)
def generate_key(*arg, **kw):
kw.update(zip(fn_args, arg))
for arg in arg_blacklist:
kw.pop(arg, None)
key = namespace + '|' + ' '.join(value_mangler(kw[k]) for k in sorted(kw))
return key
return generate_key
@warvariuc
>>> def generate_key(*arg, **kw):     
        kw.update(zip(fn_args, arg))
        return ' '.join(str(kw[k]) for k in sorted(kw))
... 

>>> fn_args = ('self', 'arg1', 'arg2')

>>> generate_key(None, 2, 3, kw1='kw1', kw3='kw3')
>>> '2 3 kw1 kw3 None'

>>> generate_key(None, 2, 3, kw1='kw1', kw2='kw3')
>>> '2 3 kw1 kw3 None'

sorted(kw) makes the same key in two different cases when keyword argument names differ but their sorting order is the same.

I think keyword argument names should be included in the key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment