3 Python templating languages you should (probably) never use

Python has accumulated a lot of templating languages, including these three that are perfect for April Fools' Day.
97 readers like this.
Hands on a keyboard with a Python book

WOCinTech Chat. Modified by Opensource.com. CC BY-SA 4.0

When reaching for a templating language for writing a Python web application, there are an abundance of robust solutions. 

There are Jinja2, Genshi, and Mako. There are even solutions like Chameleon, which are a bit older, but still recommended by the Pyramid framework.

Python has been around for a long time. In that time, deep in the corners of its system, it has accumulated some almost forgotten templating languages that are well worth poking at.

Like cute koalas on top of a eucalyptus tree, happy in their ecological niche, and sometimes as dangerous to work with, these are the templating languages few have heard of—and even fewer should use.

3. string.Template

Have you ever wondered, "How can I get a templating language with no features, but also without needing to pip install anything?" The Python standard library has you covered. While it does no looping or conditionals, the string.Template class is a minimal templating language.

Using it is simplicity itself.

>>> import string
>>> greeting = string.Template("Hello, $name, good $time!")
>>> greeting.substitute(name="OpenSource.com", time="afternoon")
'Hello, OpenSource.com, good afternoon!'

2. twisted.web.template

What gift do you give the library that has everything?

Not a templating language, certainly, because it already has one. Nestled in twisted.web.template are two templating languages. One is XML-based and has a great tutorial.

But there is another one, one that is based on using Python as a domain-specific language to produce HTML documents.

It is based on two primitives: twisted.web.template.tags, which contains tag objects, and twisted.web.template.flattenString, which will render them. Because it is part of Twisted, it has built-in support for rendering async results efficiently.

This example will render a silly little page:

async def render(reactor):
    my_title = "A Fun page"
    things = ["one", "two", "red", "blue"]
    template = tags.html(
            tags.head(
                tags.title(my_title),
            ),
            tags.body(
                tags.h1(my_title),
                tags.ul(
                    [tags.li(thing) for thing in things],
                ),
                tags.p(
                    task.deferLater(reactor, 3, lambda: "Hello "),
                    task.deferLater(reactor, 3, lambda: "world!"),
                )
            )
    )
    res = await flattenString(None, template)
    res = res.decode('utf-8')
    with open("hello.html", 'w') as fpout:
        fpout.write(res)

The template is regular Python code that uses the tags.<TAGNAME> to indicate the hierarchy. It natively supports strings as renderables, so any string is fine.

To render it, the only things you need to do are to add a preamble:

from twisted.internet import task, defer
from twisted.web.template import tags, flattenString

def main(reactor):
    return defer.ensureDeferred(render(reactor))

and an epilogue to run the whole thing:

task.react(main)

In just three seconds (and not six), it will render a nice HTML page. In real-life, those deferLaters can be, for example, calls to an HTTP API: they will be sent and processed in parallel, without having to put in any effort. I recommend you instead read about a far better use for Twisted. But still, this works.

1. Quixote

You will say, "But Python is not optimized for being an HTML-spouting domain-specific language." What if, instead of settling for Python-as-is, there was a language that transpiles to Python, but is better at defining templates? A "Python template language" (PTL), if you will.

Writing your own language is sometimes said to be a dreamer's project for someone who tilts at windmills. Irony was not lost on the creators of Quixote (available on PyPI) when they decided to do exactly that.

The following will render an equivalent template to the one done with Twisted above. Warning: the following is not valid Python:

import time

def render [html] ():
    my_title = "A Fun page"
    things = ["one", "two", "red", "blue"]
    "<html><head><title>"
    my_title
    "</head></title><body><h1>"
    my_title
    "</h1>"
    "<ul>"
    for thing in things:
        "<li>"
        thing
        "</li>"
    "<p>"
    time.sleep(3)
    (lambda: "Hello ")()
    time.sleep(3)
    (lambda: "world!")()
    "</p>"
    "</body></html>"

def write():
    result = render()
    with open("hello.html", 'w') as fpout:
        fpout.write(str(result))

However, if you put it in a file called template.ptl, you can make it importable to Quixote and write out the rendered version of the template:

>>> from quixote import enable_ptl
>>> enable_ptl()
>>> import template
>>> template.write()

Quixote installs an import hook that will cause PTL files to transpile into Python. Note that this render takes six seconds, not three; you no longer gain free asynchronicity.

So many templates in Python

Python has a long and winding history of libraries, some of which can achieve the same outcomes in more or less similar ways (for example, Python package management).

On this April Fools' Day, I hope you enjoyed exploring three ways you can create templates in Python. Instead, I recommend starting with one of these libraries for ways you should template.

Do you have another esoteric way to template? Share it in the comments below!

What to read next
Tags
Moshe sitting down, head slightly to the side. His t-shirt has Guardians of the Galaxy silhoutes against a background of sound visualization bars.
Moshe has been involved in the Linux community since 1998, helping in Linux "installation parties". He has been programming Python since 1999, and has contributed to the core Python interpreter. Moshe has been a DevOps/SRE since before those terms existed, caring deeply about software reliability, build reproducibility and other such things.

Comments are closed.

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.