2 This benchmark compares some python templating engines with Jinja 2 so
3 that we get a picture of how fast Jinja 2 is for a semi real world
4 template. If a template engine is not installed the test is skipped.\
8 from timeit import Timer
9 from jinja2 import Environment as JinjaEnvironment
12 'page_title': 'mitsuhiko\'s benchmark',
13 'table': [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10) for x in range(1000)]
16 jinja_template = JinjaEnvironment(
17 line_statement_prefix='%',
18 variable_start_string="${",
19 variable_end_string="}"
24 <title>${page_title|e}</title>
28 <h1>${page_title|e}</h1>
30 <ul class="navigation">
31 % for href, caption in [
32 ('index.html', 'Index'),
33 ('downloads.html', 'Downloads'),
34 ('products.html', 'Products')
36 <li><a href="${href|e}">${caption|e}</a></li>
55 jinja_template.render(context)
58 from tornado.template import Template
62 tornado_template = Template("""\
66 <title>{{ page_title }}</title>
70 <h1>{{ page_title }}</h1>
72 <ul class="navigation">
73 {% for href, caption in [ \
74 ('index.html', 'Index'), \
75 ('downloads.html', 'Downloads'), \
76 ('products.html', 'Products') \
78 <li><a href="{{ href }}">{{ caption }}</a></li>
83 {% for row in table %}
97 tornado_template.generate(**context)
100 from django.conf import settings
102 from django.template import Template as DjangoTemplate, Context as DjangoContext
106 django_template = DjangoTemplate("""\
110 <title>{{ page_title }}</title>
114 <h1>{{ page_title }}</h1>
116 <ul class="navigation">
117 {% for href, caption in navigation %}
118 <li><a href="{{ href }}">{{ caption }}</a></li>
123 {% for row in table %}
125 {% for cell in row %}
137 c = DjangoContext(context)
138 c['navigation'] = [('index.html', 'Index'), ('downloads.html', 'Downloads'),
139 ('products.html', 'Products')]
140 django_template.render(c)
143 from mako.template import Template as MakoTemplate
147 mako_template = MakoTemplate("""\
151 <title>${page_title|h}</title>
155 <h1>${page_title|h}</h1>
157 <ul class="navigation">
158 % for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
159 <li><a href="${href|h}">${caption|h}</a></li>
178 mako_template.render(**context)
181 from genshi.template import MarkupTemplate as GenshiTemplate
185 genshi_template = GenshiTemplate("""\
186 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
188 <title>${page_title}</title>
192 <h1>${page_title}</h1>
194 <ul class="navigation">
195 <li py:for="href, caption in [
196 ('index.html', 'Index'),
197 ('downloads.html', 'Downloads'),
198 ('products.html', 'Products')]"><a href="${href}">${caption}</a></li>
202 <tr py:for="row in table">
203 <td py:for="cell in row">${cell}</td>
212 genshi_template.generate(**context).render('html', strip_whitespace=False)
215 from Cheetah.Template import Template as CheetahTemplate
219 cheetah_template = CheetahTemplate("""\
224 <title>$cgi.escape($page_title)</title>
228 <h1>$cgi.escape($page_title)</h1>
230 <ul class="navigation">
231 #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
232 <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
248 """, searchList=[dict(context)])
251 unicode(cheetah_template)
258 tenjin_template = tenjin.Template()
259 tenjin_template.convert("""\
263 <title>${page_title}</title>
267 <h1>${page_title}</h1>
269 <ul class="navigation">
270 <?py for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]: ?>
271 <li><a href="${href}">${caption}</a></li>
276 <?py for row in table: ?>
278 <?py for cell in row: ?>
290 from tenjin.helpers import escape, to_str
291 tenjin_template.render(context, locals())
294 from spitfire.compiler import util as SpitfireTemplate
295 from spitfire.compiler.analyzer import o2_options as spitfire_optimizer
299 spitfire_template = SpitfireTemplate.load_template("""\
303 <title>$cgi.escape($page_title)</title>
307 <h1>$cgi.escape($page_title)</h1>
309 <ul class="navigation">
310 #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]
311 <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
327 """, 'spitfire_tmpl', spitfire_optimizer, {'enable_filters': False})
328 spitfire_context = dict(context, **{'cgi': cgi})
331 spitfire_template(search_list=[spitfire_context]).main()
335 from chameleon.zpt.template import PageTemplate
337 test_chameleon = None
339 chameleon_template = PageTemplate("""\
340 <html xmlns:tal="http://xml.zope.org/namespaces/tal">
342 <title tal:content="page_title">Page Title</title>
346 <h1 tal:content="page_title">Page Title</h1>
348 <ul class="navigation">
349 <li tal:repeat="item sections"><a tal:attributes="href item[0]" tal:content="item[1]">caption</a></li>
353 <tr tal:repeat="row table">
354 <td tal:repeat="cell row" tal:content="row[cell]">cell</td>
361 chameleon_context = dict(context)
362 chameleon_context['sections'] = [
363 ('index.html', 'Index'),
364 ('downloads.html', 'Downloads'),
365 ('products.html', 'Products')
367 def test_chameleon():
368 chameleon_template.render(**chameleon_context)
371 from chameleon.zpt.template import PageTemplate
372 from chameleon.genshi import language
374 test_chameleon_genshi = None
376 chameleon_genshi_template = PageTemplate("""\
377 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
379 <title>${page_title}</title>
383 <h1>${page_title}</h1>
385 <ul class="navigation">
386 <li py:for="info in sections"><a href="${info[0]}">${info[1]}</a></li>
390 <tr py:for="row in table">
391 <td py:for="cell in row">${row[cell]}</td>
397 """, parser=language.Parser())
398 chameleon_genshi_context = dict(context)
399 chameleon_genshi_context['sections'] = [
400 ('index.html', 'Index'),
401 ('downloads.html', 'Downloads'),
402 ('products.html', 'Products')
404 def test_chameleon_genshi():
405 chameleon_genshi_template.render(**chameleon_genshi_context)
408 sys.stdout.write('\r' + '\n'.join((
410 'Template Engine BigTable Benchmark'.center(80),
417 for test in 'jinja', 'mako', 'tornado', 'tenjin', 'spitfire', 'django', 'genshi', 'cheetah', 'chameleon', 'chameleon_genshi':
418 if locals()['test_' + test] is None:
419 sys.stdout.write(' %-20s*not installed*\n' % test)
421 t = Timer(setup='from __main__ import test_%s as bench' % test,
423 sys.stdout.write(' >> %-20s<running>' % test)
425 sys.stdout.write('\r %-20s%.4f seconds\n' % (test, t.timeit(number=50) / 50))
426 sys.stdout.write('-' * 80 + '\n')
427 sys.stdout.write('''\
428 WARNING: The results of this benchmark are useless to compare the
429 performance of template engines and should not be taken seriously in any
430 way. It's testing the performance of simple loops and has no real-world
431 usefulnes. It only used to check if changes on the Jinja code affect
432 performance in a good or bad way and how it roughly compares to others.
433 ''' + '=' * 80 + '\n')