Kajiki: Fast Templates for Python

Kajiki provides fast well-formed XML templates

https://travis-ci.com/jackrosenthal/kajiki.svg?branch=master

Because Kajiki’s input is XML, it can ensure that your HTML/XML output is well-formed. The Genshi-like syntax, based on XML attributes or tags, is simply beautiful and easily understood (or ignored) by web designers. But instead of the slow performance of Genshi, Kajiki compiles templates to Python code that renders with blazing-fast speed, so Kajiki can compete with the speed of Jinja, Mako, Chameleon and others. Also, one of Genshi’s misfeatures – py:match – is replaced with blocks which work like Jinja’s blocks.

By combining the best ideas out there – XML input, Genshi’s syntax and features, Jinja’s template inheritance and final compilation to Python –, Kajiki is ready to become the most widely used templating engine for web development in Python. And more features are coming soon; stay tuned!

Example

>>> import kajiki
>>> Template = kajiki.XMLTemplate('''<html>
...     <head><title>$title</title></head>
...     <body>
...         <h1>$title</h1>
...         <ul>
...             <li py:for="x in range(repetitions)">$title</li>
...         </ul>
...     </body>
... </html>''')
>>> print(Template(dict(title='Kajiki is teh awesome!', repetitions=3)).render())
<html>
    <head><title>Kajiki is teh awesome!</title></head>
    <body>
        <h1>Kajiki is teh awesome!</h1>
        <ul>
            <li>Kajiki is teh awesome!</li><li>Kajiki is teh awesome!</li><li>Kajiki is teh awesome!</li>
        </ul>
    </body>
</html>

Documentation contents

Kajiki Templating Basics

Kajiki provides two templating engines, one which is useful for generating markup (HTML or XML most likely), and one of which is useful for generating plain text. This document describes the aspects of the two engines that are similar and the basic API for using them.

Synopsis

A Kajiki xml template is a well-formed XML document that may include one or more custom tags and attributes prefixed by the namespace ‘py:’. XML templates also may contain python expressions that will be evaluated at template expansion time as well as processing instructions that may contain Python code. XML templates should be used when generating XML or HTML, as they provide awareness of well-formedness rules and proper escaping.

The following is an example of a simple Kajki markup template:

<?python
  title = "A Kajiki Template"
  fruits = ["apple", "orange", "kiwi"]
?>
<html>
  <head>
    <title py:content="title">This is replaced.</title>
  </head>
  <body>
    <p>These are some of my favorite fruits:</p>
    <ul>
      <li py:for="fruit in fruits">
        I like ${fruit}s
      </li>
    </ul>
  </body>
</html>

This template would generate output similar to this (in X(H)ML mode):

<html>
  <head>
    <title>A Kajiki Template</title>
  </head>
  <body>
    <p>These are some of my favorite fruits:</p>
    <ul>
      <li>I like apples</li>
      <li>I like oranges</li>
      <li>I like kiwis</li>
    </ul>
  </body>
</html>

or this (in HTML mode):

<html>
  <head>
    <title>A Kajiki Template</title>
  <body>
    <p>These are some of my favorite fruits:
    <ul>
      <li>I like apples
      <li>I like oranges
      <li>I like kiwis
    </ul>
Text templates, on the other hand, are plain text documents that can contain
embedded Python directives and expressions. Text templates should be used when generating non-markup text format such as email. Here is a simple text template:
Dear $name,
These are some of my favorite fruits:
%for fruit in fruts
  * $fruit
%end

This would generate something similar to the following:

Dear Rick,
These are some of my favorite fruits:
  * Apples
  * Bananas
  * Pears

Python API

In order to actually use Kajiki in generating text (either via the XML or the text-based languages), the pattern is as follows:

  1. Obtain an XMLTemplate or TextTemplate subclass containing the template source. This can either be done directly or via a template loader.
  2. Instantiate the template with one constructor argument, a dict containing all the values that should be made available as global variables to the template.
  3. Render the template instance using its render() method (for rendering to a single string) or iterating through it (for “stream”) rendering.

For instance:

>>> Template = kajiki.XMLTemplate('<h1>Hello, $name!</h1>')
>>> t = Template(dict(name='world'))
>>> t.render()
'<h1>Hello, world!</h1>'

Using text templates is similar:

>>> Template = kajiki.TextTemplate('Hello, $name!')
>>> t = Template(dict(name='world'))
>>> t.render()
'Hello, world!'

You can also use a template loader to indirectly generate the template classes. Using a template loader gives two main advantages over directly instantiating templates:

  • Compiled templates are cached and only re-parsed when the template changes.
  • Several template tags such as extends, import, and include that require knowlege of other templates become enabled.

Using a template loader would look similar to the following:

