remove simplejson dependency
[plcapi.git] / cache_utils / decorators.py
1 #coding: utf-8
2 from django.core.cache import cache
3 from django.utils.functional import wraps
4 from cache_utils.utils import _cache_key, _func_info, _func_type
5
6 def cached(timeout, group=None):
7     """ Caching decorator. Can be applied to function, method or classmethod.
8     Supports bulk cache invalidation and invalidation for exact parameter
9     set. Cache keys are human-readable because they are constructed from
10     callable's full name and arguments and then sanitized to make
11     memcached happy.
12
13     It can be used with or without group_backend. Without group_backend
14     bulk invalidation is not supported.
15
16     Wrapped callable gets `invalidate` methods. Call `invalidate` with
17     same arguments as function and the result for these arguments will be
18     invalidated.
19     """
20
21     backend_kwargs = {'group': group} if group else {}
22
23     def _cached(func):
24
25         func_type = _func_type(func)
26
27         @wraps(func)
28         def wrapper(*args, **kwargs):
29
30             # full name is stored as attribute on first call
31             if not hasattr(wrapper, '_full_name'):
32                 name, _args = _func_info(func, args)
33                 wrapper._full_name = name
34
35             # try to get the value from cache
36             key = _cache_key(wrapper._full_name, func_type, args, kwargs)
37             value = cache.get(key, **backend_kwargs)
38
39             # in case of cache miss recalculate the value and put it to the cache
40             if value is None:
41                 value = func(*args, **kwargs)
42                 cache.set(key, value, timeout, **backend_kwargs)
43             return value
44
45         def invalidate(*args, **kwargs):
46             ''' invalidates cache result for function called with passed arguments '''
47             if not hasattr(wrapper, '_full_name'):
48                 return
49             key = _cache_key(wrapper._full_name, 'function', args, kwargs)
50             cache.delete(key, **backend_kwargs)
51
52         wrapper.invalidate = invalidate
53         return wrapper
54     return _cached