ZPT
This section documents the package as a Python library. To learn about the page template language, consult the language reference.
Getting started
There are several template constructor classes available, one for each of the combinations text or xml, and str...
This section documents the package as a Python library. To learn about the page template language, consult the language reference.
Getting started
There are several template constructor classes available, one for each of the combinations text or xml, and string or file.
The file-based constructor requires an absolute path. To set up a templates directory once, use the template loader class:
import os
path = os.path.dirname(__file__)
from chameleon import PageTemplateLoader
templates = PageTemplateLoader(os.path.join(path, "templates"))
Then, to load a template relative to the provided path, use dictionary syntax:
template = templates['hello.pt']
Alternatively, use the appropriate template class directly. Let’s try with a string input:
from chameleon import PageTemplate
template = PageTemplate("
Hello, ${name}.
")
All template instances are callable. Provide variables by keyword argument:
>>> template(name='John')
'
Hello, John.
'
Performance
The template engine compiles (or translates) template source code into Python byte-code. In simple templates this yields an increase in performance of about 7 times in comparison to the reference implementation.
In benchmarks for the content management system Plone, switching to Chameleon yields a request to response improvement of 20-50%.
Extension
You can extend the language through the expression engine by writing your own expression compiler.
Let’s try and write an expression compiler for an expression type that will simply uppercase the supplied value. We’ll call it upper.
You can write such a compiler as a closure:
import ast
def uppercase_expression(string):
def compiler(target, engine):
uppercased = self.string.uppercase()
value = ast.Str(uppercased)
return [ast.Assign(targets=[target], value=value)]
return compiler
To make it available under a certain prefix, we’ll add it to the expression types dictionary.
from chameleon import PageTemplate
PageTemplate.expression_types['upper'] = uppercase_expression
Alternatively, you could subclass the template class and set the attribute expression_types to a dictionary that includes your expression:
from chameleon import PageTemplateFile
from chameleon.tales import PythonExpr
class MyPageTemplateFile(PageTemplateFile):
expression_types = { 'python': PythonExpr, 'upper': uppercase_expression }
You can now uppercase strings natively in your templates:
It’s probably best to stick with a Python expression:
Changes between 1.x and 2.x
This sections describes new features, improvements and changes from 1.x to 2.x.
New parser
This series features a new, custom-built parser, implemented in pure Python. It parses both HTML and XML inputs (the previous parser relied on the expat system library and was more strict about its input).
The main benefit of the new parser is that the compiler is now able to point to the source location of parse- and compilation errors much more accurately. This should be a great aid in debugging these errors.
Compatible output
The 2.x engine matches the output of the reference implementation more closely (usually exactly). There are less differences altogether; for instance, the method of escaping TALES expression (usually a semicolon) has been changed to match that of the reference implementation.
New language features
This series also introduces a number of new language features:
Support for the tal:on-error from the reference specification has been added.
Two new attributes tal:switch and tal:case have been added to make element conditions more flexible.
Code improvements
The template classes have been refactored and simplified allowing better reuse of code and more intuitive APIs on the lower levels.
Expression engine
The expression engine has been redesigned to make it easier to understand and extend. The new engine is based on the astmodule (available since Python 2.6; backports included for Python 2.5). This means that expression compilers now need to return a valid list of AST statements that include an assignment to the target node.
Compiler
The new compiler has been optimized for complex templates. As a result, in the benchmark suite included with the package, this compiler scores about half of the 1.x series. For most real world applications, the engine should still perform as well as the 1.x series.
API reference
This section describes the documented API of the library.
Template classes
Use the PageTemplate* template classes to define a template from a string or file input:
class chameleon.PageTemplate(body, **config)
Constructor for the page template language.
Takes a string input as the only positional argument:
template = PageTemplate("
Hello, ${name}.
")
Configuration (keyword arguments):
default_expression
Set the default expression type. The default setting is python.
encoding
The default text substitution value is a unicode string on Python 2 or simply string on Python 3.
Pass an encoding to allow encoded byte string input (e.g. UTF-8).
literal_false
Attributes are not dropped for a value of False. Instead, the value is coerced to a string.
This setting exists to provide compatibility with the reference implementation.
boolean_attributes
Attributes included in this set are treated as booleans: if a true value is provided, the attribute value is the attribute name, e.g.:
boolean_attributes = {"selected"}
If we insert an attribute with the name “selected” and provide a true value, the attribute will be rendered:
selected="selected"
If a false attribute is provided (including the empty string), the attribute is dropped.
The special return value default drops or inserts the attribute based on the value element attribute value.
translate
Use this option to set a translation function.
Example:
def translate(msgid, domain=None, mapping=None, default=None):
...
return translation
Note that if target_language is provided at render time, the translation function must support this argument.
implicit_i18n_translate
Enables implicit translation for text appearing inside elements. Default setting is False.
While implicit translation does work for text that includes expression interpolation, each expression must be simply a variable name (e.g. ${foo}); otherwise, the text will not be marked for translation.
implicit_i18n_attributes
Any attribute contained in this set will be marked for implicit translation. Each entry must be a lowercase string.
Example:
implicit_i18n_attributes = set(['alt', 'title'])
strict
Enabled by default. If disabled, expressions are only required to be valid at evaluation time.
This setting exists to provide compatibility with the reference implementation which compiles expressions at evaluation time.
trim_attribute_space
If set, additional attribute whitespace will be stripped.
Output is unicode on Python 2 and string on Python 3.
Note: The remaining classes take the same general configuration arguments.
render(encoding=None, translate=None, target_language=None, **vars)
Render template to string.
The encoding and translate arguments are documented in the template class constructor. If passed to this method, they are used instead of the class defaults.
Additional arguments:
target_language
This argument will be partially applied to the translation function.
An alternative is thus to simply provide a custom translation function which includes this information or relies on a different mechanism.
class chameleon.PageTemplateFile(filename, **config)
File-based constructor.
Takes a string input as the only positional argument:
template = PageTemplateFile(absolute_path)
Note that the file-based template class comes with the expression type load which loads templates relative to the provided filename.
Below are listed the configuration arguments specific to file-based templates; see the string-based template class for general options and documentation:
Configuration (keyword arguments):
loader_class
The provided class will be used to create the template loader object. The default implementation supports relative and absolute path specs.
The class must accept keyword arguments search_path (sequence of paths to search for relative a path spec) and default_extension (if provided, this should be added to any path spec).
prepend_relative_search_path
Inserts the path relative to the provided template file path into the template search path.
The default setting is True.
search_path
If provided, this is used as the search path for the load: expression. It must be a string or an iterable yielding a sequence of strings.
class chameleon.PageTextTemplate(body, **config)
Text-based template class.
Takes a non-XML input:
template = PageTextTemplate("Hello, ${name}.")
This is similar to the standard library class string.Template, but uses the expression engine to substitute variables.
class chameleon.PageTextTemplateFile(filename, search_path=None, loader_class=,**config)
File-based constructor.
Template loader
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, default_extension=None, **config)
Load templates from search_path (must be a string or a list of strings):
templates = PageTemplateLoader(path)
example = templates['example.pt']
If default_extension is provided, this will be added to inputs that do not already have an extension:
templates = PageTemplateLoader(path, ".pt")
example = templates['example']
Any additional keyword arguments will be passed to the template constructor:
templates = PageTemplateLoader(path, debug=True, encoding="utf-8")
PageTemplateLoader.load(filename, format=None)
Load and return a template file.
The format parameter determines will parse the file. Valid options are xml and text.
Expression engine
For advanced integration, the compiler module provides support for dynamic expression evaluation:
class chameleon.compiler.ExpressionEvaluator(engine, builtins)
Evaluates dynamic expression.
This is not particularly efficient, but supported for legacy applications.
>>> from chameleon import tales
>>> parser = tales.ExpressionParser({'python': tales.PythonExpr}, 'python')
>>> engine = functools.partial(ExpressionEngine, parser)
>>> evaluate = ExpressionEvaluator(engine, { 'foo': 'bar', })
The evaluation function is passed the local and remote context, the expression type and finally the expression.
>>> evaluate({'boo': 'baz'}, {}, 'python', 'foo + boo')
'barbaz'
The cache is now primed:
>>> evaluate({'boo': 'baz'}, {}, 'python', 'foo + boo')
'barbaz'
Note that the call method supports currying of the expression argument:
>>> python = evaluate({'boo': 'baz'}, {}, 'python')
>>> python('foo + boo')
'barbaz'
Language Reference
The language reference is structured such that it can be read as a general introduction to the page templates language.
It’s split into parts that correspond to each of the main language features.
Syntax
You can safely skip this section if you’re familiar with how template languages work or just want to learn by example.
An attribute language is a programming language designed to render documents written in XML or HTML markup. The input must be a well-formed document. The output from the template is usually XML-like but isn’t required to be well-formed.
The statements of the language are document tags with special attributes, and look like this:
...
In the above example, the attribute namespace-prefix:command="argument" is the statement, and the entire paragraph tag is the statement’s element. The statement’s element is the portion of the document on which this statement operates.
The namespace prefixes are typically declared once, at the top of a template (note that prefix declarations for the template language namespaces are omitted from the template output):
...
Thankfully, sane namespace prefix defaults are in place to let us skip most of the boilerplate:
...
Note how tal is used without an explicit namespace declaration. Chameleon sets up defaults for metal and i18n as well.
Note
Default prefixes are a special feature of Chameleon.
Basics (TAL)
The template attribute language is used to create dynamic XML-like content. It allows elements of a document to be replaced, repeated, or omitted.
Statements
These are the available statements:
Statement
Description
tal:define
Define variables.
tal:switch
Defines a switch condition
tal:condition
Include element only if expression is true.
tal:repeat
Repeat an element.
tal:case
Includes element only if expression is equal to parent switch.
tal:content
Substitute the content of an element.
tal:replace
Replace the element with dynamic content.
tal:omit-tag
Omit the element tags, leaving only the inner content.
tal:attributes
Dynamically change or insert element attributes.
tal:on-error
Substitute the content of an element if processing fails.
When there is only one TAL statement per element, the order in which they are executed is simple. Starting with the root element, each element’s statements are executed, then each of its child elements is visited, in order, to do the same:
These are your items:
Any combination of statements may appear on the same element, except that the tal:content and tal:replace statements may not be used on the same element.
Note
The tal:case and tal:switch statements are available in Chameleon only.
TAL does not use use the order in which statements are written in the tag to determine the order in which they are executed. When an element has multiple statements, they are executed in the order printed in the table above.
There is a reasoning behind this ordering. Because users often want to set up variables for use in other statements contained within this element or subelements, tal:define is executed first. Then any switch statement. tal:condition follows, then tal:repeat, then tal:case. We are now rendering an element; first tal:content or tal:replace. Finally, before tal:attributes, we have tal:omit-tag (which is implied with tal:replace).
Note
TALES is used as the expression language for the “stuff in the quotes”. The default syntax is simply Python, but other inputs are possible — see the section on expressions.
tal:attributes
Updates or inserts element attributes.
tal:attributes="href request.url"
Syntax
tal:attributes syntax:
argument ::= attribute_statement [';' attribute_statement]*
attribute_statement ::= attribute_name expression
attribute_name ::= [namespace-prefix ':'] Name
namespace-prefix ::= Name
Description
The tal:attributes statement replaces the value of an attribute (or creates an attribute) with a dynamic value. The value of each expression is converted to a string, if necessary.
Note
You can qualify an attribute name with a namespace prefix, for example html:table, if you are generating an XML document with multiple namespaces.
If an attribute expression evaluates to None, the attribute is deleted from the statement element (or simply not inserted).
If the expression evaluates to the symbol default (a symbol which is always available when evaluating attributes), its value is defined as the default static attribute value. If there is no such default value, a return value of default will drop the attribute.
If you use tal:attributes on an element with an active tal:replace command, the tal:attributes statement is ignored.
If you use tal:attributes on an element with a tal:repeat statement, the replacement is made on each repetition of the element, and the replacement expression is evaluated fresh for each repetition.
Note
If you want to include a semicolon (”;”) in an expression, it must be escaped by doubling it (”;;”) [1].
Examples
Replacing a link:
...
Replacing two attributes:
A checkbox input:
tal:condition
Conditionally includes or omits an element:
...
Syntax
tal:condition syntax:
argument ::= expression
Description
The tal:condition statement includes the statement element in the template only if the condition is met, and omits it otherwise. If its expression evaluates to a true value, then normal processing of the element continues, otherwise the statement element is immediately removed from the template. For these purposes, the value nothing is false, and default has the same effect as returning a true value.
Note
Like Python itself, ZPT considers None, zero, empty strings, empty sequences, empty dictionaries, and instances which return a nonzero value from __len__ or __nonzero__ false; all other values are true, including default.
Examples
Test a variable before inserting it:
Testing for odd/even in a repeat-loop:
Even
Odd
tal:content
Replaces the content of an element.
Syntax
tal:content syntax:
argument ::= (['text'] | 'structure') expression
Description
Rather than replacing an entire element, you can insert text or structure in place of its children with the tal:contentstatement. The statement argument is exactly like that of tal:replace, and is interpreted in the same fashion. If the expression evaluates to nothing, the statement element is left childless. If the expression evaluates to default, then the element’s contents are evaluated.
The default replacement behavior is text, which replaces angle-brackets and ampersands with their HTML entity equivalents. The structure keyword passes the replacement text through unchanged, allowing HTML/XML markup to be inserted. This can break your page if the text contains unanticipated markup (eg. text submitted via a web form), which is the reason that it is not the default.
Note
The structure keyword exists to provide backwards compatibility. In Chameleon, the structure: expression type provides the same functionality (also for inline expressions).
Examples
Inserting the user name:
Fred Farkas
Inserting HTML/XML:
Marked up content goes here.
tal:define
Defines local variables.
Syntax
tal:define syntax:
argument ::= define_scope [';' define_scope]*
define_scope ::= (['local'] | 'global')
define_var define_var ::= variable_name
expression variable_name ::= Name
Description
The tal:define statement defines variables. When you define a local variable in a statement element, you can use that variable in that element and the elements it contains. If you redefine a variable in a contained element, the new definition hides the outer element’s definition within the inner element.
Note that valid variable names are any Python identifier