# mako/cache.py # Copyright (C) 2006-2011 the Mako authors and contributors # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php from mako import exceptions cache = None class BeakerMissing(object): def get_cache(self, name, **kwargs): raise exceptions.RuntimeException("the Beaker package is required to use cache functionality.") class Cache(object): """Represents a data content cache made available to the module space of a :class:`.Template` object. :class:`.Cache` is a wrapper on top of a Beaker CacheManager object. This object in turn references any number of "containers", each of which defines its own backend (i.e. file, memory, memcached, etc.) independently of the rest. """ def __init__(self, id, starttime): self.id = id self.starttime = starttime self.def_regions = {} def put(self, key, value, **kwargs): """Place a value in the cache. :param key: the value's key. :param value: the value :param \**kwargs: cache configuration arguments. The backend is configured using these arguments upon first request. Subsequent requests that use the same series of configuration values will use that same backend. """ defname = kwargs.pop('defname', None) expiretime = kwargs.pop('expiretime', None) createfunc = kwargs.pop('createfunc', None) self._get_cache(defname, **kwargs).put_value(key, starttime=self.starttime, expiretime=expiretime) def get(self, key, **kwargs): """Retrieve a value from the cache. :param key: the value's key. :param \**kwargs: cache configuration arguments. The backend is configured using these arguments upon first request. Subsequent requests that use the same series of configuration values will use that same backend. """ defname = kwargs.pop('defname', None) expiretime = kwargs.pop('expiretime', None) createfunc = kwargs.pop('createfunc', None) return self._get_cache(defname, **kwargs).get_value(key, starttime=self.starttime, expiretime=expiretime, createfunc=createfunc) def invalidate(self, key, **kwargs): """Invalidate a value in the cache. :param key: the value's key. :param \**kwargs: cache configuration arguments. The backend is configured using these arguments upon first request. Subsequent requests that use the same series of configuration values will use that same backend. """ defname = kwargs.pop('defname', None) expiretime = kwargs.pop('expiretime', None) createfunc = kwargs.pop('createfunc', None) self._get_cache(defname, **kwargs).remove_value(key, starttime=self.starttime, expiretime=expiretime) def invalidate_body(self): """Invalidate the cached content of the "body" method for this template. """ self.invalidate('render_body', defname='render_body') def invalidate_def(self, name): """Invalidate the cached content of a particular <%def> within this template.""" self.invalidate('render_%s' % name, defname='render_%s' % name) def invalidate_closure(self, name): """Invalidate a nested <%def> within this template. Caching of nested defs is a blunt tool as there is no management of scope - nested defs that use cache tags need to have names unique of all other nested defs in the template, else their content will be overwritten by each other. """ self.invalidate(name, defname=name) def _get_cache(self, defname, type=None, **kw): global cache if not cache: try: from beaker import cache as beaker_cache cache = beaker_cache.CacheManager() except ImportError: # keep a fake cache around so subsequent # calls don't attempt to re-import cache = BeakerMissing() if type == 'memcached': type = 'ext:memcached' if not type: (type, kw) = self.def_regions.get(defname, ('memory', {})) else: self.def_regions[defname] = (type, kw) return cache.get_cache(self.id, type=type, **kw)