DBT macro ignores leading if block - jinja2

I defined a macro that starts with:
{% macro my_macro(table, first=false) %}
{%- if first -%} WITH
{%- else -%} ,
{% endif %}
tmp AS (...
In the compiled SQL I see this is completely ignored. If I paste this exact same block after the first CTE, it inserts fine. If I put any text before the if-block, it will also render the text + content of if-block.
I don't understand this behaviour. How can I make this macro work leading either with WITH or ","?
Even if I replace first with true it doesn't show up.
Additional information:
I'm working with BigQuery and dbt version 0.18.2

After trial and error I realised that using "-" to reduce white space on the first line somehow removes the text coming after it as well.
So
{%- if first -%}
WITH
...
Doesn't work, but
{% if first %}
WITH
...
is fine. It was a simple fix, but I doubt this is expected behaviour.

interesting problem! A couple of questions:
What database are you working with?
What version of dbt are you working with?
Where does first come from in your query?
On Azure Synapse and with dbt version 0.18.1, I was able to successfully use the following:
{% set first = true %}
{%- if first -%}
WITH
{%- else -%} ,
{% endif %}
top_100 AS (
SELECT 100 AS MyNumber
),
top_10 AS (
SELECT TOP 10 * FROM top_100
)
SELECT * FROM top_10

Related

Jinja non rendering blocks adds whitespaces to next rendering block

I have the following import on a jinja template that is rendered by ansible:
labels:
{% set name = 'jellyfin' %}
{% set port = '8096' %}
{% filter indent(width=8, first=True) %}
{% include './labels.yml.jinja' %}
{% endfilter %}
As you can see, there are some non rendering blocks to set some local variables and stuff. When the template is rendered by ansible, the first row of the template is shifted by the same amount of spaces that the non rendering blocks sum + 2 (32 in this case = 5 blocks with 6 spaces + 2).
For example:
labels:
# this are the labels, fools
- "traefik.enable=true"
- "traefik.backend=jellyfin"
I can remove the indentation of ALL the {% %} blocks, and then it will work properly, but looks ugly and off place.
Even if I add a minus sign to remove whitespaces to the non rendering blocks like this:
{% set name = 'jellyfin' -%}
{% set port = '8096' -%}
{% filter indent(width=8, first=True) -%}
{% include './labels.yml.jinja' -%}
{% endfilter -%}
The first line is still shifted (albeit much less)
How can I fix this?
I just had to add #jinja2: lstrip_blocks: "True" to the very top of the importing template, and that did the trick.
I gathered that information from this article, explaining my exact problem and showing a solution: https://radeksprta.eu/posts/control-whitespace-in-ansible-templates/
But I have to say that the default behaviour is very confusing.

How do i compare a String out of a list in Jinja2 to another string?

I'm using a for loop and inside that forloop i generate tables out of DataBase data.
The thing is that i need to show multiple tables, but the if statement in Jinja2 doesn't seem to work for some reason. I need to check if the string on index 2 of my_list[2] is equal to the 'None'.
{% if '{{my_list[2]}}' == 'None' %}
There is no connection.
{% else %}
There is a GOOD connection.
{% endif %}
Why isn't this working?
{% if not customer_list[2] %}
This does exactly wat i needed.

Cannot use globals as default arguments in macros

I'm adding some globals in my handler that should be available to all templates, including macros.
jinja_env.globals.update({
"SOME_CONSTANT": SOME_CONSTANT_1,
})
This works fine when I use it inside a macro like this:
{% macro is_some_constant(some_str) -%}
some_str == SOME_CONSTANT
{%- endmacro %}
But I get an undefined error when I try to use a global as a default arg to the macro:
{% macro test_something(something=SOME_CONSTANT) -%}
...
{%- endmacro %}
Result: NameError: global name 'l_SOME_CONSTANT' is not defined
Is this expected? I found this related issue which is claimed to be fixed by this PR, but still running into this. The workaround mentioned in the first link does work, but is kind of silly and annoying:
{% set SOME_CONSTANT = SOME_CONSTANT %}
{% macro test_something(something=SOME_CONSTANT) -%}
...
{%- endmacro %}
Oh, I realized I'm on jinja2 v2.8, and the fix PR was merged into 2.9 (I think). So perhaps that fixes the problem.
For now, I'll just use the hacky workaround.

Django template IF statement bug

Does anyone know how is this even possible that Django HTML-template file:
Length: {{ group_list|length }}
{% if group_list|length == 0 %}
Show Foo
{% else %}
Show Bar
{% endif %}
Returns:
Length: 0
Show Bar
Same problem on FF, Chrome and IE9+. This doesn't make any sense completely. How does one suppose to diagnose the problem?
I'm not entirely sure what's going on with {% if group_list|length == 0 %}, but you can always use if statement to test the emptiness of the list:
{% if group_list %}
Note that django also has length_is filter to test exact length, so your use case would most likely not supported by django.

Jinja join list of strings if substring match

Is it possible to do something like this in jinja2:
my_list = ['foo1', 'bar1', 'foo2', 'bar2'] # could be any number of foo's and bar's
[i for i in my_list if 'foo' in i]
I was looking at map and join, something like:
{% my_list|map('???')|join(' ') %}
But I can't find a filter that would like me do any sort of wildcard searches. The two closest ones look like 'sameas' and 'equalto' but those don't quiet work.
If you're using a recent version of Jinja2 (2.7 or later), there's a new filter called 'select', which seems to do what you want. jinja.pocoo.org/docs/dev/templates/#select You will probably have to write your own test for this, and pass it into the jinja2 object when you instantiate it.
{{ foobars|select("test") }}
If you're on an even more up to date version (2.8 or later), you can also use block assignments http://jinja.pocoo.org/docs/dev/templates/#block-assignments
{% set my_foo_bars %}
{%- for item in my_list %}
{%- if item %}
{{item}}
{% endif -%}
{% endfor -%}
{% endset %}
If you're stuck on an older version (like the jinja2 from google app engine), you would probably be best doing the processing before passing it into the template, if possible.