Documentation

Basic HTML Generation

Brevé templates are expressed as specialized Python code with a single limitation: only expressions are allowed.

Translating a typical HTML document to Brevé is usually no more complicated than the following:

  1. replace open tags with "tag ["
  2. replace the close tags with "]"
  3. put parentheses around attributes ( such as style="" and id="" ) and separate them with commas
  4. put commas between adjacent tags

Brevé also provides tools to help automate this process.

Consider the following example to get an idea of what this entails:

html [
    head [
        title [ 'A simple example' ]
    ],

    body [
        h1 [ 'This is an example of Brevé' ], br,
        div ( style = 'text-align: center;' ) [
            span [ '''
                As you can see, Brevé markup maps very
                directly to the final HTML output.
            ''' ]
        ]
    ]
]

This template would output the following:

<html>
    <head>
        <title>A simple example</title>
    </head>
    <body>
        <h1>This is an example of Brevé</h1>
        <div style="text-align: center;">
            <span>
                As you can see, Brevé markup maps very
                directly to the final HTML output.

            </span>
        </div>
    </body>
</html>

Brevé supports all the expected HTML tags.

Sometimes it's necessary to append an underscore ("_") to certain tag attributes. This is side-effect of using Python as a template language. Some words that are used as HTML attributes are also reserved Python keywords ("class" being the most commonly used one). Because it would be a Python syntax error to use the word "class" outside an actual class definition, we are forced to append an underscore to prevent this name clash. Helpfully, we don't need to actually remember which attributes conflict with Python keywords. If you don't know which might cause problems, simply append an underscore to all attributes. Brevé will accept it either way.

Back to Table of Contents

Using Variables

Template engines aren't of much use if you can't dynamically generate content. One of the primary ways to generate dynamic content is by outputting the values of variables in a template. Using variables in Brevé is quite simple: you simply pass a dictionary of variables and then use them directly in your template.

from datetime import datetime
from breve import Template, flatten
from breve.tags.html import tags

vars = dict (
    message = 'Hello, world',
    today = datetime.today ( ).strftime ( '%Y/%m/%d' )
)

t = Template ( tags, root = '.' )
t.render ( 'index', vars )
# index.b
html [
     body [
          span [ message ], br,
          span [ 'Today is ', today ]
     ]
]

Note that we didn't need to use Python's dictionary notation to reference the variables within the template. Brevé adds all the values of the dictionary to the template's local namespace.

The output of the above would be something like this:

<html>
    <body>
        <span>Hello, world</span><br />
        <span>Today is 2006/12/27</span>
    </body>
</html>

Back to Table of Contents

Special Directives

Variable substitution is useful, but Brevé supports much more powerful features that help organize your templates and assist with code reuse.

The include directive

The first and simplest of these is simple file includes. Templates may include fragments of Brevé from other files. These fragments are executed in the context of the calling template. For example:

# index.b
html [
    body [
         span ( class_ = 'title' ) [ 'Include directive' ],
         div ( class_ = 'para' ) [
             include ( 'fragment' )
         ]
    ]
]
# fragment.b
div [
     'This could have been any amount of Brevé'
]

You could also combine this with variable substitution to dynamically select fragments to include in your template, for example:

# index.b
html [
    body [
         span [ "We're going to include %.b" % page ],
         include ( page )
    ]
]

Assuming that the variable "page" was populated with the path to a file containing Brevé code, this would have included whatever file was stored in that variable.

However, there are better ways of doing this that we'll be covering next.

Back to Table of Contents

Template Inheritance

Inheritance is more complicated than simple includes, but more powerful as well. At some level it can be seen as the inverse of includes, since it's the fragments that specify what they'll be "included" in. This model is especially useful in MVC frameworks (such as TurboGears and Pylons) where a class or method (referred to as a "controller") directly represent a particular page on a website. You could solve this problem by dynamically selecting files to include as in the earlier section, but it's much better to use inheritance. It's actually much easier to demonstrate than explain, so here's a short example:

