Name your single favorite Python templating engine (and describe why it's your favorite).
Nice syntax, good customization possibilities.
Integrates well. Can be sandboxed, so you don't have to trust completely your template authors. (Mako can't).
It is also pretty fast, with the bonus of compiling your template to bytecode and cache it, as in the demonstration below:
>>> import jinja2
>>> print jinja2.Environment().compile('{% for row in data %}{{ row.name | upper }}{% endfor %}', raw=True)
from __future__ import division
from jinja2.runtime import LoopContext, Context, TemplateReference, Macro, Markup, TemplateRuntimeError, missing, concat, escape, markup_join, unicode_join
name = None
def root(context, environment=environment):
l_data = context.resolve('data')
t_1 = environment.filters['upper']
if 0: yield None
for l_row in l_data:
if 0: yield None
yield unicode(t_1(environment.getattr(l_row, 'name')))
blocks = {}
debug_info = '1=9'
This code has been generated on the fly by Jinja2. Of course the compiler optmizes it further (e.g. removing if 0: yield None
)
Django templates if you're using Django or AppEngine. They way the templating engine and syntax is constructed, it's very hard to do any code in the template layer (that's a good thing). Every time I thought I was running up against a wall in Django's templates, it's because I was trying to do something wrong that I'd carried over from a more liberal templating language.
I'd also look at Jinja2, its a superset of Django's templates, and therefore contains a lot more "powerful" syntax, which would be good or bad depending on how you look at it.
I've also used Cheetah, but once you go Django, you never go back :)
I should mention I don't like stuff like Genshi which restrict you to an XML document because its pretty inflexible when you try to do stuff that's not XML (i.e. emails, PDFs, and so forth).
Genshi. XML-based, which means your document has structure that can be manipulated rather than being an opaque string to be outputted. This enables powerful filters to be written that don't rely on regexp mangling.
It uses standard XInclude rather than custom include syntax. You can refer to other parts of the document with XPath. You can output HTML 4.01, XHTML 1.0, etc.
To sample the syntax, loops look like:
<ul>
<li py:for="item in list">${item}</li>
</ul>
By default it escapes variables so you are safe from XSS attacks, and being XML-based, all output is well-formed.
It is not sandboxable yet, although there is an experimental branch that allows this.
Unlike many other template engines, it supports real Python expressions and doesn't try to stop you from doing anything. In theory, this allows you to write spaghetti code that entangles the business logic with the presentation, which is why some other template engines restrict you from doing things. In practice, this doesn't happen. Genshi treats you like an adult who can make his own decisions, much like the way Python treats you like an adult by not having private members etc.
It has good internationalisation and localisation support, being developed by the same people who work on Babel. It also hooks into standard XML syntax, e.g. xml:lang
rather than reinventing its own syntax.
There is persistent FUD coming from the Django camp saying that Genshi is no good for non-markup output. This is simply false, in fact the use of XML makes supporting other file formats easier. For instance, I've used Genshi to generate MIME emails with attachments, multiple parts, plain text fallbacks, etc, which was made tremendously easier by the fact that I could hook into the template structure. You can't do that with a plain text system.
And of course, if you do find an advantage to using plain text, Genshi also has a plain-text variant that can be used. For instance, I store server configuration in a database, and use Genshi's plaintext mode to generate server config files.
Benchmarks comparing Genshi performance to other template engines are available on the Genshi website. Note that text mode is significantly faster than XML mode, but XML mode still performs respectably.
I'm a fan of Django's default templating system for its ease and simplicity.
Single favorite: Mako. Recently, I used Mako templates to build unit test code. The users provided the test results in spreadsheets. I used Mako to generate the Java Junit test code from the spreadsheets. Mako was easy to install and use.
I use Django a lot, but I don't have the patience to work out how to use it separately from the rest of the framework.
My favorite templating engine is python itself. For example,
def index(title, content):
return """
<html>
<head>
<title>%(title)s</title>
</head>
<body>
%(content)s
</body>
</html>
""" % {'title':title, 'content':content}
def hello(name):
return "hello %s!" % name
Nice and easy, huh?
Seconding Mako. It's dead simple to set up. For most uses, this is all the code you need:
import mako.lookup
template_lookup = mako.lookup.TemplateLookup(
directories=['/path/to/templates'], output_encoding='utf-8')
template = template_lookup.get_template('some_template.html')
rendered = template.render(c=SomeContextObject)
I really enjoyed using Cheetah. I liked that you could compile the templates and just populate it easily.
Nevow, of course.
from nevow.page import Element, renderer
from nevow.flat import flatten
from nevow.loaders import stan
from nevow.tags import html, head, title, body, div, directive
class MyElement(Element):
docFactory = stan(html[
head[title["Hello, World!"]], "\n",
body[div(render=directive("message"))]])
@renderer
def message(self, request, tag):
tag["Hello, world!"]
return tag
print flatten(MyElement())
Nevow has a number of unusual advantages:
- Use Python syntax, XML templates, or tag soup. It's all the same data structures internally.
- No code embedded in your templates. You write all your code in a real programming language (it doesn't break your debugger, your profiler, etc), but you aren't forced to write elaborate code/data bindings to make up for that. If you want to quickly inline a chunk of template in your code it's really
tags.strong["quite"]
convenient. - It's the only templating system that natively supports Twisted. Return a
Deferred
from your renderer if you want. It'll work. - Correct handling of unicode, and correct escaping of HTML entities. You don't have to think about it! If you
return "<>"
from a function, Nevow knows you meant the text less-than-sign greater-than-sign, not broken markup. - Templates can be optimized for precompilation, glomming together all non-dynamic elements at startup time rather than every render - all transparently to your application.
The main attraction, of course, is the included COMET server and JavaScript module system. You can freely inter-call between Python and JavaScript, and it's really easy:
from twisted.internet import reactor
from nevow.athena import LiveElement
class MyElement(LiveElement):
docFactory = stan(div(render=directive('liveElement')))
def ping(self, message):
reactor.callLater(5.0, self.callRemote, "pong", message)
but even if all you need to output is vanilla HTML, it can be quite nice.
I think there is no "single" template engine for Python. You have to decide that by checking your requirements. You do not work with the Django Framework? Then rule out the Django Template Engine. Do you have template designers that are not programmers or maybe not trustable (user submitted templates)? Give Jinja2 a try. Do you want to embedd the full power of Python in your templates? Mako is the engine of choice then. Are you processing XML stuff? Genshi can do that.
There are more exotic templating engines like nevow or that Markaby inspired one where I forgot the name. Cheetah/kit/TAL exist too, but they don't have any real advantages over the newer template engines listed above.
The web2py templating engine is full Python without indentation requirements (use pass
to close blocks). Example:
{{extend 'layout.html'}}
<table>
{{for i in range(10):}}
<tr><td>{{=i}}</td></tr>
{{pass}}
</table>
It also has powerful helpers:
{{extend 'layout.html'}}
<table>
{{for k,link in enumerate(['http://www.google.com']):}}
{{=TR(TD(A(link,_href=link)),_class='odd' if k%2 else 'odd')}}
{{pass}}
</table>
There IS a single Python templating engine: StringTemplate. If you need something more than Python itself (use it when you can), then there is no substitute. Check out http://www.cs.usfca.edu/~parrt/papers/mvc.templates.pdf for details of why.
And use it for other platforms, too. I have used StringTemplate on Python, Java, and .Net for years, and I have used many alternatives. I see no need to ever use anything else, nor can I even imagine that there could be a superior solution (no kidding). That design decision is done for me.
Evoque of course: best simplicity-to-power ratio, one of the few systems that can offer sandboxed execution, possibly the fastest pure-python templating engine, small codebase, runs also on python 3, ...
As a variation on the string formatting suggestion above from Kevin Holzer, here's a pretty clever hack that I found from some folks who needed to generate some KML snippets: (their code)
I hate having to edit in-line html where I can't use indenting to keep track of the structure of what I'm doing, so I found it quite handy for generating little blobs of html that had to be inserted somewhere.
Using a regex for the whitespace and **kwargs for your dictionary:
def T( text, **values ):
return re.sub( '(^\n*|\n+)[ \t]*', '', text % values )
Then you can do something like this:
T("""
<div class="record">
<div class="image">
<img width=%(width)d height=%(height)d src="%(path)s" />
<div class="name">Title: %(title)s</div>
<div class="photog">Photographer: %(photographer)s</div>
</div>
</div>
""",
path = "/some/path/to/image.jpg",
width = 400,
height = 600,
title = "Some Title",
photographer = "Jane Doe"
)
NB: Python 3 (backported to 2.6) has got: str.format(*args, **kwargs)