Testing ansible “to_nice_json” filter within Python – “No filter named ‘to_nice_json'”

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.

Leave a Comment