The templating language is fairly simple, just {{stuff}}. For example:: >>> from paste.util.template import Template, sub >>> sub('Hi {{name}}', name='Ian') 'Hi Ian' >>> Template('Hi {{repr(name)}}').substitute(name='Ian') "Hi 'Ian'" >>> Template('Hi {{name+1}}').substitute(name='Ian') # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... TypeError: cannot concatenate 'str' and 'int' objects at line 1 column 6 It also has Django-style piping:: >>> sub('Hi {{name|repr}}', name='Ian') "Hi 'Ian'" Note that None shows up as an empty string:: >>> sub('Hi {{name}}', name=None) 'Hi ' And if/elif/else:: >>> t = Template('{{if x}}{{y}}{{else}}{{z}}{{endif}}') >>> t.substitute(x=1, y=2, z=3) '2' >>> t.substitute(x=0, y=2, z=3) '3' >>> t = Template('{{if x > 0}}positive{{elif x < 0}}negative{{else}}zero{{endif}}') >>> t.substitute(x=1), t.substitute(x=-10), t.substitute(x=0) ('positive', 'negative', 'zero') Plus a for loop:: >>> t = Template('{{for i in x}}i={{i}}\n{{endfor}}') >>> t.substitute(x=range(3)) 'i=0\ni=1\ni=2\n' >>> t = Template('{{for a, b in sorted(z.items()):}}{{a}}={{b}},{{endfor}}') >>> t.substitute(z={1: 2, 3: 4}) '1=2,3=4,' >>> t = Template('{{for i in x}}{{if not i}}{{break}}' ... '{{endif}}{{i}} {{endfor}}') >>> t.substitute(x=[1, 2, 0, 3, 4]) '1 2 ' >>> t = Template('{{for i in x}}{{if not i}}{{continue}}' ... '{{endif}}{{i}} {{endfor}}') >>> t.substitute(x=[1, 2, 0, 3, 0, 4]) '1 2 3 4 ' Also Python blocks:: >>> sub('{{py:\nx=1\n}}{{x}}') '1' And some syntax errors:: >>> t = Template('{{if x}}', name='foo.html') Traceback (most recent call last): ... TemplateError: No {{endif}} at line 1 column 3 in foo.html >>> t = Template('{{for x}}', name='foo2.html') Traceback (most recent call last): ... TemplateError: Bad for (no "in") in 'x' at line 1 column 3 in foo2.html There's also an HTMLTemplate that uses HTMLisms:: >>> from paste.util.template import HTMLTemplate, sub_html, html >>> sub_html('hi {{name}}', name='') 'hi <foo>' But if you don't want quoting to happen you can do:: >>> sub_html('hi {{name}}', name=html('')) 'hi ' >>> sub_html('hi {{name|html}}', name='') 'hi ' Also a couple handy functions;: >>> t = HTMLTemplate('') >>> t.substitute(id=1, class_='foo') '' >>> t.substitute(id='with space', class_=None) '' There's a handyish looper thing you can also use in your templates (or in Python, but it's more useful in templates generally):: >>> from paste.util.looper import looper >>> seq = ['apple', 'asparagus', 'Banana', 'orange'] >>> for loop, item in looper(seq): ... if item == 'apple': ... assert loop.first ... elif item == 'orange': ... assert loop.last ... if loop.first_group(lambda i: i[0].upper()): ... print('%s:' % item[0].upper()) ... print("%s %s" % (loop.number, item)) A: 1 apple 2 asparagus B: 3 Banana O: 4 orange It will also strip out empty lines, when there is a line that only contains a directive/statement (if/for, etc):: >>> sub('{{if 1}}\n{{x}}\n{{endif}}\n', x=0) '0\n' >>> sub('{{if 1}}x={{x}}\n{{endif}}\n', x=1) 'x=1\n' >>> sub('{{if 1}}\nx={{x}}\n{{endif}}\n', x=1) 'x=1\n' Lastly, there is a special directive that will create a default value for a variable, if no value is given:: >>> sub('{{default x=1}}{{x}}', x=2) '2' >>> sub('{{default x=1}}{{x}}') '1' >>> # The normal case: >>> sub('{{x}}') # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... NameError: name 'x' is not defined at line 1 column 3 And comments work:: >>> sub('Test=x{{#whatever}}') 'Test=x'