Python: Calling python functions from mako templates

python-logoThe mako template engine is a powerful module for Python used by many large sites including reddit.com.  You simply push the variables you want into a context and then merge that with a text template.

Additionally, mako allows you to take advantage of the full power of the Python language and libraries by allowing calls to Python functions from  inside the template.

In this article I’ll provide Python sample code for merging a set of key/value pairs in a properties file with a text template.  A portion of the rendered output will come from a call to a Python function.

Prerequisites

I’m going to assume you have Python2 with pip installed.   On Ubuntu, set the dependencies using:

sudo apt-get install python-dev python-pip
pip install mako

Github project

The github project for this article contains several files:

  • mako.template – the template that drives the ultimate rendering
  • mako.properties – the values to be used in the template
  • lincoln-quote.txt – external file to be inserted into rendering
  • makoWithPythonFunction.py – merge properties and mako template
sudo apt-get install git

git clone https://github.com/fabianlee/mako-python-function.git
cd mako-python-function

The template

First, look at the template.  You can see a simple variable substitution with ${var1} and ${who}.  But even more interesting is the ${get_quote_and_indent()} which is the invocation of a Python function of the same name.

This is the first line, ${var1}

     ${get_quote_and_indent(person,"quote.txt",5)}

     ${who}

This is the last line.

This function passes arguments using ‘person’ (a value from the properties file) as well as string and integer values.

Rendered output

When invoked, the property values are merged with the template and you can see that the ‘lincoln-quote.txt’ is output with indentation.

$ ./makoWithPythonFunction.py mako.template mako.properties 
This is the first line, this was in variable 1

     Be sure you put your feet
     in the right place,
     then stand firm.

     Quote by lincoln

This is the last line.

The code

Reading the properties file for values and creating the context for mako rendering is almost boilerplate, so I will only highlight here how the ‘get_quote_and_indent’ function is exposed for invocation in the template.

The Python function first needs to be defined of course, with the function name and arguments to be passed.

def get_quote_and_indent(author,basename,indent):
  ...

Then we need to expose the function for use by adding its key name and value along with all the other values loaded into our dictionary.

myprops['get_quote_and_indent'] = get_quote_and_indent

And then we pass this myprops dictionary to the mako Context, which is subsequently rendered.

ctx = Context(buf,**myprops)
try:
  mytemplate.render_context(ctx)

 

REFERENCES

https://www.makotemplates.org/ (mako documentation)

https://github.com/pypa/pip/issues/5599#issuecomment-416318017 (pip broken on Ubuntu)

https://stackoverflow.com/questions/49964093/file-usr-bin-pip-line-9-in-module-from-pip-import-main-importerror-canno/49988228 (on uninstalling manually installed pip in favor of Ubuntu shipped pip)

NOTES

If pip broken on Ubuntu

sudo chown -R $USER:$USER ~/.cache
python -m pip uninstall pip setuptools wheel
sudo apt-get --reinstall install python-setuptools python-wheel python-pip