_The actual template where I encountered the issue first was more boilerplate-ish, but I this one describes the problem in a more intuitive way._
Suppose we have the following template:
{%- macro _tag(tag, id=none, classes=(), attrs={}) -%}
<{{ tag }}
{% if id %} id="{{ id }}" {% endif %}
{% if classes %} class="{{ classes|join(' ') }}" {% endif %}
{{ attrs|xmlattr }}>
{% if caller %} {{ caller() }} {% endif %}
</{{ tag }}>
{%- endmacro -%}
along with a higher level template that tries to {% call %}
it for some specific case:
{%- macro _div() -%}
{% call _tag('div', *varargs, **kwargs) %}
{% autoescape false %}
{% if caller %} {{ caller() }} {% endif %}
{% endautoescape %}
{% endcall %}
{%- endmacro -%}
Intuitively, doing {% call _div(...) %} <b>foo</b> {% endcall %}
should pass <b>foo</b>
to the _tag
macro, which would then render it (verbatim, thanks to autoescape). But the actual result is UndefinedError: No caller defined
on the {{ caller() }}
line inside _div
. It would seem that the scope of caller
does not extend into the {% call %}
block, thereby preventing chained calls such as the one depicted above.
There is an ugly workaround that uses the new block assignment feature from 2.8:
{%- macro _div() -%}
{% set content %}
{% if caller %} {{ caller() }} {% endif %}
{% endset %}
{% call _tag('div', *varargs, **kwargs) %}
{% autoescape false %} {{ content }} {% endautoescape %}
{% endcall %}
{%- endmacro -%}
but, of course, the original version would be much more preferable.
I'm able to reproduce this with this small example:
{% macro a() %}
start of a
{% call b() %}
{{ caller() }}
{% endcall %}
end of a
{% endmacro %}
{% macro b() %}
start of b
{{ caller() }}
end of b
{% endmacro %}
{% call b() %}
inside b only
{% endcall %}
{#
{% call a() %}
inside a
{% endcall %}
#}
This works fine as-is, when the last block is uncommented, we get the following traceback:
Traceback (most recent call last):
...
File "/usr/lib/python2.7/dist-packages/jinja2/environment.py", line 894, in render
return self.environment.handle_exception(exc_info, True)
File "templates/test.j2", line 19, in top-level template code
{% call a() %}
File "templates/test.j2", line 3, in template
{% call b() %}
File "templates/test.j2", line 11, in template
{{ caller() }}
File "templates/test.j2", line 4, in template
{{ caller() }}
jinja2.exceptions.UndefinedError: No caller defined
Small note about the workaround:
The new feature of 2.8 is not needed as this is also working fine:
{% macro a() %}
start of a
{% set content=caller() %}
{% call b() %}
{{ content }}
{% endcall %}
end of a
{% endmacro %}
{% macro b() %}
start of b
{{ caller() }}
end of b
{% endmacro %}
{% call b() %}
inside b only
{% endcall %}
{% call a() %}
inside a
{% endcall %}
This is sort of intentional as it always scopes to the closest macro. Closing as wontfix.
FYI, {% set caller_ = caller %}
also works fine, then it can be called whenever it's needed.
Anyway, this might be worth a FAQ entry. I remember a colleague having the exact same problem some time ago until we figured out that {% set caller_ = caller %}
before going into another call block helps.
Yeah, we might want to put that into the docs.
Most helpful comment
Small note about the workaround:
The new feature of 2.8 is not needed as this is also working fine: