It is not actually actively developed, and not an ambitious project. It does not
seek to take over the templating world, or adopt many new features.
I just wanted a small templating language for cases when % and
string.Template weren’t enough.

Surely the world has enough templating languages? So why did I write
another.

I initially used Cheetah as the
templating language for Paste Script, but this caused quite a few
problems. People frequently had problems installing Cheetah because
it includes a C extension. Also, the errors and invocation can be a
little confusing. This might be okay for something that used
Cheetah’s features extensively, except that the templating was a very
minor feature of the system, and many people didn’t even understand or
care about where templating came into the system.

At the same time, I was starting to create reusable WSGI components
that had some templating in them. Not a lot of templating, but enough
that string.Template had become too complicated – I need if
statements and loops.

Given this, I started looking around for a very small templating
language, and I didn’t like anything I found. Many of them seemed
awkward or like toys that were more about the novelty of the
implementation than the utility of the language.

So one night when I felt like coding but didn’t feel like working on
anything I was already working on, I wrote this. It was first called
paste.util.template, but I decided it deserved a life of its own,
hence Tempita.

Tempita tries to handle unicode gracefully, for some value of
“graceful”. Template objects have a default_encoding
attribute. It will try to use that encoding whenever unicode and
str objects are mixed in the template. E.g.:

To insert a variable or expression, use {{expression}}. You can’t
use }} in your expression, but if it comes up just use }}
(put a space between them). You can pass your expression through
filters with {{expression|filter}}, for instance
{{expression|repr}}. This is entirely equivalent to
{{repr(expression)}}. But it might look nicer to some people; I
took it from Django because I liked it. There’s a shared namespace,
so repr is just an object in the namespace.

If you want to have {{ or }} in your template, you must use
the built-in variables like {{start_braces}} and
{{end_braces}}. There’s no escape character.

You may also specify the delimiters as an argument to the Template
__init__ method:

The delimiters argument must be of length two and both items must be strings.

None, as a special case, is substituted as the empty string.

Also there is a command for setting default values in your template:

{{defaultwidth=100}}

You can use this so that the width variable will always have a
value in your template (the number 100). If someone calls
tmpl.substitute(width=200) then this will have no effect; only if
the variable is undefined will this default matter. You can use any
expression to the right of the =.

For anything more complicated, you can use blocks of Python code,
like:

{{py:x=1}}{{py:lotsofcode}}

The first form allows statements, like an assignment or raising an
exception. The second form is for multiple lines. If you have
multiple lines, then {{py: must be on a line of its own and the
code can’t start out indented (but if you have something like defx(): you would indent the body).

These blocks of code can’t output any values, but they can calculate
values and define functions. So you can do something like:

The other object is for use inside the template, and is part of the
default namespace, looper. This can be used in for loops in
some convenient ways. You basically use it like:

{{forloop,iteminlooper(seq)}}...{{endfor}}

The loop object has a bunch of useful methods and attributes:

.index

The index of the current item (like you’d get with
enumerate())

.number

The number: .index+1

.item

The item you are looking at. Which you probably already have,
but it’s there if you want it.

.next

The next item in the sequence, or None if it’s the last item.

.previous

The previous item in the sequence, or None if it’s the first
item.

.odd

True if this is an odd item. The first item is even.

.even

True if it’s even.

.first

True if this is the first item.

.last

True if this is the last item.

.length

The total length of the sequence.

.first_group(getter=None)

Returns true if this item is the first in the group, where the
group is either of equal objects (probably boring), or when you
give a getter. getter can be '.attribute', like
'.last_name' – this lets you group people by their last
name. Or a method, like '.birth_year()' – which calls the
method. If it’s just a string, it is expected to be a key in a
dictionary, like 'name' which groups on item['name'].
Or you can give a function which returns the value to group on.
This always returns true when .first returns true.

.last_group(getter=None)

Like first_group, only returns True when it’s the last of
the group. This always returns true when .last returns true.

Note that there’s currently a limitation in the templating language,
so you can’t do {{forloop,(key,value)inlooper(d.items())}}.
You’ll have to do:

It’s not really meant for extension. Instead you should just write
Python functions and classes that do what you want, and use them in
the template. You can either add the namespace to the constructor, or
extend default_namespace in your own subclass.

The extension that HTMLTemplate uses is to subclass and override
the _repr(value,pos) function. This is called on each object
just before inserting it in the template.

Two other methods you might want to look at are _eval(code,ns,pos) and _exec(code,ns,pos), which evaluate and execute
expressions and statements. You could probably make this language
safe with appropriate implementations of those methods.

There’s also a command-line version of the program. In Python 2.5+
you can run python-mtempita; in previous versions you must run
pythonpath/to/tempita/__init__.py.

The usage:

Usage:__init__.py[OPTIONS]TEMPLATEarg=valueUsepy:arg=valuetosetaPythonvalue;otherwiseallvaluesarestrings.Options:--versionshowprogram's version number and exit-h,--helpshowthishelpmessageandexit-oFILENAME,--output=FILENAMEFiletowriteoutputto(defaultstdout)--htmlUseHTMLstylefilling(includingautomaticHTMLquoting)--envPuttheenvironmentinastop-levelvariables

Currently nested structures in for loop assignments don’t work,
like for(a,b),cinx. They should.

There’s no way to handle exceptions, except in your py: code.
I’m not sure what there should be, if anything.

Probably I should try to dedent py: code.

There should be some way of calling a function with a chunk of the
template. Maybe like:

{{callexpr}}templatecode...{{endcall}}

That would mean {{expr(result_of_template_code)}}. But maybe
there should be another assignment form too, if you don’t want to
immediately put the output in the code ({{x=call}}...{{endcall}}?). For now defs could be used for this,
like: