Commits

Rick Copeland  committed 2444cd2

Add performance test suite

  • Participants
  • Parent commits 31460fd

Comments (0)

Files changed (45)

File kajiki/ir.py

 
     def py(self):
         yield self.line(
-            'yield local.__kj__.import_(%r, None, {}).__call__()' % (
+            'yield local.__kj__.import_(%r, None, {}).__main__()' % (
                 self.tpl_name))
 
 class ExtendNode(Node):
 
     def py(self):
         yield self.line(
-            'yield local.__kj__.extend(%r).__call__()' % (
+            'yield local.__kj__.extend(%r).__main__()' % (
                 self.tpl_name))
 
 class DefNode(Node):
     def py(self):
         yield self.line('yield self.__kj__.escape(%s)' % self.text)
 
+class PassNode(Node):
+
+    def py(self):
+        yield self.line('pass')
+
 class AttrNode(Node):
 
     def __init__(self, attr, value, guard=None, mode='xml'):

File kajiki/loader.py

         mod = self.modules.get(name)
         if mod: return mod
         mod = self._load(name)
+        mod.loader = self
         self.modules[name] = mod
         return mod
 
     def default_alias_for(self, name):
         return os.path.splitext(os.path.basename(name))[0]
 
+    load=import_
+
 class MockLoader(Loader):
 
     def __init__(self, modules):

File kajiki/perf/genshi_bench/basic.py

+# -*- encoding: utf-8 -*-
+# Template language benchmarks
+#
+# Objective: Test general templating features using a small template
+
+from cgi import escape
+import os
+from StringIO import StringIO
+import sys
+import timeit
+
+__all__ = ['kajiki', 'mako', 'jinja2', 'genshi', 'genshi_text']
+# __all__ = ['fastpt' ]
+
+def kajiki(dirname, verbose=False):
+    from kajiki import FileLoader
+    loader = FileLoader(base=dirname)
+    template = loader.load('template.html')
+    def render():
+        data = dict(title='Just a test', user='joe',
+                    items=['Number %d' % num for num in range(1, 15)])
+        return template(data).render()
+    if verbose:
+        print render()
+    return render
+
+def genshi(dirname, verbose=False):
+    from genshi.template import TemplateLoader
+    loader = TemplateLoader([dirname], auto_reload=False)
+    template = loader.load('template.html')
+    def render():
+        data = dict(title='Just a test', user='joe',
+                    items=['Number %d' % num for num in range(1, 15)])
+        return template.generate(**data).render('xhtml')
+
+    if verbose:
+        print render()
+    return render
+
+def genshi_text(dirname, verbose=False):
+    from genshi.core import escape
+    from genshi.template import TemplateLoader, NewTextTemplate
+    loader = TemplateLoader([dirname], auto_reload=False)
+    template = loader.load('template.txt', cls=NewTextTemplate)
+    def render():
+        data = dict(escape=escape, title='Just a test', user='joe',
+                    items=['Number %d' % num for num in range(1, 15)])
+        return template.generate(**data).render('text')
+
+    if verbose:
+        print render()
+    return render
+
+def mako(dirname, verbose=False):
+    from mako.lookup import TemplateLookup
+    lookup = TemplateLookup(directories=[dirname], filesystem_checks=False)
+    template = lookup.get_template('template.html')
+    def render():
+        data = dict(title='Just a test', user='joe',
+                    items=['Number %d' % num for num in range(1, 15)])
+        return template.render(**data)
+    if verbose:
+        print render()
+    return render
+
+def cheetah(dirname, verbose=False):
+    # FIXME: infinite recursion somewhere... WTF?
+    try:
+        from Cheetah.Template import Template
+    except ImportError:
+        print>>sys.stderr, 'Cheetah not installed, skipping'
+        return lambda: None
+    class MyTemplate(Template):
+        def serverSidePath(self, path): return os.path.join(dirname, path)
+    filename = os.path.join(dirname, 'template.tmpl')
+    template = MyTemplate(file=filename)
+
+    def render():
+        template = MyTemplate(file=filename,
+                              searchList=[{'title': 'Just a test', 'user': 'joe',
+                                           'items': [u'Number %d' % num for num in range(1, 15)]}])
+        return template.respond()
+
+    if verbose:
+        print render()
+    return render
+
+def clearsilver(dirname, verbose=False):
+    try:
+        import neo_cgi
+    except ImportError:
+        print>>sys.stderr, 'ClearSilver not installed, skipping'
+        return lambda: None
+    neo_cgi.update()
+    import neo_util
+    import neo_cs
+    def render():
+        hdf = neo_util.HDF()
+        hdf.setValue('hdf.loadpaths.0', dirname)
+        hdf.setValue('title', escape('Just a test'))
+        hdf.setValue('user', escape('joe'))
+        for num in range(1, 15):
+            hdf.setValue('items.%d' % (num - 1), escape('Number %d' % num))
+        cs = neo_cs.CS(hdf)
+        cs.parseFile('template.cs')
+        return cs.render()
+
+    if verbose:
+        print render()
+    return render
+
+def jinja2(dirname, verbose=False):
+    from jinja2 import Environment, FileSystemLoader
+    env = Environment(loader=FileSystemLoader([os.path.join(dirname, 'templates')]))
+    tmpl = env.get_template('template.html')
+
+    def render():
+        data = {'title': 'Just a test', 'user': 'joe',
+                'items': ['Number %d' % num for num in range(1, 15)]}
+        return tmpl.render(**data)
+
+    if verbose:
+        print render()
+    return render
+
+def django(dirname, verbose=False):
+    try:
+        from django.conf import settings
+        settings.configure(TEMPLATE_DIRS=[os.path.join(dirname, 'templates')])
+    except ImportError:
+        print>>sys.stderr, 'Django not installed, skipping'
+        return lambda: None
+    from django import template, templatetags
+    from django.template import loader
+    templatetags.__path__.append(os.path.join(dirname, 'templatetags'))
+    tmpl = loader.get_template('template.html')
+
+    def render():
+        data = {'title': 'Just a test', 'user': 'joe',
+                'items': ['Number %d' % num for num in range(1, 15)]}
+        return tmpl.render(template.Context(data))
+
+    if verbose:
+        print render()
+    return render
+
+def kid(dirname, verbose=False):
+    try:
+        import kid
+    except ImportError:
+        print>>sys.stderr, "Kid not installed, skipping"
+        return lambda: None
+    kid.path = kid.TemplatePath([dirname])
+    template = kid.load_template('template.kid').Template
+    def render():
+        return template(
+            title='Just a test', user='joe',
+            items=['Number %d' % num for num in range(1, 15)]
+        ).serialize(output='xhtml')
+
+    if verbose:
+        print render()
+    return render
+
+def simpletal(dirname, verbose=False):
+    try:
+        from simpletal import simpleTAL, simpleTALES
+    except ImportError:
+        print>>sys.stderr, "SimpleTAL not installed, skipping"
+        return lambda: None
+    fileobj = open(os.path.join(dirname, 'base.html'))
+    base = simpleTAL.compileHTMLTemplate(fileobj)
+    fileobj.close()
+    fileobj = open(os.path.join(dirname, 'template.html'))
+    template = simpleTAL.compileHTMLTemplate(fileobj)
+    fileobj.close()
+    def render():
+        ctxt = simpleTALES.Context(allowPythonPath=1)
+        ctxt.addGlobal('base', base)
+        ctxt.addGlobal('title', 'Just a test')
+        ctxt.addGlobal('user', 'joe')
+        ctxt.addGlobal('items', ['Number %d' % num for num in range(1, 15)])
+        buf = StringIO()
+        template.expand(ctxt, buf)
+        return buf.getvalue()
+
+    if verbose:
+        print render()
+    return render
+
+def run(engines, number=2000, verbose=False):
+    basepath = os.path.abspath(os.path.dirname(__file__))
+    for engine in engines:
+        dirname = os.path.join(basepath, engine)
+        if verbose:
+            print '%s:' % engine.capitalize()
+            print '--------------------------------------------------------'
+        else:
+            print '%s:' % engine.capitalize(),
+        t = timeit.Timer(setup='from __main__ import %s; render = %s(r"%s", %s)'
+                               % (engine, engine, dirname, verbose),
+                         stmt='render()')
+        time = t.timeit(number=number) / number
+        if verbose:
+            print '--------------------------------------------------------'
+        print '%.2f ms' % (1000 * time)
+        if verbose:
+            print '--------------------------------------------------------'
+
+
+if __name__ == '__main__':
+    engines = [arg for arg in sys.argv[1:] if arg[0] != '-']
+    if not engines:
+        engines = __all__
+
+    verbose = '-v' in sys.argv
+
+    if '-p' in sys.argv:
+        import cProfile, pstats
+        prof = cProfile.Profile()
+        prof.run('run(%r, number=200, verbose=%r)' % (engines, verbose))
+        stats = pstats.Stats(prof)
+        stats.strip_dirs()
+        # stats.sort_stats('calls')
+        stats.sort_stats('time')
+        stats.print_stats(25)
+        if verbose:
+            stats.print_callees()
+            stats.print_callers()
+    else:
+        run(engines, verbose=verbose)

File kajiki/perf/genshi_bench/bigtable.py

+# -*- encoding: utf-8 -*-
+# Template language benchmarks
+#
+# Objective: Generate a 1000x10 HTML table as fast as possible.
+#
+# Author: Jonas Borgström <jonas@edgewall.com>
+
+import cgi
+import sys
+import timeit
+from StringIO import StringIO
+from genshi.builder import tag
+from genshi.template import MarkupTemplate, NewTextTemplate
+
+import kajiki
+import jinja2
+
+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)]
+
+kajiki_tmpl = kajiki.XMLTemplate(source="""
+<table>
+<tr py:for="row in table">
+<td py:for="c in row.values()" py:content="c"/>
+</tr>
+</table>
+""")
+
+genshi_tmpl = MarkupTemplate("""
+<table xmlns:py="http://genshi.edgewall.org/">
+<tr py:for="row in table">
+<td py:for="c in row.values()" py:content="c"/>
+</tr>
+</table>
+""")
+
+genshi_tmpl2 = MarkupTemplate("""
+<table xmlns:py="http://genshi.edgewall.org/">$table</table>
+""")
+
+genshi_text_tmpl = NewTextTemplate("""
+<table>
+{% for row in table %}<tr>
+{% for c in row.values() %}<td>$c</td>{% end %}
+</tr>{% end %}
+</table>
+""")
+
+if DjangoTemplate:
+    django_tmpl = DjangoTemplate("""
+    <table>
+    {% for row in table %}
+    <tr>{% for col in row.values %}{{ col|escape }}{% endfor %}</tr>
+    {% endfor %}
+    </table>
+    """)
+
+    def test_django():
+        """Djange template"""
+        context = DjangoContext({'table': table})
+        django_tmpl.render(context)
+
+jinja2_tmpl = jinja2.Template("""
+    <table>
+    {% for row in table %}
+    <tr>{% for col in row.values() %}{{ col|escape }}{% endfor %}</tr>
+    {% endfor %}
+    </table>
+""")
+def test_jinja2():
+    '''jinja2 Template'''
+    jinja2_tmpl.render(table=table)
+
+if MakoTemplate:
+    mako_tmpl = MakoTemplate("""
+<table>
+  % for row in table:
+    <tr>
+      % for col in row.values():
+        <td>${ col | h  }</td>
+      % endfor
+    </tr>
+  % endfor
+</table>
+""")
+    def test_mako():
+        """Mako Template"""
+        mako_tmpl.render(table=table)
+
+def test_kajiki():
+    """FastPt Template"""
+    kajiki_tmpl(dict(table=table)).render()
+
+def test_genshi():
+    """Genshi template"""
+    stream = genshi_tmpl.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("""
+    <table xmlns:py="http://purl.org/kid/ns#">
+    <tr py:for="row in table">
+    <td py:for="c in row.values()" py:content="c"/>
+    </tr>
+    </table>
+    """)
+
+    kid_tmpl2 = kid.Template("""
+    <html xmlns:py="http://purl.org/kid/ns#">$table</html>
+    """)
+
+    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("""
+<table><?cs
+  each:row=rows
+?><tr><?cs each:c=row.cell
+  ?><td><?cs var:c ?></td><?cs /each
+?></tr><?cs /each?>
+</table>""")
+        cs.render()
+
+def run(which=None, number=10):
+    tests = ['test_builder', 'test_genshi', 'test_genshi_text',
+             'test_genshi_builder', 'test_mako', 'test_kid', 'test_kid_et',
+             'test_et', 'test_cet', 'test_clearsilver', 'test_django', 'test_kajiki', 'test_jinja2']
+
+    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)
+        stats.print_stats()
+        if '-v' in sys.argv:
+            stats.print_callees()
+            stats.print_callers()
+    else:
+        run(which)

File kajiki/perf/genshi_bench/cheetah/footer.tmpl

+<div id="footer">
+</div>

File kajiki/perf/genshi_bench/cheetah/header.tmpl

+<div id="header">
+  <h1>$title</h1>
+</div>

File kajiki/perf/genshi_bench/cheetah/template.tmpl

+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+  <head>
+    <title>${title}</title>
+  </head>
+  <body>
+    #include "cheetah/header.tmpl"
+
+    <h2>Loop</h2>
+    #if $items
+      <ul>
+        #for $item in $items
+          <li>$item</li>
+        #end for
+      </ul>
+    #end if
+
+    #include "cheetah/footer.tmpl"
+  </body>
+</html>

File kajiki/perf/genshi_bench/clearsilver/footer.cs

+<div id="footer">
+</div>

File kajiki/perf/genshi_bench/clearsilver/header.cs

+<div id="header">
+  <h1><?cs var:title ?></h1>
+</div>
+
+<?cs def:greeting(name) ?>
+  <p>Hello, <?cs var:name ?>!</p>
+<?cs /def ?>

File kajiki/perf/genshi_bench/clearsilver/template.cs

+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+  <head>
+    <title><?cs var:title ?></title>
+  </head>
+  <body>
+    <?cs include:"header.cs" ?>
+    <?cs call:greeting(user) ?>
+    <?cs call:greeting('me') ?>
+    <?cs call:greeting('world') ?>
+    
+    <h2>Loop</h2>
+    <?cs if:len(items) ?>
+      <ul>
+        <?cs each:item = items ?>
+          <li<?cs if:name(item) == len(items) ?> class="last"<?cs /if ?>><?cs var:item ?></li>
+        <?cs /each ?>
+      </ul>
+    <?cs /if ?>
+    
+    <?cs include:"footer.cs" ?>
+  </body>
+</html>