# contacts.b
inherits ( 'index' ) [

    override ( 'content' ) [
        div ( id = 'contacts' ) [
            ul [
                li [ a ( href = 'mailto:cliff@domain.com' ) [ 'Cliff' ] ],
                li [ a ( href = 'mailto:laura@domain.com' ) [ 'Laura' ] ]
            ]
        ]
    ]
]

What you do now is not render index.b, rather you render contacts.b:

from breve import Template, flatten
from breve.tags.html import tags

t = Template ( tags, root = '.' )
t.render ( 'contacts' )

This may seem complicated (and there are a few new directive that must be taken together), but it's really quite simple (especially if you are familiar with the concept of inheritance from Python and other programming languages).

Here's the basic flow of events:

We ask Brevé to render contact.b. However this template gives notice that it is only part of a larger whole by using the inherits directive. The inherits directive tells Brevé that this template consists only of fragments that will fill empty slots in some other template (whose name is given in the parentheses following the inherits directive).

Note: template paths are relative to the root which must be specified when instantiating the Template object. This can be done via a setting in your framework or by specifying it as the root argument to the Template object.

Next, Brevé needs to know what slots to fill in (our example has only one, but there could be several). This is what the override directive does. It tells Brevé to replace the slot named "content" with the fragment specified. More than one slot may be given:

# fragment.b
inherits ( 'index' ) [
    override ( 'main-menu' ) [
        div ( class_ = 'menu' ) [
             ul [
                  li [ a ( href = '/' ) [ 'Home' ] ],
                  li [ a ( href = '/about' ) [ 'About' ] ]
             ]
        ]
    ],

    override ( 'content' ) [
        div ( class_ = 'body-text' ) [
            '''Welcome to our humble site.  Enjoy your stay.'''
        ]
    ]
]
# index.b
html [
     body [
          slot ( 'main-menu' ),
          slot ( 'content' )
     ]
]

The output of the above would look like this:

<html>
    <body>
        <div class="main-menu">
            <ul>
                <li><a href="/"></a>Home</li>
                <li><a href="/about">About</a></li>
            </ul>
        </div>
        <div class="body-text">
            Welcome to our humble site.  Enjoy your stay.
        </div>
    </body>
</html>

Inheritance can go many layers deep and the deepest layer (i.e. the one farthest from the root template) has the final say. For example:

# frag2.b
inherits ( 'frag1' ) [
    override ( 'slot-1' ) [
        span [ 'Hello from frag2' ]
    ],
    override ( 'slot-2' ) [
        span [ 'Hello from frag2' ]
    ]
]
# frag1.b
inherits ( 'index' ) [
    override ( 'slot-1' ) [
        span [ 'Hello from frag1' ]
    ],
    override ( 'slot-3' ) [
        span [ 'Hello from frag1' ]
    ]
]
# index.b
html [
    body [
         slot ( 'slot-1' ),
         slot ( 'slot-2' ),
         slot ( 'slot-3' )
    ]
]

Then if we told our controller to render frag2.b, we would get the following:

<html>
    <body>
        <span>Hello from frag2</span>
        <span>Hello from frag2</span>
        <span>Hello from frag1</span>
    </body>
</html>

Notice that even though frag1.b specified that it would override slot-1, because frag2.b also specified that it would override slot-1 and, being further from the master document (in this case index.b), it has the last say and so does the override.

Back to Table of Contents

Conditional Expressions

For the most part, it's best to not put too much logic in your templates. It tends to make them cluttered and difficult to read. This is compounded by the fact that templates are nested by nature. Also, debugging templates is usually more difficult than debugging actual program code so the simpler they are, the better.

Regardless, it's sometimes useful to be able to embed bits of simple logic in templates. Brevé provides a single (very simple) function called test to help with this. All test does is return an empty string if the condition evaluates to False or the result of condition if condition evaluates as True.

Examples:

Using test ( ) as a conditional block:

test ( logged_in ) and (
    'Welcome, ', username
)

Using a list as a conditional:

