{"id":14967234,"url":"https://github.com/bulletmark/mutemplate","last_synced_at":"2025-10-25T17:31:46.780Z","repository":{"id":252493582,"uuid":"840605326","full_name":"bulletmark/mutemplate","owner":"bulletmark","description":"Compile template files into a standalone python file","archived":false,"fork":false,"pushed_at":"2025-01-28T00:45:21.000Z","size":58,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-28T01:34:56.909Z","etag":null,"topics":["microdot","micropython","utemplate"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bulletmark.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-10T06:15:18.000Z","updated_at":"2025-01-28T00:45:25.000Z","dependencies_parsed_at":"2025-01-28T01:29:26.637Z","dependency_job_id":"715a9b2c-b0c3-47b0-bb9b-3b5577aceef3","html_url":"https://github.com/bulletmark/mutemplate","commit_stats":{"total_commits":8,"total_committers":1,"mean_commits":8.0,"dds":0.0,"last_synced_commit":"b002583037e22b8b88ae014443471ca5694adc5a"},"previous_names":["bulletmark/mutemplate"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bulletmark%2Fmutemplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bulletmark%2Fmutemplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bulletmark%2Fmutemplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bulletmark%2Fmutemplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bulletmark","download_url":"https://codeload.github.com/bulletmark/mutemplate/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238191509,"owners_count":19431438,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["microdot","micropython","utemplate"],"created_at":"2024-09-24T13:37:40.794Z","updated_at":"2025-10-25T17:31:46.774Z","avatar_url":"https://github.com/bulletmark.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"## MUTEMPLATE - Compiles Template Files into a Standalone Python File\n[![PyPi](https://img.shields.io/pypi/v/mutemplate)](https://pypi.org/project/mutemplate/)\n[![AUR](https://img.shields.io/aur/version/mutemplate)](https://aur.archlinux.org/packages/mutemplate/)\n\n[`mutemplate`][mutemplate] is a command line tool you run on your development\nhost/PC to compile one or more input template text files into a single stand-alone\noutput Python source file which can be imported into your project and rendered\nby specifying the template name and it's parameter arguments. `mutemplate`\ncreates very lightweight and memory-efficient templates which are primarily\ndesigned for resource constrained environments such as [MicroPython][mp] on a\nmicro-controller, although created templates can be used with standard Python\nalso. `mutemplate` is derived from [`utemplate`][utemplate] and uses the same\ntemplate format which is very similar to [`Django`][django] and\n[`Jinja`][jinja] templates. (e.g. `{% if %}`, `{{var}}`).\n\nOnly essential template features are offered, for example, \"filters\"\n(`{{var|filter}}`) are syntactic sugar for function calls so are not\nimplemented, function calls can be used directly instead:\n`{{filter(var)}}`).\n\n`mutemplate` compiles templates to Python source code. Think of a\ncompiled template as a enhanced \"`f`\" string that can embed `for` loops\nand `if/else` conditionals evaluated for the arguments given at\nrun-time. A `generate()` generator function can be iterated over to\nproduce consecutive sub-strings of the rendered template. This allows\nfor minimal memory usage during template substitution and output.\nAlternatively, the `render()` function can be used to return the entire\nrendered template as a single string.\n\n`mutemplate` provides the following two commands:\n\n|Command  |Alias|Description                                                          |\n|---------|-----|---------------------------------------------------------------------|\n|`compile`|`c`  |Compile one or more template files into a single Python source file. |\n|`render` |`r`  |Render given templates + arguments to output, for exercising/testing.|\n\nThese are described in detail in the later [Usage](#usage) section.\n\nThis utility has been developed and tested on Linux and should work on\nMac OS and Windows but has not been tried on those platforms. Raise an\nissue or start a discussion on the [`mutemplate`][mutemplate] GitHub site\nif you want.\n\n## Syntax Reference\n\n- `{{\u003cexpr\u003e}}` - evaluates the given Python `\u003cexpr\u003e` expression,\n  converting it to a string and outputting to rendered content. Can be a\n  bare variable name, or a function call, a yield from/await\n  expressions, etc.\n- `{% if \u003cexpr\u003e %}, {% elif \u003cexpr\u003e %}, {% else %}, {% endif %}` - analogous to Python's if statement.\n- `{% for \u003cvar\u003e in \u003cexpr\u003e %}, {% endfor %}` - analogous to Python's for statement.\n- `{% while \u003cexpr\u003e %}, {% endwhile %}` - analogous to Python's while statement.\n- `{% set \u003cvar\u003e = \u003cexpr\u003e %}` - assignment statement.\n- `{% include \"name.tpl\" %}` - include another template. The\nname can be a string literal or a variable, e.g. `{% include {{name}} %}`.\n- `{# this is a comment #}` - comment line which is not compiled into the template.\n\nNote that all expressions and statements of the types above must be on a single line.\n\n## Template Variables Namespace\n\n`mutemplate` uses a unique approach to pass template variables from your program\ninto the template. The user passes values to a `generate(*args,\n**kwargs)` or `render(*args, **kwargs)` function as keyword and/or dict\narguments, specifically anything the Python [`dict()` constructor can\naccept](https://docs.python.org/3/library/stdtypes.html#dict). The passed\nkeyword arguments are stored as attributes in a `t` namespace which is passed as\nthe single argument to a template to access the variables, e.g. the user passes\n`avalue=5` and it is accessed within the template as `A value = {{t.avalue}}`.\n\nA child template (i.e. a template included from another template) automatically\nreceives the same `t` namespace argument although you can change and/or add\nattribute values by adding keyword arguments to the `include` line. For example,\n`{% include name.tpl name=\"mary\" %}` will change the previous example `t.name`\nto `mary` whereas `{% include name.tpl name2=\"mary\" %}` will pass `t.name` as\n`mark` (i.e. as it was passed to the parent template), and add `t.name2` as\n`mary`.\n\n## Example\n\nCreate some source template files in a directory on your PC, e.g. in\n`templates/*.tpl`. Wherever you want an argument to be substituted in\nthe template at runtime, use `{{t.var}}` or `{% if t.var %}` etc.\nAn example simple template file may be:\n\n```sh\n$ cat templates/hello.tpl\n...\nHello, {{t.name}}!\n...\n```\n\nThen run the compiler at the command line on your PC:\n\n```sh\n$ mutemplate compile -o templates.py templates/*.tpl\n```\n\nThis compiles all the template files in `templates/*.tpl` into a single\nnewly created `./templates.py` file. Copy that single file (or just the\n`.mpy` bytecode) to your MicroPython project, import it, and use it as\nfollows:\n\n```python\nfrom microdot import Response\nfrom templates import Template\n..\nreturn Response(body=Template(\"hello\").generate(name=\"mark\"))\n```\n\nThis example is using [Microdot][microdot] to output a web page and is\nusing `mutemplate` to provide output in \"string chunks\" which is\nthe [most efficient\napproach](https://microdot.readthedocs.io/en/latest/intro.html#streaming-responses).\nYou can alternately return the complete string by using `render()` in\nthe above instead of `generate()`.\n\n\u003e Note: if your template is HTML, then don't forget to set the `Content-Type`\n\u003e header for Microdot.\n\n```python\nreturn Response(body=Template(\"a_html_template\").generate(data=data),\n                headers={'Content-Type': 'text/html'}\n```\n\nMore simple text examples are available in the [examples/](examples/)\ndirectory.\n\n## Render Command\n\nApart from the primary `compile` command line argument, a `render` command is\nalso provided to render templates to your screen for checking and testing. You\nmust specify the name of a previously compiled `templates.py` file, the template\nname, and it's keyword arguments. Example usage for the above template:\n\n```sh\n$ mutemplate render templates.py hello name=mark\n```\n\nArguments must be passed as `name=value` pairs. The value is converted to a\nnative Python type if possible, otherwise it is treated as a string.\n`name=mark` is passed as a string (e.g. same as `'name=\"mark\"'`), `age=42` would\nbe passed as an int, `values=[1,2,3]` would be passed as a list, etc. You may\nneed to brush on [shell quoting rules](https://mywiki.wooledge.org/Quotes)\nif you want to get tricky with this.\n\n## Differences from `utemplate`\n\n1. `mutemplate` is a command line tool only. It produces a single python\nfile containing all your compiled templates so no run time compilation\noccurs on your Micropython device and no dynamic imports are done by the\ntemplate engine.\n\n2. The `utemplate` \"`args`\"\" parameter is not recognised and an error is\nreported if it is used in `mutemplate` templates. `utemplate` needs the\n`args` parameter to assign values to variable names based on the order\nyou pass them to the template function but you define the relationship\n`var=value` in the call for `mutemplate` so order is not relevant. Note\nan advantage of the `mutemplate` approach is that to add a new template\nvariable you only need to add it to the template and to the calling\nfunction but `utemplate` requires you to also add it to the `args`\nparameter line and you also must ensure you maintain correct order which\nis easy to get wrong. Also, the clear distinction in your templates\nbetween internal variables (i.e. temporary loop counters/variables etc)\nand externally passed-in values (i.e. those in the `t.*` namespace) is\nuseful.\n\n3. `utemplate` compiles and stores multiple copies of child templates\nwhen they are included multiple times from different parent templates\nbut `mutemplate` compiles and stores every template once only. All\n`mutemplate` parent templates link to the one same child template. E.g.\nif you have 10 templates, all including a common `header.tpl` and a\n`footer.tpl` then `utemplate` will compile and store 10 copies of the\n`header` templates + 10 copies of the `footer` templates, `mutemplate`\nwill compile and store 1 of each only.\n\n4. `utemplate` (which appears to be unmaintained - no activity for 3\nyears) has an issue where it breaks and `yields` more sub-strings then\nit needs to (whenever it hits **any** \"`{`\" character) but the parser\nhas been improved in `mutemplate` to avoid this. `mutemplate` only\nbreaks to a new `yield` when it must for a Python statement or\nexpression, so templates are rendered a little more efficiently and\nquickly.\n\n5. `mutemplate` also allows `{# comment #}` tags which are missing from\n`utemplate` but are provided by [`Django`][django] and [`Jinja`][jinja]\ntemplates and are simple to implement so are added for consistency.\n\n## Usage\n\nType `mutemplate` or `mutemplate -h` to view the usage summary:\n\n```\nusage: mutemplate [-h] {compile,c,render,r} ...\n\nCommand line tool to compile one or more template text files into a single\nimportable python source file.\n\noptions:\n  -h, --help            show this help message and exit\n\nCommands:\n  {compile,c,render,r}\n    compile (c)         Compile one or more template files into a single\n                        Python source file.\n    render (r)          Render given templates + arguments to output, for\n                        exercising/testing.\n```\n\nType `mutemplate \u003ccommand\u003e -h` to see specific help/usage for any\nindividual command:\n\n### Command `compile`\n\n```\nusage: mutemplate compile [-h] [-o OUTFILE] [-w] [-q]\n                           template_file [template_file ...]\n\nCompile one or more template files into a single Python source file.\n\npositional arguments:\n  template_file         input template file[s]\n\noptions:\n  -h, --help            show this help message and exit\n  -o OUTFILE, --outfile OUTFILE\n                        output file, default is stdout\n  -w, --watch           watch specified files forever and run on any change\n  -q, --quiet           do not print any informational messages\n\naliases: c\n```\n\n### Command `render`\n\n```\nusage: mutemplate render [-h] [-d] template_file template_name [args ...]\n\nRender given templates + arguments to output, for exercising/testing.\n\npositional arguments:\n  template_file    python template file\n  template_name    name of template to render\n  args             arguments for template\n\noptions:\n  -h, --help       show this help message and exit\n  -d, --delineate  delineate chunks with \"|\" in generated output\n\naliases: r\n```\n\n## Installation and Upgrade\n\nPython 3.7 or later is required. Arch Linux users can install\n[`mutemplate` from the\nAUR](https://aur.archlinux.org/packages/mutemplate) and skip this\nsection.\n\nNote [mutemplate is on PyPI](https://pypi.org/project/mutemplate/) so\nthe easiest way to install it is to use [`uv tool`][uvtool] (or\n[`pipx`][pipx] or [`pipxu`][pipxu]).\n\n```sh\n$ uv tool install mutemplate\n```\n\nTo upgrade:\n\n```sh\n$ uv tool upgrade mutemplate\n```\n\nTo uninstall:\n\n```sh\n$ uv tool uninstall mutemplate\n```\n\n## License\n\nCopyright (C) 2024 Mark Blakeney. This program is distributed under the\nterms of the GNU General Public License. This program is free software:\nyou can redistribute it and/or modify it under the terms of the GNU\nGeneral Public License as published by the Free Software Foundation,\neither version 3 of the License, or any later version. This program is\ndistributed in the hope that it will be useful, but WITHOUT ANY\nWARRANTY; without even the implied warranty of MERCHANTABILITY or\nFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at\n\u003chttp://www.gnu.org/licenses/\u003e for more details.\n\n[mutemplate]: https://github.com/bulletmark/mutemplate\n[utemplate]: https://github.com/pfalcon/utemplate\n[mp]: https://micropython.org/\n[microdot]: https://microdot.readthedocs.io/\n[django]: https://docs.djangoproject.com/en/5.0/ref/templates/\n[jinja]: https://jinja.palletsprojects.com/en/3.1.x/templates/\n[pipx]: https://github.com/pypa/pipx\n[pipxu]: https://github.com/bulletmark/pipxu\n[uvtool]: https://docs.astral.sh/uv/guides/tools/#installing-tools\n\n\u003c!-- vim: se ai syn=markdown: --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbulletmark%2Fmutemplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbulletmark%2Fmutemplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbulletmark%2Fmutemplate/lists"}