Commits

Andriy Kornatskyy  committed ef0ff78

Synchronized template compilation.

  • Participants
  • Parent commits 60c0d3c

Comments (0)

Files changed (4)

File src/wheezy/template/comp.py

 
 PY3 = sys.version_info[0] >= 3
 
+
+if PY3:  # pragma: nocover
+    from _thread import allocate_lock
+else:  # pragma: nocover
+    from thread import allocate_lock
+
 try:  # pragma: nocover
     import ast
 

File src/wheezy/template/engine.py

 
 from wheezy.template.builder import SourceBuilder
 from wheezy.template.builder import builder_scan
+from wheezy.template.comp import allocate_lock
 from wheezy.template.comp import compile_source
 from wheezy.template.lexer import Lexer
 from wheezy.template.lexer import lexer_scan
 
 class Engine(object):
 
-    def __init__(self, loader, extensions):
+    def __init__(self, loader, extensions, template_class=None):
+        self.templates = {}
+        self.renders = {}
+        self.loader = loader
+        self.template_class = template_class or Template
+        self.lock = allocate_lock()
         lexer_rules, preprocessors = lexer_scan(extensions)
         self.lexer = Lexer(lexer_rules, preprocessors)
         parser_rules, parser_configs = parser_scan(extensions)
         self.parser = Parser(parser_rules, parser_configs)
         builder_rules = builder_scan(extensions)
         self.builder = SourceBuilder(builder_rules)
-        self.loader = loader
-        self.templates = {}
-        self.global_vars = {'renders': {}}
+        self.global_vars = {'_r': self.get_render}
 
     def get_template(self, name):
         try:
             return self.templates[name]
         except KeyError:
-            self.templates[name] = template = self.compile_template(name)
-            return template
+            self.compile_template(name)
+            return self.templates[name]
+
+    def get_render(self, name):
+        try:
+            return self.renders[name]
+        except KeyError:
+            self.compile_template(name)
+            return self.renders[name]
+
+    # region: internal details
 
     def compile_template(self, name):
-        template_source = self.loader.load(name)
-        tokens = self.lexer.tokenize(template_source)
-        nodes = list(self.parser.parse(tokens))
-        #from pprint import pprint
-        #pprint(nodes)
-        module_source = self.builder.build_render(nodes)
-        #from wheezy.template.utils import print_source
-        #print_source(module_source, -1)
-        render_template = compile_source(
-            module_source, name, self.global_vars, -2)
-        self.global_vars['renders'][name] = render_template
-        return Template(render_template)
+        self.lock.acquire(1)
+        try:
+            if name not in self.renders:
+                template_source = self.loader.load(name)
+                tokens = self.lexer.tokenize(template_source)
+                nodes = list(self.parser.parse(tokens))
+                #from pprint import pprint
+                #pprint(nodes)
+                module_source = self.builder.build_render(nodes)
+                #from wheezy.template.utils import print_source
+                #print_source(module_source, -1)
+                render_template = compile_source(
+                    module_source, name, self.global_vars, -2)
+                self.renders[name] = render_template
+                self.templates[name] = self.template_class(
+                        name, render_template)
+        finally:
+            self.lock.release()
 
 
 class Template(object):
 
-    def __init__(self, render_template):
+    def __init__(self, name, render_template):
+        self.name = name
         self.render_template = render_template
 
     def render(self, ctx):
-        local_defs = {}
-        super_defs = {}
-        return self.render_template(ctx, local_defs, super_defs)
+        return self.render_template(ctx, {}, {})

File src/wheezy/template/ext/core.py

         if token == 'def':
             builder.build_token(lineno, 'def', value)
     lineno = builder.lineno
-    builder.add(lineno + 1, 'return renders[' + extends +
-            '](ctx, local_defs, super_defs)')
+    builder.add(lineno + 1, 'return _r(' + extends +
+            ')(ctx, local_defs, super_defs)')
     return True
 
 
     assert token == 'out'
     for lineno, token, value in nodes:
         if token == 'include':
-            builder.add(lineno, 'w(renders[' + value +
-                '](ctx, local_defs, super_defs))')
+            builder.add(lineno, 'w(_r(' + value +
+                ')(ctx, local_defs, super_defs))')
         else:
             builder.add(lineno, 'w(' + value + ')')
     return True

File src/wheezy/template/ext/tests/test_core.py

         """
         assert """\
 def render(ctx, local_defs, super_defs):
-    return renders["base.html"](ctx, local_defs, super_defs)\
+    return _r("base.html")(ctx, local_defs, super_defs)\
 """ == self.build_render("""\
 @extends("base.html")
 """)
 @end
 """
         })
+        assert '    Hi, John!\n' == self.render('tmpl.html', {})
         assert '    Hello, John!\n' == self.render('master.html', {})
-        assert '    Hi, John!\n' == self.render('tmpl.html', {})
 
     def test_include(self):
         self.templates.update({
 """
         })
         ctx = {'name': 'John'}
-        assert 'Thanks, John' == self.render('footer.html', ctx)
         assert """\
 Welcome to my site.
 Thanks, John""" == self.render('tmpl.html', ctx)
+        assert 'Thanks, John' == self.render('footer.html', ctx)