div [
    [ 'goodbye', 'hello' ][ bool ( logged_in ) ]
]

Dictionaries as selectors:

div [
    { 1: span [ 'One' ],
      2: span [ 'Two' ],
      3: span [ 'Three' ] } [ var ]
]

A nice thing about using dictionaries is that you can have a default value if var doesn't match any value in the dictionary:

div [
    { 1: span [ 'One' ],
      2: span [ 'Two' ],
      3: span [ 'Three' ] }.get ( var, '' )
]

Here's a quick reference for turning Python conditional statements into equivalent Python expressions (borrowed from an article [1] by Crispin Wellington). Take special note of his discussion explaining caveats regarding this technique.

Python Conditional Equivalent Python Expression
if A: B (A and B)
if not A: B (A or B)
if A: B
else: C
((A and B) or C)
if A: B
elif C: D
else: E
((A and B) or (C and D) or E)

Python 2.5 has also introduced a ternary "if" expression that can be used in Brevé templates:

a if b else c

So for example, you could do something like:

span [
    ( 'Welcome, %s' % user ) if ( logged_in ) else  ( 'Please log in' )
]

It's important to note that except in the context of boolean operators (and, or) and the ternary "if" operator, expressions are evaluated regardless of the truthiness of the condition. This can lead to unexpected errors if all the expressions aren't valid at the time of template evaluation.

For example, assume that the variable username isn't defined unless logged_in is True:

div [
    [ 'goodbye', 'hello %s' % username ][ bool ( logged_in ) ]
]

This will lead to an exception, even if logged_in is False.

Back to Table of Contents

Looping and Repetition

There are a couple of ways to repeat a section in a Brevé template.

List Comprehensions

ul [
    [ li [ s ] for s in items ]
]

Unfortunately, list comprehensions can become unreadable when the fragment being repeated gets complex. To help with this, Brevé 1.2 introduces couple new ways of looping: Tag Multiplication and Macro.

Tag Multiplication

This feature (new in Brevé 1.2) lets you multiply a tag by a list of dictionaries. It's more or less an implicit loop that calls string.Template.safe_substitute on all attributes and children that are strings. It's slightly slower than a list comprehension, but much more readable.

For example:

from breve.tags.html import tags
from breve.flatten import flatten
globals ( ).update ( tags )

menu_items = [
    { 'href': '/home', 'data': 'Home', 'class': 'menu-item' },
    { 'href': '/about', 'data': 'About', 'class': 'menu-item' },
    { 'href': '/docs', 'data': 'Documentation', 'class': 'menu-item' },
]

template = html [
    body [
        ul [
            li ( class_ = '$class' ) [
                a ( href='$href', class_ = '${class}-link' ) [ '$data' ]
            ] * menu_items
        ]
    ]
]

print flatten ( template )

The above would output:

<html>
  <body>
    <ul>
      <li class="menu-item">
        <a class="menu-item-link" href="/home">Home</a>
      </li>
      <li class="menu-item">
        <a class="menu-item-link" href="/about">About</a>
      </li>
      <li class="menu-item">
        <a class="menu-item-link" href="/docs">Documentation</a>
      </li>
    </ul>
  </body>
</html>

Back to Table of Contents

Macro

You can define a macro to encapsulate Brevé fragments. A macro is a function that accepts two arguments, a string and a function. The string is the name the macro will be known by in the template.

from breve.tags import macro
from breve.tags.html import tags
globals ( ).update ( tags )

data = [
    dict ( href = '/', label = 'Home' ),
    dict ( href = '/about', label = 'About' ),
    dict ( href = '/help', label = 'Help' )
]

template = (
    macro ( 'mymacro', lambda href, label:
        li [
            a ( href = href ) [ label ]
        ]
    ),

    html [
        body [
            ul [ [ mymacro ( **_d ) for _d in data ] ]
        ]
    ]
)

print template

This would output:

<html>
  <body>
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/about">About</a></li>
      <li><a href="/help">Help</a></li>
    </ul>
  </body>
</html>

