• 用python写自定义模板


    模板语法有点像php

    !/usr/bin/env python
    """
    
    
    #demo.py.html
    
    
    <html>
    <?py include head.py.html ?>
    <body>
        <?py extend test_for.py.html ?>
        <div>
            <pre> test if </pre>
            <?py if 2 > 1 ?>
            <p>Yes, it is</p>
            <?py else ?>
            <p>No it is not</p>
            <?py #endif ?>
        </div>
    
        <div>
            <pre> test def </pre>
            <?py def p() ?>
                <?py return 'hello' ?>
            <?py #enddef ?>
            Wow! ${p()}
        </div>
    </body>
    </html>
    
    
    #head.py.html
    <head>
        <title>Demo Py Template</title>
    </head>
    
    #test_for.py.html
    <div>
        <pre> test for <pre>
        <?py for _ in ['a', 'b', 'c'] ?>
        Hello ${_} #{_.upper()} 
        <?py #endfor ?>
    </div>
    """
     
    from __future__ import absolute_import, division, print_function, with_statement
    import re
    import os.path
     
     
    class TemplateLoader(object):
        pass
     
     
    class DictLoader(object):
        pass
     
     
    class Template(object):
     
        #GLOBALS = {}
     
        def __init__(self, tempalte_path):
            self.tempalte_path = tempalte_path
     
            self.globals = {
                't': lambda x: x,
                'xml_escape': xml_escape,
                'html_escape': html_escape,
                'e': escape
            }
     
            self.templates = {
     
            }
     
        def render(self, path, **kwrags):
            # the stemplae system local never be override
            _g = kwargs.update(self.globals)
            code = self.genarate(path, g)
            exec code in _g
            return _g['_tt_render']()
     
        def genarate(self, path, g):
            if path in self.templates:
                return self.templates[path](g)
     
            tempalte_path = os.path.join(self.tempalte_path, path)
            tempalte_func = TemplateParser(tempalte_path).compile()
            self.templates[path] = tempalte_func
            return tempalte_func(g)
     
     
    class TemplateParser(object):
     
        PY_TOKEN = re.compile(r'<?pys*((?:[^=0-9]).*?)s*?>')
        PY_VAR_TOKEN = re.compile(r'(?:[#$]){(.*?)}')
     
        def __init__(self, path2template, indent=None, include=False):
            self.path2template = path2template
            self.indent = indent or 1
            self.buffer = ''
            self._include = include
            if not self._include:
                self.buffer += 'def _tt_render():
    '
                self.puts('_buffer=[]')
                self.puts('_append=_buffer.append')
     
        def puts(self, line):
            self.buffer += self.indents + "%s" % (line) + '
    '
     
        def compile(self):
            code = self.parse()
            code = compile(code, '<string>', 'exec', dont_inherit=True)
            return code
     
        def parse(self):
            f = open(self.path2template)
     
            lineno = 1
            while True:
                line = f.readline()
                if not line:
                    break
                self.parse_line(line, lineno)
                lineno += 1
            if not self._include:
                self.puts('return "".join(_buffer)')
            f.close()
     
            return self.buffer
     
        def parse_line(self, line, lineno):
     
            # remove the whitespace line and comment line
            if not line.strip() or line.lstrip().startswith('#'):
                return
     
            m = self.PY_TOKEN.search(line)
            if m:
                t = m.group(1)
                parts = t.split(' ', 1)
                if parts[0] in ('from', 'import'):
                    self.stmt(t)
                    return
     
                if parts[0] == 'include':
                    self.include(parts[1])
                    return
     
                if parts[0] == 'extend':
                    self.extend(parts[1])
                    return
     
                if parts[0] in ('for', 'if', 'with', 'def', 'class', 'try'):
                    self.contoll(t)
                    self.indent += 1
                    return
     
                if parts[0] in ('else', 'elif', 'except'):
                    self.indent -= 1
                    self.contoll(t)
                    self.indent += 1
                    return
     
                if parts[0] in ('#end', '#endfor', '#endif', '#endtry', '#endclass', '#enddef', '#endwith'):
                    self.indent -= 1
                    return
     
                self.stmt(t)
                return
     
            # handle var token
            ms = self.PY_VAR_TOKEN.finditer(line)
            if ms:
                a = None
                end = 0
                start = 0
                l = ''
                for m in ms:
                    t = m.group(1)
                    start = m.start()
     
                    b = line[end:m.start()]
                    start = m.start()
                    end = m.end()
                    a = line[end:]
                    if l:
                        l += "+ '%s'" % (b) + " + str(%s) " % (t)
                    else:
                        l = "'%s'" % (b) + " + str(%s) " % (t)
     
                if a and start:
                    l += "+" + " %r" % (a)
                if l:
                    self.stmt("_append(" + l + ")")
                    return
     
            self.text(line)
     
        def text(self, content):
            content = self.indents + '_append(' + "%r" % (content) + ')
    '
            self.buffer += content
     
        def e(self, formator, t):
            self.puts('_append("' + formator + '"' + ' % ' + t + ")")
     
        def r(self):
            return '%r'
     
        def contoll(self, line):
            self.buffer += self.indents + line + ':
    '
     
        def stmt(self, stmt):
            self.buffer += self.indents + stmt + ' 
    '
     
        @property
        def indents(self):
            return '    ' * self.indent
     
        def include(self, template):
            p = TemplateParser(template, include=True)
            self.buffer += p.parse()
     
        def extend(self, template):
            p = TemplateParser(template, self.indent, include=True)
            self.buffer += p.parse()
     
     
    if __name__ == '__main__':
        t = TemplateParser('demo.py.html')
     
        code = t.compile()
        ns = {}
        exec code in ns
        # print ns
        print(ns['_tt_render']())
  • 相关阅读:
    简单工厂、工厂方法、抽象工厂
    c#之反射总结
    设计模式Builder(建造者)模式
    c#之委托和事件的区别
    c#之委托总结
    javascript之流程控制 和函数的容易忽略点
    javascript之六种数据类型以及特殊注意点
    Sublime Text 快捷键
    链接中获取文件名
    js 获取当天23点59分59秒 时间戳 (最简单的方法)
  • 原文地址:https://www.cnblogs.com/nagi/p/4191471.html
Copyright © 2020-2023  润新知