comparison piecrust/templating/jinjaengine.py @ 89:e771c202583a

Fixes to the `cache` Jinja tag. * Thread safety, since it stores common data potentially coming from pages baked at the same time. * Correctly capture and restore modifications made to the execution context (e.g. sources used in the captured section).
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 04 Sep 2014 08:13:39 -0700
parents 071cc99b1779
children 28444014ce7d
comparison
equal deleted inserted replaced
88:a643b14a59a3 89:e771c202583a
1 import re 1 import re
2 import time 2 import time
3 import logging 3 import logging
4 import threading
4 import strict_rfc3339 5 import strict_rfc3339
5 from jinja2 import Environment, FileSystemLoader, TemplateNotFound 6 from jinja2 import Environment, FileSystemLoader, TemplateNotFound
6 from jinja2.exceptions import TemplateSyntaxError 7 from jinja2.exceptions import TemplateSyntaxError
7 from jinja2.ext import Extension, Markup 8 from jinja2.ext import Extension, Markup
8 from jinja2.lexer import Token, describe_token 9 from jinja2.lexer import Token, describe_token
270 class PieCrustCacheExtension(Extension): 271 class PieCrustCacheExtension(Extension):
271 tags = set(['pccache', 'cache']) 272 tags = set(['pccache', 'cache'])
272 273
273 def __init__(self, environment): 274 def __init__(self, environment):
274 super(PieCrustCacheExtension, self).__init__(environment) 275 super(PieCrustCacheExtension, self).__init__(environment)
276 self._lock = threading.RLock()
275 277
276 environment.extend( 278 environment.extend(
277 piecrust_cache_prefix='', 279 piecrust_cache_prefix='',
278 piecrust_cache={} 280 piecrust_cache={}
279 ) 281 )
299 [], [], body).set_lineno(lineno) 301 [], [], body).set_lineno(lineno)
300 302
301 def _cache_support(self, name, caller): 303 def _cache_support(self, name, caller):
302 key = self.environment.piecrust_cache_prefix + name 304 key = self.environment.piecrust_cache_prefix + name
303 305
306 exc_stack = self.environment.app.env.exec_info_stack
307 render_ctx = exc_stack.current_page_info.render_ctx
308
304 # try to load the block from the cache 309 # try to load the block from the cache
305 # if there is no fragment in the cache, render it and store 310 # if there is no fragment in the cache, render it and store
306 # it in the cache. 311 # it in the cache.
307 rv = self.environment.piecrust_cache.get(key) 312 pair = self.environment.piecrust_cache.get(key)
308 if rv is not None: 313 if pair is not None:
314 render_ctx.used_source_names.update(pair[1])
315 return pair[0]
316
317 with self._lock:
318 pair = self.environment.piecrust_cache.get(key)
319 if pair is not None:
320 render_ctx.used_source_names.update(pair[1])
321 return pair[0]
322
323 prev_used = render_ctx.used_source_names.copy()
324 rv = caller()
325 after_used = render_ctx.used_source_names.copy()
326 used_delta = after_used.difference(prev_used)
327 self.environment.piecrust_cache[key] = (rv, used_delta)
309 return rv 328 return rv
310 rv = caller()
311 self.environment.piecrust_cache[key] = rv
312 return rv
313 329
314 330
315 class PieCrustSpacelessExtension(HtmlCompressor): 331 class PieCrustSpacelessExtension(HtmlCompressor):
316 """ A re-implementation of `SelectiveHtmlCompressor` so that we can 332 """ A re-implementation of `SelectiveHtmlCompressor` so that we can
317 both use `strip` or `spaceless` in templates. 333 both use `strip` or `spaceless` in templates.