ANN: pyTenjin 1.0.0 - a high-speed and full-featured template engine

Makoto Kuwata kwa at
Mon Feb 21 21:15:22 EST 2011

Hi all,

I released pyTenjin 1.0.0.

This release contains a lot of enhancements and changes.


* Very fast: about 10 times faster than Django template engine
* Easy to learn: no need to learn template-original language
* Full-featured: nestable layout template, partial template, preprocessing, etc.
* Lightweight: only 2000 lines of code and very fast to import.
* Google App Engine supported


* User's Guide
* Examples


    $ sudo easy_install Tenjin


    $ wget
    $ tar xzf Tenjin-1.0.0.tar.gz
    $ cd Tenjin-1.0.0/
    $ sudo python install


    ## views/example.pyhtml
    <?py #@ARGS title, items ?>
      <?py cycle = new_cycle('odd', 'even') ?>
      <?py for item in items: ?>
      <tr class="${cycle()}">
      <?py #endfor ?>

    import tenjin
    #tenjin.set_template_encoding('utf-8')  # optional (default 'utf-8')
    from tenjin.helpers import *
    from tenjin.html import *
    engine = tenjin.Engine(path=['views'])
    context = {'title': 'Example', 'items': ['Haruhi', 'Mikuru', 'Yuki'] }
    output = engine.render('example.pyhtml', context)

    ## output
    $ python
      <tr class="odd">
      <tr class="even">
      <tr class="odd">


* (IMPORTANT!!) Performance is improved (about 5 percent).
  To improve performance, compiled Python code is changed.
  OF THEM in order to clear cache data before using this release.

    ## touch all template files to clear cache data
    $ find . -name '*.pyhtml' | xargs touch
    ## show compiled python code
    $ cat ex.pyhtml
    <?py for item in items: ?>
    <?py #endfor ?>
    $ pytenjin -sb ex.pyhtml
_extend(('''<ul>\n''', ));
    for item in items:
        _extend(('''  <li>''', _escape(_to_str(item)), '''</li>\n''', ));
    _extend(('''<?ul>\n''', ));

* (IMPORTANT!!) Free-indent style supported. Now there is no limitation
  about indent.

    ## In the previous version, there is strong restriction about indent.
    <?py for item in items: ?>
    <?py #endfor ?>

    ## In this release, you can place statements freely.
          <?py for item in items: ?>
          <?py #endfor ?>

* (IMPORTANT!!) SafeTemplate and SafeEngine classes are now provided.
  These classes support autoescaping similar to Django or Jinja2.
  for details.

* (IMPORTANT!!) New function 'tenjin.set_template_encoding()' is provided.
  If you prefer templates to be unicode-base like Django or Jinja2,
  call it before importing helpers.

     ## change Tenjin to be unicode-based
     import tenjin
     tenjin.set_template_encoding('utf-8')  # call before importing helpers
     from tenjin.helpers import *
     ## The above is same as:
     #import tenjin
     #Template.encoding = 'utf-8'
     #tenjin.helpers.to_str = tenjin.helpers.generate_tostrfunc(decode='utf-8')
     #from tenjin.helpers import *

  Notice that you should NOT write '<?py # coding: utf-8 ?>' into template
  files if you call tenjin.set_template_encoding(). If you wrote it,
  SyntaxError exception would be raised.

* (IMPORTANT!!) New helper function 'cache_as()' is available for
fragment cache.
  This replaces 'not_cached()' and 'echo_cached()'.

     ## previous (obsolete)
     <?py if not_cached('cachekey1', 60): ?>
     <?py #endif ?>
     <?py echo_cached() ?>

     ## using new helper
     <?py for _ in cache_as('cachekey1', 60): ?>
     <?py #endfor ?>

  'not_cached()' and 'echo_cached()' are still available but not recommended.

* (IMPORTANT!!) New helper 'capture_as()' is available for capturing template.
  This replaces 'start_capture()' and 'stop_capture()'.

     ## preivous (obsolete)
     <?py start_capture('name') ?>
     <?py stop_capture() ?>

     ## using new helper
     <?py with capture_as('name'): ?>
     <?py #endfor ?>

  'start_capture()' and 'stop_capture()' are still available but not

  New helper 'capture_as()' allows you to nest capturing which is
  impossible with 'start_capture()' and 'stop_capture()'.

* If 'trace=True' is passed to Template class (or Engine class), output
  string will contain template file name. For example:

     <!-- ***** begin: hello.pyhtml ***** -->
     <div class="content">
       <p>Hello World!</p>
     <!-- ***** end: hello.pyhtml ***** -->

* tenjin.Engine now helps M17N of templates. If you pass 'lang' option to
  Engine, it will generates cache files for each langs from a file.
  This feature is intened to use with preprocessing in order to reduce
  catalog expantion cost (such as '${_("Hello")}')

      ## for lang='en'
      engine_en = tenjin.Engine(lang='en', preprocess=True)
      engine_en.render('index.pyhtml')  # generates 'index.pyhtml.en.cache'
      ## for lang='fr'
      engine_fr = tenjin.Engine(lang='fr', preprocess=True)
      engine_fr.render('index.pyhtml')  # generates ''

* (Experimental) New html helper 'js_link()'.

      >>> from tenjin.html import *
      >>> js_link('click', 'alert("OK")', klass='link')
      '<a href="javascript:undefined"
onclick="alert("OK");return false" class="link">click</a>'


* (IMPORTANT!!) You must close statement block of 'if', 'for', 'with', ...
  with corresponding '#endif', '#endfor', '#endwith', and so on.
  Notice that '#end' is available as almighty closer.

* (IMPORTANT!!) tenjin.GaeMemcacheCacheStorage is removed (this is already
  announced in the previous release).
  Please use tenjin.gae.GaeMemcacheStorage instead.

* 'tenjin.helpers.html' module is renamed to 'tenjin.html', but old module
  name is still available for backward compatibility.

* escape_html() (and escape()) now escapes "'" into "'".

* new_cycle() is moved from tenjin.helpers.html module to tenjin.helpers
  module because it is not only for HTML.

* In GAE environment, Tenjin uses '1.1' as dummy value of CURRENT_VERSION_ID
  when it is not provided. This prevents error when using GAE and tenjin
  on test environment.

* Python 2.3 is now unsupported. (Python 2.4 is still supported because
  CentOS uses Python 2.4).

* (internal) Tenjin.escape_expr_and_escapeflag() is changed to

* (internal) Tenjin.add_expr() is changed to take 'flags' argument.

* (internal) 'tenjin.__release__' is renamed to 'tenjin.__version__'.


* Cache file saving was failed on Windows because existing file should be
  removed before renaming file. (patched by elishowk, thank you!)

Thank you.
makoto kuwata

More information about the Python-list mailing list