15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)"""
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)A small templating language
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)This implements a small templating language.  This language implements
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)if/elif/else, for/continue/break, expressions, and blocks of Python
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)code.  The syntax is::
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  {{any expression (function calls etc)}}
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  {{any expression | filter}}
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  {{for x in y}}...{{endfor}}
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  {{if x}}x{{elif y}}y{{else}}z{{endif}}
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  {{py:x=1}}
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  {{py:
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def foo(bar):
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return 'baz'
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }}
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  {{default var = default_value}}
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  {{# comment}}
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)You use this with the ``Template`` class or the ``sub`` shortcut.
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)The ``Template`` class takes the template string and the name of
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)the template (for errors) and a default namespace.  Then (like
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)``string.Template``) you can call the ``tmpl.substitute(**kw)``
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)method to make a substitution (or ``tmpl.substitute(a_dict)``).
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)``sub(content, **kw)`` substitutes the template immediately.  You
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)can use ``__name='tmpl.html'`` to set the name of the template.
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)If there are syntax errors ``TemplateError`` will be raised.
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)"""
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import re
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import sys
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import cgi
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)try:
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    from urllib import quote as url_quote
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)except ImportError:  # Py3
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    from urllib.parse import quote as url_quote
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import os
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import tokenize
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)try:
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    from io import StringIO
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)except ImportError:
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    from cStringIO import StringIO
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from Cython.Tempita._looper import looper
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from Cython.Tempita.compat3 import bytes, basestring_, next, is_unicode, coerce_text
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)__all__ = ['TemplateError', 'Template', 'sub', 'HTMLTemplate',
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           'sub_html', 'html', 'bunch']
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)in_re = re.compile(r'\s+in\s+')
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)var_re = re.compile(r'^[a-z_][a-z0-9_]*$', re.I)
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class TemplateError(Exception):
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Exception raised while parsing a template
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, message, position, name=None):
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Exception.__init__(self, message)
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.position = position
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.name = name
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __str__(self):
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        msg = ' '.join(self.args)
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if self.position:
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            msg = '%s at line %s column %s' % (
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                msg, self.position[0], self.position[1])
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if self.name:
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            msg += ' in %s' % self.name
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return msg
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class _TemplateContinue(Exception):
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    pass
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class _TemplateBreak(Exception):
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    pass
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def get_file_template(name, from_template):
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    path = os.path.join(os.path.dirname(from_template.name), name)
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return from_template.__class__.from_filename(
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        path, namespace=from_template.namespace,
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        get_template=from_template.get_template)
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class Template(object):
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    default_namespace = {
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'start_braces': '{{',
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'end_braces': '}}',
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'looper': looper,
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    default_encoding = 'utf8'
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    default_inherit = None
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, content, name=None, namespace=None, stacklevel=None,
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 get_template=None, default_inherit=None, line_offset=0,
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 delimeters=None):
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.content = content
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        # set delimeters
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if delimeters is None:
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            delimeters = (self.default_namespace['start_braces'],
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                          self.default_namespace['end_braces'])
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            #assert len(delimeters) == 2 and all([isinstance(delimeter, basestring)
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            #                                     for delimeter in delimeters])
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.default_namespace = self.__class__.default_namespace.copy()
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.default_namespace['start_braces'] = delimeters[0]
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.default_namespace['end_braces'] = delimeters[1]
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.delimeters = delimeters
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._unicode = is_unicode(content)
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if name is None and stacklevel is not None:
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            try:
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                caller = sys._getframe(stacklevel)
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            except ValueError:
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                pass
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            else:
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                globals = caller.f_globals
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                lineno = caller.f_lineno
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if '__file__' in globals:
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    name = globals['__file__']
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    if name.endswith('.pyc') or name.endswith('.pyo'):
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        name = name[:-1]
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                elif '__name__' in globals:
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    name = globals['__name__']
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                else:
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    name = '<string>'
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if lineno:
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    name += ':%s' % lineno
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.name = name
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._parsed = parse(content, name=name, line_offset=line_offset, delimeters=self.delimeters)
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if namespace is None:
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            namespace = {}
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.namespace = namespace
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.get_template = get_template
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if default_inherit is not None:
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.default_inherit = default_inherit
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def from_filename(cls, filename, namespace=None, encoding=None,
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                      default_inherit=None, get_template=get_file_template):
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        f = open(filename, 'rb')
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        c = f.read()
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        f.close()
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if encoding:
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            c = c.decode(encoding)
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return cls(content=c, name=filename, namespace=namespace,
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                   default_inherit=default_inherit, get_template=get_template)
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    from_filename = classmethod(from_filename)
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __repr__(self):
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return '<%s %s name=%r>' % (
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.__class__.__name__,
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            hex(id(self))[2:], self.name)
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def substitute(self, *args, **kw):
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if args:
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if kw:
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                raise TypeError(
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    "You can only give positional *or* keyword arguments")
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if len(args) > 1:
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                raise TypeError(
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    "You can only give one positional argument")
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if not hasattr(args[0], 'items'):
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                raise TypeError(
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    "If you pass in a single argument, you must pass in a dictionary-like object (with a .items() method); you gave %r"
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    % (args[0],))
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            kw = args[0]
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ns = kw
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ns['__template_name__'] = self.name
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if self.namespace:
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ns.update(self.namespace)
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        result, defs, inherit = self._interpret(ns)
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if not inherit:
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            inherit = self.default_inherit
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if inherit:
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            result = self._interpret_inherit(result, defs, inherit, ns)
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return result
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _interpret(self, ns):
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        __traceback_hide__ = True
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        parts = []
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        defs = {}
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._interpret_codes(self._parsed, ns, out=parts, defs=defs)
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if '__inherit__' in defs:
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            inherit = defs.pop('__inherit__')
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            inherit = None
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return ''.join(parts), defs, inherit
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _interpret_inherit(self, body, defs, inherit_template, ns):
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        __traceback_hide__ = True
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if not self.get_template:
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise TemplateError(
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                'You cannot use inheritance without passing in get_template',
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                position=None, name=self.name)
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        templ = self.get_template(inherit_template, self)
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self_ = TemplateObject(self.name)
2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for name, value in defs.iteritems():
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            setattr(self_, name, value)
2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self_.body = body
2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ns = ns.copy()
2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ns['self'] = self_
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return templ.substitute(ns)
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _interpret_codes(self, codes, ns, out, defs):
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        __traceback_hide__ = True
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for item in codes:
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if isinstance(item, basestring_):
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                out.append(item)
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            else:
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                self._interpret_code(item, ns, out, defs)
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _interpret_code(self, code, ns, out, defs):
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        __traceback_hide__ = True
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        name, pos = code[0], code[1]
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if name == 'py':
2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self._exec(code[2], ns, pos)
2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif name == 'continue':
2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise _TemplateContinue()
2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif name == 'break':
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise _TemplateBreak()
2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif name == 'for':
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            vars, expr, content = code[2], code[3], code[4]
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            expr = self._eval(expr, ns, pos)
2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self._interpret_for(vars, expr, content, ns, out, defs)
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif name == 'cond':
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            parts = code[2:]
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self._interpret_if(parts, ns, out, defs)
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif name == 'expr':
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            parts = code[2].split('|')
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            base = self._eval(parts[0], ns, pos)
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            for part in parts[1:]:
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                func = self._eval(part, ns, pos)
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                base = func(base)
2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            out.append(self._repr(base, pos))
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif name == 'default':
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            var, expr = code[2], code[3]
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if var not in ns:
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                result = self._eval(expr, ns, pos)
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                ns[var] = result
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif name == 'inherit':
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            expr = code[2]
2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            value = self._eval(expr, ns, pos)
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            defs['__inherit__'] = value
2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif name == 'def':
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            name = code[2]
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            signature = code[3]
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            parts = code[4]
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ns[name] = defs[name] = TemplateDef(self, name, signature, body=parts, ns=ns,
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                pos=pos)
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif name == 'comment':
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            assert 0, "Unknown code: %r" % name
2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _interpret_for(self, vars, expr, content, ns, out, defs):
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        __traceback_hide__ = True
2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for item in expr:
2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if len(vars) == 1:
2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                ns[vars[0]] = item
2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            else:
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if len(vars) != len(item):
2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    raise ValueError(
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        'Need %i items to unpack (got %i items)'
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        % (len(vars), len(item)))
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                for name, value in zip(vars, item):
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    ns[name] = value
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            try:
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                self._interpret_codes(content, ns, out, defs)
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            except _TemplateContinue:
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                continue
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            except _TemplateBreak:
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                break
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _interpret_if(self, parts, ns, out, defs):
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        __traceback_hide__ = True
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        # @@: if/else/else gets through
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for part in parts:
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            assert not isinstance(part, basestring_)
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            name, pos = part[0], part[1]
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if name == 'else':
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                result = True
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            else:
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                result = self._eval(part[2], ns, pos)
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if result:
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                self._interpret_codes(part[3], ns, out, defs)
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                break
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _eval(self, code, ns, pos):
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        __traceback_hide__ = True
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        try:
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            try:
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                value = eval(code, self.default_namespace, ns)
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            except SyntaxError, e:
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                raise SyntaxError(
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    'invalid syntax in expression: %s' % code)
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return value
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        except:
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            exc_info = sys.exc_info()
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            e = exc_info[1]
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if getattr(e, 'args', None):
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                arg0 = e.args[0]
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            else:
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                arg0 = coerce_text(e)
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            e.args = (self._add_line_info(arg0, pos),)
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise exc_info[0], e, exc_info[2]
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _exec(self, code, ns, pos):
3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        __traceback_hide__ = True
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        try:
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            exec code in self.default_namespace, ns
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        except:
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            exc_info = sys.exc_info()
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            e = exc_info[1]
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if e.args:
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                e.args = (self._add_line_info(e.args[0], pos),)
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            else:
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                e.args = (self._add_line_info(None, pos),)
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise exc_info[0], e, exc_info[2]
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _repr(self, value, pos):
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        __traceback_hide__ = True
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        try:
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if value is None:
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                return ''
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if self._unicode:
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                try:
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    value = unicode(value)
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                except UnicodeDecodeError:
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    value = bytes(value)
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            else:
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if not isinstance(value, basestring_):
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    value = coerce_text(value)
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if (is_unicode(value)
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    and self.default_encoding):
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    value = value.encode(self.default_encoding)
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        except:
3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            exc_info = sys.exc_info()
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            e = exc_info[1]
3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            e.args = (self._add_line_info(e.args[0], pos),)
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise exc_info[0], e, exc_info[2]
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if self._unicode and isinstance(value, bytes):
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if not self.default_encoding:
3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    raise UnicodeDecodeError(
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        'Cannot decode bytes value %r into unicode '
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        '(no default_encoding provided)' % value)
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                try:
3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    value = value.decode(self.default_encoding)
3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                except UnicodeDecodeError, e:
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    raise UnicodeDecodeError(
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        e.encoding,
3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        e.object,
3615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        e.start,
3625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        e.end,
3635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        e.reason + ' in string %r' % value)
3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            elif not self._unicode and is_unicode(value):
3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if not self.default_encoding:
3665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    raise UnicodeEncodeError(
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        'Cannot encode unicode value %r into bytes '
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        '(no default_encoding provided)' % value)
3695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                value = value.encode(self.default_encoding)
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return value
3715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _add_line_info(self, msg, pos):
3735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        msg = "%s at line %s column %s" % (
3745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            msg, pos[0], pos[1])
3755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if self.name:
3765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            msg += " in file %s" % self.name
3775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return msg
3785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def sub(content, delimeters=None, **kw):
3815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    name = kw.get('__name')
3825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    tmpl = Template(content, name=name, delimeters=delimeters)
3835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return tmpl.substitute(kw)
3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def paste_script_template_renderer(content, vars, filename=None):
3875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    tmpl = Template(content, name=filename)
3885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return tmpl.substitute(vars)
3895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class bunch(dict):
3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, **kw):
3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for name, value in kw.iteritems():
3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            setattr(self, name, value)
3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __setattr__(self, name, value):
3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self[name] = value
3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __getattr__(self, name):
4015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        try:
4025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return self[name]
4035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        except KeyError:
4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise AttributeError(name)
4055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __getitem__(self, key):
4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if 'default' in self:
4085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            try:
4095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                return dict.__getitem__(self, key)
4105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            except KeyError:
4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                return dict.__getitem__(self, 'default')
4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
4135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return dict.__getitem__(self, key)
4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __repr__(self):
4165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        items = [
4175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            (k, v) for k, v in self.iteritems()]
4185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        items.sort()
4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return '<%s %s>' % (
4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.__class__.__name__,
4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ' '.join(['%s=%r' % (k, v) for k, v in items]))
4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)############################################################
4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)## HTML Templating
4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)############################################################
4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class html(object):
4295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, value):
4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.value = value
4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __str__(self):
4345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return self.value
4355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __html__(self):
4375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return self.value
4385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __repr__(self):
4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return '<%s %r>' % (
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.__class__.__name__, self.value)
4425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def html_quote(value, force=True):
4455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if not force and hasattr(value, '__html__'):
4465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return value.__html__()
4475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if value is None:
4485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return ''
4495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if not isinstance(value, basestring_):
4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        value = coerce_text(value)
4515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if sys.version >= "3" and isinstance(value, bytes):
4525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        value = cgi.escape(value.decode('latin1'), 1)
4535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        value = value.encode('latin1')
4545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else:
4555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        value = cgi.escape(value, 1)
4565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if sys.version < "3":
4575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if is_unicode(value):
4585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            value = value.encode('ascii', 'xmlcharrefreplace')
4595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return value
4605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def url(v):
4635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    v = coerce_text(v)
4645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if is_unicode(v):
4655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        v = v.encode('utf8')
4665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return url_quote(v)
4675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def attr(**kw):
4705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    kw = list(kw.iteritems())
4715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    kw.sort()
4725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    parts = []
4735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for name, value in kw:
4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if value is None:
4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            continue
4765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if name.endswith('_'):
4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            name = name[:-1]
4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        parts.append('%s="%s"' % (html_quote(name), html_quote(value)))
4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return html(' '.join(parts))
4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class HTMLTemplate(Template):
4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    default_namespace = Template.default_namespace.copy()
4855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    default_namespace.update(dict(
4865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        html=html,
4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        attr=attr,
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        url=url,
4895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        html_quote=html_quote,
4905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ))
4915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _repr(self, value, pos):
4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if hasattr(value, '__html__'):
4945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            value = value.__html__()
4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            quote = False
4965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            quote = True
4985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        plain = Template._repr(self, value, pos)
4995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if quote:
5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return html_quote(plain)
5015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
5025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return plain
5035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def sub_html(content, **kw):
5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    name = kw.get('__name')
5075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    tmpl = HTMLTemplate(content, name=name)
5085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return tmpl.substitute(kw)
5095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class TemplateDef(object):
5125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, template, func_name, func_signature,
5135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 body, ns, pos, bound_self=None):
5145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._template = template
5155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._func_name = func_name
5165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._func_signature = func_signature
5175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._body = body
5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._ns = ns
5195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._pos = pos
5205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._bound_self = bound_self
5215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __repr__(self):
5235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return '<tempita function %s(%s) at %s:%s>' % (
5245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self._func_name, self._func_signature,
5255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self._template.name, self._pos)
5265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __str__(self):
5285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return self()
5295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __call__(self, *args, **kw):
5315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        values = self._parse_signature(args, kw)
5325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ns = self._ns.copy()
5335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ns.update(values)
5345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if self._bound_self is not None:
5355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ns['self'] = self._bound_self
5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        out = []
5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        subdefs = {}
5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._template._interpret_codes(self._body, ns, out, subdefs)
5395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return ''.join(out)
5405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __get__(self, obj, type=None):
5425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if obj is None:
5435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return self
5445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return self.__class__(
5455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self._template, self._func_name, self._func_signature,
5465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self._body, self._ns, self._pos, bound_self=obj)
5475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def _parse_signature(self, args, kw):
5495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        values = {}
5505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        sig_args, var_args, var_kw, defaults = self._func_signature
5515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        extra_kw = {}
5525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for name, value in kw.iteritems():
5535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if not var_kw and name not in sig_args:
5545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                raise TypeError(
5555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    'Unexpected argument %s' % name)
5565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if name in sig_args:
5575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                values[sig_args] = value
5585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            else:
5595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                extra_kw[name] = value
5605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        args = list(args)
5615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        sig_args = list(sig_args)
5625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        while args:
5635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            while sig_args and sig_args[0] in values:
5645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                sig_args.pop(0)
5655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if sig_args:
5665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                name = sig_args.pop(0)
5675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                values[name] = args.pop(0)
5685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            elif var_args:
5695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                values[var_args] = tuple(args)
5705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                break
5715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            else:
5725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                raise TypeError(
5735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    'Extra position arguments: %s'
5745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    % ', '.join([repr(v) for v in args]))
5755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for name, value_expr in defaults.iteritems():
5765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if name not in values:
5775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                values[name] = self._template._eval(
5785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    value_expr, self._ns, self._pos)
5795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for name in sig_args:
5805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if name not in values:
5815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                raise TypeError(
5825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    'Missing argument: %s' % name)
5835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if var_kw:
5845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            values[var_kw] = extra_kw
5855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return values
5865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class TemplateObject(object):
5895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, name):
5915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.__name = name
5925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.get = TemplateObjectGetter(self)
5935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __repr__(self):
5955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return '<%s %s>' % (self.__class__.__name__, self.__name)
5965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class TemplateObjectGetter(object):
5995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, template_obj):
6015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.__template_obj = template_obj
6025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __getattr__(self, attr):
6045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return getattr(self.__template_obj, attr, Empty)
6055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __repr__(self):
6075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return '<%s around %r>' % (self.__class__.__name__, self.__template_obj)
6085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class _Empty(object):
6115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __call__(self, *args, **kw):
6125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return self
6135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __str__(self):
6155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return ''
6165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __repr__(self):
6185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return 'Empty'
6195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __unicode__(self):
6215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return u''
6225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __iter__(self):
6245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return iter(())
6255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __bool__(self):
6275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return False
6285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if sys.version < "3":
6305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        __nonzero__ = __bool__
6315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Empty = _Empty()
6335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)del _Empty
6345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)############################################################
6365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)## Lexing and Parsing
6375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)############################################################
6385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def lex(s, name=None, trim_whitespace=True, line_offset=0, delimeters=None):
6415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
6425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Lex a string into chunks:
6435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> lex('hey')
6455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ['hey']
6465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> lex('hey {{you}}')
6475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ['hey ', ('you', (1, 7))]
6485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> lex('hey {{')
6495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Traceback (most recent call last):
6505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ...
6515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateError: No }} to finish last expression at line 1 column 7
6525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> lex('hey }}')
6535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Traceback (most recent call last):
6545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ...
6555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateError: }} outside expression at line 1 column 7
6565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> lex('hey {{ {{')
6575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Traceback (most recent call last):
6585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ...
6595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateError: {{ inside expression at line 1 column 10
6605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
6625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if delimeters is None:
6635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        delimeters = ( Template.default_namespace['start_braces'],
6645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       Template.default_namespace['end_braces'] )
6655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    in_expr = False
6665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    chunks = []
6675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    last = 0
6685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    last_pos = (line_offset + 1, 1)
6695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    token_re = re.compile(r'%s|%s' % (re.escape(delimeters[0]),
6715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                      re.escape(delimeters[1])))
6725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for match in token_re.finditer(s):
6735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        expr = match.group(0)
6745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        pos = find_position(s, match.end(), last, last_pos)
6755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if expr == delimeters[0] and in_expr:
6765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise TemplateError('%s inside expression' % delimeters[0],
6775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                position=pos,
6785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                name=name)
6795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif expr == delimeters[1] and not in_expr:
6805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise TemplateError('%s outside expression' % delimeters[1],
6815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                position=pos,
6825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                name=name)
6835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if expr == delimeters[0]:
6845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            part = s[last:match.start()]
6855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if part:
6865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                chunks.append(part)
6875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            in_expr = True
6885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
6895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            chunks.append((s[last:match.start()], last_pos))
6905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            in_expr = False
6915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        last = match.end()
6925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        last_pos = pos
6935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if in_expr:
6945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        raise TemplateError('No %s to finish last expression' % delimeters[1],
6955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            name=name, position=last_pos)
6965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    part = s[last:]
6975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if part:
6985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        chunks.append(part)
6995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if trim_whitespace:
7005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        chunks = trim_lex(chunks)
7015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return chunks
7025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)statement_re = re.compile(r'^(?:if |elif |for |def |inherit |default |py:)')
7045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)single_statements = ['else', 'endif', 'endfor', 'enddef', 'continue', 'break']
7055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)trail_whitespace_re = re.compile(r'\n\r?[\t ]*$')
7065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)lead_whitespace_re = re.compile(r'^[\t ]*\n')
7075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def trim_lex(tokens):
7105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    r"""
7115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Takes a lexed set of tokens, and removes whitespace when there is
7125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    a directive on a line by itself:
7135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       >>> tokens = lex('{{if x}}\nx\n{{endif}}\ny', trim_whitespace=False)
7155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       >>> tokens
7165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       [('if x', (1, 3)), '\nx\n', ('endif', (3, 3)), '\ny']
7175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       >>> trim_lex(tokens)
7185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       [('if x', (1, 3)), 'x\n', ('endif', (3, 3)), 'y']
7195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
7205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    last_trim = None
7215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for i, current in enumerate(tokens):
7225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if isinstance(current, basestring_):
7235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            # we don't trim this
7245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            continue
7255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        item = current[0]
7265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if not statement_re.search(item) and item not in single_statements:
7275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            continue
7285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if not i:
7295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            prev = ''
7305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
7315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            prev = tokens[i - 1]
7325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if i + 1 >= len(tokens):
7335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            next_chunk = ''
7345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
7355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            next_chunk = tokens[i + 1]
7365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (not isinstance(next_chunk, basestring_)
7375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            or not isinstance(prev, basestring_)):
7385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            continue
7395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        prev_ok = not prev or trail_whitespace_re.search(prev)
7405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if i == 1 and not prev.strip():
7415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            prev_ok = True
7425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if last_trim is not None and last_trim + 2 == i and not prev.strip():
7435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            prev_ok = 'last'
7445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (prev_ok
7455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            and (not next_chunk or lead_whitespace_re.search(next_chunk)
7465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 or (i == len(tokens) - 2 and not next_chunk.strip()))):
7475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if prev:
7485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if ((i == 1 and not prev.strip())
7495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    or prev_ok == 'last'):
7505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    tokens[i - 1] = ''
7515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                else:
7525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    m = trail_whitespace_re.search(prev)
7535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    # +1 to leave the leading \n on:
7545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    prev = prev[:m.start() + 1]
7555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    tokens[i - 1] = prev
7565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if next_chunk:
7575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                last_trim = i
7585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if i == len(tokens) - 2 and not next_chunk.strip():
7595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    tokens[i + 1] = ''
7605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                else:
7615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    m = lead_whitespace_re.search(next_chunk)
7625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    next_chunk = next_chunk[m.end():]
7635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    tokens[i + 1] = next_chunk
7645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return tokens
7655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def find_position(string, index, last_index, last_pos):
7685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Given a string and index, return (line, column)"""
7695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    lines = string.count('\n', last_index, index)
7705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if lines > 0:
7715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        column = index - string.rfind('\n', last_index, index)
7725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else:
7735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        column = last_pos[1] + (index - last_index)
7745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return (last_pos[0] + lines, column)
7755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def parse(s, name=None, line_offset=0, delimeters=None):
7785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    r"""
7795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Parses a string into a kind of AST
7805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{x}}')
7825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        [('expr', (1, 3), 'x')]
7835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('foo')
7845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ['foo']
7855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{if x}}test{{endif}}')
7865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        [('cond', (1, 3), ('if', (1, 3), 'x', ['test']))]
7875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('series->{{for x in y}}x={{x}}{{endfor}}')
7885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ['series->', ('for', (1, 11), ('x',), 'y', ['x=', ('expr', (1, 27), 'x')])]
7895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{for x, y in z:}}{{continue}}{{endfor}}')
7905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        [('for', (1, 3), ('x', 'y'), 'z', [('continue', (1, 21))])]
7915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{py:x=1}}')
7925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        [('py', (1, 3), 'x=1')]
7935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{if x}}a{{elif y}}b{{else}}c{{endif}}')
7945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        [('cond', (1, 3), ('if', (1, 3), 'x', ['a']), ('elif', (1, 12), 'y', ['b']), ('else', (1, 23), None, ['c']))]
7955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Some exceptions::
7975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{continue}}')
7995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Traceback (most recent call last):
8005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ...
8015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateError: continue outside of for loop at line 1 column 3
8025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{if x}}foo')
8035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Traceback (most recent call last):
8045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ...
8055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateError: No {{endif}} at line 1 column 3
8065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{else}}')
8075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Traceback (most recent call last):
8085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ...
8095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateError: else outside of an if block at line 1 column 3
8105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{if x}}{{for x in y}}{{endif}}{{endfor}}')
8115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Traceback (most recent call last):
8125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ...
8135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateError: Unexpected endif at line 1 column 25
8145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{if}}{{endif}}')
8155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Traceback (most recent call last):
8165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ...
8175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateError: if with no expression at line 1 column 3
8185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{for x y}}{{endfor}}')
8195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Traceback (most recent call last):
8205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ...
8215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateError: Bad for (no "in") in 'x y' at line 1 column 3
8225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        >>> parse('{{py:x=1\ny=2}}')
8235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Traceback (most recent call last):
8245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            ...
8255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateError: Multi-line py blocks must start with a newline at line 1 column 3
8265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
8275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if delimeters is None:
8285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        delimeters = ( Template.default_namespace['start_braces'],
8295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       Template.default_namespace['end_braces'] )
8305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    tokens = lex(s, name=name, line_offset=line_offset, delimeters=delimeters)
8315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    result = []
8325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while tokens:
8335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        next_chunk, tokens = parse_expr(tokens, name)
8345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        result.append(next_chunk)
8355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return result
8365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def parse_expr(tokens, name, context=()):
8395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if isinstance(tokens[0], basestring_):
8405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return tokens[0], tokens[1:]
8415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    expr, pos = tokens[0]
8425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    expr = expr.strip()
8435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if expr.startswith('py:'):
8445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        expr = expr[3:].lstrip(' \t')
8455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if expr.startswith('\n') or expr.startswith('\r'):
8465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            expr = expr.lstrip('\r\n')
8475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if '\r' in expr:
8485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                expr = expr.replace('\r\n', '\n')
8495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                expr = expr.replace('\r', '')
8505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            expr += '\n'
8515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
8525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if '\n' in expr:
8535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                raise TemplateError(
8545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    'Multi-line py blocks must start with a newline',
8555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    position=pos, name=name)
8565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return ('py', pos, expr), tokens[1:]
8575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif expr in ('continue', 'break'):
8585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if 'for' not in context:
8595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise TemplateError(
8605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                'continue outside of for loop',
8615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                position=pos, name=name)
8625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return (expr, pos), tokens[1:]
8635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif expr.startswith('if '):
8645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return parse_cond(tokens, name, context)
8655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif (expr.startswith('elif ')
8665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          or expr == 'else'):
8675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        raise TemplateError(
8685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            '%s outside of an if block' % expr.split()[0],
8695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            position=pos, name=name)
8705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif expr in ('if', 'elif', 'for'):
8715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        raise TemplateError(
8725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            '%s with no expression' % expr,
8735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            position=pos, name=name)
8745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif expr in ('endif', 'endfor', 'enddef'):
8755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        raise TemplateError(
8765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            'Unexpected %s' % expr,
8775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            position=pos, name=name)
8785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif expr.startswith('for '):
8795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return parse_for(tokens, name, context)
8805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif expr.startswith('default '):
8815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return parse_default(tokens, name, context)
8825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif expr.startswith('inherit '):
8835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return parse_inherit(tokens, name, context)
8845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif expr.startswith('def '):
8855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return parse_def(tokens, name, context)
8865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif expr.startswith('#'):
8875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return ('comment', pos, tokens[0][0]), tokens[1:]
8885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ('expr', pos, tokens[0][0]), tokens[1:]
8895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
8915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def parse_cond(tokens, name, context):
8925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    start = tokens[0][1]
8935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    pieces = []
8945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    context = context + ('if',)
8955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while 1:
8965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if not tokens:
8975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise TemplateError(
8985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                'Missing {{endif}}',
8995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                position=start, name=name)
9005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (isinstance(tokens[0], tuple)
9015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            and tokens[0][0] == 'endif'):
9025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return ('cond', start) + tuple(pieces), tokens[1:]
9035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        next_chunk, tokens = parse_one_cond(tokens, name, context)
9045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        pieces.append(next_chunk)
9055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def parse_one_cond(tokens, name, context):
9085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    (first, pos), tokens = tokens[0], tokens[1:]
9095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    content = []
9105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if first.endswith(':'):
9115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        first = first[:-1]
9125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if first.startswith('if '):
9135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        part = ('if', pos, first[3:].lstrip(), content)
9145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif first.startswith('elif '):
9155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        part = ('elif', pos, first[5:].lstrip(), content)
9165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif first == 'else':
9175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        part = ('else', pos, None, content)
9185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else:
9195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        assert 0, "Unexpected token %r at %s" % (first, pos)
9205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while 1:
9215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if not tokens:
9225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise TemplateError(
9235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                'No {{endif}}',
9245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                position=pos, name=name)
9255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (isinstance(tokens[0], tuple)
9265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            and (tokens[0][0] == 'endif'
9275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 or tokens[0][0].startswith('elif ')
9285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 or tokens[0][0] == 'else')):
9295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return part, tokens
9305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        next_chunk, tokens = parse_expr(tokens, name, context)
9315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        content.append(next_chunk)
9325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def parse_for(tokens, name, context):
9355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    first, pos = tokens[0]
9365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    tokens = tokens[1:]
9375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    context = ('for',) + context
9385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    content = []
9395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    assert first.startswith('for ')
9405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if first.endswith(':'):
9415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        first = first[:-1]
9425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    first = first[3:].strip()
9435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    match = in_re.search(first)
9445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if not match:
9455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        raise TemplateError(
9465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            'Bad for (no "in") in %r' % first,
9475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            position=pos, name=name)
9485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    vars = first[:match.start()]
9495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if '(' in vars:
9505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        raise TemplateError(
9515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            'You cannot have () in the variable section of a for loop (%r)'
9525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            % vars, position=pos, name=name)
9535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    vars = tuple([
9545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        v.strip() for v in first[:match.start()].split(',')
9555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if v.strip()])
9565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    expr = first[match.end():]
9575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while 1:
9585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if not tokens:
9595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise TemplateError(
9605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                'No {{endfor}}',
9615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                position=pos, name=name)
9625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (isinstance(tokens[0], tuple)
9635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            and tokens[0][0] == 'endfor'):
9645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return ('for', pos, vars, expr, content), tokens[1:]
9655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        next_chunk, tokens = parse_expr(tokens, name, context)
9665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        content.append(next_chunk)
9675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def parse_default(tokens, name, context):
9705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    first, pos = tokens[0]
9715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    assert first.startswith('default ')
9725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    first = first.split(None, 1)[1]
9735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    parts = first.split('=', 1)
9745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if len(parts) == 1:
9755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        raise TemplateError(
9765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            "Expression must be {{default var=value}}; no = found in %r" % first,
9775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            position=pos, name=name)
9785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var = parts[0].strip()
9795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if ',' in var:
9805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        raise TemplateError(
9815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            "{{default x, y = ...}} is not supported",
9825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            position=pos, name=name)
9835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if not var_re.search(var):
9845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        raise TemplateError(
9855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            "Not a valid variable name for {{default}}: %r"
9865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            % var, position=pos, name=name)
9875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    expr = parts[1].strip()
9885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ('default', pos, var, expr), tokens[1:]
9895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def parse_inherit(tokens, name, context):
9925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    first, pos = tokens[0]
9935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    assert first.startswith('inherit ')
9945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    expr = first.split(None, 1)[1]
9955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ('inherit', pos, expr), tokens[1:]
9965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
9985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def parse_def(tokens, name, context):
9995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    first, start = tokens[0]
10005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    tokens = tokens[1:]
10015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    assert first.startswith('def ')
10025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    first = first.split(None, 1)[1]
10035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if first.endswith(':'):
10045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        first = first[:-1]
10055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if '(' not in first:
10065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        func_name = first
10075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        sig = ((), None, None, {})
10085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    elif not first.endswith(')'):
10095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        raise TemplateError("Function definition doesn't end with ): %s" % first,
10105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            position=start, name=name)
10115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else:
10125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        first = first[:-1]
10135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        func_name, sig_text = first.split('(', 1)
10145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        sig = parse_signature(sig_text, name, start)
10155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    context = context + ('def',)
10165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    content = []
10175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while 1:
10185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if not tokens:
10195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise TemplateError(
10205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                'Missing {{enddef}}',
10215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                position=start, name=name)
10225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (isinstance(tokens[0], tuple)
10235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            and tokens[0][0] == 'enddef'):
10245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return ('def', start, func_name, sig, content), tokens[1:]
10255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        next_chunk, tokens = parse_expr(tokens, name, context)
10265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        content.append(next_chunk)
10275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
10285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
10295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def parse_signature(sig_text, name, pos):
10305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    tokens = tokenize.generate_tokens(StringIO(sig_text).readline)
10315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    sig_args = []
10325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var_arg = None
10335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    var_kw = None
10345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    defaults = {}
10355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
10365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def get_token(pos=False):
10375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        try:
10385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            tok_type, tok_string, (srow, scol), (erow, ecol), line = next(tokens)
10395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        except StopIteration:
10405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return tokenize.ENDMARKER, ''
10415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if pos:
10425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return tok_type, tok_string, (srow, scol), (erow, ecol)
10435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
10445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return tok_type, tok_string
10455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while 1:
10465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        var_arg_type = None
10475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        tok_type, tok_string = get_token()
10485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if tok_type == tokenize.ENDMARKER:
10495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            break
10505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if tok_type == tokenize.OP and (tok_string == '*' or tok_string == '**'):
10515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            var_arg_type = tok_string
10525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            tok_type, tok_string = get_token()
10535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if tok_type != tokenize.NAME:
10545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise TemplateError('Invalid signature: (%s)' % sig_text,
10555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                position=pos, name=name)
10565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        var_name = tok_string
10575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        tok_type, tok_string = get_token()
10585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if tok_type == tokenize.ENDMARKER or (tok_type == tokenize.OP and tok_string == ','):
10595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if var_arg_type == '*':
10605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                var_arg = var_name
10615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            elif var_arg_type == '**':
10625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                var_kw = var_name
10635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            else:
10645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                sig_args.append(var_name)
10655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if tok_type == tokenize.ENDMARKER:
10665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                break
10675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            continue
10685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if var_arg_type is not None:
10695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise TemplateError('Invalid signature: (%s)' % sig_text,
10705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                position=pos, name=name)
10715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if tok_type == tokenize.OP and tok_string == '=':
10725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            nest_type = None
10735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            unnest_type = None
10745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            nest_count = 0
10755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            start_pos = end_pos = None
10765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            parts = []
10775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            while 1:
10785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                tok_type, tok_string, s, e = get_token(True)
10795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if start_pos is None:
10805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    start_pos = s
10815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                end_pos = e
10825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if tok_type == tokenize.ENDMARKER and nest_count:
10835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    raise TemplateError('Invalid signature: (%s)' % sig_text,
10845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                        position=pos, name=name)
10855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if (not nest_count and
10865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    (tok_type == tokenize.ENDMARKER or (tok_type == tokenize.OP and tok_string == ','))):
10875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    default_expr = isolate_expression(sig_text, start_pos, end_pos)
10885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    defaults[var_name] = default_expr
10895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    sig_args.append(var_name)
10905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    break
10915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                parts.append((tok_type, tok_string))
10925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if nest_count and tok_type == tokenize.OP and tok_string == nest_type:
10935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    nest_count += 1
10945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                elif nest_count and tok_type == tokenize.OP and tok_string == unnest_type:
10955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    nest_count -= 1
10965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    if not nest_count:
10975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        nest_type = unnest_type = None
10985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                elif not nest_count and tok_type == tokenize.OP and tok_string in ('(', '[', '{'):
10995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    nest_type = tok_string
11005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    nest_count = 1
11015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    unnest_type = {'(': ')', '[': ']', '{': '}'}[nest_type]
11025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return sig_args, var_arg, var_kw, defaults
11035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def isolate_expression(string, start_pos, end_pos):
11065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    srow, scol = start_pos
11075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    srow -= 1
11085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    erow, ecol = end_pos
11095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    erow -= 1
11105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    lines = string.splitlines(True)
11115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if srow == erow:
11125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return lines[srow][scol:ecol]
11135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    parts = [lines[srow][scol:]]
11145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    parts.extend(lines[srow+1:erow])
11155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if erow < len(lines):
11165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        # It'll sometimes give (end_row_past_finish, 0)
11175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        parts.append(lines[erow][:ecol])
11185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ''.join(parts)
11195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)_fill_command_usage = """\
11215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)%prog [OPTIONS] TEMPLATE arg=value
11225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Use py:arg=value to set a Python value; otherwise all values are
11245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)strings.
11255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)"""
11265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def fill_command(args=None):
11295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    import sys
11305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    import optparse
11315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    import pkg_resources
11325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    import os
11335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if args is None:
11345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        args = sys.argv[1:]
11355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    dist = pkg_resources.get_distribution('Paste')
11365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    parser = optparse.OptionParser(
11375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        version=coerce_text(dist),
11385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        usage=_fill_command_usage)
11395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    parser.add_option(
11405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        '-o', '--output',
11415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        dest='output',
11425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        metavar="FILENAME",
11435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        help="File to write output to (default stdout)")
11445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    parser.add_option(
11455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        '--html',
11465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        dest='use_html',
11475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        action='store_true',
11485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        help="Use HTML style filling (including automatic HTML quoting)")
11495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    parser.add_option(
11505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        '--env',
11515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        dest='use_env',
11525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        action='store_true',
11535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        help="Put the environment in as top-level variables")
11545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    options, args = parser.parse_args(args)
11555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if len(args) < 1:
11565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        print('You must give a template filename')
11575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        sys.exit(2)
11585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    template_name = args[0]
11595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    args = args[1:]
11605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    vars = {}
11615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if options.use_env:
11625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        vars.update(os.environ)
11635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for value in args:
11645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if '=' not in value:
11655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            print('Bad argument: %r' % value)
11665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            sys.exit(2)
11675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        name, value = value.split('=', 1)
11685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if name.startswith('py:'):
11695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            name = name[:3]
11705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            value = eval(value)
11715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        vars[name] = value
11725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if template_name == '-':
11735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        template_content = sys.stdin.read()
11745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        template_name = '<stdin>'
11755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else:
11765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        f = open(template_name, 'rb')
11775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        template_content = f.read()
11785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        f.close()
11795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if options.use_html:
11805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateClass = HTMLTemplate
11815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else:
11825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        TemplateClass = Template
11835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    template = TemplateClass(template_content, name=template_name)
11845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    result = template.substitute(vars)
11855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if options.output:
11865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        f = open(options.output, 'wb')
11875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        f.write(result)
11885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        f.close()
11895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else:
11905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        sys.stdout.write(result)
11915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
11925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)if __name__ == '__main__':
11935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    fill_command()
1194