Templates guide

Template can be used to fill dictionary-like objects with dynamic data.

Note that these are not Jinja templates but rather a tool for python data manipulation. To create a template you must define a schema and then feed it with data.

t = Template({'value': '[key]'})
t({'key': True})  # -> {'value': True}

Template engine uses a set of various operators and functions to process dynamic data. See Operators section for details.

Template can also accept a string or an iterable like list or tuple.

t = Template('[fill_this]')
t({'fill_this': 'dogs'})  # -> "dogs"

Operators

Operators can be used to transform template values before passing them to the schema.

SELECT

Set value from a data key. Nested keys are supported.

For your convenience this is a default operator which means that you don’t need to explicitly specify ‘!s:’ after an opening bracket.

"[key]"
"[key.nested]"

You can aggregate values from a list in the same way.

t = Template('[key.nested]')
t({'key': [{'nested': 1}, {'nested': 2}, {'nested': 3}]})  # -> [1, 2, 3]

If there is no such key in the data, then KeyError will be thrown. However you can provide a second argument as a default value for the key. This argument will be automatically evaluated using ast.literal_eval() unless it’s an operator.

"[key:'default']"

FORMAT

Format a string from data dict using str.format_map().

"[!f:string]"

If a data dict is nested then the flattened version will be used with all nested keys accessible using - (dot is not allowed here due to python restrictions).

"[!f:Example string - {key-nested}!]"

Multiple arguments will be joined into a single strings.

"[!f:key1:key2:key3]"  # -> "key1,key2,key3"

EVAL

Evaluate a string into a python object using ast.literal_eval(). Note that not all types are allowed in the literal eval.

"[!e:string]"

A provided value must be a proper string representation of an object.

"[!e:42]"       # -> 42
"[!e:'42']"     # -> "42"

Similarly to SELECT, multiple args will be combined in a resulting tuple.

"[!e:1:2:3]"  # -> (1,2,3)

EXEC

Execute a function (must be registered) with arguments. Each argument must be separated by :.

"[!x:<function>:<arg1>:...:<argN>]"

Arguments must respect function input.

For your convenience if an argument is not an operator (i.e not in square brackets) such argument will be automatically evaluated to spare you from writing a lot of EVAL operators. The same is not done for operator arguments which can be of non-string types.

"[!x:sum:24:18]"            # -> sum([24, 18])

There are some standard functions available. For a list of functions see Functions.

Combining operators

You can use nested brackets to combine multiple operators. For example you can use a value from the data dict in the sum function.

"[!x:sum:[key1]:[key2]]"  # -> sum([data['key1'], data['key2'])

Multi-level nesting is allowed.

"[!x:sum:[key1]:[!x:int:[key2]]]"  # -> sum([data['key1'], int(data['key2'])])

Escaping

You can escape things such as brackets with apostrophes.

"`[escaped]:[value]`"

Functions

A collection of standard functions for the EXEC operator is listed here: TEMPLATE_FUNCTIONS.

Examples

You can use templates to automatically fill configuration files on app start or create objects dynamically using external data.

import os

config_template = Template({
  'name': 'my_app',
  'id': '[!x:uuid4],
  'host': '[HOST]',
  'port': '[PORT:80]'
})

config_template(os.environ)  # will try to fill host and port values from $HOST and $PORT env vars