# Jinja2 sort filter and Python 3

**URL:** <https://forum.ansible.com/t/jinja2-sort-filter-and-python-3/24412>\
**Category:** Ansible Project\
**Created:** [May 7, 2017, 6:01pm UTC](https://forum.ansible.com/t/jinja2-sort-filter-and-python-3/24412 "2017-05-07T18:01:29Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sergey\_Baranov](https://avatars.discourse-cdn.com/v4/letter/s/f07891/32.png) [@Sergey\_Baranov](https://forum.ansible.com/u/Sergey_Baranov)\
**Post date:** [May 7, 2017, 6:01pm UTC](https://forum.ansible.com/t/jinja2-sort-filter-and-python-3/24412/1 "2017-05-07T18:01:29Z")

</div>

`

`

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 %}  
{{- indent_count }}{{ key }} {{ ‘"’ + value.split(‘\t’) | join(‘" "’) + ‘"’ }}  
{% elif value in [true, false] %}  
{{- indent_count }}{{ key }} {{ value | lower }}  
{% elif value is number %}  
{{- indent_count }}{{ key }} {{ value }}  
{% elif value is mapping %}  
{{- indent_count }}\<{{ key }}\>  
{{ print\_opts(value, indent, count+1) -}}  
{{- indent_count }}\</{{ 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
