wheezy.template¶
Introduction¶
wheezy.template is a python package written in pure Python code. It is a lightweight template library. The design goals achieved with its development:
- Compact, Expressive, Clean: Minimizes the number of keystrokes required to build a template. Enables fast and well read coding. You do not need to explicitly denote statement blocks within HTML (unlike other template systems), the parser is smart enough to understand your code. This enables a compact and expressive syntax which is really clean and just pleasure to type.
- Intuitive, No time to Learn: Basic Python programming skills plus HTML markup. You are productive right from the start. Use the full power of Python with minimal markup required to denote python statements.
- Do Not Repeat Yourself: Master layout templates for inheritance; include and import directives for maximum reuse.
- Blazingly Fast: The most effective python code offers the maximum rendering performance; ultimate speed and context preprocessor features.
Simple template:
@require(user, items)
Welcome, @user.name!
@if items:
@for i in items:
@i.name: $i.price!s.
@end
@else:
No items found.
@end
It is optimized for performance, well tested and documented.
Resources:
- source code, examples and issues tracker are available on github
- documentation
Contents¶
Getting Started¶
Install¶
wheezy.template requires python version 3.6+. It is operating system independent. You can install it from the pypi site:
$ pip install wheezy.template
Examples¶
Before we proceed let’s setup a virtualenv environment, activate it and install:
$ pip install wheezy.template
Big Table¶
The big table demo compares wheezy.template with other template engines in terms of how fast a table with 10 columns x 1000 rows can be generated:
@require(table)
<table>
@for row in table:
<tr>
@for key, value in row.items():
<td>@key!h</td><td>@value!s</td>
@end
</tr>
@end
</table>
Install packages used in benchmark test:
pip install install -O2 jinja2 mako tenjin \
tornado wheezy.html wheezy.template
Download bigtable.py source code and run it (Intel Core 2 Quad CPU Q6600 @ 2.40GHz × 4; Kernel Linux 3.2.0-2-686-pae; Debian Testing; Python 2.7.3):
$ python bigtable.py
jinja2 40.22ms 24.86rps
list_append 19.85ms 50.39rps
list_extend 18.71ms 53.46rps
mako 36.19ms 27.63rps
tenjin 28.97ms 34.52rps
tornado 55.91ms 17.89rps
wheezy_template 19.99ms 50.02rps

Real World¶
There is real world example available in the wheezy.web package. It can be found in the demo.template application. The application has a few screens: home, sign up, sign in, etc. The content implementation is available for jinja2, mako, tenjin, wheezy.template and for wheezy.template with preprocessor.
The throughtput was captured using apache benchmark (concurrecy level 500, number of request 100K):
/ /en/signin /en/signup
jinja2 9339 6422 6196
mako 9681 6720 6567
tenjin 11138 7233 7203
wheezy.template 15023 8898 8900
wheezy.template 21144 11027 11087
(preprocessor)
Environment specification:
* Client: Intel Core 2 Quad CPU Q6600 @ 2.40GHz × 4, Kernel 3.2.0-3-686-pae
* Server: Intel Xeon CPU X3430 @ 2.40GHz x 4, Kernel 3.2.0-3-amd64, uwsgi 1.2.4
* Debian Testing, Python 2.7.3, LAN 1 Gb.

