web.web.template

Package web :: Package web :: Module template |
[hide private]
[frames] | no frames]

# Module template

source code

    simple, elegant templating
    (part of web.py)

    Template design:

    Template string is split into tokens and the tokens are combined into nodes.
    Parse tree is a nodelist. TextNode and ExpressionNode are simple nodes and
    for-loop, if-loop etc are block nodes, which contain multiple child nodes.

    Each node can emit some python string. python string emitted by the
    root node is validated for safeeval and executed using python in the given environment.

    Enough care is taken to make sure the generated code and the template has line to line match,
    so that the error messages can point to exact line number in template. (It doesn't work in some cases still.)

    Grammar:

        template -> defwith sections
        defwith -> '$def with (' arguments ')' | ''
        sections -> section*
        section -> block | assignment | line

        assignment -> '$ ' <assignment expression>
        line -> (text|expr)*
        text -> <any characters other than $>
        expr -> '$' pyexpr | '$(' pyexpr ')' | '${' pyexpr '}'
        pyexpr -> <python expression>

Classes | [hide private]
| Parser Parser Base.
| PythonTokenizer Utility wrapper over python tokenizer.
| DefwithNode
| TextNode
| ExpressionNode
| AssignmentNode
| LineNode
| BlockNode
| ForNode
| CodeNode
| StatementNode
| IfNode
| ElseNode
| ElifNode
| DefNode
| VarNode
| SuiteNode Suite is a list of sections.
| ForLoop Wrapper for expression in for stament to support loop.xxx helpers.
| ForLoopContext Stackable context for ForLoop to support nested for loops.
| BaseTemplate
| Template
| CompiledTemplate
| GAE_Render
| Render The most preferred way of using templates.
| render The most preferred way of using templates.
| ParseError
| SecurityError The template seems to be trying to do something naughty.
| SafeVisitor Make sure code is safe by walking through the AST.
| TemplateResult Dictionary like object for storing template output.

Functions | [hide private]
splitline(text) Splits the given text at newline. | source code
websafe(text) Encodes `text` for raw use in HTML. | source code
frender(path, **keywords) Creates a template from the given file path. | source code
compile_templates(root) Compiles templates to python code. | source code
test() Doctest for testing template module. | source code

Variables | [hide private]
| INDENT = ``u'``` `'``
| STATEMENT_NODES = `{'for': ForNode, 'while': BlockNode, 'if': I`...``
| KEYWORDS = ``[``'``pass``'``,` `'``break``'``,` `'``continue``'``,` `'``return``'``]``
| TEMPLATE_BUILTIN_NAMES = ``[``'``dict``'``,` `'``enumerate``'``,` `'``float``'``,` `'``int``'``,``...``
| TEMPLATE_BUILTINS = ``{``'``False``'``:` False`,` `'``None``'``:` None`,` `'``True``'``:` Tru`...``
| _htmlquote_re = `re.compile(r'`[`&<>"\'`]`')`
| _htmlquote_d = ``{``u'``"``'``:` `u'``&quot;``'``,` `u'``&``'``:` `u'``&amp;``'``,` `u'``'``'``:` `u'``&#39;``...``
| ALLOWED_AST_NODES = ``[``'``Add``'``,` `'``And``'``,` `'``AssList``'``,` `'``AssName``'``,` `'``AssT``...``
| __package__ = ``'``web.web``'``
| name = ``'``__import__``'``

Function Details | [hide private]

### splitline(text) | source code
Splits the given text at newline.
    >>> splitline('foo\nbar')
    ('foo\n', 'bar')
    >>> splitline('foo')
    ('foo', '')
    >>> splitline('')
    ('', '')

### websafe(text) | source code
Encodes `text` for raw use in HTML.
    >>> websafe(u"<'&\">")
    u'&lt;&#39;&amp;&quot;&gt;'
Unlike the websafe function in utils.py, this works with unicode text.

### test() | source code
Doctest for testing template module. Define a utility function to run template test.
    >>> class TestResult:
    ...     def __init__(self, t): self.t = t
    ...     def __getattr__(self, name): return getattr(self.t, name)
    ...     def __repr__(self): return repr(unicode(self))
    ...
    >>> def t(code, **keywords):
    ...     tmpl = Template(code, **keywords)
    ...     return lambda *a, **kw: TestResult(tmpl(*a, **kw))
    ...
Simple tests.
    >>> t('1')()
    u'1\n'
    >>> t('$def with ()\n1')()
    u'1\n'
    >>> t('$def with (a)\n$a')(1)
    u'1\n'
    >>> t('$def with (a=0)\n$a')(1)
    u'1\n'
    >>> t('$def with (a=0)\n$a')(a=1)
    u'1\n'
Test complicated expressions.
    >>> t('$def with (x)\n$x.upper()')('hello')
    u'HELLO\n'
    >>> t('$(2 * 3 + 4 * 5)')()
    u'26\n'
    >>> t('${2 * 3 + 4 * 5}')()
    u'26\n'
    >>> t('$def with (limit)\nkeep $(limit)ing.')('go')
    u'keep going.\n'
    >>> t('$def with (a)\n$a.b[0]')(storage(b=[1]))
    u'1\n'
Test html escaping.
    >>> t('$def with (x)\n$x', filename='a.html')('<html>')
    u'&lt;html&gt;\n'
    >>> t('$def with (x)\n$x', filename='a.txt')('<html>')
    u'<html>\n'
Test if, for and while.
    >>> t('$if 1: 1')()
    u'1\n'
    >>> t('$if 1:\n    1')()
    u'1\n'
    >>> t('$if 1:\n    1\\')()
    u'1'
    >>> t('$if 0: 0\n$elif 1: 1')()
    u'1\n'
    >>> t('$if 0: 0\n$elif None: 0\n$else: 1')()
    u'1\n'
    >>> t('$if 0 < 1 and 1 < 2: 1')()
    u'1\n'
    >>> t('$for x in [1, 2, 3]: $x')()
    u'1\n2\n3\n'
    >>> t('$def with (d)\n$for k, v in d.iteritems(): $k')({1: 1})
    u'1\n'
    >>> t('$for x in [1, 2, 3]:\n\t$x')()
    u'    1\n    2\n    3\n'
    >>> t('$def with (a)\n$while a and a.pop():1')([1, 2, 3])
    u'1\n1\n1\n'
The space after : must be ignored.
    >>> t('$if True: foo')()
    u'foo\n'
Test loop.xxx.
    >>> t("$for i in range(5):$loop.index, $loop.parity")()
    u'1, odd\n2, even\n3, odd\n4, even\n5, odd\n'
    >>> t("$for i in range(2):\n    $for j in range(2):$loop.parent.parity $loop.parity")()
    u'odd odd\nodd even\neven odd\neven even\n'
Test assignment.
    >>> t('$ a = 1\n$a')()
    u'1\n'
    >>> t('$ a = [1]\n$a[0]')()
    u'1\n'
    >>> t('$ a = {1: 1}\n$a.keys()[0]')()
    u'1\n'
    >>> t('$ a = []\n$if not a: 1')()
    u'1\n'
    >>> t('$ a = {}\n$if not a: 1')()
    u'1\n'
    >>> t('$ a = -1\n$a')()
    u'-1\n'
    >>> t('$ a = "1"\n$a')()
    u'1\n'
Test comments.
    >>> t('$# 0')()
    u'\n'
    >>> t('hello$#comment1\nhello$#comment2')()
    u'hello\nhello\n'
    >>> t('$#comment0\nhello$#comment1\nhello$#comment2')()
    u'\nhello\nhello\n'
Test unicode.
    >>> t('$def with (a)\n$a')(u'\u203d')
    u'\u203d\n'
    >>> t('$def with (a)\n$a')(u'\u203d'.encode('utf-8'))
    u'\u203d\n'
    >>> t(u'$def with (a)\n$a $:a')(u'\u203d')
    u'\u203d \u203d\n'
    >>> t(u'$def with ()\nfoo')()
    u'foo\n'
    >>> def f(x): return x
    ...
    >>> t(u'$def with (f)\n$:f("x")')(f)
    u'x\n'
    >>> t('$def with (f)\n$:f("x")')(f)
    u'x\n'
Test dollar escaping.
    >>> t("Stop, $$money isn't evaluated.")()
    u"Stop, $money isn't evaluated.\n"
    >>> t("Stop, \$money isn't evaluated.")()
    u"Stop, $money isn't evaluated.\n"
Test space sensitivity.
    >>> t('$def with (x)\n$x')(1)
    u'1\n'
    >>> t('$def with(x ,y)\n$x')(1, 1)
    u'1\n'
    >>> t('$(1 + 2*3 + 4)')()
    u'11\n'
Make sure globals are working.
    >>> t('$x')()
    Traceback (most recent call last):
        ...
    NameError: global name 'x' is not defined
    >>> t('$x', globals={'x': 1})()
    u'1\n'
Can't change globals.
    >>> t('$ x = 2\n$x', globals={'x': 1})()
    u'2\n'
    >>> t('$ x = x + 1\n$x', globals={'x': 1})()
    Traceback (most recent call last):
        ...
    UnboundLocalError: local variable 'x' referenced before assignment
Make sure builtins are customizable.
    >>> t('$min(1, 2)')()
    u'1\n'
    >>> t('$min(1, 2)', builtins={})()
    Traceback (most recent call last):
        ...
    NameError: global name 'min' is not defined
Test vars.
    >>> x = t('$var x: 1')()
    >>> x.x
    u'1'
    >>> x = t('$var x = 1')()
    >>> x.x
    1
    >>> x = t('$var x:  \n    foo\n    bar')()
    >>> x.x
    u'foo\nbar\n'
Test BOM chars.
    >>> t('\xef\xbb\xbf$def with(x)\n$x')('foo')
    u'foo\n'
Test for with weird cases.
    >>> t('$for i in range(10)[1:5]:\n    $i')()
    u'1\n2\n3\n4\n'
    >>> t("$for k, v in {'a': 1, 'b': 2}.items():\n    $k $v")()
    u'a 1\nb 2\n'
    >>> t("$for k, v in ({'a': 1, 'b': 2}.items():\n    $k $v")()
    Traceback (most recent call last):
        ...
    SyntaxError: invalid syntax
Test datetime.
    >>> import datetime
    >>> t("$def with (date)\n$date.strftime('%m %Y')")(datetime.datetime(2009, 1, 1))
    u'01 2009\n'

Variables Details | [hide private]

  ### STATEMENT_NODES Value:
      {'for': ForNode, 'while': BlockNode, 'if': IfNode, 'elif': ElifNode, '
      else': ElseNode, 'def': DefNode, 'code': CodeNode}

  ### TEMPLATE_BUILTIN_NAMES Value:
      ['dict',
       'enumerate',
       'float',
       'int',
       'bool',
       'list',
       'long',
       'reversed',
      ...

  ### TEMPLATE_BUILTINS Value:
      {'False': False,
       'None': None,
       'True': True,
       '__import__': <built-in function __import__>,
       'abs': <built-in function abs>,
       'all': <built-in function all>,
       'any': <built-in function any>,
       'bool': <type 'bool'>,
      ...

  ### _htmlquote_d Value:
      {u'"': u'&quot;',
       u'&': u'&amp;',
       u''': u'&#39;',
       u'<': u'&lt;',
       u'>': u'&gt;'}

  ### ALLOWED_AST_NODES Value:
      ['Add',
       'And',
       'AssList',
       'AssName',
       'AssTuple',
       'Assign',
       'AugAssign',
       'Bitand',
      ...