Skip to main content

Compile template files into a standalone python file

Project description

MUTEMPLATE - Compiles Template Files into a Standalone Python File

PyPi AUR

mutemplate is a command line tool you run on your development host/PC to compile one or more template text files into a single dynamically created stand-alone Python source file which can be imported into your project and rendered by specifying the template name and it's parameter arguments. mutemplate creates very lightweight and memory-efficient templates which are primarily designed for resource constrained environments such as MicroPython on a micro-controller, although created templates can be used with standard Python also. mutemplate is derived from utemplate and uses the same template format which is very similar to Django and Jinja templates. (e.g. {% if %}, {{var}}).

Only essential template features are offered, for example, "filters" ({{var|filter}}) are syntactic sugar for function calls so are not implemented, function calls can be used directly instead: {{filter(var)}}).

mutemplate compiles templates to Python source code. Think of a compiled template as a enhanced "f" string that can embed for loops and if/else conditionals evaluated for the arguments given at run-time. A generate() generator function can be iterated over to produce consecutive sub-strings of the rendered template. This allows for minimal memory usage during template substitution and output. Alternatively, the render() function can be used to return the entire rendered template as a single string.

mutemplate provides the following two commands:

Command Alias Description
compile c Compile one or more template files into a single Python source file.
render r Render given templates + arguments to output, for exercising/testing.

These are described in detail in the later Usage section.

This utility has been developed and tested on Linux and should work on Mac OS and Windows but has not been tried on those platforms. Raise an issue or start a discussion on the mutemplate GitHub site if you want.

