

I've not written anything relating to Python for ages but today a two-fer with a post announcing (since the authors aren't publicity hounds) an update to DurusWorks, and this post on string templating in Python which came about only because Andriy Kornatskyy, the author of Wheezy.template, happened to update his results table.
Since I needed to test the new DurusWorks and the QPY templating package out anyway, I cooked up two entries for the bigtable.py benchmark. The first example utilizes QPY's smart-string escaping found in xml() and join_xml(), and, happily, this code looks almost identical (for a reason) to the standard lib inspired list_append "template" function found in bigtable.py:
from qpy import xml, join_xml
def test_qpy_list_append():
b = []
w = b.append
table = ctx['table']
w(xml('<table>\n'))
for row in table:
w(xml('<tr>\n'))
for key, value in row.items():
w(xml('<td>'))
w(key)
w(xml('</td><td>'))
w(value)
w(xml('</td>\n'))
w(xml('</tr>\n'))
w(xml('</table>'))
return join_xml(b)
Look at the results table at the end of this post and you'll see QPY is pretty fast compared to plain-ol-string operations given smart XML escaping is going on too. QPY's xml type is a subclass of Python's string class; QPY provides a C extension module for performance.
So that was fast, but coding web applications that way gets ugly even faster. Fortunately for no pain and all the gain, you can rewrite the above as:
def test_qpy_template:xml ():
table = ctx['table']
'<table>\n'
for row in table:
'<tr>\n'
for key, value in row.items():
'<td>'
key
'</td><td>'
value
'</td>\n'
'</tr>\n'
'</table>\n'
And even better, string substitutions don't get in the way of performance or smart escaping of untrusted input:
def test_qpy_template_sub:xml ():
table = ctx['table']
'<table>\n'
for row in table:
'<tr>\n'
for key, value in row.items():
'<td>%s</td><td>%s</td>\n' % (key, value)
'</tr>\n'
'</table>\n'
Or, if Python 3's .format() method turns your crank more:
def test_qpy_template_fmt:xml ():
table = ctx['table']
'<table>\n'
for row in table:
'<tr>\n'
for key, value in row.items():
'<td>{}</td><td>{}</td>\n'.format(key, value)
'</tr>\n'
'</table>\n'
Now we're talking. With these last two examples it becomes clearer that QPY templates turn traditional templating upside down in that QPY offers a sane mechanism to have content-in-code rather than code-in-content which is the common approach to HTML templating.
QPY's style will be an acquired taste for some, and is definitely not suitable for non-programmers.
Comparative results table:
Linux Mint Debian Edition, Virtual Machine on a high end Windows box
2 Cores configured, 4GB RAM
(wz) % python3 bigtable.py
msec rps tcalls funcs
chameleon 35.61 28.08 182033 25
cheetah not installed
django 504.84 1.98 1503067 51
jinja2 28.18 35.48 60020 27
list_append 33.07 30.24 103008 12
list_extend 32.96 30.34 63008 12
mako 24.24 41.26 93036 37
qpy_list_append 17.23 58.02 53008 9
qpy_template 17.06 58.63 53008 9
qpy_template_fmt 24.44 40.92 23008 10
qpy_template_sub 13.98 71.55 13008 9
tenjin 21.40 46.73 123012 16
tornado 76.35 13.10 353023 23
web2py not installed
wheezy_template 34.15 29.28 103010 14
In general the relative performance between tools looks to match Andriy's own results except for his own tool wheezy.template, and I can't account for why that would be so, but no doubt Andriy will sort things out soon.
The truly good news is there are a number of well-done, fast-enough templating solutions for Python web application developers to lean on so pick the one(s) that fit your head or project best and move on!
DurusWorks 1.2, born of QP, born of the venerable Quixote web framework, has been released. DW includes the Python object database Durus, a ZODB work-a-like with less complexity. Durus, like ZODB, has uses that go far beyond web development.
Dulcinea, a DW/QP centric package of objects, UI, and helpers, has also been updated.
QP, Durus, and DurusWorks have supported Python 2.x and Python 3.x from the same code base for years and can be found here: https://www.mems-exchange.org/software/
Tired of all the lies, Allison Robicelli finally discovers the awful truth about jogging.
Tags: Allison Robicelli running sportsI despise everything about running. I hate the New York City Marathon, which bisects my neighborhood every year, making my commute to work or any theoretical trips to the emergency room completely impossible. I hate people who are constantly posting about running over on Facebook, casually humblebragging about how they fit in a "quickie 5K" between picking up the dry cleaning and the children. I hate 5Ks, even though, where I live, they usually conclude with free beer and six-foot-long heroes (Bay Ridge, Brooklyn: Turning Everything into an Excuse for Day-Drinking Since 1853). I hate "fun runs" because, seriously, fuck you.