Unable to reference Jinja 2 variable inside a function - jinja2

So i have a slight bit of an issue with jinja variable reference within a function.
I've tried a handful of different methods to make this work, but none of them have yield any results. I hope some of you can help me out here!
{% set device_type = salt['grains.get']('device','') %}
{% set ip_addr = salt['network.ip_addrs'](' +device_type+ ')[0] %}
I'd like to have the variable device_type inside the salt function within ip_addr.
I have tried the following already and none of it gave any results:
{% set ip_addr = salt['network.ip_addrs'](\' +device_type+ \')[0] %}
{% set ip_addr = salt['network.ip_addrs'](' ~ device_type ~ ')[0] %}
{% set ip_addr = salt['network.ip_addrs']( {{ device_type }})[0] %}
{% set ip_addr = salt['network.ip_addrs'](' {{ device_type }} ')[0] %}
Does anyone know how I could replace the device_type within that function?

Apparently it was as easy as
{% set ip_addr = salt['network.ip_addrs']( device_type )[0] %}
Without anything supernatural.

Related

How can I use {{this}} as a parameter in a dbt jinja macro?

How can I pass the name of the current model using {{this}} as a parameter for a macro in a config function?
I have tried a couple of options and none of them works.
model/Table1.sql
{{ config(post_hook= calculate_test("{{this}}") ) }}
macro/calculate_test.sql
{% macro calculate_test(tableN) %}
{%- set tableName = tableN -%}
{% set sql %}
SELECT
COUNT(*) as cnt
FROM {{ tableName }}
{% endset %}
{% set results = run_query(sql) %}
{% endmacro %}
The error is:
You’re almost there! Only thing is that you’ve got extra curly brackets and misplaced quotes. The entire config block is Jinja so you don’t need the curly brackets around ‘this’.
{{ config(post_hook= “calculate_test(this)” ) }}

Comparing timestamps gives type error in jinja2 template

I'm trying to compare two timestamps but getting a type error:
"TypeError: '<' not supported between instances of 'float' and 'str'
The template code is using 'as_timestamp' and the documentation recommended using float() when comparing.
I'm trying to get the name and date of the sensor that has a date value that is closest to now() (in Home Assistant).
So I'm trying to do the following:
{%- set list = ['sensor.1','sensor.2','sensor.3','sensor.4'] -%}
{%- set data = namespace(min_date=float(as_timestamp(now() + timedelta(days = 360))), min_name = '') -%}
{%- for i in list %}
{%- set value = states(i) %}
{%- if float(as_timestamp(value)) < float(data.min_date) %}
{%- set data.min_date = value -%}
{%- set data.min_name = state_attr(i, 'friendly_name') -%}
{% endif %}
{%- endfor %}
{{ data.min_name + ' (' + data.min_date | timestamp_custom('%Y-%m-%dT%H:%M:%S%z') + ')' }}
Any ideas why data.min_date is a str in the comparison, despite the value being defined with both float() and as_timestamp() ?
had to remove the 'as_timestamp' from the initial value assignment and add it to the if statement. that solved it.

Grouping if statements

I'm trying to find a way to have the "if contains" conditions all appear in one line rather than having to repeat the code every single time.
Here is what the code looks like:
var selector = document.querySelector('tr[data-variant-id="{{ item.variant.id }}"] .product__description__variant');
{% assign pre_order_message = '' %}
{% for tag in item.product.tags %}
{% if tag contains 'weeks' %}
{% assign count = count | plus: 1 %}
{% assign pre_order_message = tag | split:'**' | last %}
var para = document.createElement("p");
para.classList.add('hc-shipping');
var node = document.createTextNode("Expected to begin shipping {{ pre_order_message }} from order date.");
para.appendChild(node);
selector.after(para);
{% endif %}
{% endfor %}
var selector = document.querySelector('tr[data-variant-id="{{ item.variant.id }}"] .product__description__variant');
{% assign pre_order_message = '' %}
{% for tag in item.product.tags %}
{% if tag contains 'January' %}
{% assign count = count | plus: 1 %}
{% assign pre_order_message = tag | split:'**' | last %}
var para = document.createElement("p");
para.classList.add('hc-shipping');
var node = document.createTextNode("Expected to begin shipping {{ pre_order_message }}.");
para.appendChild(node);
selector.after(para);
{% endif %}
{% endfor %}
I just want to make sure I can group together what lies between the ' ... ' on the line, that states {% if tag contains ' ' %}. Any way to fix? Thanks!
You can use and/or to combine conditions, more info about this here.
By the way if you just want to make sure a tag exists in product tags, you can do this:
{% if item.product.tags contains 'weeks' %}
Do something...
{% endif %}
Instead of looping through all the tags, you'll save a couple of lines that way ;)
One last thing, you can DRY the code by using code snippets, here's a quick read about this.

twig: set variable with function

I want to set a variable with the content of a translation function:
{% set somevar = XXXXX %}
Within content, I call the translation like this, but I fail to put the function result into the var:
{% trans into _locale %}somefield{% endtrans %}
I tried many different aproaches, but I always failed, any hint is highly appreciated.
Try with:
{% set somevar %}
{% trans into _locale %}somefield{% endtrans %}
{% endset %}
Found solution:
{% set somevar = 'somefield' %}
{{ somevar|trans(_locale) }}

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