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 = """\
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 # recompile template each rendering because that's what django
141 # is doing in normal situations too. Django is not thread safe
142 # so we can't cache it in regular apps either.
143 DjangoTemplate(django_template).render(c)
146 from mako.template import Template as MakoTemplate
150 mako_template = MakoTemplate("""\
154 <title>${page_title|h}</title>
158 <h1>${page_title|h}</h1>
160 <ul class="navigation">
161 % for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
162 <li><a href="${href|h}">${caption|h}</a></li>
181 mako_template.render(**context)
184 from genshi.template import MarkupTemplate as GenshiTemplate
188 genshi_template = GenshiTemplate("""\
189 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
191 <title>${page_title}</title>
195 <h1>${page_title}</h1>
197 <ul class="navigation">
198 <li py:for="href, caption in [
199 ('index.html', 'Index'),
200 ('downloads.html', 'Downloads'),
201 ('products.html', 'Products')]"><a href="${href}">${caption}</a></li>
205 <tr py:for="row in table">
206 <td py:for="cell in row">${cell}</td>
215 genshi_template.generate(**context).render('html', strip_whitespace=False)
218 from Cheetah.Template import Template as CheetahTemplate
222 cheetah_template = CheetahTemplate("""\
227 <title>$cgi.escape($page_title)</title>
231 <h1>$cgi.escape($page_title)</h1>
233 <ul class="navigation">
234 #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
235 <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
251 """, searchList=[dict(context)])
254 unicode(cheetah_template)
261 tenjin_template = tenjin.Template()
262 tenjin_template.convert("""\
266 <title>${page_title}</title>
270 <h1>${page_title}</h1>
272 <ul class="navigation">
273 <?py for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]: ?>
274 <li><a href="${href}">${caption}</a></li>
279 <?py for row in table: ?>
281 <?py for cell in row: ?>
293 from tenjin.helpers import escape, to_str
294 tenjin_template.render(context, locals())
297 from spitfire.compiler import util as SpitfireTemplate
298 from spitfire.compiler.analyzer import o2_options as spitfire_optimizer
302 spitfire_template = SpitfireTemplate.load_template("""\
306 <title>$cgi.escape($page_title)</title>
310 <h1>$cgi.escape($page_title)</h1>
312 <ul class="navigation">
313 #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]
314 <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
330 """, 'spitfire_tmpl', spitfire_optimizer, {'enable_filters': False})
331 spitfire_context = dict(context, **{'cgi': cgi})
334 spitfire_template(search_list=[spitfire_context]).main()
336 sys.stdout.write('\r' + '\n'.join((
338 'Template Engine BigTable Benchmark'.center(80),
345 for test in 'jinja', 'mako', 'tornado', 'tenjin', 'spitfire', 'django', 'genshi', 'cheetah':
346 if locals()['test_' + test] is None:
347 sys.stdout.write(' %-20s*not installed*\n' % test)
349 t = Timer(setup='from __main__ import test_%s as bench' % test,
351 sys.stdout.write(' >> %-20s<running>' % test)
353 sys.stdout.write('\r %-20s%.4f seconds\n' % (test, t.timeit(number=50) / 50))
354 sys.stdout.write('-' * 80 + '\n')
355 sys.stdout.write('''\
356 WARNING: The results of this benchmark are useless to compare the
357 performance of template engines and should not be taken seriously in any
358 way. It's testing the performance of simple loops and has no real-world
359 usefulnes. It only used to check if changes on the Jinja code affect
360 performance in a good or bad way and how it roughly compares to others.
361 ''' + '=' * 80 + '\n')