How to check if a variable is an integer in Jinja2? - jinja2

The aim is to check whether a variable is an integer and if that is true insert hello.
Attempt
{% if int(variable) %} hello {% endif %}
Result
'int' is undefined"

To use the Jinja2 int builtin filter (which tries to cast the value to an int):
You need to use the filter format, like this:
{% if variable|int != 0 %} hello {% endif %}
By default, if casting to int fails it returns 0, but you can change this by specifying a different default value as the first parameter. Here I've changed it to -1 for a case where 0 might be a valid value for variable.
{% if variable|int(-1) != -1 %} hello {% endif %}
see the: Jinja2 Docs - int builtin filter for more info
To use the Jinja2 number builtin test (which returns true if the variable is already a number):
a better solution, rather than using the int filter (which will cast a integer like string to an int) is to use the builtin test number, like this:
{% if variable is number %} hello {% endif %}
see the: Jinja2 Docs - number builtin test

For anyone using Salt, this did not work for me when put is saltstack state.
{% if variable|number %} hello {% endif %}
This did work however:
{% if variable is number %} hello {% endif %}

None of these solutions worked for me, however this did :
{% if variable is even or variable is odd %}

Related

Condition based on the three first letters of a string?

In my Jinja template, model.DataType value can be user defined or built in. My requirenement is if model.DataType start with the three letters ARR, then do a specific operation.
Example of values:
ARRstruct124
ARR_int123
ARR123123
CCHAR
UUINT
etc.
{% set evenDataType = model.eventDataType %}
{%if evenDataType | regex_match('^ARR', ignorecase=False) %}
// do the operation
{%else%}
// do the operation
{% endif %}
With this template, I am getting the error
{%if evenDataType | regex_match('^ARR', ignorecase=False) %}
jinja2.exceptions.TemplateAssertionError: no filter named 'regex_match'
There is indeed no regex_match filter in the Jinja builtin filters. You might have found some examples using it, but this is an additional filter provided by Ansible, so it won't work outside of Ansible.
This said, your requirement does not need a regex to be fulfilled, you can use the startswith() method of a Python string.
So, you template should be:
{% set evenDataType = model.eventDataType %}
{% if evenDataType.startswith('ARR') %}
`evenDataType` starts with 'ARR'
{% else %}
`evenDataType` does not starts with 'ARR'
{% endif %}

Compare two grain values inside state.sls using jinja expressions

I am creating a state which will trigger some module if both of the grains are not matching. I have tried several options, but no luck.
Based on comparison, False will trigger my module and that module will change GRAIN_B value to match with GRAIN_A. So during every highstate my module will not get triggered, unless there is a change in GRAIN_A.
Any suggestions please.
I have tried several jinja expressions.
{% if grains['GRAIN_A'] not in grains.get('GRAIN_B','None') %}
{% set GRAIN_B = grains.get('GRAIN_B','None') %}
{% if grains['GRAIN_A'] != {{ GRAIN_B }} %}```
```{% if grains['GRAIN_A'] not in grains.get('GRAIN_B','None') %}
MY_MODULE:
module.run:
- func: MYMODULE.FUNCTION_A
{% endif %}```
Issue fixed, there is a \n character in my GRAIN_A output, which makes the evaluation condition fails.
This condition works already.
{% if grains['GRAIN_A'] not in grains.get('GRAIN_B','None') %}
MY_MODULE:
module.run:
- func: MYMODULE.FUNCTION_A
{% endif %}

Jinja "==" (compare condition) doesn't work?

while writing an application in django, I've encountered a problem. I want to make page-number links, with current page not being a link. So in template I do this:
{% for i in pages %}
{% if i == curr_page %} {{ i }}
{% else %} {{ i }}
{% endif %}
Only problem? Jinja doesn't seem to notice two numbers being equal. I've changed the 2nd line to {% if i != curr_page %} {{i}}!={{curr_page}} and got "... 5!=6 6!=6 7!=6 ...".
What should I do?
Because they are not of same data type. In your view, cast them to int before passing to context dict.
pages = list(map(int, pages))
curr_page = int(curr_page)

Jinja2 for loop behaving similarly to with

I'd like to iterate over a set of objects and find the maximum of one particular attribute, however jinja2 ignores any action within an iterator on a variable declared outside of the iterator. For example:
{% set maximum = 1 %}
{% for datum in data %}
{% if datum.frequency > 1 %}
{% set maximum = datum.frequency %}
{% endif %}
{% endfor %}
{# maximum == 1 #}
datum.frequency is definitely greater than 1 for some datum in data.
EDIT (solution)
This is similar to this post, but there's a bit more to it. The following works and is very ugly.
{% set maximum = [1] %}
{% for datum in data %}
{% if datum.freq > maximum[-1] %}
{% if maximum.append( datum.freq ) %}{% endif %}
{% endif %}
{% endfor %}
{% set maximum = maximum[-1] %}
Have you considered writing a custom filter to return the highest value of a particular attribute within your collection? I prefer to minimize the amount of logic I use in Jinja2 templates as part of maintaining a 'separation of concerns'.
Here is a link to a very good example of how one can be written in python:
Custom jinja2 filter for iterator
Once you have your filter returning the value you need access it by using '|' like so:
{% set maximum = datum|filtername %}

In Jinja2, how do you test if a variable is undefined?

Converting from Django, I'm used to doing something like this:
{% if not var1 %} {% endif %}
and having it work if I didn't put var1 into the context. Jinja2 gives me an undefined error. Is there an easy way to say {% if var1 == None %} or similar?
From the Jinja2 template designer documentation:
{% if variable is defined %}
value of variable: {{ variable }}
{% else %}
variable is not defined
{% endif %}
{% if variable is defined %} is true if the variable is None.
Since not is None is not allowed, that means that
{% if variable != None %}
is really your only option.
You could also define a variable in a jinja2 template like this:
{% if step is not defined %}
{% set step = 1 %}
{% endif %}
And then You can use it like this:
{% if step == 1 %}
<div class="col-xs-3 bs-wizard-step active">
{% elif step > 1 %}
<div class="col-xs-3 bs-wizard-step complete">
{% else %}
<div class="col-xs-3 bs-wizard-step disabled">
{% endif %}
Otherwise (if You wouldn't use {% set step = 1 %}) the upper code would throw:
UndefinedError: 'step' is undefined
In the Environment setup, we had undefined = StrictUndefined, which prevented undefined values from being set to anything. This fixed it:
from jinja2 import Undefined
JINJA2_ENVIRONMENT_OPTIONS = { 'undefined' : Undefined }
Consider using default filter if it is what you need. For example:
{% set host = jabber.host | default(default.host) -%}
or use more fallback values with "hardcoded" one at the end like:
{% set connectTimeout = config.stackowerflow.connect.timeout | default(config.stackowerflow.timeout) | default(config.timeout) | default(42) -%}
You can use kind of Jinja Elvis operator
{{ 'OK' if variable is defined else 'N/A' }}
or additionally check emptiness
{{ 'OK' if (variable is defined and variable) else 'N/A' }}
Jinja templates - Template Designer Documentation
{% if variable is defined %} works to check if something is undefined.
You can get away with using {% if not var1 %} if you default your variables to False eg
class MainHandler(BaseHandler):
def get(self):
var1 = self.request.get('var1', False)
I had an issue like this in Ansible. Ended up having to do a test on both #Garret and #Carsten / #azalea answers, so:
{% if variable is defined and variable %}
value of variable: {{ variable }}
{% else %}
variable is not defined or is falsy
{% endif %}
You can do this :
- debug:
msg: "Executed only if variable is defined"
when:
- variable is defined