# -*- encoding: utf-8 -*- # Template language benchmarks # # Objective: Generate a 1000x10 HTML table as fast as possible. # # Author: Jonas Borgström from __future__ import print_function import cgi import sys import timeit from StringIO import StringIO from genshi.builder import tag from genshi.filters.i18n import Translator from genshi.filters.tests.i18n import DummyTranslations from genshi.template import MarkupTemplate, NewTextTemplate try: from elementtree import ElementTree as et except ImportError: et = None try: import cElementTree as cet except ImportError: cet = None try: import neo_cgi, neo_cs, neo_util except ImportError: neo_cgi = None try: import kid except ImportError: kid = None try: from django.conf import settings settings.configure() from django.template import Context as DjangoContext from django.template import Template as DjangoTemplate except ImportError: DjangoContext = DjangoTemplate = None try: from mako.template import Template as MakoTemplate except ImportError: MakoTemplate = None 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)] genshi_tmpl = MarkupTemplate("""
""") genshi_tmpl_i18n = MarkupTemplate("""
${c}
""") t = Translator(DummyTranslations()) t.setup(genshi_tmpl_i18n) genshi_tmpl2 = MarkupTemplate(""" $table
""") genshi_text_tmpl = NewTextTemplate(""" {% for row in table %} {% for c in row.values() %}{% end %} {% end %}
$c
""") if DjangoTemplate: django_tmpl = DjangoTemplate(""" {% for row in table %} {% for col in row.values %}{{ col|escape }}{% endfor %} {% endfor %}
""") def test_django(): """Djange template""" context = DjangoContext({'table': table}) django_tmpl.render(context) if MakoTemplate: mako_tmpl = MakoTemplate(""" % for row in table: % for col in row.values(): % endfor % endfor
${ col | h }
""") def test_mako(): """Mako Template""" mako_tmpl.render(table=table) def test_genshi(): """Genshi template""" stream = genshi_tmpl.generate(table=table) stream.render('html', strip_whitespace=False) def test_genshi_i18n(): """Genshi template w/ i18n""" stream = genshi_tmpl_i18n.generate(table=table) stream.render('html', strip_whitespace=False) def test_genshi_text(): """Genshi text template""" stream = genshi_text_tmpl.generate(table=table) stream.render('text') def test_genshi_builder(): """Genshi template + tag builder""" stream = tag.TABLE([ tag.tr([tag.td(c) for c in row.values()]) for row in table ]).generate() stream = genshi_tmpl2.generate(table=stream) stream.render('html', strip_whitespace=False) def test_builder(): """Genshi tag builder""" stream = tag.TABLE([ tag.tr([ tag.td(c) for c in row.values() ]) for row in table ]).generate() stream.render('html', strip_whitespace=False) if kid: kid_tmpl = kid.Template("""
""") kid_tmpl2 = kid.Template(""" $table """) def test_kid(): """Kid template""" kid_tmpl.table = table kid_tmpl.serialize(output='html') if cet: def test_kid_et(): """Kid template + cElementTree""" _table = cet.Element('table') for row in table: td = cet.SubElement(_table, 'tr') for c in row.values(): cet.SubElement(td, 'td').text=str(c) kid_tmpl2.table = _table kid_tmpl2.serialize(output='html') if et: def test_et(): """ElementTree""" _table = et.Element('table') for row in table: tr = et.SubElement(_table, 'tr') for c in row.values(): et.SubElement(tr, 'td').text=str(c) et.tostring(_table) if cet: def test_cet(): """cElementTree""" _table = cet.Element('table') for row in table: tr = cet.SubElement(_table, 'tr') for c in row.values(): cet.SubElement(tr, 'td').text=str(c) cet.tostring(_table) if neo_cgi: def test_clearsilver(): """ClearSilver""" hdf = neo_util.HDF() for i, row in enumerate(table): for j, c in enumerate(row.values()): hdf.setValue("rows.%d.cell.%d" % (i, j), cgi.escape(str(c))) cs = neo_cs.CS(hdf) cs.parseStr("""
""") cs.render() def run(which=None, number=10): tests = ['test_builder', 'test_genshi', 'test_genshi_i18n', 'test_genshi_text', 'test_genshi_builder', 'test_mako', 'test_kid', 'test_kid_et', 'test_et', 'test_cet', 'test_clearsilver', 'test_django'] if which: tests = filter(lambda n: n[5:] in which, tests) for test in [t for t in tests if hasattr(sys.modules[__name__], t)]: t = timeit.Timer(setup='from __main__ import %s;' % test, stmt='%s()' % test) time = t.timeit(number=number) / number if time < 0.00001: result = ' (not installed?)' else: result = '%16.2f ms' % (1000 * time) print('%-35s %s' % (getattr(sys.modules[__name__], test).__doc__, result)) if __name__ == '__main__': which = [arg for arg in sys.argv[1:] if arg[0] != '-'] if '-p' in sys.argv: import cProfile, pstats prof = cProfile.Profile() prof.run('run(%r, number=1)' % which) stats = pstats.Stats(prof) stats.strip_dirs() stats.sort_stats('time', 'calls') stats.print_stats(25) if '-v' in sys.argv: stats.print_callees() stats.print_callers() else: run(which)