123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- # mako/cache.py
- # Copyright (C) 2006-2016 the Mako authors and contributors <see AUTHORS file>
- #
- # This module is part of Mako and is released under
- # the MIT License: http://www.opensource.org/licenses/mit-license.php
- from mako import compat, util
- _cache_plugins = util.PluginLoader("mako.cache")
- register_plugin = _cache_plugins.register
- register_plugin("beaker", "mako.ext.beaker_cache", "BeakerCacheImpl")
- class Cache(object):
- """Represents a data content cache made available to the module
- space of a specific :class:`.Template` object.
- .. versionadded:: 0.6
- :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.
- """
- 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, *args):
- # check for a stale template calling the
- # constructor
- if isinstance(template, compat.string_types) and args:
- return
- self.template = template
- self.id = template.module.__name__
- self.starttime = template.module._modified_time
- self._def_regions = {}
- self.impl = self._load_impl(self.template.cache_impl)
- def _load_impl(self, name):
- return _cache_plugins.load(name)(self)
- def get_or_create(self, key, creation_function, **kw):
- """Retrieve a value from the cache, using the given creation function
- to generate a new value."""
- return self._ctx_get_or_create(key, creation_function, None, **kw)
- def _ctx_get_or_create(self, key, creation_function, context, **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_or_create(
- key,
- creation_function,
- **self._get_cache_kw(kw, context))
- def set(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.
- """
- self.impl.set(key, value, **self._get_cache_kw(kw, None))
- put = set
- """A synonym for :meth:`.Cache.set`.
- This is here for backwards compatibility.
- """
- def get(self, key, **kw):
- """Retrieve a value from the cache.
- :param key: the value's key.
- :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, None))
- def invalidate(self, key, **kw):
- """Invalidate a value in the cache.
- :param key: the value's key.
- :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.
- """
- self.impl.invalidate(key, **self._get_cache_kw(kw, None))
- def invalidate_body(self):
- """Invalidate the cached content of the "body" method for this
- template.
- """
- 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, __M_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, __M_defname=name)
- def _get_cache_kw(self, kw, context):
- defname = kw.pop('__M_defname', None)
- if not defname:
- tmpl_kw = self.template.cache_args.copy()
- tmpl_kw.update(kw)
- elif defname in self._def_regions:
- tmpl_kw = self._def_regions[defname]
- else:
- tmpl_kw = self.template.cache_args.copy()
- tmpl_kw.update(kw)
- self._def_regions[defname] = tmpl_kw
- if context and self.impl.pass_context:
- tmpl_kw = tmpl_kw.copy()
- tmpl_kw.setdefault('context', context)
- return tmpl_kw
- class CacheImpl(object):
- """Provide a cache implementation for use by :class:`.Cache`."""
- def __init__(self, cache):
- self.cache = cache
- pass_context = False
- """If ``True``, the :class:`.Context` will be passed to
- :meth:`get_or_create <.CacheImpl.get_or_create>` as the name ``'context'``.
- """
- def get_or_create(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 set(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()
|