cache.py 7.8 KB

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