Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# mako/cache.py 

2# Copyright 2006-2020 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 

7from mako import compat 

8from mako import util 

9 

10_cache_plugins = util.PluginLoader("mako.cache") 

11 

12register_plugin = _cache_plugins.register 

13register_plugin("beaker", "mako.ext.beaker_cache", "BeakerCacheImpl") 

14 

15 

16class Cache(object): 

17 

18 """Represents a data content cache made available to the module 

19 space of a specific :class:`.Template` object. 

20 

21 .. versionadded:: 0.6 

22 :class:`.Cache` by itself is mostly a 

23 container for a :class:`.CacheImpl` object, which implements 

24 a fixed API to provide caching services; specific subclasses exist to 

25 implement different 

26 caching strategies. Mako includes a backend that works with 

27 the Beaker caching system. Beaker itself then supports 

28 a number of backends (i.e. file, memory, memcached, etc.) 

29 

30 The construction of a :class:`.Cache` is part of the mechanics 

31 of a :class:`.Template`, and programmatic access to this 

32 cache is typically via the :attr:`.Template.cache` attribute. 

33 

34 """ 

35 

36 impl = None 

37 """Provide the :class:`.CacheImpl` in use by this :class:`.Cache`. 

38 

39 This accessor allows a :class:`.CacheImpl` with additional 

40 methods beyond that of :class:`.Cache` to be used programmatically. 

41 

42 """ 

43 

44 id = None 

45 """Return the 'id' that identifies this cache. 

46 

47 This is a value that should be globally unique to the 

48 :class:`.Template` associated with this cache, and can 

49 be used by a caching system to name a local container 

50 for data specific to this template. 

51 

52 """ 

53 

54 starttime = None 

55 """Epochal time value for when the owning :class:`.Template` was 

56 first compiled. 

57 

58 A cache implementation may wish to invalidate data earlier than 

59 this timestamp; this has the effect of the cache for a specific 

60 :class:`.Template` starting clean any time the :class:`.Template` 

61 is recompiled, such as when the original template file changed on 

62 the filesystem. 

63 

64 """ 

65 

66 def __init__(self, template, *args): 

67 # check for a stale template calling the 

68 # constructor 

69 if isinstance(template, compat.string_types) and args: 

70 return 

71 self.template = template 

72 self.id = template.module.__name__ 

73 self.starttime = template.module._modified_time 

74 self._def_regions = {} 

75 self.impl = self._load_impl(self.template.cache_impl) 

76 

77 def _load_impl(self, name): 

78 return _cache_plugins.load(name)(self) 

79 

80 def get_or_create(self, key, creation_function, **kw): 

81 """Retrieve a value from the cache, using the given creation function 

82 to generate a new value.""" 

83 

84 return self._ctx_get_or_create(key, creation_function, None, **kw) 

85 

86 def _ctx_get_or_create(self, key, creation_function, context, **kw): 

87 """Retrieve a value from the cache, using the given creation function 

88 to generate a new value.""" 

89 

90 if not self.template.cache_enabled: 

91 return creation_function() 

92 

93 return self.impl.get_or_create( 

94 key, creation_function, **self._get_cache_kw(kw, context) 

95 ) 

96 

97 def set(self, key, value, **kw): 

98 r"""Place a value in the cache. 

99 

100 :param key: the value's key. 

101 :param value: the value. 

102 :param \**kw: cache configuration arguments. 

103 

104 """ 

105 

106 self.impl.set(key, value, **self._get_cache_kw(kw, None)) 

107 

108 put = set 

109 """A synonym for :meth:`.Cache.set`. 

110 

111 This is here for backwards compatibility. 

112 

113 """ 

114 

115 def get(self, key, **kw): 

116 r"""Retrieve a value from the cache. 

117 

118 :param key: the value's key. 

119 :param \**kw: cache configuration arguments. The 

120 backend is configured using these arguments upon first request. 

121 Subsequent requests that use the same series of configuration 

122 values will use that same backend. 

123 

124 """ 

