Template globals not visible in {% import %}'ed file when it's {% include %}'ed by another file
clarkwang opened this issue · 2 comments
clarkwang commented
I've come up with the following minimal repro steps.
Python script:
$ cat test.py
#!/usr/bin/env python3
import jinja2 as j2
import os, sys
print(f'jinja2 version: {j2.__version__}')
env = j2.Environment(loader=j2.FileSystemLoader('.') )
tmpl = env.get_template(sys.argv[1], globals={ 'ENV': os.getenv })
print(tmpl.render() )
Data files:
$ cat common
{% set var1 = ENV('HOME') %}
$ cat file1
{% include 'file2' %}
$ cat file2
{% import 'common' as COMMON %}
{{ COMMON.var1 }}
To repro the issue:
$ python3 test.py file2
jinja2 version: 3.1.3
/root
$ python3 test.py file1
jinja2 version: 3.1.3
Traceback (most recent call last):
File "/root/void/python/jinja/t1/test.py", line 10, in <module>
print(tmpl.render() )
^^^^^^^^^^^^^
File "/usr/local/py3/lib/python3.11/site-packages/jinja2/environment.py", line 1301, in render
self.environment.handle_exception()
File "/usr/local/py3/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "file1", line 1, in top-level template code
{% include 'file2' %}
^^^^^^^^^^^^^^^^^^^^^^
File "file2", line 1, in top-level template code
{% import 'common' as COMMON %}
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/py3/lib/python3.11/site-packages/jinja2/environment.py", line 1405, in make_module
return TemplateModule(self, ctx)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/py3/lib/python3.11/site-packages/jinja2/environment.py", line 1535, in __init__
body_stream = list(template.root_render_func(context))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "common", line 1, in top-level template code
{% set var1 = ENV('HOME') %}
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/py3/lib/python3.11/site-packages/jinja2/utils.py", line 83, in from_obj
if hasattr(obj, "jinja_pass_arg"):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jinja2.exceptions.UndefinedError: 'ENV' is undefined
As we can see, python3 test.py file2
works but python3 test.py file1
fails.
j7an commented
@clarkwang The error occurs because globals
is being incorrectly passed to get_template
. The correct way to add globals
to the Jinja2 environment is to set them on the Environment
object itself.
#!/usr/bin/env python3
import jinja2 as j2
import os
import sys
print(f'jinja2 version: {j2.__version__}')
# Set up Jinja2 environment and add the global function
env = j2.Environment(loader=j2.FileSystemLoader('.'))
env.globals['ENV'] = os.getenv
# Load the template specified by the first command line argument
tmpl = env.get_template(sys.argv[1])
# Render the template
print(tmpl.render())
get_env_variable
Function: You use theos.getenv
directly without wrapping it in another function. This makes the template code{% set var1 = ENV('HOME') %}
work correctly, asENV
now maps directly toos.getenv
.- Setting Global in Environment: By setting
env.globals['ENV'] = os.getenv
, the environment variable access function is globally available in all templates rendered by this environment.
davidism commented
@j7an adding globals to a template is supported: https://jinja.palletsprojects.com/en/3.1.x/api/#the-global-namespace. That said, you're correct that they're not setting the globals in the correct place. In their example, they set the globals on file1
, but it's common
that needs access. They should either set the globals on common
, or on the environment as you showed.