A lightweight template engine in Python.

Version 1.6.0

Template Markup

There are three kinds of template markup: comments, print statements, and syntax tags. Comments are the simplest kind; they look like this:

{# This is a comment. #}

Comments can span multiple lines and can be used to comment-out sections of template code.

Print statements evaluate and print expressions. They look like this:

{{ post.title }}

Print statements come in two flavours: regular and escaped. Escaped print statements escape HTML syntax characters in their output before printing it. They look like this:

{{{ post.title }}}

Escaped print statements are simply a shortcut for applying the built-in escape filter to their content. The example above is equivalent to:

{{ post.title|escape }}

Print statements can make use of two other constructs. First, print statements can contain multiple expressions separated by the || sigil. The first expression to evaluate as 'truthy' will be printed:

{{ post.title || "Untitled Post" }}

Second, print statements can make use of a C-style ternary operator:

{{ is_homepage ?? site.title :: post.title }}

If the first (test) expression evaluates as 'truthy', the value of the second expression will be printed, otherwise the value of the third expression will be used.

Note that a single print statement can make use of or-chaining or the ternary construct, but not both.


An expression consists of a variable name or a Python literal, optionally followed by a chain of pipe-separated filters.

Variables use . syntax to drill into nested dictionaries or objects. If a variable evaluates to a callable it gets called automatically. If the callable requires arguments you can supply them in brackets:

{{ some.callable("foo", 42) }}

Filters are chainable functions that modify the value of an expression. You apply them using the pipe symbol:

{{ post.title|escape }}

Like callables, filters accept arguments in brackets:

{{ post.content|striptags|truncatewords(50) }}

You can find a list of built-in filters here.

Note that expressions can use simple Python literals in place of variables:

{% if day|lower in ("saturday", "sunday") %}
    It's the weekend!
{% endif %}

The following literal structures can be used in expressions as arguments to callables or in place of variables: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None.

Syntax Tags

Syntax tags implement a broad range of behaviours like looping, conditional branching, and template inheritance. They look like this:

{% tag %}

Some syntax tags have block scope and require a closing tag. They look like this:

{% tag %} ... {% endtag %}

Tags with block scope can contain further template markup and can be nested to any depth.

You can find a list of built-in syntax tags here.