diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-10-01 17:55:59 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2011-10-01 17:55:59 -0400 |
| commit | 643701f1d30e1af70dbd4e99cf8e3b9517f74561 (patch) | |
| tree | 7470dcb58bff8288b161598f2132773f610c66d2 /mako/cache.py | |
| parent | 5cd508ffe0d7eaadd6516fc35137c93d1d6577a9 (diff) | |
| download | external_python_mako-643701f1d30e1af70dbd4e99cf8e3b9517f74561.tar.gz external_python_mako-643701f1d30e1af70dbd4e99cf8e3b9517f74561.tar.bz2 external_python_mako-643701f1d30e1af70dbd4e99cf8e3b9517f74561.zip | |
- Template caching has been converted into a plugin
system, whereby the usage of Beaker is just the
default plugin. Template and TemplateLookup
now accept a string "cache_impl" parameter which
refers to the name of a cache plugin, defaulting
to the name 'beaker'. New plugins can be
registered as pkg_resources entrypoints under
the group "mako.cache", or registered directly
using mako.cache.register_plugin(). The
core plugin is the mako.cache.CacheImpl
class.
- The <%def>, <%block> and <%page> tags now accept
any argument named "cache_*", and the key
minus the "cache_" prefix will be passed as keyword
arguments to the CacheImpl methods.
- Template and TemplateLookup now accept an argument
cache_args, which refers to a dictionary containing
cache parameters. The cache_dir, cache_url, cache_type,
cache_timeout arguments are deprecated (will probably
never be removed, however) and can be passed
now as cache_args={'url':<some url>, 'type':'memcached',
'timeout':50, 'dir':'/path/to/some/directory'}
Diffstat (limited to 'mako/cache.py')
| -rw-r--r-- | mako/cache.py | 233 |
1 files changed, 168 insertions, 65 deletions
diff --git a/mako/cache.py b/mako/cache.py index ce73ae5..5793987 100644 --- a/mako/cache.py +++ b/mako/cache.py @@ -6,89 +6,146 @@ 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.") +def register_plugin(name, modulename, attrname): + """Register the given :class:`.CacheImpl` under the given + name. + + This is an alternative to using a setuptools-installed entrypoint. + + """ + import pkg_resources + dist = pkg_resources.get_distribution("mako") + entry_map = dist.get_entry_map() + if 'mako.cache' not in entry_map: + entry_map['mako.cache'] = cache_map = {} + else: + cache_map = entry_map['mako.cache'] + cache_map[name] = \ + pkg_resources.EntryPoint.parse('%s = %s:%s' % (name, modulename, attrname), dist=dist) + +register_plugin("beaker", "mako.ext.beaker_cache", "BeakerCacheImpl") 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. + space of a specific :class:`.Template` object. + + As of Mako 0.5.1, :class:`.Cache` by itself is mostly a + container for a :class:`.CacheImpl` object, which implements + a fixed API to provide caching services; specific subclasses exist to + implement different + caching strategies. Mako includes a backend that works with + the Beaker caching system. Beaker itself then supports + a number of backends (i.e. file, memory, memcached, etc.) + + The construction of a :class:`.Cache` is part of the mechanics + of a :class:`.Template`, and programmatic access to this + cache is typically via the :attr:`.Template.cache` attribute. """ - - def __init__(self, id, starttime): - self.id = id - self.starttime = starttime - self.def_regions = {} - - def put(self, key, value, **kwargs): + + impl = None + """Provide the :class:`.CacheImpl` in use by this :class:`.Cache`. + + This accessor allows a :class:`.CacheImpl` with additional + methods beyond that of :class:`.Cache` to be used programmatically. + + """ + + id = None + """Return the 'id' that identifies this cache. + + This is a value that should be globally unique to the + :class:`.Template` associated with this cache, and can + be used by a caching system to name a local container + for data specific to this template. + + """ + + starttime = None + """Epochal time value for when the owning :class:`.Template` was + first compiled. + + A cache implementation may wish to invalidate data earlier than + this timestamp; this has the effect of the cache for a specific + :class:`.Template` starting clean any time the :class:`.Template` + is recompiled, such as when the original template file changed on + the filesystem. + + """ + + def __init__(self, template): + self.template = template + self.impl = self._load_impl(self.template.cache_impl) + self.id = template.module.__name__ + self.starttime = template.module._modified_time + self._def_regions = {} + + def _load_impl(self, name): + import pkg_resources + for impl in pkg_resources.iter_entry_points( + "mako.cache", + name): + return impl.load()(self) + else: + raise exceptions.RuntimeException( + "Cache implementation '%s' not present" % + name) + + def get_and_replace(self, key, creation_function, **kw): + """Retrieve a value from the cache, using the given creation function + to generate a new value.""" + + if not self.template.cache_enabled: + return creation_function() + + return self.impl.get_and_replace(key, creation_function, **self._get_cache_kw(kw)) + + def put(self, key, value, **kw): """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. + :param \**kw: cache configuration arguments. """ - - 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): + + self.impl.put(key, value, **self._get_cache_kw(kw)) + + def get(self, key, **kw): """Retrieve a value from the cache. :param key: the value's key. - :param \**kwargs: cache configuration arguments. The + :param \**kw: 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. """ + return self.impl.get(key, **self._get_cache_kw(kw)) - 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): + def invalidate(self, key, **kw): """Invalidate a value in the cache. :param key: the value's key. - :param \**kwargs: cache configuration arguments. The + :param \**kw: 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) + self.impl.invalidate(key, **self._get_cache_kw(kw)) def invalidate_body(self): """Invalidate the cached content of the "body" method for this template. """ - self.invalidate('render_body', defname='render_body') + self.invalidate('render_body', __M_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) + self.invalidate('render_%s' % name, __M_defname='render_%s' % name) def invalidate_closure(self, name): """Invalidate a nested <%def> within this template. @@ -101,24 +158,70 @@ class Cache(object): """ - 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', {})) + self.invalidate(name, __M_defname=name) + + def _get_cache_kw(self, kw): + defname = kw.pop('__M_defname', None) + if not defname: + tmpl_kw = self.template.cache_args.copy() + tmpl_kw.update(kw) + return tmpl_kw + elif defname in self._def_regions: + return self._def_regions[defname] else: - self.def_regions[defname] = (type, kw) - return cache.get_cache(self.id, type=type, **kw) -
\ No newline at end of file + tmpl_kw = self.template.cache_args.copy() + tmpl_kw.update(kw) + self._def_regions[defname] = tmpl_kw + return tmpl_kw + +class CacheImpl(object): + """Provide a cache implementation for use by :class:`.Cache`.""" + + def __init__(self, cache): + self.cache = cache + + def get_and_replace(self, key, creation_function, **kw): + """Retrieve a value from the cache, using the given creation function + to generate a new value. + + This function *must* return a value, either from + the cache, or via the given creation function. + If the creation function is called, the newly + created value should be populated into the cache + under the given key before being returned. + + :param key: the value's key. + :param creation_function: function that when called generates + a new value. + :param \**kw: cache configuration arguments. + + """ + raise NotImplementedError() + + def put(self, key, value, **kw): + """Place a value in the cache. + + :param key: the value's key. + :param value: the value + :param \**kw: cache configuration arguments. + + """ + raise NotImplementedError() + + def get(self, key, **kw): + """Retrieve a value from the cache. + + :param key: the value's key. + :param \**kw: cache configuration arguments. + + """ + raise NotImplementedError() + + def invalidate(self, key, **kw): + """Invalidate a value in the cache. + + :param key: the value's key. + :param \**kw: cache configuration arguments. + + """ + raise NotImplementedError() |