Syntax Reference

  • {{<expr>}} - evaluates the given Python <expr> expression, converting it to a string and outputting to rendered content. Can be a bare variable name, or a function call, a yield from/await expressions, etc.
  • {% if <expr> %}, {% elif <expr> %}, {% else %}, {% endif %} - analogous to Python's if statement.
  • {% for <var> in <expr> %}, {% endfor %} - analogous to Python's for statement.
  • {% while <expr> %}, {% endwhile %} - analogous to Python's while statement.
  • {% set <var> = <expr> %} - assignment statement.
  • {% include "name.tpl" %} - include another template. The name can be a string literal or a variable, e.g. {% include {{name}} %}.
  • {# this is a comment #} - comment line which is not compiled into the template.

Note that all expressions and statements of the types above must be on a single line.

Template Variables Namespace

mutemplate uses a unique approach to pass template variables from your program into the template. The user passes values to a generate(*args, **kwargs) or render(*args, **kwargs) function as keyword and/or dict arguments, specifically anything the Python dict() constructor can accept. The passed keyword arguments are stored as attributes in a t namespace which is passed as the single argument to a template to access the variables, e.g. the user passes avalue=5 and it is accessed within the template as A value = {{t.avalue}}.

A child template (i.e. a template included from another template) automatically receives the same t namespace argument although you can change and/or add attribute values by adding keyword arguments to the include line. For example, {% include name.tpl name="mary" %} will change the previous example t.name to mary whereas {% include name.tpl name2="mary" %} will pass t.name as mark (i.e. as it was passed to the parent template), and add t.name2 as mary.

Example

Create some source template files in a directory on your PC, e.g. in templates/*.tpl. Wherever you want an argument to be substituted in the template at runtime, use {{t.var}} or {% if t.var %} etc. An example simple template file may be:

$ cat templates/hello.tpl
...
Hello, {{t.name}}!
...

Then run the compiler at the command line on your PC:

$ mutemplate compile -o templates.py templates/*.tpl

# Note: if you only have *.tpl files in the templates directory you can
# alternately specify just the directory name:

$ mutemplate compile -o templates.py templates

This compiles all the template files in templates/*.tpl into a single newly created ./templates.py file. Copy that single file (or just the .mpy bytecode) to your MicroPython project, import it, and use it as follows:

from microdot import Response
from templates import Template
..
return Response(body=Template("hello").generate(name="mark"))

This example is using Microdot to output a web page and is using mutemplate to provide output in "string chunks" which is the most efficient approach. You can alternately return the complete string by using render() in the above instead of generate().

Note: if your template is HTML, then don't forget to set the Content-Type header for Microdot.

return Response(body=Template("a_html_template").generate(data=data),
                headers={'Content-Type': 'text/html'}

More simple text examples are available in the examples/ directory.

Render Command

Apart from the primary compile command line argument, a render command is also provided to render templates to your screen for checking and testing. You must specify the name of a previously compiled templates.py file, the template name, and it's keyword arguments. Example usage for the above template:

$ mutemplate render templates.py hello name=mark

Arguments must be passed as name=value pairs. The value is converted to a native Python type if possible, otherwise it is treated as a string. name=mark is passed as a string (e.g. same as 'name="mark"'), age=42 would be passed as an int, values=[1,2,3] would be passed as a list, etc. You may need to brush on shell quoting rules if you want to get tricky with this.

Differences from utemplate

  1. mutemplate is a command line tool only. It produces a single python file containing all your compiled templates so no run time compilation occurs on your Micropython device and no dynamic imports are done by the template engine.

  2. The utemplate "args"" parameter is not recognised and an error is reported if it is used in mutemplate templates. utemplate needs the args parameter to assign values to variable names based on the order you pass them to the template function but you define the relationship var=value in the call for mutemplate so order is not relevant. Note an advantage of the mutemplate approach is that to add a new template variable you only need to add it to the template and to the calling function but utemplate requires you to also add it to the args parameter line and you also must ensure you maintain correct order which is easy to get wrong. Also, the clear distinction in your templates between internal variables (i.e. temporary loop counters/variables etc) and externally passed-in values (i.e. those in the t.* namespace) is useful.

  3. utemplate compiles and stores multiple copies of child templates when they are included multiple times from different parent templates but mutemplate compiles and stores every template once only. All mutemplate parent templates link to the one same child template. E.g. if you have 10 templates, all including a common header.tpl and a footer.tpl then utemplate will compile and store 10 copies of the header templates + 10 copies of the footer templates, mutemplate will compile and store 1 of each only.

  4. utemplate (which appears to be unmaintained - no activity for 3 years) has an issue where it breaks and yields more sub-strings then it needs to (whenever it hits any "{" character) but the parser has been improved in mutemplate to avoid this. mutemplate only breaks to a new yield when it must for a Python statement or expression, so templates are rendered a little more efficiently and quickly.

  5. mutemplate also allows {# comment #} tags which are missing from utemplate but are provided by Django and Jinja templates and are simple to implement so are added for consistency.

Usage

Type mutemplate or mutemplate -h to view the usage summary:

usage: mutemplate [-h] {compile,c,render,r} ...

Command line tool to compile one or more template text files into a single
importable python source file.

options:
  -h, --help            show this help message and exit

Commands:
  {compile,c,render,r}
    compile (c)         Compile one or more template files into a single
                        Python source file.
    render (r)          Render given templates + arguments to output, for
                        exercising/testing.

Type mutemplate <command> -h to see specific help/usage for any individual command:

Command compile

usage: mutemplate compile [-h] [-o OUTFILE] [-w] [-q]
                           template_file [template_file ...]

Compile one or more template files into a single Python source file.

positional arguments:
  template_file         input template file[s] (or dir[s] containing template
                        file[s])

options:
  -h, --help            show this help message and exit
  -o OUTFILE, --outfile OUTFILE
                        output file, default is stdout
  -w, --watch           watch specified files forever and run on any change
  -q, --quiet           do not print any informational messages

aliases: c

Command render

usage: mutemplate render [-h] [-d] template_file template_name [args ...]

Render given templates + arguments to output, for exercising/testing.

positional arguments:
  template_file    python template file
  template_name    name of template to render
  args             arguments for template

options:
  -h, --help       show this help message and exit
  -d, --delineate  delineate chunks with "|" in generated output

aliases: r

Installation and Upgrade

Python 3.7 or later is required. Arch Linux users can install mutemplate from the AUR and skip this section.

The easiest way to install mutemplate is to use pipx (or pipxu, or uv tool).

$ pipx install mutemplate

To upgrade:

$ pipx upgrade mutemplate

To uninstall:

$ pipx uninstall mutemplate

License

Copyright (C) 2024 Mark Blakeney. This program is distributed under the terms of the GNU General Public License. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at http://www.gnu.org/licenses/ for more details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mutemplate-1.2.tar.gz (17.9 kB view details)

Uploaded Source

Built Distribution

mutemplate-1.2-py3-none-any.whl (12.7 kB view details)

Uploaded Python 3

File details

Details for the file mutemplate-1.2.tar.gz.

File metadata

  • Download URL: mutemplate-1.2.tar.gz
  • Upload date:
  • Size: 17.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.12.7

File hashes

Hashes for mutemplate-1.2.tar.gz
Algorithm Hash digest
SHA256 c546d56786092fe8bdbe652fd77140233117eb40ce3fbebbb167a62e90ec30b0
MD5 234e6a43835fca59c16c1cd7b47b2c04
BLAKE2b-256 f9b1042ea49b3f03c4124a801caec3d93a477dbedcfe063d3fefe85e403b2f62

See more details on using hashes here.

File details

Details for the file mutemplate-1.2-py3-none-any.whl.

File metadata

  • Download URL: mutemplate-1.2-py3-none-any.whl
  • Upload date:
  • Size: 12.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.12.7

File hashes

Hashes for mutemplate-1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 126dddeec5820e1e189f219b471ad84729ed916cae450d7fa4dbf4924cdad821
MD5 6ea93d5185ef31e5e35392843f672c1a
BLAKE2b-256 11ee9e22ef7565a3788ebfd4df70a62a7a0a46276ede95d5f3b9288fa98808fd

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page