Jinja variables in function - jinja2

I have defined a variable in jinja by using:
{% set my_var = 10 %}
And a macro by doing:
{% macro my_function(my_var) %}
where my_col > my_var
{% endmacro %}
I want to call the macro on the variable I've set in order to obtain the string:
where my_col > 10
I've tried with
{{my_function(my_var)}}
but it doesn't work. I'm not sure if I have to change the call or the macro. Do you know how can I achieve this?
Thanks in advance!

There was a bug in the function definition, it needs to be defined like:
{% macro my_function(my_var) %}
where my_col > {{ my_var }}
{% endmacro %}

Related

How to dynamically call dbt macros using jinja?

I have a use case where I would like to define the name of a macro and then apply it to one column.
A simplified example could be as follows. I have two macros defined that I want to call dynamically in my model (both take one column as an input):
cast_to_string
convert_empty_string_to_null_value
Now, I want to call them dynamically. See the example below
{%- set macro_names = ["cast_to_string", "convert_empty_string_to_null_value"] -%}
select
{% for macro_name in macro_names %}
-- this should dynamically be evaluated to `{{ cast_to_string(my_column) }}`
-- and `{{ convert_empty_string_to_null_value(my_column) }}`
{{ macro_name(my_column) }}
{% endfor %}
from my_model
However, this will throw an error saying that a string is not callable.
I also tried using {% raw %} {{ {% endraw %} to escape brackets, but that didn’t work either.
So, my question is, if there is a way to dynamically call macros in jinja/dbt?
I think it should work if you remove the quotes :
{%- set macro_names = [cast_to_string, convert_empty_string_to_null_value] -%}
So that jinja doesn't interpret it as string and you can use it as a Callable
I achieve it using this example :
{%- set macro_names = [print_lower, print_upper] -%}
{% for macro_name in macro_names %}
{{ macro_name("test") }}
{% endfor %}
and
{% macro print_lower(string) %}
{{ print(string|lower) }}
{% endmacro %}
{% macro print_upper(string) %}
{{ print(string|upper) }}
{% endmacro %}

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)” ) }}

Store result of a query in a variable ( jinja)

I am trying to put the result of a query in a variable but it doesn't work.
I am not sure what to do so it returns 0 as expected. Any ideas? I am using dbt and jinja.
With the below code the results_list variable is (Decimal('0'),))
MACRO
{% macro source_freshness(model, column_name) %}
{% set freshness_query %}
SELECT COUNT 0 AS count
{% endset %}
{% set results = run_query(freshness_query) %}
{% if execute %}
{% set results_list = results.columns[0].values() %}
{% else %}
{% set results_list = [] %}
{% endif %}
{{ return(results_list) }}
{% endmacro %}
call in a model:
{% set freshness_query_test = source_freshness(ref('model'),'date') %}
{% if count in freshness_query_test == 0 %}
do this
{% else %}
do that
{% endif %}
Thank you!
thanks for your help with this. I have not been able to find a direct answer but what I have done is to add the macro in a separate model, and then use the call statement logic in the shared answer Hi, how do we define select statement as a variable in dbt?

Whare are the difference between set and with in jinja

I am beginner in computer science and trying to use python flask framework to create a webserver.
In the tutorials, I have seen the below jinja usage in the HTML which are
{% set a = somefunction() %}
{% with a = somefunction() %}
May I know what are the differences? Thanks.
While you may use {% set %} to define a variable, the {% with %} statement additionally creates a new scope which can be ended using the {% endwith %} statement.
For example:
{% with myvar=1 %}
...
{% endwith %}
myvar will only be available before the corresponding endwith.
You can also use with to create a local scope:
{% with %}
{% set myvar=1 %}
...
{% endwith %}
myvar will only be available within the given scope.
You can find information about these statements here (the examples shown here were taken from there also).
Variables inside a {% with %} statement are restricted to that particular statement, while variables created via {% set %} are accessible from anywhere in the template (they are global).
>>> import jinja2
>>> t = jinja2.Template("{% set a = 'Global' %}{% with a = 'Local' %}{{ 'First a is ' + a +'\n' }}{% endwith %}{{ 'Second a is ' + a }}")
>>> print(t.render())
First a is Local
Second a is Global

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