How to use string with integer variable value combine in range function? - jinja2

How can I use jinja2 to concatenate strings and numbers.
Ansible 2.5 .
I have two variables Point1 and Point2 and both are integer variables(some randome numbers based on some calculation.
Point1 = 5
Point2 = 7
Here, I want to use them in range function. How would I use them.
{% for x in range(2) %}
---
{% for i in range('Point'+x|string) %} <!-- here I'm trying to access Point1 and Point2 variable values one by one-->
---
{% endfor %}
{% endfor %}
I tried like below as well but the value is becoming as zero.
{% set point = ('point'+x|string)|int %}
Range function requires integer value but here I'm giving string value.
Please suggest me how can I access those values in range function.
Can anyone please suggest?

In your case it's better not try to access external variables by name but use the another approach. Look:
{% set points=[Point1, Point2] %}
{% for x in range(2) %}
# ---
{% for i in range(points[x]) %}
> ---
{% endfor %}
{% endfor %}
At the first line you make an array of Point1 and Point2 values. Next, in loops, everything you need is to access this array by index. You'll got the same result as you want but with smaller effort.

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 %}

How to set loop.index as a variable in Jinja

{% for data in data_list %}
{% set data_index = {{loop.index}} %}
for data_dict in data:
pass
In my inner loop, I need to use the loop index in the outer loop, so I intend to set it to a variable as above. But the syntax is invalid.
How to do that? Or is there another way to get the outer loop index?
i think, you should not use Expressions({{..}}) inside statements ({%..%}), try this :
{% for data in data_list %}
{% set data_index = loop.index %}
for data_dict in data:
pass
You could use the built-in enumerate function for the same to get i as the variable and also use it in an inner loop if you want.
{% for i,data in enumerate(data_list) %}
{{ i }}
{% for j in range(i) %}
{% endfor %}
{% endfor %}
All you need to do is pass enumerate or whatever built-in python function you need as a parameter to the render template function as shown below
#app.get("/foo")
def foo():
return render_template("foo.html", enumerate=enumerate, range=range)

Using Jekyll, how do you alter an array's contents using a for loop?

Say I have an array thingy.foo = ['abc', 'def'] in my scope.
My goal is to be able to loop over all the items in thingy.foo and apply some conditional logic to it, overwriting the existing item in the array... Something like this:
{% for item in thingy.foo %}
{% assign thingy.foo[forloop.index0] = site.data.lookups[item] | default: item %}
{% endfor %}
What I am doing do the item is a bit irrelevant, the part I'm having issues with is updating the item in the array. The code compiles and runs. Within the loop, I can confirm that the "lookup" part works (if I assign it to t and inspect t then I get a looked up value, but thingy.foo[0] is still the original value).
Is it possible to update/overwrite arrays in Jekyll?
(this is intended for use on GitHub Pages, so I cannot use custom plugins).
It looks like you cannot mutate existing arrays... but you can loop over the initial array and mutate items into a new array, like this:
{% assign newArray = '' | split: '' %}
{% for item in thingy.foo %}
{% assign newItem = site.data.lookups[item] | default: item %}
{% assign newArray = newArray | push: newItem %}
{% endfor %}
The newArray now contains a list of altered items from thingy.foo.

How to check if a variable is an integer in 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 %}

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 %}