Skip to content

Commit

Permalink
improve jinja2 templating error report for TemplateError (#783)
Browse files Browse the repository at this point in the history
jinja2.TemplateError does not include the template line number
which can be of great help when troubleshooting errors like
   'foo' has no attribute 'bar'

The line number can however be inferred from the stack trace.
This was inspired by
https://github.com/saltstack/salt/blob/master/salt/utils/templates.py

Example output:

   Jsonnet error: failed to compile test/main.jsonnet:
    RUNTIME ERROR: Jsonnet jinja2 failed to render templates/abc.j2:
     Jinja2 TemplateError: 'foo' has no attribute 'bar', at templates/abc.j2:240

Signed-off-by: David Verbeiren <[email protected]>
  • Loading branch information
dverbeir authored Oct 30, 2021
1 parent 1cd4291 commit b4f08a5
Showing 1 changed file with 15 additions and 1 deletion.
16 changes: 15 additions & 1 deletion kapitan/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import sys
import re
import tarfile
import traceback
from zipfile import ZipFile
from collections import Counter, defaultdict
from functools import lru_cache, wraps
Expand Down Expand Up @@ -123,6 +124,14 @@ def sha256_string(string):
return sha256(string.encode("UTF-8")).hexdigest()


def _jinja_error_info(trace_data):
"""Extract jinja2 templating related frames from traceback data"""
try:
return [x for x in trace_data if x[2] in ("top-level template code", "template", "<module>")][-1]
except IndexError:
pass


def render_jinja2_file(name, context, jinja2_filters=defaults.DEFAULT_JINJA2_FILTERS_PATH, search_paths=None):
"""Render jinja2 file name with context"""
path, filename = os.path.split(name)
Expand All @@ -136,7 +145,12 @@ def render_jinja2_file(name, context, jinja2_filters=defaults.DEFAULT_JINJA2_FIL
)
load_jinja2_filters(env)
load_jinja2_filters_from_file(env, jinja2_filters)
return env.get_template(filename).render(context)
try:
return env.get_template(filename).render(context)
except jinja2.TemplateError as e:
# Exception misses the line number info. Retreive it from traceback
err_info = _jinja_error_info(traceback.extract_tb(sys.exc_info()[2]))
raise CompileError(f"Jinja2 TemplateError: {e}, at {err_info[0]}:{err_info[1]}")


def render_jinja2(path, context, jinja2_filters=defaults.DEFAULT_JINJA2_FILTERS_PATH, search_paths=None):
Expand Down

0 comments on commit b4f08a5

Please sign in to comment.