-
-
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_exceptionThis 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.