How can I comment in a Jinja directive? - jinja2

I have a Jinja set directive as follows:
{% set mylist = [
"item 1",
"another item",
"yet another item",
] %}
I would like to add a comment to the second list item. Does Jinja support that? I've tried the following:
{% set mylist = [
"item 1",
"another item", # My comment
"yet another item",
] %}
and
{% set mylist = [
"item 1",
"another item", ## My comment
"yet another item",
] %}
, but none of them work. I'm using Jinja 2.6.

Since you are using Jinja 2.2+ then you can use whatever your environment configures for line_comment_prefix (part of the line statements feature). This feature must be enabled by the application that Jinja is embedded in (for example, in Flask, this is done by setting app.jinja_options['line_comment_prefix'] = "whatever#you$want").
app = Flask(__name__)
app.jinja_options['line_statement_prefix'] = '#'
app.jinja_options['line_comment_prefix'] = '#::'
Then you can write a template that uses line comments:
{% set mylist = [
"first item",
"another item", #:: needed for raisins - see #12345
"a third item"
] %}
If you are using Jinja 2.1 or lower then those versions do not support inline comments. However, you can use a comment block:
{#
BUG: Added "another item" because of raisins.
Don't remove it until #12345 is fixed
#}
{% set mylist = [
"item 1",
"another item",
"yet another item",
] %}

I guess everyone's going to find that out via documentation but just in case, I'll leave it here as well:
Since Jinja 2.2, line-based comments are available as well. For
example, if the line-comment prefix is configured to be ##, everything
from ## to the end of the line is ignored (excluding the newline
sign):
# for item in seq:
<li>{{ item }}</li> ## this comment is ignored
# endfor

Related

HL7v2 to FHIR conversion default CodeSystem rules not working

In the HL7v2 to FHIR conversion CodeSystem templates, their default, i.e., "else" part in the if-then-else rule, is not working.
For example, for Patient.communication.language in the Resource/_Patient.liquid template, it has the following line to map a language code to a dictionary containing "code", "display", and "system".
{% include 'DataType/CWECodeableConcept' mapping: 'CodeSystem/Language', CWE: PID.15 -%}
In the CodeSystem/_Language.liquid template, if no matching code, it would output the input values.
{% else -%}
"code" : "{{ inCode }}",
"display" : "{{ inCode }}",
"system" : "",
{% endif -%}
My case has PID.15="English" and it has no matching code. So, I expect the following output.
{
"code" : "English",
"display" : "English",
"system" : "",
}
What happens is no output at all.
I also tried to add the following rule with no success.
{% elsif inCode == 'English' -%}
"code" : "{{ inCode }}",
"display" : "{{ inCode }}",
"system" : "",
I appears that CodeSystem/_Language.liquid does not take changes, nor does it handle no-matched codes with "else" condition. I tested the changes with the "FHIR Converter" extension in Visual Studio Code. What can I do to make the "else" condition in CodeSystem/_Language.liquid working?
Try this:
Make required changes in the /CodeSystem/CodeSystem.json file and that should work for you.
Also, update the VS Code extension to the latest version.
"CodeSystem/Language": {
"A": {
"code": "A's code",
"display": "A's display",
"system": "A's system"
},
"__default__": {
"code": "English",
"display": "English",
"system": "English"
}
},
Explanation:
The following statement is calling _DataType/CWECodeableConcept and passing 'CodeSystem/Language' to mapping parameter, and the value of PID.15 to the CWE parameter.
{% include 'DataType/CWECodeableConcept' mapping: 'CodeSystem/Language', CWE: PID.15 -%}
Inside the _CWECodeableConcept.liquid, since mapping is populated it executes the if blocks, and not the else blocks.
{% if mapping -%}
"code":"{{ CWE.1.Value | get_property: mapping, 'code' }}",
"display":"{{ CWE.1.Value | get_property: mapping, 'display' }}",
"system":"{{ CWE.1.Value | get_property: mapping, 'system' }}",
"version":"{{ CWE.1.Value | get_property: mapping, 'version' }}",
{% else -%}
"code":"{{ CWE.1.Value }}",
"display":"{{ CWE.2.Value }}",
"system":"{{ CWE.3.Value }}",
"version":"{{ CWE.7.Value }}",
{% endif -%}
Inside the if block, get_property is used to fetch the code, display, system, and version for the mapping CodeSystem/Language corresponding to the value in CWE.(1|4|10).Value.
get_property uses the /CodeSystem/CodeSystem.json file, and not the individual files under the CodeSystem folder.
The behavior of get_property is documented here. However, the documentation does not mention the name of the config file it uses. We are fixing the documentation in the next release.
For quicker turnaround, we recommend raising an issue on the FHIR converter github repo.

Jinja2 if/else on user defined variable