Macros can be put anywhere in the template as long as they will be evaluated prior to being used. It's probably a good idea to either group them at the top of the template or define them immediately prior to the location they will be used.

Macros can also be nested, but remember that lambda is limited to a single expression so you must put parentheses around the macro body:

macro ( 'menu_macro', lambda url_list: (
    macro ( 'link_macro', lambda url, name:
        a ( href=url ) [ name ]
    ),
    [ ul [ link_macro ( url, name ) ]
      for url, name in url_list ]
) )

There are currently a few limitations where macros can be defined and used:

  1. They can't be defined across inheritance directives (i.e. defined in an override directive and then used in the master template, or vice-versa).

Back to Table of Contents

Assign

Assign is a function that lets you set a variable's value within a template. Assign cannot be used within a macro, although the variable it defines can:

from breve.tags.html import tags
from breve.tags import macro, assign
globals ( ).update ( tags )

data = [
    dict ( href = '/', label = 'Home' ),
    dict ( href = '/about', label = 'About' ),
    dict ( href = '/help', label = 'Help' )
]

template = html [
    body [
        assign ( 'mystyle', 'link' ),
        macro ( 'mymacro', lambda href, label:
            li [
                a ( href = href, class_ = mystyle ) [ label ]
            ]
        ),
        ul [
            [ mymacro ( **_d ) for _d in data ]
        ]
    ]
]

print template

would output:

<html>
  <body>
    <ul>
      <li><a class="link" href="/">Home</a></li>
      <li><a class="link" href="/about">About</a></li>
      <li><a class="link" href="/help">Help</a></li>
    </ul>
  </body>
</html>

It's worth noting that because macro defines a function, the macro itself can be defined prior to assign, even if it relies on the variable assign sets:

from breve.tags.html import tags
from breve.tags import macro, assign
from breve.flatten import flatten
globals ( ).update ( tags )

external_links = [
    dict ( href = 'http://www.google.com', label = 'Google' ),
    dict ( href = 'http://www.amazon.com', label = 'Amazon' ),
    dict ( href = 'http://www.yahoo.com', label = 'Yahoo!' )
]

internal_links = [
    dict ( href = '/', label = 'Home' ),
    dict ( href = '/about', label = 'About' ),
    dict ( href = '/help', label = 'Help' )
]

template = (
    macro ( 'link_macro', lambda href, label:
        li [
            a ( href = href, class_ = link_style ) [ label ]
        ]
    ),

    html [
        body [
            assign ( 'link_style', 'internal-link' ),
            ul [
                [ link_macro ( **_d ) for _d in internal_links ]
            ],

            assign ( 'link_style', 'external-link' ),
            ul [
                [ link_macro ( **_d ) for _d in external_links ]
            ]
        ]
    ]
)

print flatten ( template )

This would output:

<html>
  <body>
    <ul>
      <li><a class="internal-link" href="/">Home</a></li>
      <li><a class="internal-link" href="/about">About</a></li>
      <li><a class="internal-link" href="/help">Help</a></li>
    </ul>
    <ul>
      <li><a class="external-link" href="http://www.google.com">Google</a></li>
      <li><a class="external-link" href="http://www.amazon.com">Amazon</a></li>
      <li><a class="external-link" href="http://www.yahoo.com">Yahoo!</a></li>
    </ul>
  </body>
</html>

assign has the same limitations as macro (see previous section).

Back to Table of Contents

Let

Let is much like assign with a simpler syntax and allowing definition of more than one variable. A key difference, however, is that let creates a local variable, while assign creates a global.

let ( msg='Hello, world', page_title='A Test' ),

html [
    head [ title [ page_title ] ],
    body [ div [ msg ] ]
]

let can be used in place of both assign and macro.

As always, be wary about name clashes with tags and other variables.

Back to Table of Contents

Custom Flatteners

So far, most of the features of Brevé are pretty typical of most template engines. In fact, Brevé offers far fewer features than most (we consider this a good thing). However, Brevé tries to offer the fewest but most powerful and expressive features.