125 return self.impl.get(key, **self._get_cache_kw(kw, None)) 

126 

127 def invalidate(self, key, **kw): 

128 r"""Invalidate a value in the cache. 

129 

130 :param key: the value's key. 

131 :param \**kw: cache configuration arguments. The 

132 backend is configured using these arguments upon first request. 

133 Subsequent requests that use the same series of configuration 

134 values will use that same backend. 

135 

136 """ 

137 self.impl.invalidate(key, **self._get_cache_kw(kw, None)) 

138 

139 def invalidate_body(self): 

140 """Invalidate the cached content of the "body" method for this 

141 template. 

142 

143 """ 

144 self.invalidate("render_body", __M_defname="render_body") 

145 

146 def invalidate_def(self, name): 

147 """Invalidate the cached content of a particular ``<%def>`` within this 

148 template. 

149 

150 """ 

151 

152 self.invalidate("render_%s" % name, __M_defname="render_%s" % name) 

153 

154 def invalidate_closure(self, name): 

155 """Invalidate a nested ``<%def>`` within this template. 

156 

157 Caching of nested defs is a blunt tool as there is no 

158 management of scope -- nested defs that use cache tags 

159 need to have names unique of all other nested defs in the 

160 template, else their content will be overwritten by 

161 each other. 

162 

163 """ 

164 

165 self.invalidate(name, __M_defname=name) 

166 

167 def _get_cache_kw(self, kw, context): 

168 defname = kw.pop("__M_defname", None) 

169 if not defname: 

170 tmpl_kw = self.template.cache_args.copy() 

171 tmpl_kw.update(kw) 

172 elif defname in self._def_regions: 

173 tmpl_kw = self._def_regions[defname] 

174 else: 

175 tmpl_kw = self.template.cache_args.copy() 

176 tmpl_kw.update(kw) 

177 self._def_regions[defname] = tmpl_kw 

178 if context and self.impl.pass_context: 

179 tmpl_kw = tmpl_kw.copy() 

180 tmpl_kw.setdefault("context", context) 

181 return tmpl_kw 

182 

183 

184class CacheImpl(object): 

185 

186 """Provide a cache implementation for use by :class:`.Cache`.""" 

187 

188 def __init__(self, cache): 

189 self.cache = cache 

190 

191 pass_context = False 

192 """If ``True``, the :class:`.Context` will be passed to 

193 :meth:`get_or_create <.CacheImpl.get_or_create>` as the name ``'context'``. 

194 """ 

195 

196 def get_or_create(self, key, creation_function, **kw): 

197 r"""Retrieve a value from the cache, using the given creation function 

198 to generate a new value. 

199 

200 This function *must* return a value, either from 

201 the cache, or via the given creation function. 

202 If the creation function is called, the newly 

203 created value should be populated into the cache 

204 under the given key before being returned. 

205 

206 :param key: the value's key. 

207 :param creation_function: function that when called generates 

208 a new value. 

209 :param \**kw: cache configuration arguments. 

210 

211 """ 

212 raise NotImplementedError() 

213 

214 def set(self, key, value, **kw): 

215 r"""Place a value in the cache. 

216 

217 :param key: the value's key. 

218 :param value: the value. 

219 :param \**kw: cache configuration arguments. 

220 

221 """ 

222 raise NotImplementedError() 

223 

224 def get(self, key, **kw): 

225 r"""Retrieve a value from the cache. 

226 

227 :param key: the value's key. 

228 :param \**kw: cache configuration arguments. 

229 

230 """ 

231 raise NotImplementedError() 

232 

233 def invalidate(self, key, **kw): 

234 r"""Invalidate a value in the cache. 

235 

236 :param key: the value's key. 

237 :param \**kw: cache configuration arguments. 

238 

239 """ 

240 raise NotImplementedError()