Home | History | Annotate | Download | only in mako
      1 # mako/cache.py
      2 # Copyright (C) 2006-2015 the Mako authors and contributors <see AUTHORS file>
      3 #
      4 # This module is part of Mako and is released under
      5 # the MIT License: http://www.opensource.org/licenses/mit-license.php
      6 
      7 from mako import compat, util
      8 
      9 _cache_plugins = util.PluginLoader("mako.cache")
     10 
     11 register_plugin = _cache_plugins.register
     12 register_plugin("beaker", "mako.ext.beaker_cache", "BeakerCacheImpl")
     13 
     14 
     15 class Cache(object):
     16     """Represents a data content cache made available to the module
     17     space of a specific :class:`.Template` object.
     18 
     19     .. versionadded:: 0.6
     20        :class:`.Cache` by itself is mostly a
     21        container for a :class:`.CacheImpl` object, which implements
     22        a fixed API to provide caching services; specific subclasses exist to
     23        implement different
     24        caching strategies.   Mako includes a backend that works with
     25        the Beaker caching system.   Beaker itself then supports
     26        a number of backends (i.e. file, memory, memcached, etc.)
     27 
     28     The construction of a :class:`.Cache` is part of the mechanics
     29     of a :class:`.Template`, and programmatic access to this
     30     cache is typically via the :attr:`.Template.cache` attribute.
     31 
     32     """
     33 
     34     impl = None
     35     """Provide the :class:`.CacheImpl` in use by this :class:`.Cache`.
     36 
     37     This accessor allows a :class:`.CacheImpl` with additional
     38     methods beyond that of :class:`.Cache` to be used programmatically.
     39 
     40     """
     41 
     42     id = None
     43     """Return the 'id' that identifies this cache.
     44 
     45     This is a value that should be globally unique to the
     46     :class:`.Template` associated with this cache, and can
     47     be used by a caching system to name a local container
     48     for data specific to this template.
     49 
     50     """
     51 
     52     starttime = None
     53     """Epochal time value for when the owning :class:`.Template` was
     54     first compiled.
     55 
     56     A cache implementation may wish to invalidate data earlier than
     57     this timestamp; this has the effect of the cache for a specific
     58     :class:`.Template` starting clean any time the :class:`.Template`
     59     is recompiled, such as when the original template file changed on
     60     the filesystem.
     61 
     62     """
     63 
     64     def __init__(self, template, *args):
     65         # check for a stale template calling the
     66         # constructor
     67         if isinstance(template, compat.string_types) and args:
     68             return
     69         self.template = template
     70         self.id = template.module.__name__
     71         self.starttime = template.module._modified_time
     72         self._def_regions = {}
     73         self.impl = self._load_impl(self.template.cache_impl)
     74 
     75     def _load_impl(self, name):
     76         return _cache_plugins.load(name)(self)
     77 
     78     def get_or_create(self, key, creation_function, **kw):
     79         """Retrieve a value from the cache, using the given creation function
     80         to generate a new value."""
     81 
     82         return self._ctx_get_or_create(key, creation_function, None, **kw)
     83 
     84     def _ctx_get_or_create(self, key, creation_function, context, **kw):
     85         """Retrieve a value from the cache, using the given creation function
     86         to generate a new value."""
     87 
     88         if not self.template.cache_enabled:
     89             return creation_function()
     90 
     91         return self.impl.get_or_create(
     92             key,
     93             creation_function,
     94             **self._get_cache_kw(kw, context))
     95 
     96     def set(self, key, value, **kw):
     97         """Place a value in the cache.
     98 
     99         :param key: the value's key.
    100         :param value: the value.
    101         :param \**kw: cache configuration arguments.
    102 
    103         """
    104 
    105         self.impl.set(key, value, **self._get_cache_kw(kw, None))
    106 
    107     put = set
    108     """A synonym for :meth:`.Cache.set`.
    109 
    110     This is here for backwards compatibility.
    111 
    112     """
    113 
    114     def get(self, key, **kw):
    115         """Retrieve a value from the cache.
    116 
    117         :param key: the value's key.
    118         :param \**kw: cache configuration arguments.  The
    119          backend is configured using these arguments upon first request.
    120          Subsequent requests that use the same series of configuration
    121          values will use that same backend.
    122 
    123         """
    124         return self.impl.get(key, **self._get_cache_kw(kw, None))
    125 
    126     def invalidate(self, key, **kw):
    127         """Invalidate a value in the cache.
    128 
    129         :param key: the value's key.
    130         :param \**kw: cache configuration arguments.  The
    131          backend is configured using these arguments upon first request.
    132          Subsequent requests that use the same series of configuration
    133          values will use that same backend.
    134 
    135         """
    136         self.impl.invalidate(key, **self._get_cache_kw(kw, None))
    137 
    138     def invalidate_body(self):
    139         """Invalidate the cached content of the "body" method for this
    140         template.
    141 
    142         """
    143         self.invalidate('render_body', __M_defname='render_body')
    144 
    145     def invalidate_def(self, name):
    146         """Invalidate the cached content of a particular ``<%def>`` within this
    147         template.
    148 
    149         """
    150 
    151         self.invalidate('render_%s' % name, __M_defname='render_%s' % name)
    152 
    153     def invalidate_closure(self, name):
    154         """Invalidate a nested ``<%def>`` within this template.
    155 
    156         Caching of nested defs is a blunt tool as there is no
    157         management of scope -- nested defs that use cache tags
    158         need to have names unique of all other nested defs in the
    159         template, else their content will be overwritten by
    160         each other.
    161 
    162         """
    163 
    164         self.invalidate(name, __M_defname=name)
    165 
    166     def _get_cache_kw(self, kw, context):
    167         defname = kw.pop('__M_defname', None)
    168         if not defname:
    169             tmpl_kw = self.template.cache_args.copy()
    170             tmpl_kw.update(kw)
    171         elif defname in self._def_regions:
    172             tmpl_kw = self._def_regions[defname]
    173         else:
    174             tmpl_kw = self.template.cache_args.copy()
    175             tmpl_kw.update(kw)
    176             self._def_regions[defname] = tmpl_kw
    177         if context and self.impl.pass_context:
    178             tmpl_kw = tmpl_kw.copy()
    179             tmpl_kw.setdefault('context', context)
    180         return tmpl_kw
    181 
    182 
    183 class CacheImpl(object):
    184     """Provide a cache implementation for use by :class:`.Cache`."""
    185 
    186     def __init__(self, cache):
    187         self.cache = cache
    188 
    189     pass_context = False
    190     """If ``True``, the :class:`.Context` will be passed to
    191     :meth:`get_or_create <.CacheImpl.get_or_create>` as the name ``'context'``.
    192     """
    193 
    194     def get_or_create(self, key, creation_function, **kw):
    195         """Retrieve a value from the cache, using the given creation function
    196         to generate a new value.
    197 
    198         This function *must* return a value, either from
    199         the cache, or via the given creation function.
    200         If the creation function is called, the newly
    201         created value should be populated into the cache
    202         under the given key before being returned.
    203 
    204         :param key: the value's key.
    205         :param creation_function: function that when called generates
    206          a new value.
    207         :param \**kw: cache configuration arguments.
    208 
    209         """
    210         raise NotImplementedError()
    211 
    212     def set(self, key, value, **kw):
    213         """Place a value in the cache.
    214 
    215         :param key: the value's key.
    216         :param value: the value.
    217         :param \**kw: cache configuration arguments.
    218 
    219         """
    220         raise NotImplementedError()
    221 
    222     def get(self, key, **kw):
    223         """Retrieve a value from the cache.
    224 
    225         :param key: the value's key.
    226         :param \**kw: cache configuration arguments.
    227 
    228         """
    229         raise NotImplementedError()
    230 
    231     def invalidate(self, key, **kw):
    232         """Invalidate a value in the cache.
    233 
    234         :param key: the value's key.
    235         :param \**kw: cache configuration arguments.
    236 
    237         """
    238         raise NotImplementedError()
    239