File kajiki/perf/genshi_bench/django/templates/base.html

+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+
+  {% block content %}
+    {% block header %}
+      <div id="header">
+        <h1>{{ title|escape }}</h1>
+      </div>
+    {% endblock %}
+
+    {% block footer %}
+      <div id="footer"></div>
+    {% endblock %}
+  {% endblock %}
+
+</html>

File kajiki/perf/genshi_bench/django/templates/template.html

+{% extends "base.html" %}
+{% load bench %}
+
+{% block content %}
+  <head>
+    <title>{{title|escape}}</title>
+  </head>
+
+  <body>
+    {% block header %}{% endblock %}
+
+    <div>{% greeting user %}</div>
+    <div>{% greeting "me" %}</div>
+    <div>{% greeting "world" %}</div>
+
+    <h2>Loop</h2>
+    {% if items %}
+      <ul>
+        {% for item in items %}
+          <li{% if forloop.last %} class="last"{% endif %}>{{ item|escape }}</li>
+        {% endfor %}
+      </ul>
+    {% endif %}
+
+    {% block footer %}{% endblock %}
+  </body>
+{% endblock %}

File kajiki/perf/genshi_bench/django/templatetags/__init__.py

Empty file added.

File kajiki/perf/genshi_bench/django/templatetags/bench.py

+from django.template import Library, Node, resolve_variable
+from django.utils.html import escape
+
+register = Library()
+
+def greeting(name):
+    return 'Hello, %s!' % escape(name)
+greeting = register.simple_tag(greeting)

File kajiki/perf/genshi_bench/genshi/base.html

+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/"
+      py:strip="">
+
+  <p py:def="greeting(name)">
+    Hello, ${name}!
+  </p>
+
+  <py:match path="body" once="true"><body>
+    <div id="header">
+      <h1>${title}</h1>
+    </div>
+    ${select('*')}
+    <div id="footer" />
+  </body></py:match>
+
+</html>

File kajiki/perf/genshi_bench/genshi/template.html

+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      lang="en">
+  <xi:include href="base.html" />
+  <head>
+    <title>${title}</title>
+  </head>
+  <body>
+    <div>${greeting(user)}</div>
+    <div>${greeting('me')}</div>
+    <div>${greeting('world')}</div>
+
+    <h2>Loop</h2>
+    <ul py:if="items">
+      <li py:for="idx, item in enumerate(items)" py:content="item"
+          class="${idx + 1 == len(items) and 'last' or None}" />
+    </ul>
+
+  </body>
+</html>

File kajiki/perf/genshi_bench/genshi_text/footer.txt

+<div id="footer"></div>

File kajiki/perf/genshi_bench/genshi_text/header.txt

+<div id="header">
+  <h1>${escape(title)}</h1>
+</div>

File kajiki/perf/genshi_bench/genshi_text/template.txt

+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+
+<head>
+  <title>${escape(title)}</title>
+</head>
+
+<body>
+  {% include header.txt %}
+  {% def greeting(name) %}
+    Hello, ${name}!
+  {% end %}
+
+  <div>${greeting(user)}</div>
+  <div>${greeting("me")}</div>
+  <div>${greeting("world")}</div>
+  
+  <h2>Loop</h2>
+  {% if items %}<ul>
+    {% for idx, item in enumerate(items) %}\
+      <li{% if idx + 1 == len(items) %} class="last"{% end %}>${escape(item)}</li>
+    {% end %}
+  </ul>{% end %}
+  
+  {% include footer.txt %}
+</body>

File kajiki/perf/genshi_bench/jinja2/templates/base.html

+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+
+  {% block content %}
+    {% block header %}
+      <div id="header">
+        <h1>{{ title|escape }}</h1>
+      </div>
+    {% endblock %}
+
+    {% block footer %}
+      <div id="footer"></div>
+    {% endblock %}
+  {% endblock %}
+
+</html>

File kajiki/perf/genshi_bench/jinja2/templates/template.html

