Lukas Schwarz

Pystpl - A Simple Python Template Parser

GitHub GitHub

For a different project I needed a template parser in python. Of course, there exists already a large amount of template engines. However, out of interest, I decided to write my own template engine suited for my needs. The library itself consists of a single file and contains only a few hundred lines of code. The library has the following features:

  • Variable tag markers (default "[[" and "]]")
  • Placeholders for variables including arbitrarily nested dicts or class properties
  • Strings can be marked to be translated by gettext
  • Loops including loop count variable
  • Conditional expressions, if and else
  • Option to define an escaping method for variables
  • Expressive error messages including line/character if template contains errors

Usage

The usage is straight forward. Consider the following example template text

text = """
Lorem ipsum dolor sit [[var1]] amet, consectetur adipisicing [[foo.bar]] elit.
[[FOR i,item1 IN list1]][[FOR j,item2 IN list2]]
    [[i]],[[j]]: [[item1]], [[item2]]
[[ENDFOR]][[ENDFOR]]
[[FOR item IN list1]]
    [[item]]
[[ENDFOR]]
[[IF var2 == "lalilu"]]
    var2 is lalilu
[[ELSE]]
    var2 is not lalilu
[[ENDIF]]
[[IF var3 > 103]]
    var3 > 103
[[ENDIF]]
[[IF var3 < 103]]
    var3 < 103
[[ENDIF]]
[[IF var3 <= 103]]
    var3 <= 103
[[ENDIF]]
[[IF var3 <= 103]]
    var3 <= 103
[[ENDIF]]
[[IF var3 != 103]]
    var3 != 103
[[ENDIF]]
[[IF var1 == var2]]
    var1 == var2
[[ENDIF]]
"""

Variables are marked as [[variablename]]. The loop and condition syntax is the same as in normal python also marked with opening and closing characters like [[SOME EXPRESSION]]. For further syntax information see the README.

To evaluate the example consider the following code

import pystpl

# example data
data = {
    "var1" : "this is a test",
    "var2" : "lalilu",
    "var3" : 10,
    "foo" : {"bar" : 123},
    "list1" : [44,56,11],
    "list2" : ["blub", "haha"]
}

# define an example quote method
def quote(text):
    return text.replace("a", "AA")

try:
    # parse template
    tpl = pystpl.Tpl(text)

    # evaluate template and fill placeholders with data
    print(tpl.substitute(data, quote))
except pystpl.TplError as e:
    print(e)

The output is


Lorem ipsum dolor sit this is AA test amet, consectetur adipisicing 123 elit.
    1,1: 44, blub
    1,2: 44, hAAhAA
    2,1: 56, blub
    2,2: 56, hAAhAA
    3,1: 11, blub
    3,2: 11, hAAhAA
    44
    56
    11
    var2 is lalilu
    var3 < 103
    var3 <= 103
    var3 <= 103
    var3 != 103

Benchmark

To check how my implementation performs considering the execution time in comparison with other template engines I used the benchsimple benchmark, which I found on the website www.simple-is-better.org. The configuration file for the benchmark and the result can be found here. Running the benchmark in comparison with other engines gives the following result:

pystpl 0.0.1
-------
  import:       10.4709 ms
  complete:      3.7436 ms
  parse only:    0.4104 ms
  render only:   3.2643 ms

Cheetah ?.?
-------
  import:       80.0281 ms
  complete:      2.2945 ms
  parse only:    0.0251 ms
  render only:   2.2269 ms

mako 1.0.6
-------
  import:       92.7191 ms
  complete:      5.8826 ms
  parse only:    5.6144 ms
  render only:   0.2084 ms


jinja2 2.9.6
-------
  import:       68.5041 ms
  complete:      7.1358 ms
  parse only:    6.8045 ms
  render only:   0.3144 ms

Compared with other template engines, my implementation performs quite well.