Reputation: 15217
I switched to Jinja from Django but a lot of my templates broke when referencing
{{ entity.property }}
if entity is not defined. Is there away to ignore the UndefinedErrors in certain situations, Otherwise I'll have to add in a lot of
{% if entity %}{{ entity.property }}{% endif %}
wrappers.
Thanks, Richard
Upvotes: 23
Views: 15788
Reputation: 8005
If you're using Jinja2 within ansible, there's a setting that lets you specify the default behaviour for a missing variable. In ansible.cfg:
[Defaults]
error_on_undefined_vars=False
Note that this, and the defaults filter, only works if what's missing is at the end of a dot path. Eg: {{ a.b.c }}
will work if 'c' is missing, but will still fail with a KeyError if 'b' is missing.
Upvotes: 0
Reputation: 1187
Also was looking for a solution and used @s29 SilentUndefined class, but I`ve caught "'str' object is not callable" error when undefined variable was tried to be called, so this is my workaround, it could be helpful for someone
class SilentUndefined(Undefined):
def _fail_with_undefined_error(self, *args, **kwargs):
class EmptyString(str):
def __call__(self, *args, **kwargs):
return ''
return EmptyString()
__add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
__truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
__mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
__getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \
__float__ = __complex__ = __pow__ = __rpow__ = \
_fail_with_undefined_error
Upvotes: 2
Reputation: 2057
I also needed to reset the class's magic methods to make object attributes etc work correctly. Adding to @rattray --
from jinja2 import Undefined, Template
class SilentUndefined(Undefined):
def _fail_with_undefined_error(self, *args, **kwargs):
return ''
__add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
__truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
__mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
__getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \
__float__ = __complex__ = __pow__ = __rpow__ = \
_fail_with_undefined_error
It'd make sense to be a jinja setting. A lot of people would be coming from django templates which are silent by default.
Upvotes: 6
Reputation: 1618
I built on @rattray's answer above:
from jinja2 import Undefined, Template
class SilentUndefined(Undefined):
def _fail_with_undefined_error(self, *args, **kwargs):
return ''
Then used it with template string:
person_dict = {'first_name': 'Frank', 'last_name': 'Hervert'}
t2 = Template("{{ person1.last_name }}, {{ person.last_name }}", undefined=SilentUndefined)
print t2.render({'person': person_dict})
# ', Hervert'
I needed to ignore the errors when rendering a Template from string directly instead of using Environment.
Upvotes: 7
Reputation: 6069
Building off of Sean's excellent and helpful answer, I did the following:
from jinja2 import Undefined
import logging
class SilentUndefined(Undefined):
'''
Dont break pageloads because vars arent there!
'''
def _fail_with_undefined_error(self, *args, **kwargs):
logging.exception('JINJA2: something was undefined!')
return None
and then env = Environment(undefined=SilentUndefined)
where I was calling that.
In the django_jinja library, which I use, the above is in base.py
and is actually a modification of initial_params
Upvotes: 9
Reputation: 160033
Jinja2 actually uses a special class for undefined entities. You can subclass this Undefined
class from Jinja2 to include __getattr__
and other attribute accessors that you want to be able to use even on undefined entities and have them return a blank unicode string (for example).
Upvotes: 6