I have a separate file for helper macros, so I import one when needed. Here is problematic macro:
{% macro row_cycler(tiles) -%}
{%- set row1 = [] -%}
{%- set row2 = [] -%}
{%- set row3 = [] -%}
{%- set row4 = [] -%}
{%- set rows = cycler(row1, row2, row3, row4) -%}
{% for column in tiles|batch(4) -%}
{% for tile in column -%}
{%- do rows.next().append(tile) -%}
{%- endfor %}
{%- endfor %}
{{ dict(row1=row1, row2=row2, row3=row3, row4=row4) }}
{%- endmacro %}
Seems it returns dict, but it's not. It returns "markupsafe.Markup object", it leads to something that:
UndefinedError: 'markupsafe.Markup object' has no attribute 'itervalues'
and so on. How can I force Jinja to return dict without converting?
No, macros can only return template snippets (in the form of Markup
objects), not Python objects like dictionaries. Use Python code for that instead; add a function to the items passed into the template or add a template global.
In your case it looks as if you are re-implementing the slice()
filter, so perhaps that's not even needed in this case.
I overcame a similar problem in Ansible (it has a built-in filter from_json
) by returning a json
string and parsing it back into a dictionary:
{% macro get_dict() -%}
{%- set d = dict() -%}
{{- d.update(foo="bar") -}}
{{- d.update(spam="eggs") -}}
{{- d|to_json -}}
{%- endmacro %}
{% set d = get_dict()|from_json %}
{% for key, value in d.items() %}
{{- key }}: {{ value }}
{% endfor %}
If not using Ansible, one could easily define the from_json
filter, something like below (where env
is an instance of jinja2.Environment
):
def from_json(val):
return json.loads(val)
env.filters["from_json"] = from_json
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With