Jinja rendering and context#
ibek uses Jinja to turn IOC parameters and support definitions into startup
commands and database substitutions. Jinja runs during generation;
EPICS $(MACRO) expressions belong to the later database/IOC processing stages.
databases:
- file: example.db
args:
P: "{{ P }}" # ibek substitutes the entity parameter
PORT: "{{ controller }}" # ibek substitutes the referenced entity ID
HOST: "$(DEVICE_HOST)" # left for EPICS macro expansion
ibek does not run Jinja over the contents of every .db file. It renders the
filename and argument values into ioc.subst; EPICS tooling expands the
referenced database templates.
Evaluation order#
Render the IOC’s
ioc_name.Load top-level entities in order. For each entity, render
pre_defines,parameters, thenpost_defines, in each group’s declaration order.Expand repeats and sub-entities, rendering child inputs in their parent or iteration context before validating the child.
Generate PVI output when enabled, render the startup environment assignments, pre-init and post-init snippets, then render database substitutions.
Use earlier values as dependencies. Parameter fields exist before their
individual render, so an early expression can see a later parameter’s raw
value; it cannot rely on that value already having been expanded. Use
post_defines for calculations requiring resolved parameters. Enum labels are
mapped to their output values after top-level entity validation, so defines
should not depend on that conversion having happened yet.
Jinja expressions are evaluated where supported, not recursively over every
YAML node. In particular, native list/dict parameter contents and shared
anchor storage are not generally traversed and rendered. Return a whole typed
collection from an expression when it needs calculation.
Names in an entity template#
Name |
Value |
|---|---|
Parameter and define names |
This entity’s fields, with defines added as they are evaluated. |
|
Entity type and enable flag. |
|
Rendered IOC name. |
|
Stem of the first input filename: |
|
Read-only view of the process environment. |
|
Shared helper object described below. |
Names stored by |
Shared values available to subsequent renders. |
Object references expose the target entity’s attributes: {{ controller.P }}.
Rendering the object itself, {{ controller }}, produces its ID. IDs must
already exist when references are resolved.
Shared helper variables take precedence over entity fields of the same name.
The special IOC names and _global are supplied by ibek; avoid reusing those
names. env is a Jinja global default, so an existing entity field or shared
variable called env takes precedence and remains compatible.
Unknown names in entity expressions raise an error containing the offending
template. Normal Jinja expressions, loops, tests and filters are available;
ibek adds no custom filters. Literal braces can be escaped with
{% raw %}{{ literal }}{% endraw %}.
Environment variables#
The env mapping is new in the unreleased changes.
On older ibek releases, use _global.get_env('NAME').
{{ env.EPICS_ROOT }}
{{ env['EPICS_ROOT'] }}
{{ env.get('DEVICE_HOST', 'localhost') }}
env reads the environment of the running ibek process at render time, not
values that will be set later by generated epicsEnvSet commands. Values are
strings. A missing direct lookup fails in entity templates; .get() supplies
an explicit fallback. Use brackets for names that overlap mapping methods,
such as env['items'] or env['get']. The mapping cannot be modified through
the template.
For a numeric parameter, convert explicitly:
count:
type: int
description: Number of channels
default: "{{ env.get('CHANNEL_COUNT', '4') | int }}"
_global.get_env('NAME') remains supported with unchanged behavior: it returns
an empty string when the variable is unset. There is no requirement to migrate
existing definitions.
Typed expressions#
Jinja produces text. ibek converts string expressions for typed int, float,
bool, list and dict parameters back into Python values. The result must
be a valid literal of the intended kind; {{ count > 0 }} produces a suitable
boolean. Native YAML values need no Jinja expression.
In untyped expansion contexts, such as repeat values, an expression ending
in | list or | int also tells ibek to recover the corresponding type:
values: "{{ range(1, 5) | list }}"
Use only actual Jinja filters. In particular, bool and dict are not Jinja
filters: use a declared parameter type for those conversions, not | bool or
| dict.
Assembly templates#
The packaged st.cmd.jinja joins the already rendered startup blocks. It sees
env_var_elements, script_elements, post_ioc_init_elements, _global,
shared helper variables and env. ioc.subst.jinja receives the grouped
templates data and env.
These assembly templates retain their existing permissive Jinja undefined behavior; the strict missing-name errors described above apply to entity expressions. Inserted startup blocks are already rendered text and are not recursively evaluated by the assembly pass.