Template Extensions

When it comes to creating text documents, like Custom Templates or exporting tests, plans and stories into ReST or Markdown, tmt relies on the well-known Jinja package. All Jinja templating features are supported, and, on top of filters and tests shipped with Jinja, tmt adds several custom ones.

Filters

basename

Return the last component of the given path.

# "/etc/fstab" -> "fstab"
{{ "/etc/fstab" | basename }}

# "/var/log/" -> "log"
{{ "/var/log/" | basename }}

dedent

Remove any common leading whitespace from every line in the string.

# "foo bar" -> "foo bar"
{{ "foo bar" | dedent }}

# '''
#    foo
#    bar
#        baz
# '''
#  ->
# '''
# foo
# bar
#    baz
# '''
{{ "\n    foo\n    bar\n        baz\n" | dedent }}

format_duration

Render result duration in the hh:mm:ss format.

If the duration is not defined, return a placeholder marker instead.

# {"duration": None} -> '..:..:..'
{{ {"duration": None} | format_duration }}

# {"duration": "12:34:56"} -> '12:34:56'
{{ {"duration": "12:34:56"} | format_duration }}

guest_full_name

Render guest’s “full name”.

Implemented by calling format_guest_full_name().

# {"name": "foo", "role": None} -> 'foo'
{{ {"name": "foo", "role": None} | guest_full_name }}

# {"name": "foo", "role": "bar"} -> 'foo (bar)'
{{ {"name": "foo", "role": "bar"} | guest_full_name }}

listed

Return a nice, human readable description of an iterable.

# [0] -> "0"
{{ [0] | listed }}

# [0, 1] -> "0 and 1"
{{ [0, 1] | listed }}

# [0, 1, 2] -> "0, 1, or 2"
{{ [0, 1, 2] | listed(join='or') }}

# [0, 1, 2] -> '"0", "1" and "2"'
{{ [0, 1, 2] | listed(quote='"') }}

# [0, 1, 2, 3] -> "0, 1, 2 and 1 more"
{{ [0, 1, 2, 3] | listed(max=3) }}

# [0, 1, 2, 3, 4] -> "0, 1, 2 and 2 more numbers"
{{ [0, 1, 2, 3, 4, 5] | listed('number', max=3) }}

# [0, 1, 2, 3, 4, 5] -> "6 categories"
{{ [0, 1, 2, 3, 4, 5] | listed('category') }}

# [0, 1, 2, 3, 4, 5, 6] -> "7 leaves"
{{ [0, 1, 2, 3, 4, 5, 6] | listed("leaf", "leaves") }}

match

Return re.Match if the string matches a given pattern.

Pattern is tested in “match” mode, i.e. it must match from the beginning of the string. See Regular Expressions description for more details.

 # 'foo/bar' -> 'foo/bar'
{{ 'foo/bar' | match('foo/.*').group() }}

# 'foo/bar' -> ''
{{ 'foo/bar' | match('foo/(.+?)/(.*)') }}

# 'foo/bar/baz' -> 'bar'
{{ 'foo/bar' | match('foo/(.+?)/.*').group(1) }}

prefix

Add prefix to each line of a string.

# "foo\nbar" -> "baz foo\nbaz bar"
{{ "foo\nbar" | prefix("baz") }}

regex_findall

Return a list of all non-overlapping matches in the string.

If one or more capturing groups are present in the pattern, return a list of groups; this will be a list of tuples if the pattern has more than one group.

Empty matches are included in the result.

# '/var/log/mail.log' => ['/', '/', '/']
{{ '/var/log/mail.log' | regex_findall('/') }}

regex_match

Return string matching a given pattern.

Pattern is tested in “match” mode, i.e. it must match from the beginning of the string. See Regular Expressions description for more details.

If the string matches and pattern contains capture groups, the first group is returned. If the string matches, but patterns contains no capture group, the whole match is returned. Otherwise, an empty string is returned.

# 'foo/bar' -> 'foo/bar'
{{ 'foo/bar' | regex_match('foo/.*') }}

# 'foo/bar' -> ''
{{ 'foo/bar' | regex_match('foo/(.+?)/(.*)') }}

# 'foo/bar/baz' -> 'bar'
{{ 'foo/bar/baz' | regex_match('foo/(.+?)/.*') }}

regex_replace

Replace a substring defined by a regular expression with another string.

Return the string obtained by replacing the leftmost non-overlapping occurrences of pattern in string by the replacement. If the pattern isn’t found, string is returned unchanged.

Backreferences in the replacement string are replaced with the substring matched by a group in the pattern.

# 'foo/bar' -> 'foo/baz'
{{ 'foo/bar' | regex_replace('(.+)/bar', '/baz') }}

# 'foo/bar' -> 'foo/bar'
{{ 'foo/bar' | regex_replace('(.+)/baz', '/') }}

shell_quote

Return a shell-escaped version of the string.

# "foo bar" -> "'foo bar'"
{{ "foo bar" | shell_quote }}

style

Evaluate terminal-style colorization tags supported by Click.

Implemented by passing all arguments to click.style().

to_yaml

Render a given object as a YAML snippet.

# {"foo": "bar", "baz": false} -> foo: bar\nbaz: false
{{ {"foo": "bar", "baz": false} | to_yaml }}

web_git_url

Sanitize git url using tmt.utils.web_git_url()

{{ "/path/to/the/code.py" | web_git_url(STORY.fmf_id.url, STORY.fmf_id.ref) }}

{{ "/tmt/base.py" | web_git_url("https://github.com/teemtee/tmt.git", "main") }}
-> https://github.com/teemtee/tmt/tree/main/tmt/base.py

Tests

unit

Return true if the object is a unit.

{% if value is unit %}
    Value is a Pint's ``Quantity`` instance.
{% endif %}