-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Environment.getattr() and Environment.getitem() discard errors
from (TypeError
, LookupError
, AttributeError
) and return Undefined instead.
When the Undefined raises UndefinedError
, the original exception,
and its traceback, is lost. This makes debugging hard.
My use case
The CPython buildbot release dashboard
uses lazily computed attributes (with cached_property
).
In other words, “business logic” is driven by the template rendering.
This avoids additional logic to pre-determine which data the template will need.
Unfortunately, any AttributeError
that occurs deep in application code bubbles
up and is replaced by a traceback-less UndefinedError
.
Possible workarounds outside Jinja
A hacky workaround is a decorator that replaces AttributeError
by a different kind of error.
(The linked code doesn't use it -- I apply it only when debugging.)
It is also possible to subclass Undefined
to preserve the exception:
class StrictUndefinedWithCause(jinja2.StrictUndefined):
__slots__ = ['_original_exception']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._original_exception = sys.exception()
def _fail_with_undefined_error(self, *args, **kwargs):
try:
super()._fail_with_undefined_error(*args, **kwargs)
except BaseException as exc:
raise exc from self._original_exception
This would work well if Environment.getitem
and Environment.getattr
always called their self.undefined(...)
inside except
blocks.
That's not always the case -- and that's the main reason I can't find
a good solution without changes in Jinja.
I suggest that Jinja itself adds the relevant tracebacks when it raises
UndefinedError
, and adds tests to ensure it does that.