One of the simplest and yet most powerful features of Brevé is the concept of flatteners. As I mentioned earlier, there's only one process to turn a Brevé template into its final HTML form and that process is called "flattening". All the tags such as div and span that you use in Brevé templates have a default flattener. In fact, anything that can be printed (i.e. via print statement) in Python can be flattened by Brevé.

However, sometimes we want certain things to be flattened in a particular way. Quite often the string representation of Python objects isn't at all what we'd want in our HTML output. Consider the first example back in Chapter 1 that used the datetime object. In that example, we formatted the output in the controller prior to passing it to the template.

Let's try it again using a custom flattener:

# test.py
from datetime import datetime
from breve import Template, register_flattener, escape
from breve.tags.html import tags

def flatten_date ( o ):
    return escape ( o.strftime ( '%Y/%m/%d' ) )
register_flattener ( datetime, flatten_date )

vars = dict ( today = datetime.today ( ) )

t = Template ( tags, root = '.' )
t.render ( 'index', vars )
# index.b
html [
    body [
        span [ 'Today is', today ]
    ]
]

The function register_flattener takes two arguments: a Python type and a function that returns a Python string (or preferably, Unicode object). Whenever Brevé encounters an object that matches the registered type (this is an exact match via a dictionary lookup, not the result of isinstance, for example), it will pass that object to the specified function to be flattened. The output of the function is what will appear in the final HTML output. For example, the code above would output:

<html>
    <body>
        <span>Today is 2006/12/27</span>
    </body>
</html>

This is an extremely simple example, but it doesn't take much to imagine the ways this concept can be applied. Database records could be flattened to forms, Python lists could be flattened to HMTL tables or lists. The beautiful thing is that no special formatting need appear anywhere but in the flattener. Again this fits with the Brevé philosophy of keeping templates as simple and clean as possible.

Important: Notice that we called escape ( ) before returning the flattened object. All output in Brevé templates is escaped by default except for custom flatteners. Custom flatteners are assumed to know what they are doing and their output is passed untouched to the browser. Passing unescaped output might open security flaws (such as XSS) or at least cause rendering issues. Be very certain you know what you are doing if you return unescaped data, or better yet, don't do it.

A few notes about register_flattener and flattening in general:

  • If there is no registered flattener for an object, the builtin str function is tried.
  • There are a few pre-registered flatteners for built-in Python objects: str, list, tuple, unicode. If you change these, you might break Brevé. If you change them, you'll need to make sure the default behavior is intact.
  • Flatteners are registered based on the type of the object. There can be only one flattener per type. If you want to have variations in how a particular type is flattened, subclass the type and register a flattener for the subclass. If you want to override the default flattener, simply register a new one.
  • You can achieve the same functionality as register_flattener by simply defining a __str__ method for a class.
  • When defining custom flatteners, be wary of XML escaping and quoting issues. Custom flatteners are assumed to return the final representation of the object and no further escaping is done. You can use breve.tags.escape ( ) on the data before you return it from the renderer in order to guarantee the data is properly escaped.
  • If you want to turn off all escaping or define a different escaping mechanism, redefine the default str flattener or unregister it using unregister_flattener ( str ), but be certain to call breve.tags.escape ( ) for any untrusted data.

Warning: changing the default flattener for list or tuple will lead to strange breakage in Brevé!

Back to Table of Contents

Custom Renderers

Much as flatteners allow you to generate custom HTML when a particular Python object is encountered, renderers allow you to generate custom template code for particular template tags. While flatteners generate the final HTML, renderers generate template fragments.

Example:

# test.py
from breve import Template
from breve.tags.html import tags as T

def hello_renderer ( tag, data = None ):
    return tag [
        T.span ( style = 'font-weight: bold;' ) [ 'Hello, world!' ]
    ]

vars = dict ( 'hello_renderer', hello_renderer )

t = Template ( T, root = '.' )
print t.render ( vars )
# index.b
html [
    body [
        div ( render = hello_renderer )
    ]
]

This would output:

