class Engine(object): """ The core component of template engine. """ def __init__(self, loader, extensions, template_class=None): self.lock = allocate_lock() self.templates = {} self.renders = {} self.modules = {} self.global_vars = { '_r': self.render, '_i': self.import_name } self.loader = loader self.template_class = template_class or Template self.compiler = Compiler(self.global_vars, -2) self.lexer = Lexer(**lexer_scan(extensions)) self.parser = Parser(**parser_scan(extensions)) self.builder = SourceBuilder(**builder_scan(extensions)) def get_template(self, name): """ Returns compiled template. """ try: return self.templates[name] except KeyError: self.compile_template(name) return self.templates[name] def render(self, name, ctx, local_defs, super_defs): """ Renders template by name in given context. """ try: return self.renders[name](ctx, local_defs, super_defs) except KeyError: self.compile_template(name) return self.renders[name](ctx, local_defs, super_defs) def remove(self, name): """ Removes given ``name`` from internal cache. """ self.lock.acquire(1) try: if name in self.renders: del self.templates[name] del self.renders[name] if name in self.modules: del self.modules[name] finally: self.lock.release() # region: internal details def import_name(self, name): try: return self.modules[name] except KeyError: self.compile_import(name) return self.modules[name] def compile_template(self, name): self.lock.acquire(1) try: if name not in self.renders: template_source = self.loader.load(name) if template_source is None: raise IOError('Template "%s" not found.' % name) tokens = self.lexer.tokenize(template_source) nodes = self.parser.parse(tokens) source = self.builder.build_render(nodes) #self.print_debug(name, tokens, nodes, source) render_template = self.compiler.compile_source( source, name)['render'] self.renders[name] = render_template self.templates[name] = self.template_class( name, render_template) finally: self.lock.release() def compile_import(self, name): self.lock.acquire(1) try: if name not in self.modules: template_source = self.loader.load(name) if template_source is None: raise IOError('Import "%s" not found.' % name) tokens = self.lexer.tokenize(template_source) nodes = self.parser.parse(tokens) source = self.builder.build_module(nodes) #self.print_debug(name, tokens, nodes, source) self.modules[name] = self.compiler.compile_module( source, name) finally: self.lock.release() def print_debug(self, name, tokens, nodes, source): # pragma: nocover print(name.center(80, '-')) from pprint import pprint #pprint(tokens) pprint(nodes) from wheezy.template.utils import print_source print_source(source, -1)
class Engine(object): """ The core component of template engine. """ def __init__(self, loader, extensions, template_class=None): self.lock = allocate_lock() self.templates = {} self.renders = {} self.modules = {} self.global_vars = {'_r': self.render, '_i': self.import_name} self.loader = loader self.template_class = template_class or Template self.compiler = Compiler(self.global_vars, -2) self.lexer = Lexer(**lexer_scan(extensions)) self.parser = Parser(**parser_scan(extensions)) self.builder = SourceBuilder(**builder_scan(extensions)) def get_template(self, name): """ Returns compiled template. """ try: return self.templates[name] except KeyError: self.compile_template(name) return self.templates[name] def render(self, name, ctx, local_defs, super_defs): """ Renders template by name in given context. """ try: return self.renders[name](ctx, local_defs, super_defs) except KeyError: self.compile_template(name) return self.renders[name](ctx, local_defs, super_defs) def remove(self, name): """ Removes given ``name`` from internal cache. """ self.lock.acquire(1) try: if name in self.renders: del self.templates[name] del self.renders[name] if name in self.modules: del self.modules[name] finally: self.lock.release() # region: internal details def import_name(self, name): try: return self.modules[name] except KeyError: self.compile_import(name) return self.modules[name] def compile_template(self, name): self.lock.acquire(1) try: if name not in self.renders: template_source = self.loader.load(name) if template_source is None: raise IOError('Template "%s" not found.' % name) tokens = self.lexer.tokenize(template_source) nodes = self.parser.parse(tokens) source = self.builder.build_render(nodes) #self.print_debug(name, tokens, nodes, source) render_template = self.compiler.compile_source(source, name)['render'] self.renders[name] = render_template self.templates[name] = self.template_class( name, render_template) finally: self.lock.release() def compile_import(self, name): self.lock.acquire(1) try: if name not in self.modules: template_source = self.loader.load(name) if template_source is None: raise IOError('Import "%s" not found.' % name) tokens = self.lexer.tokenize(template_source) nodes = self.parser.parse(tokens) source = self.builder.build_module(nodes) #self.print_debug(name, tokens, nodes, source) self.modules[name] = self.compiler.compile_module(source, name) finally: self.lock.release() def print_debug(self, name, tokens, nodes, source): # pragma: nocover print(name.center(80, '-')) from pprint import pprint #pprint(tokens) pprint(nodes) from wheezy.template.utils import print_source print_source(source, -1)
class ParserTestCase(unittest.TestCase): """ Test the ``Parser``. """ def setUp(self): from wheezy.template.parser import Parser self.parser = Parser({}) self.tokens = [ (1, 'a', 11), (2, 'b', 12), (3, 'c', 13), (4, 'b', 14), (5, 'c', 15), ] def test_end_continue(self): """ Ensure end nodes are inserted before continue tokens. """ self.parser.continue_tokens = ['b'] nodes = list(self.parser.end_continue(self.tokens)) assert 7 == len(nodes) assert (2, 'end', None) == nodes[1] assert (2, 'b', 12) == nodes[2] assert (4, 'end', None) == nodes[4] assert (4, 'b', 14) == nodes[5] def test_parse_unchanged(self): """ If there is no parser tokens defined the result is unchanged input. """ nodes = list(self.parser.parse(self.tokens)) assert self.tokens == nodes def test_parse_with_rules(self): """ Ensure the rules applied. """ self.parser.rules['a'] = lambda value: value * 100 self.parser.rules['b'] = lambda value: value * 10 nodes = list(self.parser.parse(self.tokens)) assert (1, 'a', 1100) == nodes[0] assert (2, 'b', 120) == nodes[1] assert (4, 'b', 140) == nodes[3] def test_out_tokens(self): """ Tokens from ``out_tokens`` are combined together into a single node. """ self.parser.out_tokens = ['a', 'b'] nodes = list(self.parser.parse(self.tokens)) assert 4 == len(nodes) assert (1, 'out', [(1, 'a', 11), (2, 'b', 12)]) == nodes[0] assert (4, 'out', [(4, 'b', 14)]) == nodes[2] self.parser.out_tokens = ['b', 'c'] nodes = list(self.parser.parse(self.tokens)) assert 2 == len(nodes) assert (2, 'out', [(2, 'b', 12), (3, 'c', 13), (4, 'b', 14), (5, 'c', 15)]) == nodes[1] def test_compound(self): """ """ self.parser.compound_tokens = ['b'] self.parser.end_tokens = ['c'] nodes = list(self.parser.parse(self.tokens)) assert 3 == len(nodes) assert (2, 'b', (12, [(3, 'c', 13)])) == nodes[1] assert (4, 'b', (14, [(5, 'c', 15)])) == nodes[2]
class ParserTestCase(unittest.TestCase): """Test the ``Parser``.""" def setUp(self) -> None: self.parser = Parser({}) self.tokens = [ (1, "a", "11"), (2, "b", "12"), (3, "c", "13"), (4, "b", "14"), (5, "c", "15"), ] def test_end_continue(self) -> None: """Ensure end nodes are inserted before continue tokens.""" self.parser.continue_tokens = ["b"] nodes = list(self.parser.end_continue(self.tokens)) assert 7 == len(nodes) assert (2, "end", "") == nodes[1] assert (2, "b", "12") == nodes[2] assert (4, "end", "") == nodes[4] assert (4, "b", "14") == nodes[5] def test_parse_unchanged(self) -> None: """If there is no parser tokens defined the result is unchanged input. """ nodes = list(self.parser.parse(self.tokens)) assert self.tokens == nodes def test_parse_with_rules(self) -> None: """Ensure the rules applied.""" self.parser.rules["a"] = lambda value: value + "100" self.parser.rules["b"] = lambda value: value + "10" nodes = list(self.parser.parse(self.tokens)) assert (1, "a", "11100") == nodes[0] assert (2, "b", "1210") == nodes[1] assert (4, "b", "1410") == nodes[3] def test_out_tokens(self) -> None: """Tokens from ``out_tokens`` are combined together into a single node. """ self.parser.out_tokens = ["a", "b"] nodes = list(self.parser.parse(self.tokens)) assert 4 == len(nodes) assert (1, "out", [(1, "a", "11"), (2, "b", "12")]) == nodes[0] assert (4, "out", [(4, "b", "14")]) == nodes[2] self.parser.out_tokens = ["b", "c"] nodes = list(self.parser.parse(self.tokens)) assert 2 == len(nodes) assert ( 2, "out", [(2, "b", "12"), (3, "c", "13"), (4, "b", "14"), (5, "c", "15")], ) == nodes[1] def test_compound(self) -> None: """""" self.parser.compound_tokens = ["b"] self.parser.end_tokens = ["c"] nodes = list(self.parser.parse(self.tokens)) assert 3 == len(nodes) assert (2, "b", ("12", [(3, "c", "13")])) == nodes[1] assert (4, "b", ("14", [(5, "c", "15")])) == nodes[2]
class Engine(object): """The core component of template engine.""" def __init__( self, loader: Loader, extensions: typing.List[typing.Any], template_class: typing.Optional[TemplateClass] = None, ) -> None: self.lock = allocate_lock() self.templates: typing.Dict[str, SupportsRender] = {} self.renders: typing.Dict[str, RenderTemplate] = {} self.modules: typing.Dict[str, ModuleType] = {} self.global_vars = {"_r": self.render, "_i": self.import_name} self.loader = loader self.template_class = template_class or Template self.compiler = Compiler(self.global_vars, -2) self.lexer = Lexer(**lexer_scan(extensions)) self.parser = Parser(**parser_scan(extensions)) self.builder = SourceBuilder(**builder_scan(extensions)) def get_template(self, name: str) -> SupportsRender: """Returns compiled template.""" try: return self.templates[name] except KeyError: self.compile_template(name) return self.templates[name] def render( self, name: str, ctx: typing.Mapping[str, typing.Any], local_defs: typing.Mapping[str, typing.Any], super_defs: typing.Mapping[str, typing.Any], ) -> str: """Renders template by name in given context.""" try: return self.renders[name](ctx, local_defs, super_defs) except KeyError: self.compile_template(name) return self.renders[name](ctx, local_defs, super_defs) def remove(self, name: str) -> None: """Removes given ``name`` from internal cache.""" self.lock.acquire(True) try: if name in self.renders: del self.templates[name] del self.renders[name] if name in self.modules: del self.modules[name] finally: self.lock.release() # region: internal details def import_name(self, name: str) -> ModuleType: try: return self.modules[name] except KeyError: self.compile_import(name) return self.modules[name] def compile_template(self, name: str) -> None: self.lock.acquire(True) try: if name not in self.renders: template_source = self.loader.load(name) if template_source is None: raise IOError('Template "%s" not found.' % name) tokens = self.lexer.tokenize(template_source) nodes = self.parser.parse(tokens) source = self.builder.build_render(nodes) # print_debug(name, tokens, nodes, source) try: render_template = self.compiler.compile_source( source, name)["render"] except SyntaxError as e: raise complement_syntax_error(e, template_source, source) self.renders[name] = render_template self.templates[name] = self.template_class( name, render_template) finally: self.lock.release() def compile_import(self, name: str) -> None: self.lock.acquire(True) try: if name not in self.modules: template_source = self.loader.load(name) if template_source is None: raise IOError('Import "%s" not found.' % name) tokens = self.lexer.tokenize(template_source) nodes = self.parser.parse(tokens) source = self.builder.build_module(nodes) # print_debug(name, tokens, nodes, source) try: self.modules[name] = self.compiler.compile_module( source, name) except SyntaxError as e: raise complement_syntax_error(e, template_source, source) finally: self.lock.release()