Skip to content

User Guide

Template Writing

https://www.makotemplates.org/ documents the template language. Within the template the following symbols are available

Symbol Description
datamodel Datamodel - the data container
output_filepath pathlib.Path with outputfile path
output_tags tuple[str, ...] with tags about code-generation type, see Tags
makolator Makolator - Makolator Engine
makolator.open_outputfile Makolator.open_outputfile - Create file handle with timestamp preserving.
makolator.gen Makolator.gen - generate file
makolator.inplace Makolator.inplace - update file
makolator.clean Makolator.clean - remove fully-generated files
makolator.info Makolator.info - Information Container
run run - Identical to subprocess.run and capture stdout.
indent Indent single line or multiple lines by two spaces: ${text | indent}
indent(spaces) Indent single line or multiple lines by given number of spaces: ${text | indent(4)}
indent(spaces, rstrip=True) Indent single line or multiple lines by given number of spaces, but avoid end-line whitespaces: ${text | indent(4, rstrip=True)}
prefix(text) Prefix single line or multiple lines by given text: ${text | prefix('// ')}
prefix(text, rstrip=True) Prefix single line or multiple lines by given text, but avoid end-line whitespaces: ${text | prefix('// ', rstrip=True)}
comment(text) Prefix single line or multiple lines by comment separator from Config: ${text | comment('Text set as comment')}
tex Escape latex special characters: ${text | tex}

Tags

Tag Description
@generated Always included, as all files are generated
@fully-generated Included if the file is generated via Makolator.gen and does not include any static-code which must be kept.
@inplace-generated Included if the file is created via Makolator.inplace

run Examples

run(['echo', '"Hello World"'])
run('echo "Hello World"', shell=True)
run('mycmd --output file && cat file', shell=True)
The variable ${TMPDIR} in the arguments will be replaced by a temporary directory path.

File Generation

The template test.txt.mako:

<%def name="afunc(pos, opt=None)">\
output_filepath.name=${output_filepath.name}
output_tags=${" ".join(output_tags)}
pos=${pos}
% if opt:
options: ${opt}
% endif

</%def>
# ${makolator.info.genwarning}
# This file is updated by '${makolator.info.cli}'

Text
${afunc('abc')}
${afunc('def', opt=5)}

A generate (makolator gen test.txt.mako test.txt) will result in:

# THIS FILE IS GENERATED!!! DO NOT EDIT MANUALLY. CHANGES ARE LOST.
# This file is updated by 'makolator gen test.txt.mako test.txt'

Text
output_filepath.name=test.txt
output_tags=@generated @fully-generated
pos=abc


output_filepath.name=test.txt
output_tags=@generated @fully-generated
pos=def
options: 5

Inplace Code Generation

Assume the following file:

This is just some handwritten text.

    GENERATE INPLACE BEGIN afunc("foo")
obsolete
    GENERATE INPLACE END afunc

This is also something in between.

// ==== GENERATE INPLACE BEGIN afunc("foo", "bar") ====
    will be updated
// ==== GENERATE INPLACE END afunc ====

The lines between GENERATE INPLACE BEGIN and GENERATE INPLACE END can be filled via a template like:

<%def name="afunc(pos, opt=None)">\
${output_filepath.name}
pos=${pos}
% if opt:
options: ${opt}
% endif

</%def>

An inplace update (makolator inplace inplace.txt.mako file.txt) will result in:

This is just some handwritten text.

    GENERATE INPLACE BEGIN afunc("foo")
    inplace.txt
    pos=foo

    GENERATE INPLACE END afunc

This is also something in between.

// ==== GENERATE INPLACE BEGIN afunc("foo", "bar") ====
inplace.txt
pos=foo
options: bar

// ==== GENERATE INPLACE END afunc ====

Inplace Skeleton

The inplce code generation is a powerful mechanism. There is only the challenge to create a proper file with placeholders at the beginning. A template is allowed to serve a <%def name="create_inplace()">:

<%def name="afunc(pos, opt=None)">\
${output_filepath.name}
pos=${pos}
% if opt:
options: ${opt}
% endif

</%def>

<%def name="create_inplace()">\
-- GENERATE INPLACE BEGIN afunc("foo2")
created
-- GENERATE INPLACE END afunc
manually maintained code goes here
this is just the default
-- GENERATE INPLACE BEGIN afunc("foo3")
-- GENERATE INPLACE END afunc
</%def>

A missing inplace file is an error by default. The -c option activates the create_inplace mechanism: makolator inplace inplace-create.txt.mako file-create.txt -c

-- GENERATE INPLACE BEGIN afunc("foo2")
file-create.txt
pos=foo2

-- GENERATE INPLACE END afunc
manually maintained code goes here
this is just the default
-- GENERATE INPLACE BEGIN afunc("foo3")
file-create.txt
pos=foo3

-- GENERATE INPLACE END afunc

Inplace Template

The file can contain templates too:

You can define your own template in the source code

// MAKO TEMPLATE BEGIN
// <%def name="repeat(num)">\
// # ${makolator.info.inplacewarning}
// # This section is updated via '${makolator.info.cli}'
// ${output_filepath.name}
// % for idx in range(num):
// item${idx}
// % endfor
// </%def>
// MAKO TEMPLATE END


GENERATE INPLACE BEGIN repeat(2)
obsolete
GENERATE INPLACE END repeat


GENERATE INPLACE BEGIN repeat(5)
obsolete
GENERATE INPLACE END repeat

The inplace update (makolator inplace file.txt) will result in:

You can define your own template in the source code

// MAKO TEMPLATE BEGIN
// <%def name="repeat(num)">\
// # ${makolator.info.inplacewarning}
// # This section is updated via '${makolator.info.cli}'
// ${output_filepath.name}
// % for idx in range(num):
// item${idx}
// % endfor
// </%def>
// MAKO TEMPLATE END


GENERATE INPLACE BEGIN repeat(2)
# THIS SECTION IS GENERATED!!! DO NOT EDIT MANUALLY. CHANGES ARE LOST.
# This section is updated via 'makolator inplace inplace-mako.txt'
inplace-mako.txt
item0
item1
GENERATE INPLACE END repeat


GENERATE INPLACE BEGIN repeat(5)
# THIS SECTION IS GENERATED!!! DO NOT EDIT MANUALLY. CHANGES ARE LOST.
# This section is updated via 'makolator inplace inplace-mako.txt'
inplace-mako.txt
item0
item1
item2
item3
item4
GENERATE INPLACE END repeat

Static Code

Fully and inplace generated files might want to leave space for user manipulation, which is kept even on update. These locations need to be prepared by ${staticcode('name')}, where name is a unique identifier within the target file.

Assume the following template:

<%def name="example(greet='Hello')">\
output_tags=${" ".join(output_tags)}
${greet} before

${staticcode('a', default='obsolete a')}

${greet} middle

${staticcode('b')}

${greet} after

</%def>
${example()}

and an outdated generated file:

Outdated before

// STATIC BEGIN a
kept a
// STATIC END a

Outdated middle

// STATIC BEGIN b ignored
kept b
// STATIC END b

Outdated after

An update (makolator gen file.txt.mako file.txt) will result in:

output_tags=@generated
Hello before

// STATIC BEGIN a
kept a
// STATIC END a

Hello middle

// STATIC BEGIN b
kept b
// STATIC END b

Hello after