如何以确定的顺序打印jinja dict?

时间:2015-11-16 18:55:23

标签: jinja2 salt-stack

我有一个配置文件,其中特定设置需要一个长丑陋的json样式字典。我想在YAML中定义这个字典并用Jinja打印出来。目前看起来像这样:

{%- load_yaml as some_conf_val %}
val1: something
val2: completely
val3: different
{%- endload %}

option = {{ some_conf_val }}

# Results in:
option = {'val2': 'completely', 'val1': 'something', 'val3': 'different'}

幸运的是,这正是所配置程序所期望的格式,并且yaml块比内联版本更容易阅读和修改。但是,密钥既不按字母顺序排列,也不按定义顺序排列,这使我怀疑它们的输出顺序是非确定性的。在重新运行状态几次时,它们总是以相同的顺序出现,但这并不能证明这一点。

这是一个问题,因为如果输出字符串被更改,它将被视为对文件的更改并触发服务重新启动,即使没有任何功能已更改。我并不关心密钥的具体顺序,但我确实每次都需要这个顺序。

我怎样才能做到这一点?或者它是否已经确定,并且看起来不像?

(如果我理解正确,jinja dicts真的是python dicts,并且python dicts是无序的,所以如果没有包含比我试图没有的代码更麻烦的代码,这可能是不可能的。写作。但我不希望。)

2 个答案:

答案 0 :(得分:1)

你是对的,Python的标准字典是无序的。 collections模块中有一个有序版本:collections.OrderedDict。我们可以使用定制的Jinja2过滤器将其用于此目的。

自定义过滤器首先将输入转换为OrderedDict,然后转换为JSON,最后替换双引号:

from json import dumps
from collections import OrderedDict

def conffilter(value):
    return dumps(OrderedDict(value)).replace('"', '\'')

然后我们必须add this new filter到Jinja2:

 env.filters['conffilter'] = conffilter

其中env是您应用中的Jinja2 Environment对象(例如,在Flask中它是app.jinja_env)。

现在我们可以将新过滤器与Jinja2的dictsort过滤器一起使用。

# Define a list for testing:
{%- set some_conf_val = {'val2': 'completely', 'val1': 'something', 'val3': 'different'} -%}

# Unordered dict output
option = {{ some_conf_val }}
# Result:
option = {'val1': 'something', 'val3': 'different', 'val2': 'completely'}

# Ordered list of tuples
option = {{ some_conf_val|dictsort }}
# Result:
option = [('val1', 'something'), ('val2', 'completely'), ('val3', 'different')] 

# Ordered dict-like output:
option = {{ some_conf_val|dictsort|conffilter }}
# Result:
option = {'val1': 'something', 'val2': 'completely', 'val3': 'different'} 

答案 1 :(得分:1)

事实证明,saltstack为json输出提供了一个过滤器,可以对其键进行排序,并可以按摩以获得我想要的效果。我最终使用的解决方案如下所示:

option = {{ some_conf_val|json|replace('"', "'") }}

# Results in:
option = {'val1': 'something', 'val2': 'completely', 'val3': 'different'}

替换操作是因为该选项最终被提供给关心它所关注的引用的东西。它可能不适用于其他情况。

据我所知,排序行为尚未记录,但您可以在源here中找到它。