<html>
    <body>
        <div>
            <span style='font-weight: bold;'>Hello, world</span>
        </div>
    </body>
</html>

You'll notice, however, that the renderer can accept a second argument "data". You can pass any value or variable in here, for example:

# test.py
from breve import Template
from breve.tags.html import tags as T

def hello_renderer ( tag, data = None ):
    return tag [
        T.span ( style = 'font-weight: bold;' ) [ 'Hello, %s' % data ]
    ]

vars = dict ( hello_renderer = hello_renderer )
t = Template ( T, root = '.' )
print t.render ( vars )
# index.b
html [
    body [
        div ( render = hello_renderer, data = 'Joe' )
    ]
]

This would output:

<html>
    <body>
        <div>
            <span style='font-weight: bold;'>Hello, Joe</span>
        </div>
    </body>
</html>

Again, this is a very simple (and rather contrived) example, but these simple building blocks are quite powerful when combined in creative ways.

Custom Loaders

Brevé supports using custom loaders for finding and loading templates. A loader is a class that provides two methods, stat and load. stat accepts a template name and a root and returns a timestamp and a uid. In typical use, the timestamp reflects the last modification time of the template and the uid is a globally unique identifier for the template. In most cases the uid will simply be the full path to the template, but this is not required, it could just as well be the primary key from a database table or a even a URL. The only requirement is that it is globally unique for each template. The timestamp is also somewhat arbitrary in that it is only compared to the last timestamp returned by stat. This value is used for caching and determines whether the cached value will be returned or whether load will be called to fetch the template. If you wanted to completely bypass caching, you could simply return a sequence ( 1, 2, 3, ...) and the cache would be considered perpetually stale, forcing calls to load. The load method simply accepts the uid returned by the stat method and returns a string representing a Brevé template or fragment.

The default loader simply prepends the root to the requested template and tries to read it from the filesystem.

The following is a simple example that allows for templates to be searched for in multiple directories (i.e. a search path):

import os
from breve import Template
from breve.tags.html import tags

class PathLoader ( object ):
    __slots__ = [ 'paths' ]

    def __init__ ( self, *paths ):
        self.paths = paths

    def stat ( self, template, root ):
        for p in self.paths:
            f = os.path.join ( root, p, template )
            if os.path.isfile ( f ):
                timestamp = long ( os.stat ( f ).st_mtime )
                uid = f
                return uid, timestamp
        raise OSError, 'No such file or directory %s' % template

    def load ( self, uid ):

        return file ( uid, 'U' ).read ( )

loader = PathLoader ( 'path1', 'path2', 'path3', '' )
t = Template ( tags, root = root )
print t.render ( 'index', loader = loader )

The include directive also accepts a loader argument. This allows loaders to be mixed within the same template. Note that loaders are inherited. This means that if you include a template and specify a loader for that include directive, then the new loader will be in effect until the include directive finishes, at which point the prior loader will be restored. This means that if the included template also includes another template, the specified loader will be used to include this template as well. This is managed internally as a stack, so there is no limit to the number of loaders that can be called.

Back to Table of Contents

Standalone Operation

Rendering a Brevé template is a two-part operation: instantiation and rendering. Each stage has a few options that control the final output:

t = Template ( tags, root = '.', doctype = '', xmlns = '' )
print t.render ( template, vars = None )

Arguments

  • tags: a dictionary of legal entities.
  • root: the base directory prepended to all template references.
  • doctype: the XML DTD
  • xmlns: the XML namespace
  • template: the filename (sans extension) of the template to be rendered
  • vars: a dictionary or Namespace of variable names to provide in the template

Tags are a mapping of strings to flattenable objects. "Flattenable" means that there is either a flattener defined for the object type (using register_flattener ( )) or the object has a meaningful representation when calling str ( ) on it.

Namespace is simply a convenience object that presents both mapping and attribute access ( i.e. an item key can can be referenced in Namespace ns as ns [ 'key' ] or ns.key ).

Using Brevé tags outside a template:

