pallets / jinja

A very fast and expressive template engine.
https://jinja.palletsprojects.com
BSD 3-Clause "New" or "Revised" License
10.23k stars 1.6k forks source link

add sort_keys argument to `tojson` filter #1933

Closed AbdouMechraoui closed 7 months ago

AbdouMechraoui commented 7 months ago

Hello, I am using jinja2 templating in the context of AWX. There are certain templates in AWX that only allow builtin jinja2 filters to be used, such as the Notification-Templates. The issue that I am dealing with relates to the inability to unset the sort_keys flag in the environment policy. Although JSON is an unordered set, sometimes sorting is not desired.

It would be nice to enable or disable this flag through a filter parameter, when the user does not have access to the environment policies. Currently, one can control the indentation through parameter indent. The parameter sort_keys should function the same way.

tldr: It would be nice to control the sorting behavior of tojson through parameter sort_keys.

Current implementation tojson:

from jinja2 import Environment

env = Environment(autoescape=True)

# Given
dict_ = {"e": "some_value", "b": "some_value", "a": "some_value", "d": "some_value", "c": "some_value" }

t = env.from_string("{{ x|tojson }}")
print(t.render(x=dict_))

This produces the following:

{"a": "some_value", "b": "some_value", "c": "some_value", "d": "some_value", "e": "some_value"}

Desired implementation tojson:

from jinja2 import Environment

env = Environment(autoescape=True)

# Given
dict_ = {"e": "some_value", "b": "some_value", "a": "some_value", "d": "some_value", "c": "some_value" }

# Default behavior
t = env.from_string("{{ x|tojson(sort_keys=False) }}")
print(t.render(x=dict_))

This should produce the following:

{"e": "some_value", "b": "some_value", "a": "some_value", "d": "some_value", "c": "some_value"}

I would be happy to add a PR, if you'd entertain it :D

davidism commented 7 months ago

You can use env.policies["json.dumps_kwargs"] = {...} to set other arguments for every call to tojson. I don't plan to add individual arguments to this filter. Note that indent will already not work if using a different JSON library that doesn't use the same arguments, like orjson.dumps. You can also override the filter to do what you want instead with env.filters["tojson"] = my_tojson.

AbdouMechraoui commented 7 months ago

Thanks for the prompt response. All options you have mentioned require access to the environment policy, which is not possible since I am using a stable AWX release. Is it possible to change or modify the environment policy in a template file?

As per your second point, this can be avoided perhaps if the do_tojson() method accepts **kwargs instead of individual arguments.