blob: 15830a0b728d4411aeb7f09120030457f9f4f6f3 [file] [log] [blame]
Armin Ronacher32a910f2008-04-26 23:21:03 +02001"""\
Armin Ronacher2feed1d2008-04-26 16:26:52 +02002 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
Armin Ronacher32a910f2008-04-26 23:21:03 +02004 template. If a template engine is not installed the test is skipped.\
Armin Ronacher2feed1d2008-04-26 16:26:52 +02005"""
Armin Ronacherde6bf712008-04-26 01:44:14 +02006import sys
Armin Ronacher32a910f2008-04-26 23:21:03 +02007import cgi
Armin Ronacher00d5d212008-04-13 01:10:18 +02008from timeit import Timer
Armin Ronacher2feed1d2008-04-26 16:26:52 +02009from jinja2 import Environment as JinjaEnvironment
Armin Ronacher449167d2008-04-11 17:55:05 +020010
Armin Ronacherde6bf712008-04-26 01:44:14 +020011context = {
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)]
14}
Armin Ronacher449167d2008-04-11 17:55:05 +020015
Armin Ronacher00d5d212008-04-13 01:10:18 +020016jinja_template = JinjaEnvironment(
17 line_statement_prefix='%',
18 variable_start_string="${",
19 variable_end_string="}"
20).from_string("""\
21<!doctype html>
22<html>
23 <head>
Armin Ronacherde6bf712008-04-26 01:44:14 +020024 <title>${page_title|e}</title>
Armin Ronacher00d5d212008-04-13 01:10:18 +020025 </head>
26 <body>
27 <div class="header">
28 <h1>${page_title|e}</h1>
29 </div>
30 <ul class="navigation">
31 % for href, caption in [
32 ('index.html', 'Index'),
33 ('downloads.html', 'Downloads'),
34 ('products.html', 'Products')
35 ]
36 <li><a href="${href|e}">${caption|e}</a></li>
37 % endfor
38 </ul>
39 <div class="table">
40 <table>
41 % for row in table
42 <tr>
43 % for cell in row
44 <td>${cell}</td>
45 % endfor
46 </tr>
47 % endfor
48 </table>
49 </div>
50 </body>
51</html>\
Armin Ronacher449167d2008-04-11 17:55:05 +020052""")
Armin Ronacher00d5d212008-04-13 01:10:18 +020053
Armin Ronacher2feed1d2008-04-26 16:26:52 +020054def test_jinja():
55 jinja_template.render(context)
56
57try:
58 from django.conf import settings
59 settings.configure()
60 from django.template import Template as DjangoTemplate, Context as DjangoContext
61except ImportError:
62 test_django = None
63else:
64 django_template = DjangoTemplate("""\
Armin Ronacher00d5d212008-04-13 01:10:18 +020065<!doctype html>
66<html>
67 <head>
Armin Ronacherde6bf712008-04-26 01:44:14 +020068 <title>{{ page_title }}</title>
Armin Ronacher00d5d212008-04-13 01:10:18 +020069 </head>
70 <body>
71 <div class="header">
72 <h1>{{ page_title }}</h1>
73 </div>
74 <ul class="navigation">
75 {% for href, caption in navigation %}
76 <li><a href="{{ href }}">{{ caption }}</a></li>
77 {% endfor %}
78 </ul>
79 <div class="table">
80 <table>
81 {% for row in table %}
82 <tr>
83 {% for cell in row %}
84 <td>{{ cell }}</td>
85 {% endfor %}
86 </tr>
87 {% endfor %}
88 </table>
89 </div>
90 </body>
91</html>\
92""")
93
Armin Ronacher2feed1d2008-04-26 16:26:52 +020094 def test_django():
95 c = DjangoContext(context)
96 c['navigation'] = [('index.html', 'Index'), ('downloads.html', 'Downloads'),
97 ('products.html', 'Products')]
98 django_template.render(c)
99
100try:
101 from mako.template import Template as MakoTemplate
102except ImportError:
103 test_mako = None
104else:
105 mako_template = MakoTemplate("""\
Armin Ronacher00d5d212008-04-13 01:10:18 +0200106<!doctype html>
107<html>
108 <head>
Armin Ronacherde6bf712008-04-26 01:44:14 +0200109 <title>${page_title|h}</title>
Armin Ronacher00d5d212008-04-13 01:10:18 +0200110 </head>
111 <body>
112 <div class="header">
113 <h1>${page_title|h}</h1>
114 </div>
115 <ul class="navigation">
116 % for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
117 <li><a href="${href|h}">${caption|h}</a></li>
118 % endfor
119 </ul>
120 <div class="table">
121 <table>
122 % for row in table:
123 <tr>
124 % for cell in row:
125 <td>${cell}</td>
126 % endfor
127 </tr>
128 % endfor
129 </table>
130 </div>
131 </body>
132</html>\
133""")
134
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200135 def test_mako():
136 mako_template.render(**context)
137
138try:
139 from genshi.template import MarkupTemplate as GenshiTemplate
140except ImportError:
141 test_genshi = None
142else:
143 genshi_template = GenshiTemplate("""\
Armin Ronacherde6bf712008-04-26 01:44:14 +0200144<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
145 <head>
146 <title>${page_title}</title>
147 </head>
148 <body>
149 <div class="header">
150 <h1>${page_title}</h1>
151 </div>
152 <ul class="navigation">
153 <li py:for="href, caption in [
154 ('index.html', 'Index'),
155 ('downloads.html', 'Downloads'),
156 ('products.html', 'Products')]"><a href="${href}">${caption}</a></li>
157 </ul>
158 <div class="table">
159 <table>
160 <tr py:for="row in table">
161 <td py:for="cell in row">${cell}</td>
162 </tr>
163 </table>
164 </div>
165 </body>
166</html>\
167""")
168
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200169 def test_genshi():
170 genshi_template.generate(**context).render('html', strip_whitespace=False)
171
172try:
173 from Cheetah.Template import Template as CheetahTemplate
174except ImportError:
175 test_cheetah = None
176else:
177 cheetah_template = CheetahTemplate("""\
Armin Ronacherde6bf712008-04-26 01:44:14 +0200178#import cgi
179<!doctype html>
180<html>
181 <head>
182 <title>$cgi.escape($page_title)</title>
183 </head>
184 <body>
185 <div class="header">
186 <h1>$cgi.escape($page_title)</h1>
187 </div>
188 <ul class="navigation">
189 #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
190 <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
191 #end for
192 </ul>
193 <div class="table">
194 <table>
195 #for $row in $table:
196 <tr>
197 #for $cell in $row:
198 <td>$cell</td>
199 #end for
200 </tr>
201 #end for
202 </table>
203 </div>
204 </body>
205</html>\
206""", searchList=[dict(context)])
Armin Ronacher00d5d212008-04-13 01:10:18 +0200207
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200208 def test_cheetah():
209 unicode(cheetah_template)
Armin Ronacher00d5d212008-04-13 01:10:18 +0200210
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200211try:
212 import tenjin
213except ImportError:
214 test_tenjin = None
215else:
216 tenjin_template = tenjin.Template()
217 tenjin_template.convert("""\
218<!doctype html>
219<html>
220 <head>
221 <title>${page_title}</title>
222 </head>
223 <body>
224 <div class="header">
225 <h1>${page_title}</h1>
226 </div>
227 <ul class="navigation">
228<?py for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]: ?>
229 <li><a href="${href}">${caption}</a></li>
230<?py #end ?>
231 </ul>
232 <div class="table">
233 <table>
234<?py for row in table: ?>
235 <tr>
236<?py for cell in row: ?>
237 <td>#{cell}</td>
238<?py #end ?>
239 </tr>
240<?py #end ?>
241 </table>
242 </div>
243 </body>
244</html>\
245""")
Armin Ronacher00d5d212008-04-13 01:10:18 +0200246
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200247 def test_tenjin():
248 from tenjin.helpers import escape, to_str
249 tenjin_template.render(context, locals())
Armin Ronacher00d5d212008-04-13 01:10:18 +0200250
Armin Ronacher32a910f2008-04-26 23:21:03 +0200251try:
252 from spitfire.compiler import util as SpitfireTemplate
253 from spitfire.compiler.analyzer import o2_options as spitfire_optimizer
254except ImportError:
255 test_spitfire = None
256else:
257 spitfire_template = SpitfireTemplate.load_template("""\
258<!doctype html>
259<html>
260 <head>
261 <title>$cgi.escape($page_title)</title>
262 </head>
263 <body>
264 <div class="header">
265 <h1>$cgi.escape($page_title)</h1>
266 </div>
267 <ul class="navigation">
268 #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]
269 <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
270 #end for
271 </ul>
272 <div class="table">
273 <table>
274 #for $row in $table
275 <tr>
276 #for $cell in $row
277 <td>$cell</td>
278 #end for
279 </tr>
280 #end for
281 </table>
282 </div>
283 </body>
284</html>\
285""", 'spitfire_tmpl', spitfire_optimizer, {'enable_filters': False})
286 spitfire_context = dict(context, **{'cgi': cgi})
287
288 def test_spitfire():
289 spitfire_template(search_list=[spitfire_context]).main()
290
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200291sys.stdout.write('\r' + '\n'.join((
Armin Ronacherde6bf712008-04-26 01:44:14 +0200292 '=' * 80,
293 'Template Engine BigTable Benchmark'.center(80),
Armin Ronacher32a910f2008-04-26 23:21:03 +0200294 '=' * 80,
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200295 __doc__,
Armin Ronacherde6bf712008-04-26 01:44:14 +0200296 '-' * 80
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200297)) + '\n')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200298for test in 'jinja', 'tenjin', 'mako', 'spitfire', 'django', 'genshi', 'cheetah':
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200299 if locals()['test_' + test] is None:
Armin Ronacher32a910f2008-04-26 23:21:03 +0200300 sys.stdout.write(' %-20s*not installed*\n' % test)
Armin Ronacher2feed1d2008-04-26 16:26:52 +0200301 continue
Armin Ronacher00d5d212008-04-13 01:10:18 +0200302 t = Timer(setup='from __main__ import test_%s as bench' % test,
303 stmt='bench()')
Armin Ronacher32a910f2008-04-26 23:21:03 +0200304 sys.stdout.write(' >> %-20s<running>' % test)
Armin Ronacherde6bf712008-04-26 01:44:14 +0200305 sys.stdout.flush()
Armin Ronacher32a910f2008-04-26 23:21:03 +0200306 sys.stdout.write('\r %-20s%.4f seconds\n' % (test, t.timeit(number=20) / 20))
307sys.stdout.write('-' * 80 + '\n')
308sys.stdout.write('''\
309 WARNING: The results of this benchmark are useless to compare the
310 performance of template engines and should not be taken seriously in any
311 way. It's testing the performance of simple loops and has no real-world
312 usefulnes. It only used to check if changes on the Jinja code affect
313 performance in a good or bad way and how it roughly compares to others.
314''' + '=' * 80 + '\n')