Cylc8 & Rose template variables (jinja2:suite.rc)

There is a change coming with Cylc8/Rose2 to the way template variables are evaluated. Very few configurations should be affected by this change.

Rose2019.01.4 will log warnings when it encounters any template variables that are incompatible with Cylc8/Rose2 in the output of rose suite-run.

What Are Template Variables?

Rose can be used to configure “template variables” which are passed to the “template engine” which is used to process the suite.rc file.

For example if you define the variable answer in the rose-suite.conf file:

[jinja2:suite.rc]
answer=42

Then you could use it in the suite.rc file:

#!Jinja2
[runtime]
    [[root]]
        [[[environment]]]
            ANSWER = {{ answer }}

What Types Does Rose2019 Support?

Rose2019 uses the Jinja2 template engine to parse values specified in the [jinja2:suite.rc] section. This was intended to allow defining variables in different types. Jinja2 is very close to Python so this gives us the ability to specify inputs in the standard Python formats:

# All the intended use cases
[jinja2:suite.rc]
string="mystring"
int=42
float=12.34
bool=True
list=[1, 2, 3]
tuple=(1, 2, 3)
dict={'a': 1, 'b': 2, 'c': 3}
# python3
set={1, 2, 3}

However, an unintended consequence is that it also let through Jinja2 expressions:

# Examples of unintended usage
[jinja2:suite.rc]
yuck=[0] + range(5)
mess=[1, 2, 3] + range(3) | len + 5
nooo=(5 / 3) != 2

This was never the intended purpose of the [jinja2:suite.rc] section. There are a number of reasons that this is problematic, not least that a large proportion of these uses will break with the upcoming Python3 Rose. For example, in Python3 range() returns a generator not a list so [0] + range(5) will break and the rules for integer division have changed so (5 / 3) != 2 might not function as intended.

What Types Will Rose2/Cylc8 Support?

With the upcoming Python3.7+ Cylc8/Rose2 releases template variables will be restricted to Python literals (i.e. all of the intended use cases in the first example).

You will not be able to provide expressions, functions or conditionals:

# All things which won't be possible in Cylc8/Rose2
[jinja2:suite.rc]
expression=40 + 2
function=range(5)
conditional=42 == 84/2

How Do I Upgrade Jinja2 Expressions?

Before

rose-suite.conf

[env]
VAR=40

[jinja2:suite.rc]
list_expression=[0] + [1]
range1=[0] + range(1, 5) | list
range2=range(0, 10, 2)
maths=$VAR + 2

After

rose-suite.conf

[env]

[jinja2:suite.rc]
list_expression=[0, 1]
_range1=(0, 5)
_range2=(0, 10, 2)
VAR=40

suite.rc

#!Jinja2
# NOTE: the list() here protects against Python3 changes
{% set range1=list(range(*_range1)) %}
{% set range2=list(range(*_range2)) %}
{% set maths = VAR + 2 %}

Sidenote: Cylc Template Variable Type Support

Cylc7 allows Jinja2 variables to be specified to cylc run using the -s command line option, however, these variables are only ever interpreted as strings. This can cause some problems e.g:

suite.rc

[cylc]
    [[parameters]]
         foo = 0 .. {{ INT + 2 }}
$ cylc run <suite> -s INT=40  # this
Traceback ...
Type Error: "40" + 2

With Cylc8 template variables will be evaluated the same way in Cylc as in Rose meaning that they will be safely inter-operable:

-s INT=42
-s LIST='[1, 2, 3]'   # note these quotes are stripped by the shell
-s 'STRING="string"'  # note the outer quotes are needed to prevent
                      # the inner ones from being stripped by the shell
-s BOOL=True
-s 'DICT={"a": 1, "b": 2}'
# and so on ...
1 Like

Update - Feedback

Some of the Jinja2 nuances are heavily used in Rose suite configurations so we will expand what is outlined above to include all valid Jinja2 literals.

For example Jinja2 accepts both the Pythonic booleans (True/False) and the lower-case alternative (true/false). We will continue to support both in Rose suite configurations to avoid compatibility / upgrade issues.

Here are examples of Pythonic syntax, Jinja2 nuances and Rose2019 nuances which will all be supported (non-exhaustive):

[jinja2:suite.rc]

# Pythonic (recommended where possible)
BOOL=True
TUPLE=(1, 2, 3)
INTEGER=42

# Jinja2 nuances
BOOL=true
TUPLE=1, 2, 3
INTEGER=042

# Rose2019 nuances
STRING="this"
      =" is"
      =" a"
      =" single"
      =" string!"
LIST=[
    =1,
    =2
    =]

Cylc8 will support only Pythonic literals via the CLI and set-file interfaces.

We will release Rose2019.01.5 with revised rules in the new year.