Page Templates

Chameleon Page Templates (CPT) is a system which can generate HTML and XML.

The system is formed by the Template Attribute Language (TAL), the Expression Syntax (TALES), Intertionalization (I18N) and the Macro Expansion Template Attribute Language (METAL).

Note that this template system is based on (and closely resembles) Zope Page Templates (ZPT). If you know that system, you should be able to pick up the present system right away.

Getting started

There are several template constructor classes available, one for each of the combinations text or xml, and string or file.

Most projects will benefit from the simplicity of the template loader utility:

from chameleon import PageTemplateLoader
templates = PageTemplateLoader("/some/absolute/path")

To load a template file "hello.pt" relative to the provided path, use the dictionary syntax:

template = templates['hello.pt']

The alternative is to invoke the appropriate constructor directly. Let’s try with a string input:

from chameleon import PageTemplate
template = PageTemplate("<div>Hello, $name.</div>")

All template instances are callable. Provide arguments as keywords:

>>> template(name='John')
'<div>Hello, John.</div>'

Learning the language

For an introduction to the language, please see the getting started section on the Zope website. Note that the expression language used in the examples there is path, not Python.

Incompatibilities and differences

There are a number of incompatibilities and differences between CPT and ZPT. We list them here for a brief overview:

Default expression

The default expression is Python (or "python:"). The path expression syntax is not supported in the base package.

Template arguments

Arguments passed by keyword to the render- or call method are inserted directly into the template execution namespace. This is different from ZPT where these are only available through the options dictionary.

Zope:

<div tal:content="options/title" />

Chameleon:

<div tal:content="title" />

Special symbols

The CONTEXTS symbol is not available.

New language features

The CPT system comes with a number of features and extensions that will be new to users of ZPT. Some take inspiration from Genshi.

Imports

The package introduces the import: expression which imports global names:

<div tal:define="compile import: re.compile">
  ...

Tuple unpacking

The tal:define and tal:repeat clauses supports tuple unpacking:

tal:define="(a, b, c) [1, 2, 3]"

Extended iterable unpacking using the asterisk character is not currently supported (even for platforms that support it natively).

Dictionary lookup as fallback after attribute error

If attribute lookup (using the obj.<name> syntax) raises an AttributeError exception, a secondary lookup is attempted using dictionary lookup — obj['<name>'].

Behind the scenes, this is done by rewriting all attribute-lookups to a custom lookup call:

def lookup_attr(obj, key):
    try:
        return getattr(obj, key)
    except AttributeError as exc:
        try:
            get = obj.__getitem__
        except AttributeError:
            raise exc
        try:
            return get(key)
        except KeyError:
            raise exc

Inline expression operator

In element attributes and in the text or tail of an element, string expression interpolation is available using the ${...} syntax:

<span class="content-${item_type}">
   ${title or item_id}
</span>

Literal content

While the tal:content and tal:repeat attributes both support the structure keyword which inserts the content as a literal (without XML-escape), an object may also provide an __html__ method to the same effect.

The result of the method will be inserted as structure.

This is particularly useful for content which is substituted using the expression operator: "${...}" since the structure keyword is not allowed here.

Switches

Two new attributes have been added: tal:switch and tal:case. A case attribute works like a condition and only allows content if the value matches that of the nearest parent switch value.

Writing an expression compiler

To extend the language with a new expression prefix, you need to write an expression compiler.

Let’s try and write a compiler for an expression type that will simply uppercase the supplied value.

import ast

class UppercaseExpr(object):
    def __init__(self, string):
        self.string = string

    def __call__(self, target, engine):
        uppercased = self.string.uppercase()
        value = ast.Str(uppercased)
        return [ast.Assign(targets=[target], value=value)]

That’s it for the compiler.

To make it available under a certain prefix, we’ll add it to the expression types dictionary.

from chameleon import PageTemplate

PageTemplate.expression_type['upper'] = UppercaseExpr

To avoid changing the existing template class, instead we could have subclassed, copied the existing expression_type dictionary and added our expression compiler there.

Adding custom expressions can be a powerful way to make the templates in your project more expressive.

API reference

This section contains an autogenerated API reference.

The PageTemplate* constructors create template instances from source files.

Some systems have framework support for loading templates from files. The following loader class is directly compatible with the Pylons framework and may be adapted to other frameworks:

class chameleon.PageTemplateLoader(search_path=None, **kwargs)