0001"""Caching decorators"""
0002import inspect
0003import logging
0004
0005from decorator import decorator
0006from paste.deploy.converters import asbool
0007
0008import pylons
0009
0010log = logging.getLogger(__name__)
0011
0012def beaker_cache(key="cache_default", expire="never", type="dbm",
0013 query_args=False, **b_kwargs):
0014 """Cache decorator utilizing Beaker. Caches action or other function that
0015 returns a pickle-able object as a result.
0016
0017 Optional arguments:
0018
0019 key
0020 None - No variable key, uses function name as key
0021 "cache_default" - Uses all function arguments as the key
0022 string - Use kwargs[key] as key
0023 list - Joins the arguments in the list
0024 expire
0025 Time in seconds before cache expires, defaults to never
0026 type
0027 Type of cache to use: dbm, memory, file, memcached
0028 query_args
0029 Uses the query arguments as the key, defaults to False
0030
0031 If cache_enabled is set to False in the .ini file, then cache is disabled
0032 globally.
0033 """
0034 def wrapper(func, *args, **kwargs):
0035 """Decorator wrapper"""
0036 log.debug("Wrapped with key: %s, expire: %s, type: %s, query_args: %s",
0037 key, expire, type, query_args)
0038 enabled = pylons.config.get("cache_enabled", "True")
0039 if not asbool(enabled):
0040 log.debug("Caching disabled, skipping cache lookup")
0041 return func(*args, **kwargs)
0042
0043 my_cache = pylons.cache.get_cache('%s.%s' % (func.__module__,
0044 func.__name__))
0045 cache_key = _make_key(func, key, args, kwargs, query_args)
0046
0047 if expire == "never":
0048 cache_expire = None
0049 else:
0050 cache_expire = expire
0051
0052
0053 def create_func():
0054 log.debug("Creating new cache copy with key: %s, type: %s",
0055 cache_key, type)
0056 result = func(*args, **kwargs)
0057 glob_response = pylons.response._current_obj()
0058 full_response = dict(headers=glob_response.headers,
0059 status=glob_response.status_code,
0060 cookies=glob_response.cookies,
0061 content=result)
0062 return full_response
0063
0064 response = my_cache.get_value(cache_key, createfunc=create_func,
0065 type=type, expiretime=cache_expire,
0066 **b_kwargs)
0067 glob_response = pylons.response._current_obj()
0068 glob_response.headers = response['headers']
0069 glob_response.status_code = response['status']
0070 glob_response.cookies = response['cookies']
0071 return response['content']
0072 return decorator(wrapper)
0073
0074def _make_key(func, key, args, kwargs, query_args):
0075 """Helps make unique key from largs, kwargs and request.GET"""
0076 if key == "cache_default":
0077 if query_args:
0078 cache_key = repr(dict(pylons.request.GET))
0079 else:
0080 cache_key = repr(kwargs.items())
0081 largs_keys = _make_dict_from_args(func, args)
0082 cache_key += repr(largs_keys.items())
0083 elif not key:
0084 cache_key = func.__name__
0085 else:
0086 if query_args:
0087 dic = pylons.request.GET
0088 else:
0089 largs_keys = _make_dict_from_args(func, args)
0090 dic = kwargs.copy()
0091 dic.update(largs_keys)
0092 if isinstance(key, list):
0093 cache_key = " ".join(["%s=%s" % (k, dic[k]) for k in key])
0094 else:
0095 cache_key = "%s=%s" % (key, dic[key])
0096 return cache_key
0097
0098def _make_dict_from_args(func, args):
0099 """Inspects function for name of args"""
0100 args_keys = {}
0101 for i, arg in enumerate(inspect.getargspec(func)[0]):
0102 if arg != "self":
0103 args_keys[arg] = args[i]
0104 return args_keys