+{% extends "base.html" %}
+{% macro greeting(name) %}Hello, {{name | escape}}{%- endmacro %}
+{% block content %}
+  <head>
+    <title>{{title|escape}}</title>
+  </head>
+
+  <body>
+    {% block header %}{% endblock %}
+
+    <div>{{ greeting(user) }}</div>
+    <div>{{ greeting("me") }}</div>
+    <div>{{ greeting("world") }}</div>
+
+    <h2>Loop</h2>
+    {% if items %}
+      <ul>
+        {% for item in items %}
+          <li{% if loop.last %} class="last"{% endif %}>{{ item|escape }}</li>
+        {% endfor %}
+      </ul>
+    {% endif %}
+
+    {% block footer %}{% endblock %}
+  </body>
+{% endblock %}

File kajiki/perf/genshi_bench/jinja2/templatetags/__init__.py

Empty file added.

File kajiki/perf/genshi_bench/jinja2/templatetags/bench.py

+from django.template import Library, Node, resolve_variable
+from django.utils.html import escape
+
+register = Library()
+
+def greeting(name):
+    return 'Hello, %s!' % escape(name)
+greeting = register.simple_tag(greeting)

File kajiki/perf/genshi_bench/kajiki/base.html

+<html xmlns:py="http://genshi.edgewall.org/">
+  <head>
+    <title>${title}</title>
+  </head>
+
+  <body>
+    <div id="header">
+      <h1>${title}</h1>
+    </div>
+    <py:block name="content"/>
+    <div id="footer"/>
+  </body>
+
+</html>
+

File kajiki/perf/genshi_bench/kajiki/lib.html

+<html xmlns:py="http://genshi.edgewall.org/"
+      py:strip="True">
+
+  <p py:def="greeting(name)">
+    Hello, ${name}!
+  </p>
+
+</html>

File kajiki/perf/genshi_bench/kajiki/template.html

+<py:extends href="base.html">
+  <py:block name="content">
+    <py:import href="lib.html" alias="lib"/>
+    <div>${lib.greeting(user)}</div>
+    <div>${lib.greeting('me')}</div>
+    <div>${lib.greeting('world')}</div>
+
+    <h2>Loop</h2>
+    <ul py:if="items">
+      <li py:for="idx, item in enumerate(items)" py:content="item"
+          class="${idx + 1 == len(items) and 'last' or None}" />
+    </ul>
+  </py:block>
+</py:extends>

File kajiki/perf/genshi_bench/kid/base.kid

+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://purl.org/kid/ns#">
+
+  <p py:def="greeting(name)">
+    Hello, ${name}!
+  </p>
+
+  <body py:match="item.tag == '{http://www.w3.org/1999/xhtml}body'" py:strip="">
+    <div id="header">
+      <h1>${title}</h1>
+    </div>
+    ${item}
+    <div id="footer" />
+  </body>
+</html>

File kajiki/perf/genshi_bench/kid/template.kid

+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://purl.org/kid/ns#"
+      py:extends="'base.kid'"
+      lang="en">
+  <head>
+    <title>${title}</title>
+  </head>
+  <body>
+    <div>${greeting(user)}</div>
+    <div>${greeting('me')}</div>
+    <div>${greeting('world')}</div>
+    
+    <h2>Loop</h2>
+    <ul py:if="items">
+      <li py:for="idx, item in enumerate(items)" py:content="item"
+          class="${idx + 1 == len(items) and 'last' or None}" />
+    </ul>
+  </body>
+</html>

File kajiki/perf/genshi_bench/mako/footer.html

+<div id="footer">
+</div>

File kajiki/perf/genshi_bench/mako/header.html

+<div id="header">
+  <h1>${title | h}</h1>
+</div>
+
+

File kajiki/perf/genshi_bench/mako/template.html

+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+  <head>
+    <title>${title}</title>
+  </head>
+  <body>
+    <%def name="greeting(name)">
+      <p>Hello, ${name | h}!</p>
+    </%def>
+  
+    <%include file="header.html"/>
+  
+    ${greeting(user)}
+    ${greeting('me')}
+    ${greeting('world')}
+    
+    <h2>Loop</h2>
+    % if items:
+      <ul>
+        % for idx, item in enumerate(items): 
+          <li ${idx+1==len(items) and "class='last'" or ""}>${item | h}</li>
+        % endfor
+      </ul>
+    % endif
+    <%include file="footer.html"/>
+  </body>
+</html>

File kajiki/perf/genshi_bench/myghty/base.myt

+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+
+<%method wrap>
+<%args scope="request">
+  title
+</%args>
+<div id="header">
+  <h1><% title %></h1>
+</div>
+
+<% m.content() %>
+
+</%method>
+
+<div id="footer"></div>
+</html>
+
+<%method greeting>
+<%args>
+   name
+</%args>
+Hello, <% name | h %>
+</%method>

File kajiki/perf/genshi_bench/myghty/template.myt

+<%args>
+	title
+	items
+	user
+</%args>
+
+<head>
+  <title><% title %></title>
+</head>
+
+ <&|base.myt:wrap &>
+  <div><& base.myt:greeting, name=user &></div>
+  <div><& base.myt:greeting, name="me"&></div>
+  <div><& base.myt:greeting, name="world" &></div>
+
+  <h2>Loop</h2>
+%if items:
+      <ul>
+%	for item in items:
+  <li><% item %></li>
+%
+      </ul>
+%
+
+ </&>

File kajiki/perf/genshi_bench/simpletal/base.html

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+
+  <p metal:define-macro="greeting">
+    Hello, <span metal:define-slot="name">name</span>
+  </p>
+
+  <body metal:define-macro="content">
+    <div id="header">
+      <h1 tal:content="title" />
+    </div>
+    <div metal:define-slot="content" tal:omit-tag="" />
+    <div id="footer"></div>
+  </body>
+
+</html>

File kajiki/perf/genshi_bench/simpletal/template.html