It's also possible to simply create fragments of XML outside of a template (e.g. in Python's interactive interpreter):

Python 2.4.4 (#1, Oct 23 2006, 13:58:00)
[GCC 4.1.1 20061011 (Red Hat 4.1.1-30)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from breve.tags.html import tags as T
>>> print T.html [ T.body [ T.div [ 'this is a test' ] ] ]
<html><body><div>this is a test</div></body></html>
>>>

If you wanted to embed Brevé code in a standalone Python app (or perhaps a CGI), you could do something like this:

from breve.flatten import flatten
from breve.tags.html import tags
globals ( ).update ( tags )

template = html [
    head [
        title [ 'Example' ]
    ],

    body [
        div [ "We're using Brevé in a Python app." ]
    ]
]

print flatten ( template )

Note that while it's convenient to mash the Brevé tags into the global namespace, it's probably better to just use T or some other short name as in the previous example. There's enough HTML tags that could get stepped on by local variable (e.g. a, b, p) to make this not recommended (but still shown here for consenting adults).

Back to Table of Contents

The Brevé API

Function Reference

  • register_global ( name, variable|function ) This function takes a string name and registers it with the Brevé template as a global variable. This is a handy way to make sure that functions, renderers, etc are available application-wide without needing to explicictly pass them.
  • register_flattener ( type, function ) This function associates a Python type with a function that will render it as a string. There can only be one flattener per type.
  • util.escape ( string ) Escape &, <, and > in a string of data.

Instantiation-time Options

These options are passed to the Template class as arguments.

  • extension - The default extension for Brevé templates. Defaults to "b".
  • root - The base directory prepended to all template references (including inter-template references). Defaults to '.'
  • doctype - The HTML doctype. Defaults to the XHTML 1.0 Transitional doctype.
  • xml_encoding - The XML encoding of the output. Default is '<?xml version="1.0" encoding="UTF-8"?>'.
  • namespace - All variables passed into the template will be placed in a Namespace object with this name (e.g. a value of 'vars' would result in the variable foo being addressable as vars.foo or vars [ 'foo' ] within the template). Useful for avoiding name clashes with XML tags and template local variables or doing dynamic variable addressing. Default is None (disabled).
  • tidy - If the Python tidy library is installed, and this flag is True, then output is filtered through tidy prior to being returned. Default is False (disabled). It is currently recommended to not use this as Tidy significantly alters its input and as such isn't useful for debugging. A replacement is being worked on.

Render-time Options

These options are passed to a template object's render() method.

  • loader - This argument tells render() to use a custom loader.
  • format - This argument causes Brevé to attempt to import a Python module of the same name that contains custom tag definitions (see Creating New XML Tags for more details). Default is 'html'.

These values be passed as parameters or set directly on the breve.Template object prior to rendering:

from breve import Template
from breve.tags.html import tags

Template.tidy = True
Template.root = 'templates'

t = Template ( tags )

or as arguments:

from breve import Template
from breve.tags.html import tags

t = Template ( tags, root = 'templates', debug = False )
t.render ( mytemplate )

Further Notes

The Template object is only meant to be used a single time. Its primary purpose is to create a context (state) for evaluation of the template. Using a Template a second time can have unexpected results.

Back to Table of Contents

Escaping, Not Escaping

It's important to note that all plain strings in a Brevé template are automatically escaped. This means that if you want to output XML, you need to enclose it in an xml directive:

xml ( '''<b>this is bold</b>''' )

Custom flatteners, on the other hand, are assumed to output completely rendered XML. Therefore if you define a custom flattener, it is not automatically escaped and you should take care to escape any questionable content yourself using breve.tags.escape():

from breve.flatten import register_flattener
from breve.tags import escape

class Foo ( str ):
    content = '''<some unsafe content>'''

def flatten_foo ( o ):
    return escape ( o.content )
register_flattener ( Foo, flatten_foo )

Back to Table of Contents

edit page
Back to top
Rendered using Brevé 1.2.6Copyright © 2007, Cliff Wells