Jinja2 sort filter and Python 3

`

`

Hi everyone!

I’m using this jinja2 macro for xml configs:

`

{%- macro print_opts(options, indent=’ ', count=0) %}
{% for key in options.keys() | sort2 %}
{% set value = options[key] %}
{% if value is string %}
{{- indentcount }}{{ key }} {{ ‘"’ + value.split(‘\t’) | join(‘" "’) + ‘"’ }}
{% elif value in [true, false] %}
{{- indent
count }}{{ key }} {{ value | lower }}
{% elif value is number %}
{{- indentcount }}{{ key }} {{ value }}
{% elif value is mapping %}
{{- indent
count }}<{{ key }}>
{{ print_opts(value, indent, count+1) -}}
{{- indentcount }}</{{ key.split()[0] }}>
{% elif value is sequence %}
{% for i in value | sort2 -%}
{{ print_opts({key: i}, indent, count) -}}
{%- endfor %}
{% else %}
{{- indent
count }}{{ key }} “{{ value }}”
{% endif %}
{% endfor %}
{% endmacro %}

`

This macro works fine with Python 2, but I need Python 3 support also. The problem is sort filter.
First, I’ve had the problem with dict sorting in Py3 (unorderable types: dict() < dict()) and created this custom sort filter:

`

from jinja2._compat import string_types
from operator import itemgetter

def environmentfilter(f):
“”“Decorator for marking environment dependent filters. The current
:class:Environment is passed to the filter as first argument.
“””
f.environmentfilter = True
return f

@environmentfilter
def do_sort(environment, value, reverse=False, case_sensitive=False,
attribute=None):

if not case_sensitive:
def sort_func(item):
if isinstance(item, string_types):
item = item.lower()
return item
else:
sort_func = None

if attribute is not None:
getter = make_attrgetter(environment, attribute)
def sort_func(item, processor=sort_func or (lambda x: x)):
return processor(getter(item))

print(type(value))
if isinstance(value, list) and isinstance(value[0], dict):
return sorted(value, key=lambda x:sorted(x.keys()), reverse=reverse)
else:
return sorted(value, key=sort_func, reverse=reverse)

class FilterModule(object):
‘’’
custom jinja2 sort filter
‘’’

def filters(self):
return {
‘sort2’: do_sort
}

`

Here I am using different sorted key for list of dicts. But then I catch the next problem - list sorting.
With Python 2 print(type(value)) returns <type ‘list’> and sorting works as expected
With Python 3 it returns <class ‘dict_keys’> and I am getting different sorting per each ansible role running, config file always has changed state.

Please help me resolve this problem. Maybe someone knows a simpler solution to make this macro work on both Python versions.

Thanks