2026-01-23 16:54:36 +01:00
Playing with Jinja
====================
2025-09-16 18:51:35 +02:00
.. objectives :: Objectives
In this section we will learn how to create new ways of calculation.
Up to now, our only way of dynamically (that is, during the runtime) calculating
a value is to point on another variable's value. But this is not the only way.
2026-02-12 11:12:22 +01:00
We will learn how to insert `Jinja templating language <https://jinja.palletsprojects.com/en/stable/> `_ into our structure files.
Please note that we do not intend to template our YAML files.
That is a completely different activity.
2026-02-26 16:36:43 +01:00
We will simply insert YAML code to calculate the value of a variable, a property, or a parameter.
2026-02-12 11:12:22 +01:00
2026-01-23 16:54:36 +01:00
.. prerequisites :: Prerequisites
2025-11-05 10:18:35 +01:00
2026-01-23 16:54:36 +01:00
- We assume that Rougail's library is :ref: `installed <installation>` on your computer.
2025-11-05 10:18:35 +01:00
2026-01-23 16:54:36 +01:00
- It is possible to retrieve the current state of the various Rougail files manipulated in this tutorial step
by checking out the corresponding tag of the `rougail-tutorials` git repository.
Each tag corresponds to a stage of progress in the tutorial.
Of course, you can also decide to copy/paste or download the tutorial files contents while following the tutorial steps.
If you want to follow this tutorial with the help of the corresponding :tutorial: `rougail-tutorials git repository <src/branch/1.1>` ,
this workshop page corresponds to the tags :tutorial: `v1.1_070 <src/tag/v1.1_070>` to :tutorial: `v1.1_072 <src/tag/v1.1_072>`
in the repository.
::
git clone https://forge.cloud.silique.fr/stove/rougail-tutorials.git
git switch --detach v1.1_070
2026-02-26 16:36:43 +01:00
.. type-along :: Why the Jinja templating engine ?
2026-02-16 18:55:51 +01:00
2026-02-26 16:36:43 +01:00
We are going to embed some `Hinja templating code <https://jinja.palletsprojects.com/en/stable/> `_ in our structure file.
2026-02-16 18:55:51 +01:00
.. glossary ::
Jinja
`Jinja <https://jinja.palletsprojects.com> `_ is a template engine.
we are using Jinja in a classical way, that is, Jinja allows us to handle different cases,
for example with the `if` statement.
2026-02-17 11:03:13 +01:00
.. questions :: What about a `Jinja` calculation?
The :term: `Jinja` templating language enables some complex calculation.
For example we can code more complex behavior for hiding or disabling a variable, that is
not only depending on the value of another variable as we saw before.
2026-01-23 16:54:36 +01:00
A conditional hidden family with Jinja
---------------------------------------
2026-02-16 18:55:51 +01:00
Here we are going to use the Jinja conditional (testing) statement.
Here is our structure file:
2026-02-12 11:12:22 +01:00
.. extinclude :: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_070/firefox/20-manual.yml
:language: yaml
:caption: The :file:`firefox/20-manual.yml` structure file with some `jinja` code in the `hidden` property
..
%YAML 1.2
---
version: 1.1
manual:
use_for_https: true # Also use this proxy for HTTPS
'{{ identifier }}_proxy':
description: '{{ identifier }} Proxy'
hidden:
jinja: |-
{% if _.use_for_https %}
HTTPS is same has HTTP
{% endif %}
dynamic:
- HTTPS
- SOCKS
address:
description: '{{ identifier }} address'
default:
variable: __.http_proxy.address
port:
description: '{{ identifier }} port'
default:
variable: __.http_proxy.port
version:
description: SOCKS host version used by proxy
choices:
- v4
- v5
default: v5
disabled:
type: identifier
when: HTTPS
...
2026-02-26 16:36:43 +01:00
In this Jinja code, we are testing the `use_for_https` variable:
2026-02-16 18:55:51 +01:00
.. code-block :: jinja
{% if _.use_for_https %}
HTTPS is same has HTTP
{% endif %}
If this variable is set to `true` , the `"HTTPS is same has HTTP"` expression
will appear.
2026-02-12 11:12:22 +01:00
2026-02-26 16:36:43 +01:00
.. note :: Have a look at the `Jinja website's test section <https://jinja.palletsprojects.com/en/stable/templates/#tests> `_
2026-02-16 18:55:51 +01:00
for a closer look about testing a variable.
But first, let's set our `use_for_https` variable to `false` :
2026-02-12 11:12:22 +01:00
.. extinclude :: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_070/config/01/config.yml
:language: yaml
2026-02-16 18:55:51 +01:00
:caption: The :file:`config/01/config.yml` user data file with the `use_for_https` set to `false`
2026-02-12 11:12:22 +01:00
..
---
proxy_mode: Manual proxy configuration
manual:
http_proxy:
address: http.proxy.net
port: 3128
use_for_https: false
https_proxy:
address: https.proxy.net
Nothing special appears when we launch the Rougail CLI:
.. raw :: html
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_070/config/01/cmd_ro.txt
:class: terminal
..
2026-02-16 18:55:51 +01:00
rougail -m firefox/ -u yaml -yf config/01/config.yml
2026-02-12 11:12:22 +01:00
2026-02-16 18:55:51 +01:00
We have this output:
2026-02-12 11:12:22 +01:00
2026-02-16 18:55:51 +01:00
.. raw :: html
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_070/config/01/output_ro.html
:class: output
2026-02-12 11:12:22 +01:00
2026-02-16 18:55:51 +01:00
..
Variables:
┣━━ 📓 Configure Proxy Access to the Internet: Manual proxy configuration ◀ loaded from the YAML file "config/01/config.yml" (⏳ No proxy)
┗━━ 📂 Manual proxy configuration
┣━━ 📂 HTTP Proxy
┃ ┣━━ 📓 HTTP address: http.proxy.net ◀ loaded from the YAML file "config/01/config.yml"
┃ ┗━━ 📓 HTTP Port: 3128 ◀ loaded from the YAML file "config/01/config.yml" (⏳ 8080)
┣━━ 📓 Also use this proxy for HTTPS: false ◀ loaded from the YAML file "config/01/config.yml" (⏳ true)
┣━━ 📂 HTTPS Proxy
┃ ┣━━ 📓 HTTPS address: https.proxy.net ◀ loaded from the YAML file "config/01/config.yml" (⏳ http.proxy.net)
┃ ┗━━ 📓 HTTPS port: 3128
┗━━ 📂 SOCKS Proxy
┣━━ 📓 SOCKS address: http.proxy.net
┣━━ 📓 SOCKS port: 3128
┗━━ 📓 SOCKS host version used by proxy: v5
If we set the `use_for_https` to `true` in the :file: `config.yml` user data file,
then we launch again the Rougail CLI:
.. raw :: html
:url: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_070/config/01/cmd_ro.txt
:class: terminal
2026-02-12 11:12:22 +01:00
2026-02-16 18:55:51 +01:00
then we have a warning:
2026-02-12 11:12:22 +01:00
::
🔔 Warning
┗━━ Manual proxy configuration
┗━━ HTTPS Proxy
2026-02-16 18:55:51 +01:00
┗━━ HTTPS address: 🔔 family "HTTPS Proxy" has property hidden,
so cannot access to "HTTPS address",
it will be ignored when loading from the YAML file "config/01/config.yml"
2026-02-12 11:12:22 +01:00
2026-02-17 11:03:13 +01:00
What is interesting here is to launch the Rougail CLI in the :term: `read write mode` :
2026-02-12 11:12:22 +01:00
2026-02-22 11:46:47 +01:00
.. code-block :: bash
:class: terminal
rougail -m firefox/ --cli.root manual.https_proxy -u yaml \
2026-02-16 18:55:51 +01:00
-yf config/01/config.yml --cli.read_write
Then we have an error:
2026-02-12 11:12:22 +01:00
.. code-block :: bash
ERROR: cannot access to optiondescription "HTTPS Proxy"
because has property "hidden"
(HTTPS is same has HTTP)
2026-02-26 16:36:43 +01:00
.. note :: Note that we can see the "HTTPS is same has HTTP" string (the one that was present in the Jinja code)
2026-02-17 11:03:13 +01:00
as an explanation inside the error message.
2025-09-16 18:51:35 +02:00
2026-02-26 16:36:43 +01:00
.. type-along :: Without calculation
2025-09-16 18:51:35 +02:00
2026-02-17 11:03:13 +01:00
Let's reason on the previous HTTPS proxy configuration's manual mode settings:
2025-09-16 18:51:35 +02:00
.. code-block :: yaml
use_for_https:
default: true
https_proxy:
type: family
2026-02-17 11:03:13 +01:00
description: HTTPS Proxy
2025-09-16 18:51:35 +02:00
hidden:
2026-02-17 11:03:13 +01:00
variable: _.use_for_https
2025-09-18 17:17:02 +02:00
2026-02-26 16:36:43 +01:00
We see here that the `https_proxy` family is hidden
2026-02-17 11:03:13 +01:00
depending on the value of another variable. This is what we saw before,
how to hide a variable.
2025-09-18 17:17:02 +02:00
2026-02-17 11:03:13 +01:00
Now we can code the same behavior in a somehow different way:
2025-09-18 17:17:02 +02:00
.. code-block :: yaml
2026-02-17 11:03:13 +01:00
https_proxy':
description: HTTPS Proxy
2025-09-18 17:17:02 +02:00
hidden:
2026-02-17 11:03:13 +01:00
jinja: |-
{% if _.use_for_https %}
HTTPS is same has HTTP
2025-09-18 17:17:02 +02:00
{% endif %}
2025-09-19 16:30:07 +02:00
2026-02-21 21:50:09 +01:00
This code has the same result and yes, it's done in a more complicated way.
2026-02-17 11:03:13 +01:00
We have replaced this simple `hidden` property variable parameter by
2026-02-26 16:36:43 +01:00
a Jinja parameter. The hidden process is done by a calculation.
2025-09-19 16:30:07 +02:00
2026-02-21 21:50:09 +01:00
The fact is that it has same result, but it opens more possibilities,
we will see them later.
2025-09-18 17:17:02 +02:00
2026-02-21 21:50:09 +01:00
Jinja with a description
-----------------------------
.. type-along :: For those who follow the tutorial with the help of the git repository
Now you need to checkout the `v1.1_071` version::
git switch --detach v1.1_071
2026-02-26 16:36:43 +01:00
It is preferable to include a description related to the Jinja calcuation.
2026-02-21 21:50:09 +01:00
That allows the calculation performed by the Jinja code to be understood rapidely
without having to read the code itself.
This is useful for the :term: `integrators <integrator>` who review these :term: `structure files <structure file>` .
.. extinclude :: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_071/firefox/20-manual.yml
:language: yaml
2026-02-26 16:36:43 +01:00
:caption: The :file:`firefox/20-manual.yml` structure file with a description added to the `Jinja` code
2026-02-21 21:50:09 +01:00
..
%YAML 1.2
---
version: 1.1
manual:
use_for_https: true # Also use this proxy for HTTPS
'{{ identifier }}_proxy':
description: '{{ identifier }} Proxy'
hidden:
jinja: |-
{% if _.use_for_https %}
HTTPS is same has HTTP
{% endif %}
description: in HTTPS case if "_.use_for_https" is set to "true"
dynamic:
- HTTPS
- SOCKS
address:
description: '{{ identifier }} address'
default:
variable: __.http_proxy.address
port:
description: '{{ identifier }} port'
default:
variable: __.http_proxy.port
version:
description: SOCKS host version used by proxy
choices:
- v4
- v5
default: v5
disabled:
type: identifier
when: HTTPS
...
This description will appear `in the documentation output for the family <https://forge.cloud.silique.fr/stove/rougail-tutorials/src/tag/v1.1_071#https-proxy-or-socks-proxy> `_
With this rougail command:
.. code-block :: bash
rougail -m firefox -o doc --doc.output_format html > readme.html
2026-02-26 16:36:43 +01:00
It outputs an HTML report, here is a part of it about the `https_proxy` with the `hidden` property:
2026-02-21 21:50:09 +01:00
.. raw :: html
2026-02-22 11:08:32 +01:00
:class: output
2026-02-21 21:50:09 +01:00
manual.<i>https</i>_proxy <br/>
<b>Hidden</b>: in HTTPS case if "manual.use_for_https" is set to "true" <br/>
<b>Identifiers</b>:
<ul><li>HTTPS</li>
2026-02-22 11:08:32 +01:00
We can see that the hidden explanation for the `manual.https_proxy` family
is the `hidden` property's description.
2026-02-21 21:50:09 +01:00
Jinja with a parameter
---------------------------
.. type-along :: For those who follow the tutorial with the help of the git repository
Now you need to checkout the `v1.1_072` version::
git switch --detach v1.1_072
Regarding dynamic families as in the use case we are dealing with, here is an interesting Rougail feature:
it is possible to retrieve the family identifiers and declare them as parameters in the Jinja calculation.
.. extinclude :: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/commit/v1.1_072/firefox/20-manual.yml
:language: yaml
:caption: The :file:`firefox/20-manual.yml` structure file with an identifier type parameter in the hidden property
..
%YAML 1.2
---
version: 1.1
manual:
use_for_https: true # Also use this proxy for HTTPS
'{{ identifier }}_proxy':
description: '{{ identifier }} Proxy'
hidden:
jinja: |-
{% if my_identifier == 'HTTPS' and _.use_for_https %}
HTTPS is same has HTTP
{% endif %}
description: in HTTPS case if "_.use_for_https" is set to "true"
params:
my_identifier:
type: identifier
dynamic:
- HTTPS
- SOCKS
address:
description: '{{ identifier }} address'
default:
variable: __.http_proxy.address
port:
description: '{{ identifier }} port'
default:
variable: __.http_proxy.port
version:
description: SOCKS host version used by proxy
choices:
- v4
- v5
default: v5
disabled:
type: identifier
when: HTTPS
...
We have added an `identifier` type parameter to the `hidden` property:
.. code-block :: yaml
hidden:
params:
my_identifier:
type: identifier
Thus we can refine our Jinja code and hide the `https_proxy` dynamic family,
that is only in the case where the identifier is `HTTPS` .
.. code-block :: yaml
hidden:
jinja: |-
{% if my_identifier == 'HTTPS' and _.use_for_https %}
HTTPS is same has HTTP
{% endif %}
In this Jinja code, we can understand that only the `https_proxy` dynamic family
will be hidden when the `_.use_for_https` variable is set to `true` .
2025-09-18 17:17:02 +02:00
2026-02-22 11:46:47 +01:00
Let's set the `_.use_for_https` variable to `true` .
We have a warning:
2026-02-22 11:08:32 +01:00
2026-02-22 11:46:47 +01:00
.. code-block :: text
2026-02-22 11:08:32 +01:00
🔔 Warning
┗━━ Manual proxy configuration
┗━━ HTTPS Proxy
2026-02-22 11:46:47 +01:00
┗━━ HTTPS address: 🔔 family "HTTPS Proxy" has property hidden,
so cannot access to "HTTPS address", it will be ignored
when loading from the YAML file "config/01/config.yml"
2026-02-22 11:08:32 +01:00
2026-02-22 11:46:47 +01:00
It's helpful to run this command in read/write mode:
2026-02-22 11:08:32 +01:00
2026-02-22 11:46:47 +01:00
.. code-block :: bash
:class: terminal
2026-02-22 11:08:32 +01:00
2026-02-22 11:46:47 +01:00
rougail -m firefox/ --cli.root manual.https_proxy -u yaml \
-yf config/01/config.yml --cli.read_write
2025-09-16 18:51:35 +02:00
2026-02-22 11:46:47 +01:00
because at that moment we get an error:
.. code-block :: bash
:class: output
ERROR: cannot access to optiondescription "HTTPS Proxy"
because has property "hidden" (HTTPS is same has HTTP)
So the Jinja code worked well since the `https_proxy` family is hidden only when
the `use_for_https` variable is set to `true` and the identifier is HTTPS
(the `socks_proxy` family, however, is not hidden).
.. keypoints :: Key points
2025-09-19 16:30:07 +02:00
2026-02-26 16:36:43 +01:00
We have seen that the `disabled` or `hidden` properties could be calculated.
The default values can be calculated too. We'll see a bunch of examples later on.
2025-09-19 16:30:07 +02:00
**progress**
2026-02-22 11:46:47 +01:00
2026-02-26 16:36:43 +01:00
- calculation with a Jinja type calculation: we can hide a family
2026-02-22 11:46:47 +01:00
- we know how to describe a calcuation
- we know how to output some documentation (in markdown or in html) of the :term: `configuration`
- we can calculate with a dynamic family identifer
2025-09-19 16:30:07 +02:00
2026-02-22 11:46:47 +01:00
**keywords**
2026-02-26 16:36:43 +01:00
- Jinja type calcuation for a hidden property
- Jinja calcuation's description
2026-02-22 11:46:47 +01:00
- identifier type parameter
2025-09-16 18:51:35 +02:00
Here we have come to the possibility of making any kind of calculations based on the state of the :term: `configuration` .
This is an important feature to manage the stateful aspect of a configuration.