Armin Ronacher | ed03db5 | 2007-02-28 22:39:44 +0100 | [diff] [blame] | 1 | # -*- coding: utf-8 -*_ |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 2 | # Template language benchmarks |
| 3 | # |
| 4 | # Objective: Generate a 1000x10 HTML table as fast as possible. |
| 5 | # adapted for jinja 1 |
| 6 | # |
| 7 | # Author: Jonas Borgström <jonas@edgewall.com> |
| 8 | # Author: Armin Ronacher <armin.ronacher@active-4.com> |
| 9 | |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame^] | 10 | import os |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 11 | import sys |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame^] | 12 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) |
| 13 | |
| 14 | import cgi |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 15 | import timeit |
Armin Ronacher | 5adf94f | 2007-03-29 22:11:59 +0200 | [diff] [blame] | 16 | import jdebug |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 17 | from StringIO import StringIO |
| 18 | |
Armin Ronacher | 1cc232c | 2007-09-07 17:52:41 +0200 | [diff] [blame^] | 19 | |
Armin Ronacher | ccf284b | 2007-05-21 16:44:26 +0200 | [diff] [blame] | 20 | try: |
| 21 | from genshi.builder import tag |
| 22 | from genshi.template import MarkupTemplate |
| 23 | have_genshi = True |
| 24 | except ImportError: |
| 25 | have_genshi = False |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 26 | |
| 27 | from jinja import Environment |
| 28 | |
Alexander Schremmer | 303a7e4 | 2007-02-28 22:44:14 +0100 | [diff] [blame] | 29 | try: |
| 30 | from django.conf import settings |
| 31 | settings.configure() |
| 32 | from django.template import Context as DjangoContext |
| 33 | from django.template import Template as DjangoTemplate |
| 34 | have_django = True |
| 35 | except ImportError: |
| 36 | have_django = False |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 37 | |
Armin Ronacher | e98c5f5 | 2007-04-21 09:39:06 +0200 | [diff] [blame] | 38 | try: |
| 39 | from kid import Template as KidTemplate |
| 40 | have_kid = True |
| 41 | except ImportError: |
| 42 | have_kid = False |
| 43 | |
Armin Ronacher | ccf284b | 2007-05-21 16:44:26 +0200 | [diff] [blame] | 44 | try: |
| 45 | from Cheetah.Template import Template as CheetahTemplate |
| 46 | have_cheetah = True |
| 47 | except ImportError: |
| 48 | have_cheetah = False |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 49 | |
Alexander Schremmer | 303a7e4 | 2007-02-28 22:44:14 +0100 | [diff] [blame] | 50 | try: |
| 51 | from mako.template import Template as MakoTemplate |
| 52 | have_mako = True |
| 53 | except ImportError: |
| 54 | have_mako = False |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 55 | |
Armin Ronacher | fb5bebc | 2007-04-27 18:24:19 +0200 | [diff] [blame] | 56 | table = [dict(zip('abcdefghij', map(unicode,range(1, 11)))) |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 57 | for x in range(1000)] |
| 58 | |
Armin Ronacher | ccf284b | 2007-05-21 16:44:26 +0200 | [diff] [blame] | 59 | if have_genshi: |
| 60 | genshi_tmpl = MarkupTemplate(""" |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 61 | <table xmlns:py="http://genshi.edgewall.org/"> |
| 62 | <tr py:for="row in table"> |
| 63 | <td py:for="c in row.values()" py:content="c"/> |
| 64 | </tr> |
| 65 | </table> |
| 66 | """) |
| 67 | |
Armin Ronacher | e98c5f5 | 2007-04-21 09:39:06 +0200 | [diff] [blame] | 68 | if have_kid: |
| 69 | kid_tmpl = KidTemplate(""" |
| 70 | <table xmlns:py="http://purl.org/kid/ns#"> |
| 71 | <tr py:for="row in table"> |
| 72 | <td py:for="c in row.values()" py:content="c"/> |
| 73 | </tr> |
| 74 | </table> |
| 75 | """) |
| 76 | |
Alexander Schremmer | 303a7e4 | 2007-02-28 22:44:14 +0100 | [diff] [blame] | 77 | if have_django: |
| 78 | django_tmpl = DjangoTemplate(""" |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 79 | <table> |
| 80 | {% for row in table %} |
Armin Ronacher | e98c5f5 | 2007-04-21 09:39:06 +0200 | [diff] [blame] | 81 | <tr>{% for col in row.values %}<td>{{ col }}</td>{% endfor %}</tr> |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 82 | {% endfor %} |
| 83 | </table> |
| 84 | """) |
| 85 | |
| 86 | jinja_tmpl = Environment().from_string(''' |
| 87 | <table> |
Armin Ronacher | 5adf94f | 2007-03-29 22:11:59 +0200 | [diff] [blame] | 88 | {% for row in table -%} |
Armin Ronacher | e98c5f5 | 2007-04-21 09:39:06 +0200 | [diff] [blame] | 89 | <tr>{% for col in row.values() %}<td>{{ col }}</td>{% endfor %}</tr> |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 90 | {% endfor %} |
| 91 | </table> |
| 92 | ''') |
| 93 | |
Armin Ronacher | ccf284b | 2007-05-21 16:44:26 +0200 | [diff] [blame] | 94 | if have_cheetah: |
| 95 | cheetah_tmpl = CheetahTemplate(''' |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 96 | <table> |
| 97 | #for $row in $table |
| 98 | <tr> |
| 99 | #for $col in $row.values() |
Armin Ronacher | e98c5f5 | 2007-04-21 09:39:06 +0200 | [diff] [blame] | 100 | <td>$col</td> |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 101 | #end for |
| 102 | </tr> |
| 103 | #end for |
| 104 | </table> |
| 105 | ''', searchList=[{'table': table, 'escape': cgi.escape}]) |
| 106 | |
Alexander Schremmer | 303a7e4 | 2007-02-28 22:44:14 +0100 | [diff] [blame] | 107 | if have_mako: |
| 108 | mako_tmpl = MakoTemplate(''' |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 109 | <table> |
| 110 | % for row in table: |
| 111 | <tr> |
| 112 | % for col in row.values(): |
Armin Ronacher | e98c5f5 | 2007-04-21 09:39:06 +0200 | [diff] [blame] | 113 | <td>${col}</td> |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 114 | % endfor |
| 115 | </tr> |
| 116 | % endfor |
| 117 | </table> |
| 118 | ''') |
| 119 | |
| 120 | def test_django(): |
| 121 | """Django Templates""" |
Alexander Schremmer | 303a7e4 | 2007-02-28 22:44:14 +0100 | [diff] [blame] | 122 | if not have_django: |
| 123 | return |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 124 | context = DjangoContext({'table': table}) |
| 125 | django_tmpl.render(context) |
| 126 | |
| 127 | def test_jinja(): |
| 128 | """Jinja Templates""" |
| 129 | jinja_tmpl.render(table=table) |
| 130 | |
| 131 | def test_genshi(): |
| 132 | """Genshi Templates""" |
Armin Ronacher | ccf284b | 2007-05-21 16:44:26 +0200 | [diff] [blame] | 133 | if not have_genshi: |
| 134 | return |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 135 | stream = genshi_tmpl.generate(table=table) |
| 136 | stream.render('html', strip_whitespace=False) |
| 137 | |
Armin Ronacher | e98c5f5 | 2007-04-21 09:39:06 +0200 | [diff] [blame] | 138 | def test_kid(): |
| 139 | """Kid Templates""" |
| 140 | if not have_kid: |
| 141 | return |
| 142 | kid_tmpl.table = table |
| 143 | kid_tmpl.serialize(output="html") |
| 144 | |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 145 | def test_cheetah(): |
| 146 | """Cheetah Templates""" |
Armin Ronacher | ccf284b | 2007-05-21 16:44:26 +0200 | [diff] [blame] | 147 | if not have_cheetah: |
| 148 | return |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 149 | cheetah_tmpl.respond() |
| 150 | |
| 151 | def test_mako(): |
| 152 | """Mako Templates""" |
Alexander Schremmer | 303a7e4 | 2007-02-28 22:44:14 +0100 | [diff] [blame] | 153 | if not have_mako: |
| 154 | return |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 155 | mako_tmpl.render(table=table) |
| 156 | |
| 157 | |
| 158 | def run(which=None, number=10): |
Armin Ronacher | e98c5f5 | 2007-04-21 09:39:06 +0200 | [diff] [blame] | 159 | tests = ['test_django', 'test_jinja', 'test_kid', 'test_genshi', |
| 160 | 'test_cheetah', 'test_mako'] |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 161 | |
| 162 | if which: |
| 163 | tests = filter(lambda n: n[5:] in which, tests) |
| 164 | |
| 165 | for test in [t for t in tests if hasattr(sys.modules[__name__], t)]: |
| 166 | t = timeit.Timer(setup='from __main__ import %s;' % test, |
| 167 | stmt='%s()' % test) |
| 168 | time = t.timeit(number=number) / number |
| 169 | |
| 170 | if time < 0.00001: |
| 171 | result = ' (not installed?)' |
| 172 | else: |
| 173 | result = '%16.2f ms' % (1000 * time) |
| 174 | print '%-35s %s' % (getattr(sys.modules[__name__], test).__doc__, result) |
| 175 | |
| 176 | |
| 177 | if __name__ == '__main__': |
| 178 | which = [arg for arg in sys.argv[1:] if arg[0] != '-'] |
| 179 | |
| 180 | if '-p' in sys.argv: |
Armin Ronacher | 5adf94f | 2007-03-29 22:11:59 +0200 | [diff] [blame] | 181 | from cProfile import Profile |
| 182 | from pstats import Stats |
| 183 | p = Profile() |
| 184 | p.runcall(test_jinja) |
| 185 | stats = Stats(p) |
Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame] | 186 | stats.strip_dirs() |
| 187 | stats.sort_stats('time', 'calls') |
| 188 | stats.print_stats() |
| 189 | else: |
| 190 | run(which) |