User Guide¶
wheezy.template uses Engine
to store
configuration information and load templates. Here is a typical example that
loads templates from the file system:
from wheezy.template.engine import Engine
from wheezy.template.ext.core import CoreExtension
from wheezy.template.loader import FileLoader
searchpath = ['content/templates-wheezy']
engine = Engine(
loader=FileLoader(searchpath),
extensions=[CoreExtension()]
)
template = engine.get_template('template.html')
You can render content from console:
wheezy.template demos/helloworld/hello.txt demos/helloworld/hello.json
another example:
wheezy.template -s demos/master index.html
Loaders¶
Loader is used to provide template content to Engine
by some name requested by an application. What exactly consitutes a name and how each loader
interprets it, is up to the loader implementation.
wheezy.template comes with the following loaders:
FileLoader
- loads templates from file system (directories
- search path of directories to scan for template,encoding
- template content encoding).DictLoader
- loads templates from python dictionary (templates
- a dict where key corresponds to template name and value to template content).ChainLoader
- loads templates fromloaders
in turn until one succeeds.
Core Extension¶
The CoreExtension
includes support for
basic python statements, variables processing and markup.
Context¶
In order to use variables passed to a template you use require
statement and
list names you need to pick from the context. These names becomes
visible from the require
statement to the
end of the template scope (imagine a single template is a python function).
Context access syntax:
@require(var1, var2, ...)
Variables¶
The application passes variables to the template renderer via context. Variable access syntax:
@variable_name
@{variable_name}
@{ variable_name }
Example:
from wheezy.template.engine import Engine
from wheezy.template.ext.core import CoreExtension
from wheezy.template.loader import DictLoader
template = """\
@require(name)
Hello, @name"""
engine = Engine(
loader=DictLoader({'x': template}),
extensions=[CoreExtension()]
)
template = engine.get_template('x')
print(template.render({'name': 'John'}))
Variable syntax is not limited to a single name access. You are able to use full power of python to access items in a dict, attributes, function calls, etc.
Filters¶
Variables can be formatted by filters. Filters are separated from the variable
by the !
symbol. Filter syntax:
@variable_name!filter1!filter2
@{variable_name!!filter1!filter2}
@{ variable_name !! filter1!filter2 }
The filters are applied from left to right, so the above syntax is equvivalent to the following call:
@filter1(filter2(variable_name))
Example:
@user.age!s
@{user.age!!s}
@{ user.age !!s }
Assuming the age property of user is integer we apply a string filter.
You are able to use custom filters, here is an example on how to use html escape filter:
try:
from wheezy.html.utils import escape_html as escape
except ImportError:
import cgi
escape = cgi.escape
# ... initialize Engine.
engine.global_vars.update({'e': escape})
First we try import an optimized version of html escape from wheezy.html
package and if it is not available fallback to the one from the cgi
package. Next we
update the engine’s global variables with the escape function, which is accessible as the e
filter name in template:
@user.name!e
@{ user.name !! e }
You are able use engine global_vars
dictionary in order to simplify your
template access to some commonly used variables.
R-value expressions¶
You can use single line r-value expresions that evaluates to a rendered value:
@{ accepted and 'YES' or 'NO' }
@{ (age > 20 and age < 120) and 'OK' or '?' }
@{ n > 0 and 1 or -1 !! s }
Line Statements¶
The following python line statements are supported: if, else, elif, for. Here is simple example:
@require(items)
@if items:
@for i in items:
@i.name: $i.price!s.
@end
@else:
No items found.
@end
Line Join¶
In case you need continue a long line without breaking it with new line during
rendering use line join (\
):
@if menu_name == active:
<li class='active'> \
@else:
<li> \
@endif
Inheritance¶
Template inheritance allows you to build a master template that contains common layout of your site and defines areas that a child templates can override.
Master Template¶
Master template is used to provide common layout of your site. Let’s define
a master template (name shared/master.html
):
<html>
<head>
<title>
@def title():
@end
@title() - My Site</title>
</head>
<body>
<div id="content">
@def content():
@end
@content()
</div>
<div id="footer">
@def footer():
© Copyright 2012 by Me.
@end
footer()
</div>
</body>
</html>
In this example, the @def tags define python functions (substitution areas). These functions are inserted into a specific places (right after definition). These places become place holders for child templates. The @footer place holder defines default content while @title and @content are just empty.
Child Template¶
Child templates are used to extend master templates via the defined place holders:
@extends("shared/master.html")
@def title():
Welcome
@end
@def content():
<h1>Home</h1>
<p>
Welcome to My Site!
</p>
@end
In this example, the @title and @content place holders are overriden by the child template.
Note, @import and @require tokens are allowed at @extends token level.
Include¶
The include is useful to insert a template content just in place of the statement:
@include("shared/snippet/script.html")
Import¶
The import is used to reuse some code stored in other files. So you are able import all functions defined by that template:
@import "shared/forms.html" as forms
@forms.textbox('username')
or just certain name:
@from "shared/forms.html" import textbox
@textbox(name='username')
Once imported you use these names as variables in a template.
Code Extension¶
The CodeExtension
includes support for
embedded python code. Syntax:
@(
# any python code
)
Preprocessor¶
The Preprocessor
processes templates
with syntax for the preprocessor engine and varying runtime templates (with runtime
engine factory) by some key function that is context driven. Here is an
example:
from wheezy.html.utils import html_escape
from wheezy.template.engine import Engine
from wheezy.template.ext.core import CoreExtension
from wheezy.template.ext.determined import DeterminedExtension
from wheezy.template.loader import FileLoader
from wheezy.template.preprocessor import Preprocessor
def runtime_engine_factory(loader):
engine = Engine(
loader=loader,
extensions=[
CoreExtension(),
])
engine.global_vars.update({
'h': html_escape,
})
return engine
searchpath = ['content/templates']
engine = Engine(
loader=FileLoader(searchpath),
extensions=[
CoreExtension('#', line_join=None),
DeterminedExtension(['path_for', '_']),
])
engine.global_vars.update({
})
engine = Preprocessor(runtime_engine_factory, engine,
key_factory=lambda ctx: ctx['locale'])
In this example, the Preprocessor
is
defined to use engine with the start token
defined as ‘#’. Any directives starting with #
are processed once only
by the preprocessor engine. The key_factory
is dependent on runtime context
and particularly on ‘locale’. This way runtime engine factory is varied by
locale so locale dependent functions (_
and path_for
) are processed only
once by the preprocessor. See complete example in wheezy.web demo.template
applicaiton.
Modules¶
wheezy.template¶
-
class
wheezy.template.
Engine
(loader: wheezy.template.typing.Loader, extensions: List[Any], template_class: Optional[Callable[[str, Callable[[Mapping[str, Any], Mapping[str, Any], Mapping[str, Any]], str]], wheezy.template.typing.SupportsRender]] = None)[source]¶ The core component of template engine.
-
class
wheezy.template.
CodeExtension
(token_start: str = '@')[source]¶ Includes support for embedded python code.
-
class
wheezy.template.
CoreExtension
(token_start: str = '@', line_join: str = '\')[source]¶ Includes basic statements, variables processing and markup.
-
class
wheezy.template.
DictLoader
(templates: Mapping[str, str])[source]¶ Loads templates from python dictionary.
templates
- a dict where key corresponds to template name and value to template content.
-
class
wheezy.template.
FileLoader
(directories: List[str], encoding: str = 'UTF-8')[source]¶ Loads templates from file system.
directories
- search path of directories to scan for template.encoding
- decode template content per encoding.
-
class
wheezy.template.
PreprocessLoader
(engine: wheezy.template.engine.Engine, ctx: Optional[Mapping[str, Any]] = None)[source]¶ Performs preprocessing of loaded template.
-
class
wheezy.template.
Preprocessor
(runtime_engine_factory: Callable[[wheezy.template.typing.Loader], wheezy.template.engine.Engine], engine: wheezy.template.engine.Engine, key_factory: Callable[[Mapping[str, Any]], str])[source]¶ Preprocess templates with
engine
and vary runtime templates bykey_factory
function usingruntime_engine_factory
.
wheezy.template.builder¶
wheezy.template.compiler¶
wheezy.template.console¶
wheezy.template.engine¶
-
class
wheezy.template.engine.
Engine
(loader: wheezy.template.typing.Loader, extensions: List[Any], template_class: Optional[Callable[[str, Callable[[Mapping[str, Any], Mapping[str, Any], Mapping[str, Any]], str]], wheezy.template.typing.SupportsRender]] = None)[source]¶ The core component of template engine.
-
class
wheezy.template.engine.
Template
(name: str, render_template: Callable[[Mapping[str, Any], Mapping[str, Any], Mapping[str, Any]], str])[source]¶ Simple template class.
-
wheezy.template.engine.
complement_syntax_error
(err: SyntaxError, template_source: str, source: str) → SyntaxError[source]¶ Complements SyntaxError with template and source snippets, like one below:
File "shared/snippet/widget.html", line 4 if : template snippet: 02 <h1> 03 @msg!h 04 @if : 05 sd 06 @end generated snippet: 02 _b = []; w = _b.append; w('<h1>\n ') 03 w(h(msg)); w('\n') 04 if : 05 w(' sd\n') 06 if : ^ SyntaxError: invalid syntax
wheezy.template.lexer¶
-
class
wheezy.template.lexer.
Lexer
(lexer_rules: List[Tuple[Pattern[AnyStr], Callable[[Match[AnyStr]], Tuple[int, str, str]]]], preprocessors: Optional[List[Callable[[str], str]]] = None, postprocessors: Optional[List[Callable[[List[Tuple[int, str, str]]], str]]] = None, **ignore)[source]¶ Tokenizes input source per rules supplied.
wheezy.template.loader¶
-
class
wheezy.template.loader.
ChainLoader
(loaders: List[wheezy.template.typing.Loader])[source]¶ Loads templates from
loaders
until first succeed.
-
class
wheezy.template.loader.
DictLoader
(templates: Mapping[str, str])[source]¶ Loads templates from python dictionary.
templates
- a dict where key corresponds to template name and value to template content.
-
class
wheezy.template.loader.
FileLoader
(directories: List[str], encoding: str = 'UTF-8')[source]¶ Loads templates from file system.
directories
- search path of directories to scan for template.encoding
- decode template content per encoding.
-
class
wheezy.template.loader.
PreprocessLoader
(engine: wheezy.template.engine.Engine, ctx: Optional[Mapping[str, Any]] = None)[source]¶ Performs preprocessing of loaded template.
-
wheezy.template.loader.
autoreload
(engine: wheezy.template.engine.Engine, enabled: bool = True) → wheezy.template.engine.Engine[source]¶ Auto reload template if changes are detected in file.
Limitation: master (inherited), imported and preprocessed templates.
It is recommended to use application server that supports file reload instead.
wheezy.template.parser¶
-
class
wheezy.template.parser.
Parser
(parser_rules: Dict[str, Callable[[str], Union[str, List[str]]]], parser_configs: Optional[List[Callable[[wheezy.template.typing.ParserConfig], None]]] = None, **ignore)[source]¶ continue_tokens
are used to insertend
node right before them to simulate a block end. Such nodes have token valueNone
.out_tokens
are combined together into a single node.
wheezy.template.preprocessor¶
-
class
wheezy.template.preprocessor.
Preprocessor
(runtime_engine_factory: Callable[[wheezy.template.typing.Loader], wheezy.template.engine.Engine], engine: wheezy.template.engine.Engine, key_factory: Callable[[Mapping[str, Any]], str])[source]¶ Preprocess templates with
engine
and vary runtime templates bykey_factory
function usingruntime_engine_factory
.
wheezy.template.utils¶
wheezy.template.ext.code¶
wheezy.template.ext.core¶
-
class
wheezy.template.ext.core.
CoreExtension
(token_start: str = '@', line_join: str = '\')[source]¶ Includes basic statements, variables processing and markup.
-
wheezy.template.ext.core.
rvalue_token
(m: Match[str]) → Tuple[int, str, str][source]¶ Produces variable token as r-value expression.
wheezy.template.ext.determined¶
-
class
wheezy.template.ext.determined.
DeterminedExtension
(known_calls: List[str], runtime_token_start: str = '@', token_start: str = '#')[source]¶ Tranlates function calls between template engines.
Strictly determined known calls are converted to preprocessor calls, e.g.:
@_('Name:') @path_for('default') @path_for('static', path='/static/css/site.css')
Those that are not strictly determined are ignored and processed by runtime engine.
-
wheezy.template.ext.determined.
determined
(expression: str) → bool[source]¶ Checks if expresion is strictly determined.
>>> determined("'default'") True >>> determined('name') False >>> determined("'default', id=id") False >>> determined("'default', lang=100") True >>> determined('') True
-
wheezy.template.ext.determined.
parse_args
(text: str) → List[str][source]¶ Parses argument type of parameters.
>>> parse_args('') [] >>> parse_args('10, "x"') ['10', '"x"'] >>> parse_args("'x', 100") ["'x'", '100'] >>> parse_args('"default"') ['"default"']
-
wheezy.template.ext.determined.
parse_kwargs
(text: str) → Mapping[str, str][source]¶ Parses key-value type of parameters.
>>> parse_kwargs('id=item.id') {'id': 'item.id'} >>> sorted(parse_kwargs('lang="en", id=12').items()) [('id', '12'), ('lang', '"en"')]
-
wheezy.template.ext.determined.
parse_params
(text: str) → Tuple[List[str], Mapping[str, str]][source]¶ Parses function parameters.
>>> parse_params('') ([], {}) >>> parse_params('id=item.id') ([], {'id': 'item.id'}) >>> parse_params('"default"') (['"default"'], {}) >>> parse_params('"default", lang="en"') (['"default"'], {'lang': '"en"'})