+<!DOCTYPE html
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+  <head>
+    <title tal:content="title">Title</title>
+  </head>
+  <body metal:use-macro="base/macros/content">
+    <div metal:fill-slot="content">
+
+      <div metal:use-macro="base/macros/greeting">
+        <span metal:fill-slot="name" tal:content="user" tal:omit-tag=""></span>
+      </div>
+      <div metal:use-macro="base/macros/greeting">
+        <span metal:fill-slot="name" tal:omit-tag="">me</span>
+      </div>
+      <div metal:use-macro="base/macros/greeting">
+        <span metal:fill-slot="name" tal:omit-tag="">world</span>
+      </div>
+
+      <h2>Loop</h2>
+      <ul tal:condition="items">
+        <li tal:repeat="item items" tal:content="item"
+            tal:attributes="class python:repeat['item'].getEnd() and 'last' or None">Item</li>
+      </ul>
+
+    </div>
+  </body>
+</html>

File kajiki/perf/genshi_bench/xpath.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2006-2008 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://genshi.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://genshi.edgewall.org/log/.
+
+
+try:
+    from os import times
+    def time_func():
+        tup = times()
+        #just user time
+        return tup[0] # + tup[1]
+except ImportError:
+    from time import time as time_func
+
+from genshi.core import START, END
+from genshi.path import Path
+from genshi.input import XML
+
+def benchmark(f, acurate_time=1):
+    """Checks how much time does function f work. It runs it as
+    many times as needed for avoiding inaccuracy"""
+
+    runs = 1
+    while True:
+        start_time = time_func()
+        for _ in xrange(runs):
+            f()
+        dt = time_func() - start_time
+        if dt >= acurate_time:
+            break
+        runs *= 2
+    return dt / runs
+
+def spell(t):
+    """Returns spelled representation of time"""
+    units = [(0.000001, 'microsecond', 'microseconds'),
+             (0.001, 'milisecond', 'miliseconds'),
+             (1, 'second', 'seconds'),
+             (60, 'minute', 'minutes'),
+             (60*60, 'hour', 'hours'),
+            ]
+    i = 0
+    at = abs(t)
+    while i + 1 < len(units) and at >= units[i + 1][0]:
+        i += 1
+    t /= units[i][0]
+    if t >= 2:
+        name = units[i][2]
+    else:
+        name = units[i][1]
+    return "%f %s"%(t, name)
+
+def test_paths_in_streams(exprs, streams, test_strategies=False):
+    for expr in exprs:
+        print "Testing path %r" % expr
+        for stream, sname in streams:
+            print '\tRunning on "%s" example:' % sname
+
+            path = Path(expr)
+            def f():
+                for e in path.select(stream):
+                    pass
+            t = spell(benchmark(f))
+            print "\t\tselect:\t\t%s" % t
+
+            def f():
+                path = Path(expr)
+                for e in path.select(stream):
+                    pass
+            t = spell(benchmark(f))
+            print "\t\tinit + select:\t%s" % t
+
+            if test_strategies and len(path.paths) == 1:
+                from genshi.path import GenericStrategy, SingleStepStrategy, \
+                                        SimplePathStrategy
+                from genshi.tests.path import FakePath
+                strategies = (GenericStrategy, SingleStepStrategy,
+                              SimplePathStrategy)
+                for strategy in strategies:
+                    if not strategy.supports(path.paths[0]):
+                        continue
+                    print "\t\t%s Strategy"%strategy.__name__
+                    fp = FakePath(strategy(path.paths[0]))
+                    def f():
+                        for e in fp.select(stream):
+                            pass
+                    t = spell(benchmark(f))
+                    print "\t\t\tselect:\t\t%s"%t
+
+
+def test_documents(test_strategies=False):
+    streams = []
+
+    s = XML("""\
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" xmlns:py="http://genshi.edgewall.org/" py:strip="" lang="en">
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+        <title>Foo</title>
+    </head>
+    <body>
+        <h1>Hello</h1>
+    </body>
+</html>
+""")
+    streams.append((s, "small document"))
+
+    s = XML("""\
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" xmlns:py="http://genshi.edgewall.org/" py:strip="" lang="en">
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+        <title>Foo</title>
+    </head>
+    <body>
+        <h1>Hello</h1>
+        <div id="splash">
+            <ul>
+                <li><a class="b1" href="http://genshi.edgewall.org/">
+                        <strong>Genshi</strong>
+                        Python toolkit for generating output for the web</a></li>
+                <li><a class="b2" href="http://babel.edgewall.org/">
+                        <strong>Babel</strong>
+                        Python library for I18n/L10n in web applications</a></li>
+                <li><a class="b3" href="http://bitten.edgewall.org/">
+                        <strong>Bitten</strong>
+                        Continuous integration plugin for Trac</a></li>
+                <li><a class="b4" href="http://posterity.edgewall.org/">
+                        <strong>Posterity</strong>
+                        Web-based email system</a></li>
+            </ul>
+            <div id="trac-splash">
+                <a href="http://trac.edgewall.org/">
+                    <strong>Trac</strong> Web-based lightweight project management
+                    system
+                </a>
+            </div>
+        </div>
+    </body>
+</html>
+""")
+    streams.append((s, "big document"))
+
+    paths = [
+        '.',
+        '*|text()',
+        'html',
+        'html[@lang="en"]',
+        'html/body/h1/text()',
+        'html/body/div/a/@href',
+        'html/body/div[@id="splash"]/a[@class="b4"]/strong/text()',
+        'descendant-or-self::text()',
+        'descendant-or-self::h1/text()',
+    ]
+    test_paths_in_streams(paths, streams, test_strategies)
+
+if __name__ == '__main__':
+    from sys import argv
+    if "--strategies" in argv:
+        test_strategies = True
+    else:
+        test_strategies = False
+    test_documents(test_strategies)

File kajiki/perf/tables.html

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<table xmlns:py="http://genshi.edgewall.org/">
+  <tbody>
+    <tr py:for="i in xrange(size)">
+      <td py:for="j in xrange(size)">
+        $i, $j
+      </td>
+    </tr>
+  </tbody>
+</table>

