I want to test an Ansible Jinja2 template using a Python script, based on the answer provided here: How can I test jinja2 templates in ansible?
This code used to work, however I don’t remember in which environment. Now, when I run it, I get an error about the filter not being found:
#!/usr/bin/env bash
# python3 -m pip install ansible
python3 <<EOF
import ansible
import jinja2
print(ansible.__version__)
print(jinja2.__version__)
output = jinja2.Template("Hello {{ var | to_nice_json }}!").render(var=f"{{ 'a': 1, 'b': 2 }}")
print(output)
EOF
This returns:
2.15.6
3.1.2
Traceback (most recent call last):
File "<stdin>", line 7, in <module>
File "/Users/werner/.pyenv/versions/3.11.6/lib/python3.11/site-packages/jinja2/environment.py", line 1208, in __new__
return env.from_string(source, template_class=cls)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/werner/.pyenv/versions/3.11.6/lib/python3.11/site-packages/jinja2/environment.py", line 1105, in from_string
return cls.from_code(self, self.compile(source), gs, None)
^^^^^^^^^^^^^^^^^^^^
File "/Users/werner/.pyenv/versions/3.11.6/lib/python3.11/site-packages/jinja2/environment.py", line 768, in compile
self.handle_exception(source=source_hint)
File "/Users/werner/.pyenv/versions/3.11.6/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<unknown>", line 1, in template
jinja2.exceptions.TemplateAssertionError: No filter named 'to_nice_json'.
The jinja2
pip dependency is pulled in via ansible
.
How would I make my Python code find the right filter, or get jinja2 to load the filter?
The solution is to load the filter explicitly into the jinja2
environment:
import ansible
import jinja2
from ansible.plugins.filter.core import to_nice_json
print(ansible.__version__)
print(jinja2.__version__)
env = jinja2.Environment()
# Add the Ansible specific filter to the Jinja2 environment
env.filters['to_nice_json'] = to_nice_json
template = env.from_string("Hello {{ var | to_nice_json }}!")
output = template.render(var=f"{{ 'a': 1, 'b': 2 }}")
print(output)
This prints:
Hello "{ 'a': 1, 'b': 2 }"!
I am not sure why this worked before without all that extra loading.