loader = PackageLoader()
Template = loader.import_('my.package.text.template')
t = Template(dict(title='Hello, world!')
print t.render()

Template Expressions and Code Blocks

Python expressions can be used in “plain text” areas of templates, including, in XML templates, tag attributes. They are also used in some directive arguments. Whenever a Python expression is used in a “plain text” area, it must be prefixed by a dollar sign ($) and possibly enclosed in curly braces. If the expression starts with a letter and contains only letters, digits, dots, and underscores, then the curly braces may be omitted. In all other cases, they are required. For example:

>>> Template = kajiki.XMLTemplate('<em>${items[0].capitalize()}</em>')
>>> Template(dict(items=['first', 'second'])).render()
'<em>First</em>'
>>> import sys
>>> Template = kajiki.TextTemplate('Maxint is $sys.maxsize')
>>> Template(dict(sys=sys)).render()
'Maxint is 9223372036854775807'

Escaping

If you need a literal dollar sign where Kajiki would normally detect an expression, you can simply double the dollar sign:

>>> Template = kajiki.XMLTemplate('<em>$foo</em>')
>>> Template().render()
Traceback (most recent call last):
   ...
NameError: global name 'foo' is not defined
>>> Template = kajiki.XMLTemplate('<em>$$foo</em>')
>>> Template().render()
'<em>$foo</em>'

Code Blocks

Templates also support full Python syntax, using the <?py ?> processing instruction:

<div>
    <?py import sys>
    Maxint is $sys.maxint
</div>

This will produce the following output:

<div>
    Maxint is 9223372036854775807
</div>

In text blocks, the %py (or {%py%} directive accomplishes the same goal:

%py import sys
Maxint is $sys.maxint

This will produce:

Maxint is 9223372036854775807

In both of the above cases, the Python code runs in the ‘local scope’ of the template’s main rendering function, so any variables defined there will not be accessible in functions or blocks defined elsewhere in the template. To force the python block to run at ‘module-level’ in XML templates, simply prefix the first line of the Python with a percent (%) sign:

>>> Template = kajiki.XMLTemplate('''<div
... ><?py %import os
... ?><py:def function="test()"
... >${os.path.join('a', 'b', 'c')}</py:def
... >${test()}</div>''')
>>> Template().render()
'<div>a/b/c</div>'

In text templates, replace the %py directive with %py%:

>>> Template = kajiki.TextTemplate('''%py% import os
... %def test()
... ${os.path.join('a','b','c')}\\
... %end
... ${test()}''')
>>> Template().render()
'a/b/c'

Built-in Functions and Variables

All templates have access to the following functions and variables:

literal(x)

Wrap some user-generated text so that it doesn’t get escaped along with everything else.

local

The current template being defined

self

The current template being defined, or, if used in the context of a parent template that is being extended, the final (“child-most”) template in the inheritance hierarchy.

parent

The parent template (via py:extends) of the template being defined

child

The child template (via py:extends) of the template being defined

Template Directives

Template directives provide control flow and inheritance functionality for templates. As their syntax depends on whether you’re using XML or text templates, please refer to Kajiki XML Templates or Kajiki Text Templates for more information.

Kajiki XML Templates

Kajiki provides a full-featured XML-based template engine that guarantees well-formed output when generating HTML and XML. This document describes that language. Templates are XML files that include template directives that control how the template is rendered and expressions that are substituted into the generated text at render time.

Please see Kajiki Templating Basics for general information on embedding Python code in templates.

Output Modes

Although Kajiki XML templates must be well-formed XML documents, Kajiki is capable of rendering HTML or XML. By default, Kajiki will inspect the doctype of the template to determine how to render:

>>> tpl_text = '''<!DOCTYPE html>
... <html>
...     <head><!-- Some stuff here --></head>
...     <body>
...         <form>
...             <input type="checkbox" checked="checked"/>
...             <select>
...                 <option selected="selected">One</option>
...                 <option>Two</option>
...                 <option>Three</option>
...             </select>
...         </form>
...     </body>
... </html>'''
>>> Template = kajiki.XMLTemplate(tpl_text)
>>> print(Template().render().strip())
<!DOCTYPE html><html>
    <head><!--  Some stuff here  -->
    <body>
        <form>
            <input checked type="checkbox">
            <select>
                <option selected>One
                <option>Two
                <option>Three
            </select>
        </form>
>>> # If we want to override the detected type, we can pass a 'mode' param
>>> Template = kajiki.XMLTemplate(tpl_text, mode='xml')
>>> print(Template().render().strip())
<!DOCTYPE html><html>
    <head><!--  Some stuff here  --></head>
    <body>
        <form>
            <input checked="checked" type="checkbox"/>
            <select>
                <option selected="selected">One</option>
                <option>Two</option>
                <option>Three</option>
            </select>
        </form>
    </body>
</html>
>>> # We can also omit the generated DOCTYPE by specifying the template
>>> # is a fragment
>>> Template = kajiki.XMLTemplate(tpl_text, mode='xml', is_fragment=True)
>>> print(Template().render().strip())
<html>
    <head><!--  Some stuff here  --></head>
    <body>
        <form>
            <input checked="checked" type="checkbox"/>
            <select>
                <option selected="selected">One</option>
                <option>Two</option>
                <option>Three</option>
            </select>
        </form>
    </body>
</html>

Note

In Kajiki, you can use normal XML comments, and the comments will exist in the generated markup. If you wish the comments to be removed before rendering the document, you can begin the comment with the syntax <!–! instead of <!–:

>>> Template = kajiki.XMLTemplate('''<div>
... <!-- This comment is preserved.
... --><!--! This comment is stripped. -->
... </div>''')
>>> print(Template().render())
<div>
<!--  This comment is preserved.
 -->
</div>

Basic Expressions

Let’s start with a hello world template:

>>> Template = kajiki.XMLTemplate('<div>Hello, $name!</div>')
>>> print(Template(dict(name='world')).render())
<div>Hello, world!</div>

By default, the $-syntax picks up any identifiers following it, as well as any periods. If you want something more explicit, use the extended expression form as follows:

>>> Template = kajiki.XMLTemplate('<div>Hello, 2+2 is ${2+2}</div>')
>>> print(Template().render())
<div>Hello, 2+2 is 4</div>

If you wish to include a literal $, simply double it:

>>> Template = kajiki.XMLTemplate('<div>The price is $$${price}</div>')
>>> print(Template(dict(price='5.00')).render())
<div>The price is $5.00</div>

You can also include expressions in template attributes:

>>> Template = kajiki.XMLTemplate('<div id="$foo">Bar</div>')
>>> print(Template(dict(foo='baz')).render())
<div id="baz">Bar</div>

Control Flow

Kajiki provides several directives that affect the rendering of a template. This section describes the various directives. Directives in text templates can either appear as special attributes on tags prefixed by py: or as standalone tags whose tagname is prefixed by py:.

py:if, py:else

Only render the enclosed content if the expression evaluates to a truthy value:

>>> Template = kajiki.XMLTemplate('<div><py:if test="foo">bar</py:if><py:else>baz</py:else></div>')
>>> print(Template(dict(foo=True)).render())
<div>bar</div>
>>> print(Template(dict(foo=False)).render())
<div>baz</div>
>>> Template = kajiki.XMLTemplate('<div><span py:if="foo">bar</span></div>')
>>> print(Template(dict(foo=True)).render())
<div><span>bar</span></div>
>>> print(Template(dict(foo=False)).render())
<div></div>

py:switch, py:case, py:else

Perform multiple tests to render one of several alternatives. The first matching case is rendered, and if no case matches, the else branch is rendered:

>>> Template = kajiki.XMLTemplate('''<div>
... $i is <py:switch test="i % 2">
... <py:case value="0">even</py:case>
... <py:else>odd</py:else>
... </py:switch></div>''')
>>> print(Template(dict(i=4)).render())
<div>
4 is even</div>
>>> print(Template(dict(i=3)).render())
<div>
3 is odd</div>

py:for

Repeatedly render the content for each item in an iterable:

>>> Template = kajiki.XMLTemplate('''<ul>
... <li py:for="x in range(sz)">$x</li>
... </ul>''')
>>> print(Template(dict(sz=3)).render())
<ul>
<li>0</li><li>1</li><li>2</li>
</ul>

py:def

Defines a function that can be used elsewhere in the template:

>>> Template = kajiki.XMLTemplate('''<div
... ><py:def function="evenness(n)"
... ><py:if test="n%2==0">even</py:if><py:else>odd</py:else></py:def
... ><ul>
... <li py:for="x in range(sz)">$x is ${evenness(x)}</li>
... </ul></div>''')
>>> print(Template(dict(sz=3)).render())
<div><ul>
<li>0 is even</li><li>1 is odd</li><li>2 is even</li>
</ul></div>

py:call

Call a function, passing a block of template code as a ‘lambda’ parameter. Note that this is a special case of calling when you wish to insert some templated text in the expansion of a function call. In normal circumstances, you would just use ${my_function(args)}.

>>> Template = kajiki.XMLTemplate('''<div
... ><py:def function="quote(caller, speaker)"
... ><ul>
...    <li py:for="i in range(sz)">Quoth $speaker, ${caller(i)}</li>
... </ul></py:def
... ><py:call args="n" function="quote(%caller, 'the raven')"
... >Nevermore $n</py:call></div>''')
>>> print(Template(dict(sz=3)).render())
<div><ul>
   <li>Quoth the raven, Nevermore 0</li><li>Quoth the raven, Nevermore 1</li><li>Quoth the raven, Nevermore 2</li>
</ul></div>

py:include

Includes the text of another template verbatim. The precise semantics of this tag depend on the TemplateLoader being used, as the TemplateLoader is used to parse the name of the template being included and render its contents into the current template. For instance, with the FileLoader, you might use the following:

<py:include href="path/to/base.txt"/>

whereas in the PackageLoader you would use

<py:include href="package1.package2.base"/>

py:import

With py:import, you can make the functions defined in another template available without expanding the full template in-place. Suppose that we saved the following template in a file lib.xml:

<py:def function="evenness(n)">
   <py:if test="n%2==0">even</py:if><py:else>odd</py:else>
</py:def>

Then (using the FileLoader) we could write a template using the evenness function as follows:

<div>
   <py:import href="lib.xml" alias="lib"/>
   <ul>
      <li py:for="i in range(sz)">$i is ${lib.evenness(i)}</li>
   </ul>
</div>
py:with

Using py:with, you can temporarily assign variables values for the extent of the block:

>>> Template = kajiki.XMLTemplate('''<div py:with="a='foo'">
... <div>$a</div>
... <div py:with="a=5">$a</div>
... <div>$a</div>
... </div>''')
>>> print(Template().render())
<div>
<div>foo</div>
<div>5</div>
<div>foo</div>
</div>

Content Generation

py:attrs

With the py:attrs custom attribute, you can include dynamic attributes in an xml/html tag by passing a either a Python dict or a list of pairs:

>>> Template = kajiki.XMLTemplate('<div py:attrs="attrs"/>')
>>> print(Template(dict(attrs={'id':'foo', 'class':'bar'})).render())
<div class="bar" id="foo"/>
>>> print(Template(dict(attrs=[('id', 'foo'), ('class', 'bar')])).render())
<div class="bar" id="foo"/>

Any attribute values that evaluate to None will not be emitted in the generated markup:

>>> Template = kajiki.XMLTemplate('<div py:attrs="attrs"/>')
>>> print(Template(dict(attrs={'id':'foo', 'class':None})).render())
<div id="foo"/>

py:strip

With py:strip, you can remove the tag to which the attribute is attached without removing the content of the tag:

>>> Template = kajiki.XMLTemplate('<div><div py:strip="True">Foo</div></div>')
>>> print(Template().render())
<div>Foo</div>

As a shorthand, if the value of the py:strip attribute is empty, that has the same effect as using a truth value (i.e. the element is stripped).

py:content

With py:content, you can remove the tag to which the attribute is attached without removing the content of the tag:

>>> Template = kajiki.XMLTemplate('<div py:content="content"/>')
>>> print(Template(dict(content="Foo")).render())
<div>Foo</div>

py:replace

With py:replace, you can replace the entire tag to which the document is attached and its children:

>>> Template = kajiki.XMLTemplate('<div py:replace="content"/>')
>>> print(Template(dict(content="Foo")).render())
Foo

Inheritance (py:extends, py:block)

Kajiki supports a concept of inheritance whereby child templates can extend parent templates, replacing their “methods” (functions) and “blocks” (to be defined below). For instance, consider the following template “parent.xml”:

<div>
   <py:def function="greet(name)"
      >Hello, $name!</py:def>
   <py:def function="sign(name)"
      >Sincerely,<br/>
      <em>$name</em></py:def>
   ${greet(to)}

   <p py:block="body">It was good seeing you last Friday.
   Thanks for the gift!</p>

   ${sign(from_)}
</div>

This would render to something similar to the following (assuming a context of dict(to=Mark, from_=Rick):

<div>
   Hello, Mark!

   <p>It was good seeing you last friday.
   Thanks for the gift!</p>

   Sincerely, <br/>
   Rick
</div>

Now we can extend “parent.xml” with “child.xml”:

<py:extends href="parent.xml">
   <py:def function="greet(name)"
   >Dear $name:</py:def>
   <py:block name="body">${parent_block()}
   <p>And don't forget you owe me money!</p>
   </py:block>
</py:extends>

Rendering this template would then give us:

<div>
   Dear, Mark:

   <p>It was good seeing you last friday.
   Thanks for the gift!</p>
   <p>And don't forget you owe me money!</p>

   Sincerely, <br/>
   Rick
</div>

Notice how in the child block, we have overridden both the block “body” and the function “greet.” When overriding a block, we always have access to the parent template’s block of the same name via the parent_block() function.

If you ever need to access the parent template itself (perhaps to call another function), kajiki provides access to a special variable in child templates parent. Likewise, if a template is being extended, the variable child is available. Kajiki also provides the special variables local (the template currently being defined) and self (the child-most template of an inheritance chain). The following example illustrates these variables in a 3-level inheritance hierarchy:

>>> parent = kajiki.XMLTemplate('''<div
... ><h1 py:def="header()">Header name=$name</h1
... ><h6 py:def="footer()">Footer</h6
... ><div py:def="body()">
... id() = ${id()}
... local.id() = ${local.id()}
... self.id() = ${self.id()}
... child.id() = ${child.id()}
... </div><span py:def="id()">parent</span>
... ${header()}
... ${body()}
... ${footer()}
... </div>''')
>>> mid = kajiki.XMLTemplate('''<py:extends href="parent.html"
... ><span py:def="id()">mid</span
... ></py:extends>''')
>>> child=kajiki.XMLTemplate('''<py:extends href="mid.html"
... ><span py:def="id()">child</span
... ><div py:def="body()">
... <h2>Child Body</h2>
... ${parent.body()}
... </div></py:extends>''')
>>> loader = kajiki.MockLoader({
... 'parent.html':parent,
... 'mid.html':mid,
... 'child.html':child})
>>> Template = loader.import_('child.html')
>>> print(Template(dict(name='Rick')).render())
<div>
<h1>Header name=Rick</h1>
<div>
<h2>Child Body</h2>
<div>
id() = <span>child</span>
local.id() = <span>parent</span>
self.id() = <span>child</span>
child.id() = <span>mid</span>
</div>
</div>
<h6>Footer</h6>
</div>

Built-in functions

The following functions are available by default in template code, in addition to the standard built-ins that are available to all Python code.

defined(name)

This function determines whether a variable of the specified name exists in the context data, and returns True if it does.

When would you use it? Well, suppose you tried the following template snippet:

<h3 py:if=’user’>$user.name</h3>

If you don’t pass, from your python code, a “user” variable to the template, the above code will fail with this exception: NameError: global name 'user' is not defined. This is undesired!

Following Genshi, Kajiki offers the defined() function to make that condition possible, so you can write this:

<h3 py:if=”defined(‘user’)”>$user.name</h3>

literal(text)

All good templating languages escape text by default to avoid certain attacks. But sometimes you have an HTML snippet that you wish to include in a page, and you know the HTML is safe.

The literal() function marks a given string as being safe for inclusion, meaning it will not be escaped in the serialization stage. Use this with care, as not escaping a user-provided string may allow malicious users to open your web site to cross-site scripting attacks. Example:

${literal(name_of_the_variable_containing_the_html)}

Kajiki is a reimplementation of most of Genshi and, since Genshi has a Markup() function for the same purpose, we provide Markup() as a synonym, too.

value_of(name, default=None)

This function returns the value of the variable with the specified name if such a variable is defined, and returns the value of the default parameter if no such variable is defined.

Genshi has this, too. Example:

<div py:if="value_of('explanation')">${explanation}</div>

In the above example, the div will only appear in the output if the explanation variable exists in the context and has a truish value. (Remember in Python, None and the empty string are not truish, they are evaluated as False.)

Tips on writing your templates

Kajiki takes XML as input, with the exception that it recognizes HTML entities in addition to XML entities. (HTML has many more entities than XML; for instance, XML does not define &nbsp).

If your template contains complex content in <style> or <script> tags, you should either:

  1. Externalize these contents onto their own files, or

  2. Remembering that Kajiki takes XML as input, use CDATA sections inside these tags in order to escape characters that are illegal in XML, such as <, > and &. Here is an example:

    <style><![CDATA[
        html > body { display: none; }
    ]]></style>
    <script><![CDATA[
        if (1 < 2) { document.write("<p>Albatross!!!</p>"); }
    ]]></script>
    

This is not necessary when you are writing HTML because HTML defines that the content of <style> and <script> tags is CDATA by default. However, Kajiki takes XML as input.

Kajiki Text Templates

Kajiki provides a full-featured text template engine in addition to the XML templating engine for cases where you don’t want to necessarily generate markup. This document describes that language. Templates are text files that include template directives that control how the template is rendered and expressions that are substituted into the generated text at render time.

Please see Kajiki Templating Basics for general information on embedding Python code in templates.

Basic Expressions

Let’s start with a hello world template:

>>> Template = kajiki.TextTemplate('Hello, $name!')
>>> print(Template(dict(name='world')).render())
Hello, world!

By default, the $-syntax picks up any identifiers following it, as well as any periods. If you want something more explicit, use the extended expression form as follows:

>>> Template = kajiki.TextTemplate('Hello, 2+2 is ${2+2}')
>>> print(Template().render())
Hello, 2+2 is 4

If you wish to include a literal $, simply double it:

>>> Template = kajiki.TextTemplate('The price is $$${price}')
>>> print(Template(dict(price='5.00')).render())
The price is $5.00

Control Flow

Kajiki provides several directives that affect the rendering of a template. This section describes the various directives. Directives in text templates can either be enclosed by {% … %} characters or they can exist on a line by themselves prefixed by a %. Template directives must always be terminated by an ‘end’ directive (either {%end%} or %end.

Note

Whitespace can sometimes be tricky in text templates. Kajiki provides a bit of help in managing it. First, if you wish to break a line without having the newline included in the generated text, simply end the line with a backslash (). Kajiki will also remove any whitespace before a tag that begins with the delimiter {%-. Directives that appear on their own line via the % prefix never appear in the output, and neither they do not generate any whitespace.

%if, %else

Only render the enclosed content if the expression evaluates to a truthy value:

>>> Template = kajiki.TextTemplate('{%if foo %}bar{%else%}baz{%end%}')
>>> print(Template(dict(foo=True)).render())
bar
>>> print(Template(dict(foo=False)).render())
baz

%switch, %case, %else

Perform multiple tests to render one of several alternatives. The first matching case is rendered, and if no case matches, the else branch is rendered:

>>> Template = kajiki.TextTemplate('''$i is \
... {%switch i % 2 %}{%case 0%}even{%else%}odd{%end%}''')
>>> print(Template(dict(i=4)).render())
4 is even
>>> print(Template(dict(i=3)).render())
3 is odd

%for

Repeatedly render the content for each item in an iterable:

>>> Template = kajiki.TextTemplate('''%for i in range(3)
... $i
... %end''')
>>> print(Template().render(), end='')
0
1
2

%def

Defines a function that can be used elsewhere in the template:

>>> Template = kajiki.TextTemplate('''%def evenness(n)
...     {%-if n % 2 == 0 %}even{%else%}odd{%end%}\\
... %end
... %for i in range(2)
... $i is ${evenness(i)}
... %end''')
>>> print(Template().render(), end='')
0 is even
1 is odd

%call

Call a function, passing a block of template code as a ‘lambda’ parameter. Note that this is a special case of calling when you wish to insert some templated text in the expansion of a function call. In normal circumstances, you would just use ${my_function(args)}.

>>> Template = kajiki.TextTemplate('''%def quote(caller, speaker)
...     %for i in range(2)
... Quoth $speaker, "${caller(i)}."
...     %end
... %end
... %call(n) quote(%caller, 'the raven')
... Nevermore $n\\
... %end''')
>>> print(Template().render(), end='')
Quoth the raven, "Nevermore 0."
Quoth the raven, "Nevermore 1."

%include

Includes the text of another template verbatim. The precise semantics of this tag depend on the TemplateLoader being used, as the TemplateLoader is used to parse the name of the template being included and render its contents into the current template. For instance, with the FileLoader, you might use the following:

%include "path/to/base.txt"

whereas in the PackageLoader you would use

%include package1.package2.base

%import

With %import, you can make the functions defined in another template available without expanding the full template in-place. Suppose that we saved the following template in a file lib.txt:

%def evenness(n)
    %if n % 2 == 0
        even\
    %else
        odd\
    %end
%end

Then (using the FileLoader) we could write a template using the evenness function as follows:

%import "lib.txt" as lib
%for i in range(5)
%i is ${lib.evenness(i)}
%end

Inheritance (%extends, %block)

Kajiki supports a concept of inheritance whereby child templates can extend parent templates, replacing their “methods” (functions) and “blocks” (to be defined below). For instance, consider the following template “parent.txt”:

%def greet(name)
Hello, $name!\
%end
%def sign(name)
Sincerely,
$name\
%end
${greet(to)}

%block body
It was good seeing you last Friday.  Thanks for the gift!
%end

${sign(from_)}

This would render to the following (assuming a context of dict(to=Mark, from_=Rick):

Now we can extend “parent.txt” with “child.txt”:

%extends "parent.txt"
%def greet(name)
Dear $name:\
%end
%block body
${parent_block()}\

And don't forget you owe me money!
%end

Rendering this template would then give us:

Dear Mark:

It was good seeing you last Friday! Thanks for the gift!

And don't forget you owe me money!

Sincerely,
Rick

Notice how in the child block, we have overridden both the block “body” and the function “greet.” When overriding a block, we always have access to the parent template’s block of the same name via the parent_block() function.

If you ever need to access the parent template itself (perhaps to call another function), kajiki provides access to a special variable in child templates parent. Likewise, if a template is being extended, the variable child is available. Kajiki also provides the special variables local (the template currently being defined) and self (the child-most template of an inheritance chain). The following example illustrates these variables in a 3-level inheritance hierarchy:

>>> parent = kajiki.TextTemplate('''
... %def header()
... # Header name=$name
... %end
... %def footer()
... # Footer
... %end
... %def body()
... ## Parent Body
... id() = ${id()}
... local.id() = ${local.id()}
... self.id() = ${self.id()}
... child.id() = ${child.id()}
... %end
... %def id()
... parent\\
... %end
... ${header()}${body()}${footer()}''')
>>> mid = kajiki.TextTemplate('''%extends "parent.txt"
... %def id()
... mid\\
... %end
... ''')
>>> child = kajiki.TextTemplate('''%extends "mid.txt"
... %def id()
... child\\
... %end
... %def body()
... ## Child Body
... ${parent.body()}\\
... %end
... ''')
>>> loader = kajiki.MockLoader({
... 'parent.txt':parent,
... 'mid.txt':mid,
... 'child.txt':child})
>>> Template = loader.import_('child.txt')
>>> print(Template(dict(name='Rick')).render(), end='')
# Header name=Rick
## Child Body
## Parent Body
id() = child
local.id() = parent
self.id() = child
child.id() = mid
# Footer

Migrating from Genshi

Kajiki uses syntax derived from the syntax of Genshi. In particular, the following directives are supported, with semantics intended to be nearly identical to those of Genshi.

  • py:def
  • py:choose – renamed py:with
  • py:when – renamed py:case
  • py:otherwise – renamed py:else
  • py:for
  • py:if
  • py:with
  • py:replace
  • py:content
  • py:attrs
  • py:strip
  • xi:include – renamed py:include

Note that, in particular, py:match is not supported. But Kajiki supports the following additional directives:

  • py:extends - indicates that this is an extension template. The parent template will be read in and used for layout, with any py:block directives in the child template overriding the py:block directives defined in the parent.
  • py:block - used to name a replaceable ‘slot’ in a parent template, or to specify a slot override in a child template. The py:block semantics are modeled after the {% block %} semantics of Jinja2.

Generally, migration consists of a few steps that can be simple or quite difficult based on your fondness of the py:match directive in Genshi. In simple cases where you have one master.html template with a few py:match directives that is xi:included into all your page templates, the following steps should suffice:

  • Rename tags and attributes as indicated above; e.g. xi:include becomes py:include.
  • Rewrite your include directives to use Kajiki’s module naming system and relative imports.
  • In a simple case where you have only a few py:match directives, all of which are in a master.html template that is being included from child templates, I recommend that you rewrite the master.html as layout.html, defining named py:block regions that will be overridden in child templates.
  • In your child templates, remove the <xi:include href="master.html"> that probably lurks near the top. Then add a py:extends directive to the top-level tag (usually <html>). The tag the parts of the child template that are intended to override parts of the parent template with the py:block directive.

Kajiki also provides some helper functions of Genshi:

  • defined('some_variable') (which returns True if ‘some_variable’ exists in the template context),
  • value_of('name', default_value), and
  • Markup(some_string) (which marks a string so it won’t be escaped in the output), though Kajiki prefers to call this literal(some_string).

Example Migration

Suppose you have a couple of Genshi templates, one of which called master.html and one of which is index.html. (TurboGears developers may recognize these files as slightly modified versions of the default templates deposited in a TG quickstarted project.) The contents of master.html are:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:py="http://genshi.edgewall.org/"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      py:strip="">
    <xi:include href="header.html" />
    <xi:include href="sidebars.html" />
    <xi:include href="footer.html" />
<head py:match="head" py:attrs="select('@*')">
    <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
    <title py:replace="''">Your title goes here</title>
    <meta py:replace="select('*')"/>
    <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/style.css')}" />
    <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/admin.css')}" />
</head>

<body py:match="body" py:attrs="select('@*')">
  ${header()}
  <ul id="mainmenu">
    <li class="first"><a href="${tg.url('/')}" class="${('', 'active')[defined('page') and page=='index']}">Welcome</a></li>
        <li><a href="${tg.url('/about')}" class="${('', 'active')[defined('page') and page=='about']}">About</a></li>
        <li py:if="tg.auth_stack_enabled"><a href="${tg.url('/auth')}" class="${('', 'active')[defined('page') and page=='auth']}">Authentication</a></li>
        <li><a href="${tg.url('/environ')}" class="${('', 'active')[defined('page') and page=='environ']}">WSGI Environment</a></li>
        <li><a href="http://groups.google.com/group/turbogears">Contact</a></li>
    <span py:if="tg.auth_stack_enabled" py:strip="True">
        <li py:if="not request.identity" id="login" class="loginlogout"><a href="${tg.url('/login')}">Login</a></li>
        <li py:if="request.identity" id="login" class="loginlogout"><a href="${tg.url('/logout_handler')}">Logout</a></li>
        <li py:if="request.identity" id="admin" class="loginlogout"><a href="${tg.url('/admin')}">Admin</a></li>
    </span>
  </ul>
  <div id="content">
    <py:if test="defined('page')">
    <div class="currentpage">
     Now Viewing: <span py:replace="page"/>
     </div>
    </py:if>
    <py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
        <div py:if="flash" py:content="XML(flash)" />
    </py:with>
    <div py:replace="select('*|text()')"/>
    <!-- End of main_content -->
    ${footer()}
  </div>
</body>
</html>

Likewise, the contents of index.html are as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:py="http://genshi.edgewall.org/"
      xmlns:xi="http://www.w3.org/2001/XInclude">

  <xi:include href="master.html" />

<head>
  <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
  <title>Welcome to TurboGears 2.0, standing on the 
  shoulders of giants, since 2007</title>
</head>

<body>
    ${sidebar_top()}
  <div id="getting_started">
    <h2>Presentation</h2>
    <p>TurboGears 2 is rapid web application development toolkit designed to make your life easier.</p>
    <ol id="getting_started_steps">
      <li class="getting_started">
        <h3>Code your data model</h3>
        <p> Design your data model, Create the database, and Add some bootstrap data.</p>
      </li>
      <li class="getting_started">
        <h3>Design your URL architecture</h3>
        <p> Decide your URLs, Program your controller methods, Design your 
            templates, and place some static files (CSS and/or JavaScript). </p>
      </li>
      <li class="getting_started">
        <h3>Distribute your app</h3>
        <p> Test your source, Generate project documents, Build a distribution.</p>
      </li>
    </ol>
  </div>
  <div class="clearingdiv" />
  <div class="notice"> Thank you for choosing TurboGears. 
  </div>
</body>
</html>

In order to perform our kajiki migration, we begin by creating two empty templates. The first one will replace our master.html, and we will call it layout.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
    <py:include href="header" />
    <py:include href="footer" />

    <head>
      <title py:block="title">Your title goes here</title>
      <py:block name="head_content">
        <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/style.css')}" />
        <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/admin.css')}" />
      </py:block>
    </head>

    <body>
      <py:block name="body_header"><h1>My Header</h1></py:block>
      <ul py:block="mainmenu" id="mainmenu">
        <li class="first"><a href="${tg.url('/')}" class="${('', 'active')[defined('page') and page=='index']}">Welcome</a></li>
        <li><a href="${tg.url('/about')}" class="${('', 'active')[defined('page') and page=='about']}">About</a></li>
        <li py:if="tg.auth_stack_enabled"><a href="${tg.url('/auth')}" class="${('', 'active')[defined('page') and page=='auth']}">Authentication</a></li>
        <li><a href="${tg.url('/environ')}" class="${('', 'active')[defined('page') and page=='environ']}">WSGI Environment</a></li>
        <li><a href="http://groups.google.com/group/turbogears">Contact</a></li>
      </ul>
      <div id="content">
        <py:if test="defined('page')">
          <div class="currentpage">
            Now Viewing: <span py:replace="page"/>
          </div>
        </py:if>
        <py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
          <div py:if="flash" py:content="XML(flash)" />
        </py:with>
        <py:block name="body_text">Your body text goes here</py:block>
        <py:block name="bodyfooter">${footer()}</py:block>
      </div>
    </body>
</html>

Note the introduction of the py:block directive, and the disappearance of the py:match directives from master.html. py:block mimics the behavior of Jinja2 “blocks”, providing a name to a construct in a parent template which can be replaced by the contents of py:block -named constructs in child templates. For instance, the “title” slot in layout.html:

1
      <title py:block="title">Your title goes here</title>

can be replaced by a similarly-named slot in the child document index_kajiki.html:

1
2
3
4
5
6
7
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html py:extends="layout">
    <py:include href="sidebars" />

    <title py:block="title">Welcome to TurboGears 2.0, standing on the 
      shoulders of giants, since 2007</title>

We also provide a way of including the contents of the parent template’s slot in a child template’s slot using ${parent_block()}. The following slot in layout.html:

1
      <py:block name="body_header"><h1>My Header</h1></py:block>

can be replaced in include/index_kajiki.html with:

1
2
3
4
    <py:block name="body_header">
      ${parent_block()}
      <h1>Some extra header data</h1>
    </py:block>

Yielding the following html once rendered:

1
2
 <h1>My Header</h1>
 <h1>Some extra header data</h1>

Internationalization

Kajiki provides supporting infrastructure for internationalizing and localizing templates. This includes functionality for extracting localizable strings from templates, as well as translation of localizable strings.

Basics

To internationalize and translate templates, other templating solutions require that you wrap all localizable strings in a gettext() function call (usually aliased to _() for brevity). In this case, you would write your templates similar to the following:

<p>${_('Hello, world!')}</p>

This approach, however, adds lots of noise to your templates. Kajiki does not require that you wrap localizable strings since it automatically finds all “translatable text” in XML templates (any text outside of an XML tag).

In order to actually use translation, you must replace the placeholder function in kajiki.i18n.gettext with the actual gettext function. For instance, you might place the following in your top-level script to enable the Python gettext module:

from gettext import gettext
from kajiki import i18n
i18n.gettext = gettext

Extraction

Kajiki also provides support for extracting all localizable strings found in a template. This functionality is integrated with the excellent message extraction framework provided by the Babel project. Typically, you would notify Babel of the location of your templates before running the extraction routine:

# Python source
[python:**.py]
# Kajiki Templates
[kajiki:**/templates/**.html]

Please consult the Babel documentation for further details. If all goes well, the extraction process should create a POT file containing the strings from your Kajiki templates and your Python source files.

Kajiki Runtime

It’s sometimes good to have a mental model of the Python code that Kajiki creates in order to generate your templates. This document uses several examples taken from the text templating language to illustrate the semantics of Kajiki templates. If in doubt, you can always view the Python text generated for a template by examining the py_text attribute of the generated Template class.

xml_template.XMLTemplate(filename=None, mode=None, is_fragment=False, encoding=u'utf-8', autoblocks=None, cdata_scripts=True, strip_text=False, base_globals=None)

Given XML source code of a Kajiki Templates parses and returns a template class.

The source code is parsed to its DOM representation by _Parser, which is then expanded to separate directives from tags by _DomTransformer and then compiled to the Intermediate Representation tree by _Compiler.

The Intermediate Representation generates the Python code which creates a new kajiki.template._Template subclass through kajiki.template.Template().

The generated code is then executed to return the newly created class.

Calling .render() on an instance of the generate class will then render the template.

class kajiki.ir.TemplateNode(mod_py=None, defs=None)[source]

Represents the root Intermediate Representation node of a template.

Iterating over this will generate the Python code for the class that provides all the functions that are part of the template including the __main__ function that represents the template code itself.

The generated class will then be passed to kajiki.template.Template() to create a kajiki.template._Template subclass that has the render method to render the template.

template.Template()

Creates a new _Template subclass from an entity with exposed functions.

Kajiki uses classes as containers of the exposed functions for convenience, but any object that can have the functions as attributes works.

To be a valid template the original entity must provide at least a __main__ function:

class Example:
    @kajiki.expose
    def __main__():
        yield 'Hi'

t = kajiki.Template(Example)
output = t().render()

print(output)
'Hi'
class kajiki.template._Template(context=None)[source]

Base Class for all compiled Kajiki Templates.

All kajiki templates created from a kajiki.ir.TemplateNode will be subclasses of this class.

As the template body code runs inside __main__ method of this class, the instance of this class is always available as self inside the template code.

This class also makes available some global object inside the template code itself:

  • local which is the instance of the template
  • defined which checks if the given variable is defined inside the template scope.
  • Markup which marks the passed object as markup code and prevents escaping for its content.
  • __kj__ which is a special object used by generated code providing features like keeping track of py:with stack or or the gettext function used to translate text.
defined(name)[source]

Check if a variable was provided to the template or not

render()[source]

Render the template to a string.

class kajiki.xml_template._Compiler(filename, doc, mode=None, is_fragment=False, autoblocks=None, cdata_scripts=True)[source]

Compiles a DOM tree into Intermediate Representation kajiki.ir.TemplateNode.

Intermediate Representation is a tree of nodes that represent Python Code that should be generated to execute the template.

compile()[source]

Compile the document provided by _Parser.

Returns as kajiki.ir.TemplateNode instance representing the whole tree of nodes as their intermediate representation.

The returned template will include at least a __main__ function which is the document itself including a DOCTYPE and any function declared through py:def or as a py:block.

The TemplateNode will also include the module level code specified through <?py %.

If the compiled document didn’t specify a DOCTYPE provides one at least for HTML5.

Note

As this alters the functions and mode wide code registries of the compiler compile should never be called twice or might lead to unexpected results.

class kajiki.xml_template._Parser(filename, source)[source]

Parse an XML template into a Tree of DOM Nodes.

Nodes should then be passed to a _Compiler to be converted into the intermediate representation and then to Python Code.

parse()[source]

Parse an XML/HTML document to its DOM representation.

class kajiki.xml_template._DomTransformer(doc, strip_text=True)[source]

Applies standard Kajiki transformations to a parsed document.

Given a document generated by Parser it applies some node transformations that are necessary before applying the compilation steps to achieve result we usually expect.

This includes things like squashing consecutive text nodes and expanding py: directives.

The Transformer mutates the original document.

transform()[source]

Applies all the DOM transformations to the document.

Calling this twice will do nothing as the result is persisted.

Basic Expressions

Let’s start with a hello world template:

Hello, World!

This converts to the equivalent Python:

@kajiki.expose
def __call__():
    yield 'Hello, World!\n'

Slightly more verbose “hello_name.txt”:

Hello, $name!

This converts to the equivalent Python:

@kajiki.expose
def __call__():
     yield 'Hello, '
     yield name
     yield '!\n'

By default, the $-syntax picks up any identifiers following it, as well as any periods. If you want something more explicit, use the extended expression form as in “hello_arithmetic.txt”:

Hello, 2 + 2 is ${2+2}!

This converts to:

@kajiki.expose
def __call__():
    yield 'Hello, 2 + 2 is '
    yield 2+2
    yield '!'

If you wish to include a literal $, simply prefix it with a backslash.

Control Flow

Kajiki provides several tags that affect the rendering of a template. The following template “control_flow.txt” illustrates:

A{%for i in range(5)%}
    {%if i < 2%}Low{%elif i < 4%}Mid{%else%}High{%end%}$i
    {%switch i % 2%}
        {%case 0%}
            even
        {%default%}
            odd
        {%end%}{%end%}{%end%}

This yields the following Python:

@kajiki.expose
def __call__():
    yield 'A\n' # from the {%for... line
    for i in range(10):
        yield '\n        ' # from the newline and initial indent of next line
        if i < 2:
            yield 'Low'
        elif i < 4:
            yield 'Mid'
        else:
            yield 'High'
        yield i
        yield '\n        ' # from the {%if... newline and next indent
        local.__kj__.push_switch(i%2)
        # whitespace after {%switch is always stripped
        if local.__kj__.case(0):
            yield '\n            even\n        '
        else:
            yield '\n            odd\n        '
        local.__kj__.pop_switch()

Which would in turn generate the following text:

A
    Low0

        even

    Low1

        odd

    Mid2

        even

    Mid3

        odd

    High4

        even

If you want to strip whitespace before or after a tag, just replace {% with {%- (for stripping leading whitespace) or %} with -%} (for stripping trailing whitespace). If you would like to remove newlines, just end a line with a backslash. Here is the equivalent template with whitespace removed, “control_flow_ws.txt”:

A{%-for i in range(5) -%}\
    {%-if i < 2%}Low{%elif i < 4%}Mid{%else%}High{%end%}$i
    {%-switch i % 2%}\
        {%-case 0%}\
            even
        {%-default%}\
            odd
        {%-end%}\
    {%-end%}\
{%-end%}\

This would generate the following Python:

@kajiki.expose
def __call__():
    yield 'A'
    for i in range(10):
        if i < 2:
            yield 'Low'
        elif i < 4:
            yield 'Mid'
        else:
            yield 'High'
        yield i
        yield '\n'
        local.__kj__.push_switch(i % 2)
        if local.__kj__.case(0):
            yield 'even\n'
        else:
            yield 'odd\n'
        local.__kj__.pop_switch()

Which would generate the following text:

ALow0
even
Low1
odd
Mid2
even
Mid3
odd
High4
even

which is probably closer to what you wanted. There is also a shorthand syntax that allows for line-oriented control flow as seen in “control_flow_ws_short.txt”:

A\
%for i in range(5)
    %if i < 2
        Low\
    %elif i < 4
        Mid\
    %else
        High\
    {%-end%}$i
    %switch i % 2
        %case 0
            even
        %default
            odd
        %end
    %end
%end

This syntax yields exactly the same results as “control_flow_ws.txt” above.

Python Blocks

You can insert literal Python code into your template using the following syntax in “simple_py_block.txt”:

{%py%}\
    yield 'Prefix'
{%end%}\
Body

or alternatively:

%py
    yield 'Prefix'
%end
Body

or even more succinctly:

%py yield 'Prefix'
Body

all of which will generate the following Python:

def __call__():
    yield 'Prefix'
    yield 'Body'
Note in particular that the Python block can have any indentation, as long as it
is consistent (the amount of leading whitespace in the first non-empty line of the block is stripped from all lines within the block). You can insert module-level Python (imports, etc.) by using the %py% directive (or {%py%%} as in “module_py_block.txt”:
%py%
    import sys
    import re
%end
Hello
%py% import os
%end

This yields the following Python:

import sys
import re

import os

@kajiki.expose
def __call__():
    yield 'Hello'

Functions and Imports

Kajiki provides for code reuse via the %def and %import directives. First, let’s see %def in action in “simple_function.txt”:

%def evenness(n)
    %if n % 2 == 0
        even\
    %else
        odd\
    %end
%end
%for i in range(5)
$i is ${evenness(i)}
%end

This compiles to the following Python:

@kajiki.expose
def evenness(n):
    if n % 2:
        yield 'even'
    else:
        yield 'odd'

@kajiki.expose
def __call__():
    for i in range(5):
        yield i
        yield ' is '
        yield evenness(i)

The %import directive allows you to package up your functions for reuse in another template file (or even in a Python package). For instance, consider the following file “import_test.txt”:

%import "simple_function.txt" as simple_function
%for i in range(5)
$i is ${simple_function.evenness(i)}
%end

This would then compile to the following Python:

@kajiki.expose
def __call__():
    simple_function = local.__kj__.import_("simple_function.txt")
    for i in range(5):
        yield i
        yield ' is '
        yield simple_function.evenness(i)

Note that when using the %import directive, any “body” in the imported template is ignored and only functions are imported. If you actually wanted to insert the body of the imported template, you would simply call the imported template as a function itself (e.g. ${simple_function()}).

Sometimes it is convenient to pass the contents of a tag to a function. In this case, you can use the %call directive as shown in “call.txt”:

%def quote(caller, speaker)
    %for i in range(5)
Quoth $speaker, "${caller(i)}."
    %end
%end
%call(n) quote('the raven')
Nevermore $n\
%end

This results in the following Python:

@kajiki.expose
def quote(caller, speaker):
    for i in range(5):
        yield 'Quoth '
        yield speaker
        yield ', "'
        yield caller(i)
        yield '."'

@kajiki.expose
def __call__():
    @kajiki.expose
    def _fpt_lambda(n):
        yield 'Nevermore '
        yield n
    yield quote(_fpt_lambda, 'the raven')
    del _fpt_lambda

Which in turn yields the following output:

Quoth the raven, "Nevermore 0."
Quoth the raven, "Nevermore 1."
Quoth the raven, "Nevermore 2."
Quoth the raven, "Nevermore 3."
Quoth the raven, "Nevermore 4."

Includes

Sometimes you just want to pull the text of another template into your template verbatim. For this, you use the %include directive as in “include_example.txt”:

This is my story:
%include "call.txt"
Isn't it good?

which yields the following Python:

@kajiki.expose
def __call__():
    yield 'This is my story:\n'
    yield _fpt.import("simple_function.txt")()
    yield 'Isn't it good?\n'

Which of course yields:

This is my story:
Quoth the raven, "Nevermore 0."
Quoth the raven, "Nevermore 1."
Quoth the raven, "Nevermore 2."
Quoth the raven, "Nevermore 3."
Quoth the raven, "Nevermore 4."
Isn't it good?

Inheritance

Kajiki supports a concept of inheritance whereby child templates can extend parent templates, replacing their methods and “blocks” (to be defined below). For instance, consider the following template “parent.txt”:

%def greet(name)
Hello, $name!\
%end
%def sign(name)
Sincerely,
$name\
%end
${greet(to)}

%block body
It was good seeing you last Friday.  Thanks for the gift!
%end

${sign(from)}

This would generate the following Python:

@kajiki.expose
def greet(name):
    yield 'Hello, '
    yield name
    yield '!'

@kajiki.expose
def sign(name):
    yield 'Sincerely,\n'
    yield name

@kajiki.expose
def _fpt_block_body():
    yield 'It was good seeing you last Friday! Thanks for the gift!\n'

@kajiki.expose
def __call__():
    yield greet(to)
    yield '\n\n'
    yield self._fpt_block_body()
    yield '\n\n'
    yield sign(from)

Here is the corresponding “child.txt”:

%extends "parent.txt"
%def greet(name)
Dear $name:\
%end
%block body
${parent_block()}\\

And don't forget you owe me money!
%end

This would then yield the following Python:

@kajiki.expose
def greet(name):
    yield 'Dear '
    yield name
    yield ':'

@kajiki.expose
def _fpt_block_body():
    yield parent._fpt_block_body()
    yield '\n\n'
    yield 'And don\'t forget you owe me money!\n'

@kajiki.expose
def __call__():
    yield local.__kj__.extend(local.__kj__.import_('parent.txt')).__call__()

The final text would be (assuming context had to=’Mark’ and from=’Rick’:

Dear Mark:

It was good seeing you last Friday! Thanks for the gift!

And don't forget you owe me money!

Sincerely,
Rick

Indices and tables