Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/mako/cache.py: 46%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

69 statements  

1# mako/cache.py 

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

8 

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

10 

11register_plugin = _cache_plugins.register 

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

13 

14 

15class Cache: 

16 

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

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

19 

20 .. versionadded:: 0.6 

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

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

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

24 implement different 

25 caching strategies. Mako includes a backend that works with 

26 the Beaker caching system. Beaker itself then supports 

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

28 

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

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

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

32 

33 """ 

34 

35 impl = None 

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

37 

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

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

40 

41 """ 

42 

43 id = None 

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

45 

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

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

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

49 for data specific to this template. 

50 

51 """ 

52 

53 starttime = None 

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

55 first compiled. 

56 

57 A cache implementation may wish to invalidate data earlier than 

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

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

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

61 the filesystem. 

62 

63 """ 

64 

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

66 # check for a stale template calling the 

67 # constructor 

68 if isinstance(template, str) and args: 

69 return 

70 self.template = template 

71 self.id = template.module.__name__ 

72 self.starttime = template.module._modified_time 

73 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 function 

81 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 function 

87 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 = 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 r"""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 r"""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 

183class CacheImpl: 

184 

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

186 

187 def __init__(self, cache): 

188 self.cache = cache 

189 

190 pass_context = False 

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

192 :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 function 

197 to generate a new value. 

198 

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

200 the cache, or via the given creation function. 

201 If the creation function is called, the newly 

202 created value should be populated into the cache 

203 under the given key before being returned. 

204 

205 :param key: the value's key. 

206 :param creation_function: function that when called generates 

207 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()