Attempting to make a decision in a template based on the last character of a variable (third level domain hostname) , but the epiphany alludes me. Make a config stanza if value else, do the other.
I set a fact in play:
- name: Set third level domain name to a variable
set_fact:
my_3rd_levelname: "{{ ansible_nodename.split('.')[0] }}"
- name: Ascertain if which server we're on
set_fact:
my_one_or_two: "{{ my_3rd_levelname[-1]|int }}"
...which appears to echo out with debug, save the casting as an int...see below.
TASK [role-test : Echo out my_one_or_two] *******************************************************************************************************************
ok: [w.x.y.42] => {
"my_one_or_two": "2"
}
Then in the template.j2...
{# If my_one_or_two is even list server1 first. If not, second. #}
{% if lookup('vars,',my_one_or_two) + my_one_or_two|int is 1 %}
[some config file stanza here]
{% else %}
[some other config file stanza instead]
I've poked and hoped until I can stand it no longer and am reaching out. I've tried just using the raw variable, e.g., {% if my_one_or_two|int == 1 %} along with many other attempts, but I'm stuck. I can't seem to overcome this error:
AnsibleError: template error while templating string: expected token 'name', got 'integer'. String: [the contents of my template]
Any input would be greatly appreciated at this juncture.
Thanks
Okay...leaving this here in case someone else doesn't realize you can use any Python method that the object supports. Here's what I did. Remember the server names end in 1 or 2 and its a String.
Created a varible in /roles/[rolename]/vars...
my_simple_hostname: "{{ ansible_nodename.split('.')[0] }}"
Then used the 'endswith' method to evaluate it....
% if my_simple_hostname.endswith('1') == true %}
[content if true]
{% else %}
[content when false]
{% endif %}

Liquid map error "After parsing a value an unexpected character was encountered"

I have a very simple Liquid map (extract here below):
{
{% if content.DisplayLastName__c %}
"DisplayLastName__c": "{{ content.DisplayLastName__c }}",
{% endif %}
}
The input message of the map is the following:
{
"DisplayLastName__c": "é\" r",
"FirstName": "é\""
}
I got this error due to the fact that there is a \" in one field: "After parsing a value an unexpected character was encountered".
Am I missing something?
The following worked for me, however I don't fully know why:
{% assign vDescription = system.Data.Description | Replace: '\"', '\"' %}

Ansible & Jinja2: combine a dictionary to each element of a list

I have a variable that is an array [{'foo':1},{'bar':2}].
I want to combine it with the following hash: {'baz':3} using a set fact (?) such as my output registered variable is:
[{'foo':1, 'baz':3},{'bar':2, 'baz':3}]
I've looked into the combine filter, but it only works when I already have an hash to work with. In my case I have an array.
Is there a way to achieve that using ansible?
Actually, I have found a way. map can be used with any filters, and arguments have to be passed after a comma
- name: test
set_fact:
_test: "{{ [{'foo':1}, {'bar':2}] | map('combine', {'baz':3}) | list }}"
produces:
ok: [localhost] => {
"_test": [
{
"baz": 3,
"foo": 1
},
{
"bar": 2,
"baz": 3
}
]
}
Jinja2 doesn't have list comprehension, but I think you can use set and for loop to achieve it:
{% set outputarray = [] -%}
{% for d in inputarray -%}
{% set r = d|combine({'baz': 3}) -%}
{{ ouputarray.append(r) and '' }}
{%- endfor %}

Case statement for setting var in Ansible/Jinja2

I'm using Ansible with Jinja2 templates, and this is a scenario that I can't find a solution for in Ansible's documentation or googling around for Jinja2 examples. Here's the logic that I want to achieve in Ansible:
if {{ existing_ansible_var }} == "string1"
new_ansible_var = "a"
else if {{ existing_ansible_var }} == "string2"
new_ansible_var = "b"
<...>
else
new_ansible_var = ""
I could probably do this by combining several techniques, the variable assignment from here: Set variable in jinja, the conditional comparison here: http://jinja.pocoo.org/docs/dev/templates/#if-expression, and the defaulting filter here: https://docs.ansible.com/playbooks_filters.html#defaulting-undefined-variables ,
...but I feel like that's overkill. Is there a simpler way to do this?
If you just want to output a value in your template depending on the value of existing_ansible_var you simply could use a dict and feed it with existing_ansible_var.
{{ {"string1": "a", "string2": "b"}[existing_ansible_var] | default("") }}
You can define a new variable the same way:
{% set new_ansible_var = {"string1": "a", "string2": "b"}[existing_ansible_var] | default("") -%}
In case existing_ansible_var might not necessarily be defined, you need to catch this with a default() which does not exist in your dict:
{"string1": "a", "string2": "b"}[existing_ansible_var | default("this key does not exist in the dict")] | default("")
You as well can define it in the playbook and later then use new_ansible_var in the template:
vars:
myDict:
string1: a
string2: b
new_ansible_var: '{{myDict[existing_ansible_var | default("this key does not exist in the dict")] | default("") }}'
Something like this would work, but it's ugly. And as #podarok mentioned in his answer, it's likely unnecessary depending on exactly what you're attempting to do:
- name: set default
set_fact: new_ansible_var= ""
- name: set to 'a'
set_fact: new_ansible_var= "a"
when: "{{ existing_ansible_var }} == string1"
- name: set to 'b'
set_fact: new_ansible_var= "b"
when: "{{ existing_ansible_var }} == string2"
etc.
you don't need to set var, because I'm guessing that you trying to set var for some condition later.
Just make condition there like
- name: Later task
shell: "command is here"
when: {{ existing_ansible_var }} == "string1"
and get a profit