Consider:
#!/usr/bin/env python3
from collections import OrderedDict
import jinja2
t = '''
{% for key, value in d.iteritems() %}
* {{ key }}: {{ value }}
{% endfor %}
'''
jt = jinja2.Template(t)
d = OrderedDict()
d['one'] = 1
d['two'] = 2
d['three'] = 3
print(jt.render(d=d))
When run w/ Python 3, you get an confusing exception:
Traceback (most recent call last):
File "jinja2-OrderedDict.py", line 20, in <module>
print(jt.render(d=d))
File "/usr/lib/python3/dist-packages/jinja2/environment.py", line 895, in render
return self.environment.handle_exception(exc_info, True)
File "/usr/lib/python3/dist-packages/jinja2/environment.py", line 671, in handle_exception
raise exc_value.with_traceback(tb)
File "<template>", line 2, in <module>
jinja2.exceptions.UndefinedError: b"'collections.OrderedDict object' has no attribute 'iteritems'"
This is because the template uses iteritems, which is removed in Python 3. From the above exception, it's not clear the problem is in the template—it should be.
It works for normal Python 3 dictionaries because lines 205–210 of Jinja2 v2.61 add back an iteritems method:
# not available on python 3
if hasattr(dict, 'iterkeys'):
iterkeys = _all('iterkeys')
itervalues = _all('itervalues')
iteritems = _all('iteritems')
del _all
What's the best way to fix this? Better detect dict-like objects, try to spit out a better error, etc?
Dictionaries do not have iteritem methods in 3.x. You will need to change to .items()
. Nothing I can do about that.
It would be nice if there were a built-in filter for this and other python 2to3 oddities.
Unless you have huge dicts, using .items()
is not /that/ bad
Here's a way to get around it:
import six
env = jinja2.Environment(loader=jinja2.FileSystemLoader('your_dir'))
env.globals['six_iteritems'] = six.iteritems
template = env.get_template('your_template')
Then in your template:
use:
{% for key, value in six_iteritems(your var) %}
It's kinda ugly, but it does work.
using .items() instead .iteritems() worked
Most helpful comment
Dictionaries do not have iteritem methods in 3.x. You will need to change to
.items()
. Nothing I can do about that.