File kajiki/template.py

             setattr(self, k, v)
             self.__globals__[k] = v
         self.__kj__ = _obj(
-            render=self._render,
             extend=self._extend,
             push_switch=self._push_switch,
             pop_switch=self._pop_switch,
         self.__globals__.update(context)
 
     def __iter__(self):
-        for chunk in self.__call__():
+        for chunk in self.__main__():
             yield unicode(chunk)
 
-    def _render(self):
+    def render(self):
         return u''.join(self)
 
     def _extend(self, parent):
         p_globals = p_inst.__globals__
         # Find overrides
         for k,v in self.__globals__.iteritems():
-            if k == '__call__': continue
+            if k == '__main__': continue
             if not isinstance(v, TplFunc): continue
             p_globals[k] = v
         # Find inherited funcs
         for k, v in p_inst.__globals__.iteritems():
-            if k == '__call__': continue
+            if k == '__main__': continue
             if not isinstance(v, TplFunc): continue
             if k not in self.__globals__: 
                 self.__globals__[k] = v
     dct = dict(kajiki=kajiki)
     try:
         exec py_text in dct
-    except SyntaxError: # pragma no cover
+    except (SyntaxError, IndentationError), err: # pragma no cover
         for i, line in enumerate(py_text.splitlines()):
             print '%3d %s' % (i+1, line)
         raise
             code.co_consts,
             code.co_names,
             code.co_varnames,
-            filename,
+            filename.encode('utf-8'),
             code.co_name,
             new_firstlineno,
             new_lnotab,

File kajiki/tests/test_ir.py

     def setUp(self):
         self.tpl = ir.TemplateNode(
             defs=[ir.DefNode(
-                '__call__()',
+                '__main__()',
                 ir.TextNode('Hello, '),
                 ir.ExprNode('name'),
                 ir.TextNode('\n'))])
 
     def test(self):
         tpl = kajiki.template.from_ir(self.tpl)
-        rsp = tpl(dict(name='Rick')).__kj__.render() 
+        rsp = tpl(dict(name='Rick')).render() 
         assert rsp == 'Hello, Rick\n', rsp
 
 class TestSwitch(TestCase):
     def setUp(self):
         self.tpl = ir.TemplateNode(
             defs=[ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.ForNode(
                         'i in range(2)',
                         ir.ExprNode('i'),
             
     def test_basic(self):
         tpl = kajiki.template.from_ir(self.tpl)
-        rsp = tpl(dict()).__kj__.render() 
+        rsp = tpl(dict()).render() 
         assert rsp == '0 is even\n1 is odd\n', rsp
 
 class TestFunction(TestCase):
                     ir.ElseNode(
                         ir.TextNode('odd'))),
                   ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.ForNode(
                         'i in range(2)',
                         ir.ExprNode('i'),
 
     def test_basic(self):
         tpl = kajiki.template.from_ir(self.tpl)
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == '0 is even\n1 is odd\n', rsp
 
 class TestCall(TestCase):
                         ir.ExprNode('caller(i)'),
                         ir.TextNode('."\n'))),
                   ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.CallNode(
                         '$caller(n)',
                         "quote($caller, 'the raven')",
             
     def test_basic(self):
         tpl = kajiki.template.from_ir(self.tpl)
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert (
             rsp == 'Quoth the raven, "Nevermore 0."\n'
             'Quoth the raven, "Nevermore 1."\n'), rsp
                     ir.ExprNode('evenness(n/2)'))])
         tpl = ir.TemplateNode(
             defs=[ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.ImportNode(
                         'lib.txt',
                         'simple_function'),
         self.tpl = loader.import_('tpl.txt')
 
     def test_import(self):
-        rsp = self.tpl(dict(name='Rick')).__kj__.render()
+        rsp = self.tpl(dict(name='Rick')).render()
         assert (rsp=='0 is even half of 0 is even\n'
                 '1 is odd half of 1 is even\n'
                 '2 is even half of 2 is odd\n'
         hdr = ir.TemplateNode(
             defs=[
                 ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.TextNode('# header\n'))])
         tpl = ir.TemplateNode(
             defs=[
                 ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.TextNode('a\n'),
                     ir.IncludeNode('hdr.txt'),
                     ir.TextNode('b\n'))])
         self.tpl = loader.import_('tpl.txt')
 
     def test_include(self):
-        rsp = self.tpl(dict(name='Rick')).__kj__.render()
+        rsp = self.tpl(dict(name='Rick')).render()
         assert rsp == 'a\n# header\nb\n', rsp
 
 class TestExtends(TestCase):
         parent_tpl = ir.TemplateNode(
             defs=[
                 ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.ExprNode('header()'),
                     ir.ExprNode('body()'),
                     ir.ExprNode('footer()')),
         mid_tpl = ir.TemplateNode(
             defs=[
                 ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.ExtendNode('parent.txt')),
                 ir.DefNode(
                     'id()',
         child_tpl = ir.TemplateNode(
             defs=[
                 ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.ExtendNode('mid.txt')),
                 ir.DefNode(
                     'body()',
         self.tpl = loader.import_('child.txt')
         
     def test_extends(self):
-        rsp = self.tpl(dict(name='Rick')).__kj__.render()
+        rsp = self.tpl(dict(name='Rick')).render()
         assert (rsp == '# Header name=Rick\n'
                 '## Child Body\n'
                 '## Parent Body\n'
         p0 = ir.TemplateNode(
             defs=[
                 ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.TextNode('Parent 0'))])
         p1 = ir.TemplateNode(
             defs=[
                 ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.TextNode('Parent 1'))])
         child = ir.TemplateNode(
             defs=[
                 ir.DefNode(
-                    '__call__()',
+                    '__main__()',
                     ir.IfNode(
                         'p==0',
                         ir.ExtendNode('parent0.txt')),
         self.tpl = loader.import_('child.txt')
 
     def test_extends(self):
-        rsp = self.tpl(dict(p=0)).__kj__.render()
+        rsp = self.tpl(dict(p=0)).render()
         assert rsp == 'Parent 0', rsp
-        rsp = self.tpl(dict(p=1)).__kj__.render()
+        rsp = self.tpl(dict(p=1)).render()
         assert rsp == 'Parent 1', rsp
 
 if __name__ == '__main__':

File kajiki/tests/test_runtime.py

         @kajiki.Template
         class tpl:
             @kajiki.expose
-            def __call__():
+            def __main__():
                 yield 'Hello,'
                 yield name
                 yield '\n'
         self.tpl = tpl
 
     def test_basic(self):
-        rsp = self.tpl(dict(name='Rick')).__kj__.render()
+        rsp = self.tpl(dict(name='Rick')).render()
         assert rsp == 'Hello,Rick\n', rsp
 
 class TestSwitch(TestCase):
         @kajiki.Template
         class tpl:
             @kajiki.expose
-            def __call__():
+            def __main__():
                 for i in range(2):
                     yield i
                     yield ' is '
         self.tpl = tpl
 
     def test_basic(self):
-        rsp = self.tpl().__kj__.render()
+        rsp = self.tpl().render()
         assert rsp == '0 is even\n1 is odd\n', rsp
 
 class TestFunction(TestCase):
                 if n % 2 == 0: yield 'even'
                 else: yield 'odd'
             @kajiki.expose
-            def __call__():
+            def __main__():
                 for i in range(2):
                     yield i
                     yield ' is '
         self.tpl = tpl
 
     def test_basic(self):
-        rsp = self.tpl(dict(name='Rick')).__kj__.render()
+        rsp = self.tpl(dict(name='Rick')).render()
         assert rsp == '0 is even\n1 is odd\n', rsp
 
 class TestCall(TestCase):
                     yield caller(i)
                     yield '."\n'
             @kajiki.expose
-            def __call__():
+            def __main__():
                 @__kj__.flattener.decorate
                 def _kj_lambda(n):
                     yield 'Nevermore '
         self.tpl = tpl
 
     def test_basic(self):
-        rsp = self.tpl(dict(name='Rick')).__kj__.render()
+        rsp = self.tpl(dict(name='Rick')).render()
         assert (
             rsp == 'Quoth the raven, "Nevermore 0."\n'
             'Quoth the raven, "Nevermore 1."\n'), rsp
         @kajiki.Template
         class tpl:
             @kajiki.expose
-            def __call__():
+            def __main__():
                 simple_function = lib(dict(globals()))
                 for i in range(4):
                     yield i
         self.tpl = tpl
 
     def test_import(self):
-        rsp = self.tpl(dict(name='Rick')).__kj__.render()
+        rsp = self.tpl(dict(name='Rick')).render()
         assert (rsp=='0 is even half of 0 is even\n'
                 '1 is odd half of 1 is even\n'
                 '2 is even half of 2 is odd\n'
         @kajiki.Template
         class hdr:
             @kajiki.expose
-            def __call__():
+            def __main__():
                 yield '# header\n'
         @kajiki.Template
         class tpl:
             @kajiki.expose
-            def __call__():
+            def __main__():
                 yield 'a\n'
-                yield hdr().__call__()
+                yield hdr().__main__()
                 yield 'b\n'
         self.tpl = tpl
 
     def test_include(self):
-        rsp = self.tpl(dict(name='Rick')).__kj__.render()
+        rsp = self.tpl(dict(name='Rick')).render()
         assert rsp == 'a\n# header\nb\n', rsp
 
 class TestExtends(TestCase):
         @kajiki.Template
         class parent_tpl:
             @kajiki.expose
-            def __call__():
+            def __main__():
                 yield header()
                 yield body()
                 yield footer()
         @kajiki.Template
         class mid_tpl:
             @kajiki.expose
-            def __call__():
-                yield local.__kj__.extend(parent_tpl).__call__()
+            def __main__():
+                yield local.__kj__.extend(parent_tpl).__main__()
             @kajiki.expose
             def id():
                 yield 'mid'
         @kajiki.Template
         class child_tpl:
             @kajiki.expose
-            def __call__():
-                yield local.__kj__.extend(mid_tpl).__call__()
+            def __main__():
+                yield local.__kj__.extend(mid_tpl).__main__()
             @kajiki.expose
             def body():
                 yield '## Child Body\n'
         _self.child_tpl = child_tpl
 
     def test_extends(self):
-        rsp = self.child_tpl(dict(name='Rick')).__kj__.render()
+        rsp = self.child_tpl(dict(name='Rick')).render()
         assert (rsp == '# Header name=Rick\n'
                 '## Child Body\n'
                 '## Parent Body\n'
         @kajiki.Template
         class parent_0:
             @kajiki.expose
-            def __call__():
+            def __main__():
                 yield 'Parent 0'
         @kajiki.Template
         class parent_1:
             @kajiki.expose
-            def __call__():
+            def __main__():
                 yield 'Parent 1'
         @kajiki.Template
         class child_tpl:
             @kajiki.expose
-            def __call__():
+            def __main__():
                 if p == 0:
-                    yield local.__kj__.extend(parent_0).__call__()
+                    yield local.__kj__.extend(parent_0).__main__()
                 else:
-                    yield local.__kj__.extend(parent_1).__call__()
+                    yield local.__kj__.extend(parent_1).__main__()
         _self.child_tpl = child_tpl
 
     def test_extends(self):
-        rsp = self.child_tpl(dict(p=0)).__kj__.render()
+        rsp = self.child_tpl(dict(p=0)).render()
         assert rsp == 'Parent 0', rsp
-        rsp = self.child_tpl(dict(p=1)).__kj__.render()
+        rsp = self.child_tpl(dict(p=1)).render()
         assert rsp == 'Parent 1', rsp
 
 if __name__ == '__main__':

File kajiki/tests/test_text.py

 
     def test_auto_escape(self):
         tpl = TextTemplate(source="${'<h1>'}")
-        rsp = tpl().__kj__.render() 
+        rsp = tpl().render() 
         assert rsp == '&lt;h1&gt;', rsp
 
     def test_auto_escape_disable(self):
         tpl = TextTemplate(source="${literal('<h1>')}")
-        rsp = tpl().__kj__.render() 
+        rsp = tpl().render() 
         assert rsp == '<h1>', rsp
 
     def test_expr_brace(self):
         tpl = TextTemplate(source='Hello, ${name}\n')
-        rsp = tpl(dict(name='Rick')).__kj__.render() 
+        rsp = tpl(dict(name='Rick')).render() 
         assert rsp == 'Hello, Rick\n', rsp
 
     def test_expr_brace_complex(self):
         tpl = TextTemplate(source="Hello, ${{'name':name}['name']}\n")
-        rsp = tpl(dict(name='Rick')).__kj__.render() 
+        rsp = tpl(dict(name='Rick')).render() 
         assert rsp == 'Hello, Rick\n', rsp
 
     def test_expr_name(self):
         tpl = TextTemplate(source='Hello, $name\n')
-        rsp = tpl(dict(name='Rick')).__kj__.render() 
+        rsp = tpl(dict(name='Rick')).render() 
         assert rsp == 'Hello, Rick\n', rsp
         tpl = TextTemplate(source='Hello, $obj.name\n')
         class Empty: pass
         Empty.name = 'Rick'
-        rsp = tpl(dict(obj=Empty)).__kj__.render() 
+        rsp = tpl(dict(obj=Empty)).render() 
         assert rsp == 'Hello, Rick\n', rsp
 
 class TestSwitch(TestCase):
         tpl = TextTemplate('''%for i in range(2)
 $i is {%switch i % 2 %}{%case 0%}even\n{%else%}odd\n{%end%}\\
 %end''')
-        rsp = tpl(dict(name='Rick')).__kj__.render() 
+        rsp = tpl(dict(name='Rick')).render() 
         assert rsp == '0 is even\n1 is odd\n', rsp
 
     def test_ljust(self):
         tpl = TextTemplate('''     %for i in range(2)
 $i is {%switch i % 2 %}{%case 0%}even\n{%else%}odd\n{%end%}\\
 %end''')
-        rsp = tpl(dict(name='Rick')).__kj__.render() 
+        rsp = tpl(dict(name='Rick')).render() 
         assert rsp == '0 is even\n1 is odd\n', rsp
         tpl = TextTemplate('''     {%-for i in range(2)%}\\
 $i is {%switch i % 2 %}{%case 0%}even{%else%}odd{%end%}
     {%-end%}''')
-        rsp = tpl(dict(name='Rick')).__kj__.render() 
+        rsp = tpl(dict(name='Rick')).render() 
         assert rsp == '0 is even\n1 is odd\n', rsp
 
     def test_rstrip(self):
         tpl = TextTemplate('''     %for i in range(2)
 $i is {%switch i % 2 %}{%case 0-%}    even\n{%else%}odd\n{%end%}\\
 %end''')
-        rsp = tpl(dict(name='Rick')).__kj__.render() 
+        rsp = tpl(dict(name='Rick')).render() 
         assert rsp == '0 is even\n1 is odd\n', rsp
 
 class TestFunction(TestCase):
 $i is ${evenness(i)}
 %end
 ''')
-        rsp = tpl(dict(name='Rick')).__kj__.render() 
+        rsp = tpl(dict(name='Rick')).render() 
         assert rsp == '0 is even\n1 is odd\n', rsp
 
 class TestCall(TestCase):
 %call(n) quote(%caller ,'the raven')
 Nevermore $n\\
 %end''')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert (
             rsp == 'Quoth the raven, "Nevermore 0."\n'
             'Quoth the raven, "Nevermore 1."\n'), rsp
             'lib.txt':lib,
             'tpl.txt':tpl})
         tpl = loader.import_('tpl.txt')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert (rsp=='0 is even half of 0 is even\n'
                 '1 is odd half of 1 is even\n'
                 '2 is even half of 2 is odd\n'
             'lib.txt':lib,
             'tpl.txt':tpl})
         tpl = loader.import_('tpl.txt')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert (rsp=='0 is even half of 0 is even\n'
                 '1 is odd half of 1 is even\n'
                 '2 is even half of 2 is odd\n'
 b
 ''')})
         tpl = loader.import_('tpl.txt')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == 'a\n# header\nb\n', rsp
 
 class TestExtends(TestCase):
             'mid.txt':mid,
             'child.txt':child})
         tpl = loader.import_('child.txt')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert (rsp == '# Header name=Rick\n'
                 '## Child Body\n'
                 '## Parent Body\n'
 ''')
                 })
         tpl = loader.import_('child.txt')
-        rsp = tpl(dict(p=0)).__kj__.render()
+        rsp = tpl(dict(p=0)).render()
         assert rsp == 'Parent 0', rsp
-        rsp = tpl(dict(p=1)).__kj__.render()
+        rsp = tpl(dict(p=1)).render()
         assert rsp == 'Parent 1', rsp
 
     def test_block(self):
 %end
 ''')})
         child = loader.import_('child.txt')
-        rsp = child({'to':'Mark', 'from_':'Rick'}).__kj__.render()
+        rsp = child({'to':'Mark', 'from_':'Rick'}).render()
         assert (rsp=='''Dear Mark:
 It was good seeing you last Friday.  Thanks for the gift!
 
 %end
 ${add(5)}
 ''')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == '15\n', rsp
 
 class TestPython(TestCase):
 import os
 %end
 ${os.path.join('a','b','c')}''')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == 'a/b/c'
 
     def test_indent(self):
     import re
 %end
 ${os.path.join('a','b','c')}''')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == 'a/b/c'
 
     def test_short(self):
         tpl = TextTemplate('''%py import os
 ${os.path.join('a','b','c')}''')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == 'a/b/c'
 
     def test_mod(self):
 ${os.path.join('a','b','c')}\\
 %end
 ${test()}''')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == 'a/b/c'
 
 class TestDebug(TestCase):
         loader = FileLoader(base=os.path.join(os.path.dirname(__file__), 'data'))
         tpl = loader.import_('debug.txt')
         try:
-            tpl().__kj__.render()
+            tpl().render()
             assert False, 'Should have raised ValueError'
         except ValueError:
             exc_info = sys.exc_info()

File kajiki/tests/test_xml.py

 
     def test_expr_name(self):
         tpl = XMLTemplate(source='<div>Hello, $name</div>')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == '<div>Hello, Rick</div>', rsp
 
     def test_expr_braced(self):
         tpl = XMLTemplate(source='<div>Hello, ${name}</div>')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == '<div>Hello, Rick</div>', rsp
 
     def test_expr_brace_complex(self):
         tpl = XMLTemplate(source="<div>Hello, ${{'name':name}['name']}</div>")
-        rsp = tpl(dict(name='Rick')).__kj__.render() 
+        rsp = tpl(dict(name='Rick')).render() 
         assert rsp == '<div>Hello, Rick</div>', rsp
 
 class TestSwitch(TestCase):
 <py:case value="0">even</py:case>
 <py:else>odd</py:else>
 </py:switch></div>''')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == '''<div>
 0 is even</div><div>
 1 is odd</div>''', rsp
 <py:for each="i in range(2)">$i is ${evenness(i)}
 </py:for
 ></div>''')
-        rsp = tpl(dict(name='Rick')).__kj__.render()
+        rsp = tpl(dict(name='Rick')).render()
         assert rsp == '''<div>
 0 is <div>even</div>
<