codekingpro/portable-devtools
114k
1# mako/cache.py2# Copyright 2006-2024 the Mako authors and contributors <see AUTHORS file>3#4# This module is part of Mako and is released under5# the MIT License: http://www.opensource.org/licenses/mit-license.php6 7from mako import util8 9_cache_plugins = util.PluginLoader("mako.cache")10 11register_plugin = _cache_plugins.register12register_plugin("beaker", "mako.ext.beaker_cache", "BeakerCacheImpl")13 14 15class Cache:16 17 """Represents a data content cache made available to the module18 space of a specific :class:`.Template` object.19 20 .. versionadded:: 0.621 :class:`.Cache` by itself is mostly a22 container for a :class:`.CacheImpl` object, which implements23 a fixed API to provide caching services; specific subclasses exist to24 implement different25 caching strategies. Mako includes a backend that works with26 the Beaker caching system. Beaker itself then supports27 a number of backends (i.e. file, memory, memcached, etc.)28 29 The construction of a :class:`.Cache` is part of the mechanics30 of a :class:`.Template`, and programmatic access to this31 cache is typically via the :attr:`.Template.cache` attribute.32 33 """34 35 impl = None36 """Provide the :class:`.CacheImpl` in use by this :class:`.Cache`.37 38 This accessor allows a :class:`.CacheImpl` with additional39 methods beyond that of :class:`.Cache` to be used programmatically.40 41 """42 43 id = None44 """Return the 'id' that identifies this cache.45 46 This is a value that should be globally unique to the47 :class:`.Template` associated with this cache, and can48 be used by a caching system to name a local container49 for data specific to this template.50 51 """52 53 starttime = None54 """Epochal time value for when the owning :class:`.Template` was55 first compiled.56 57 A cache implementation may wish to invalidate data earlier than58 this timestamp; this has the effect of the cache for a specific59 :class:`.Template` starting clean any time the :class:`.Template`60 is recompiled, such as when the original template file changed on61 the filesystem.62 63 """64 65 def __init__(self, template, *args):66 # check for a stale template calling the67 # constructor68 if isinstance(template, str) and args:69 return70 self.template = template71 self.id = template.module.__name__72 self.starttime = template.module._modified_time73 self._def_regions = {}74 self.impl = self._load_impl(self.template.cache_impl)75 76 def _load_impl(self, name):77 return _cache_plugins.load(name)(self)78 79 def get_or_create(self, key, creation_function, **kw):80 """Retrieve a value from the cache, using the given creation function81 to generate a new value."""82 83 return self._ctx_get_or_create(key, creation_function, None, **kw)84 85 def _ctx_get_or_create(self, key, creation_function, context, **kw):86 """Retrieve a value from the cache, using the given creation function87 to generate a new value."""88 89 if not self.template.cache_enabled:90 return creation_function()91 92 return self.impl.get_or_create(93 key, creation_function, **self._get_cache_kw(kw, context)94 )95 96 def set(self, key, value, **kw):97 r"""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 = set108 """A synonym for :meth:`.Cache.set`.109 110 This is here for backwards compatibility.111 112 """113 114 def get(self, key, **kw):115 r"""Retrieve a value from the cache.116 117 :param key: the value's key.118 :param \**kw: cache configuration arguments. The119 backend is configured using these arguments upon first request.120 Subsequent requests that use the same series of configuration121 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 r"""Invalidate a value in the cache.128 129 :param key: the value's key.130 :param \**kw: cache configuration arguments. The131 backend is configured using these arguments upon first request.132 Subsequent requests that use the same series of configuration133 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 this140 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 this147 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 no157 management of scope -- nested defs that use cache tags158 need to have names unique of all other nested defs in the159 template, else their content will be overwritten by160 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_kw177 if context and self.impl.pass_context:178 tmpl_kw = tmpl_kw.copy()179 tmpl_kw.setdefault("context", context)180 return tmpl_kw181 182 183class CacheImpl:184 185 """Provide a cache implementation for use by :class:`.Cache`."""186 187 def __init__(self, cache):188 self.cache = cache189 190 pass_context = False191 """If ``True``, the :class:`.Context` will be passed to192 :meth:`get_or_create <.CacheImpl.get_or_create>` as the name ``'context'``.193 """194 195 def get_or_create(self, key, creation_function, **kw):196 r"""Retrieve a value from the cache, using the given creation function197 to generate a new value.198 199 This function *must* return a value, either from200 the cache, or via the given creation function.201 If the creation function is called, the newly202 created value should be populated into the cache203 under the given key before being returned.204 205 :param key: the value's key.206 :param creation_function: function that when called generates207 a new value.208 :param \**kw: cache configuration arguments.209 210 """211 raise NotImplementedError()212 213 def set(self, key, value, **kw):214 r"""Place a value in the cache.215 216 :param key: the value's key.217 :param value: the value.218 :param \**kw: cache configuration arguments.219 220 """221 raise NotImplementedError()222 223 def get(self, key, **kw):224 r"""Retrieve a value from the cache.225 226 :param key: the value's key.227 :param \**kw: cache configuration arguments.228 229 """230 raise NotImplementedError()231 232 def invalidate(self, key, **kw):233 r"""Invalidate a value in the cache.234 235 :param key: the value's key.236 :param \**kw: cache configuration arguments.237 238 """239 raise NotImplementedError()240 