return ProcessedTraceback(exc_info[0], exc_info[1], frames)
+def get_jinja_locals(real_locals):
+ ctx = real_locals.get('context')
+ if ctx:
+ locals = ctx.get_all()
+ else:
+ locals = {}
+
+ local_overrides = {}
+
+ for name, value in iteritems(real_locals):
+ if not name.startswith('l_'):
+ continue
+ _, depth, name = name.split('_', 2)
+ depth = int(depth)
+ cur_depth = local_overrides.get(name, (-1,))[0]
+ if cur_depth < depth:
+ local_overrides[name] = (depth, value)
+
+ for name, (_, value) in local_overrides.iteritems():
+ if value is missing:
+ locals.pop(name, None)
+ else:
+ locals[name] = value
+
+ return locals
+
+
def fake_exc_info(exc_info, filename, lineno):
"""Helper for `translate_exception`."""
exc_type, exc_value, tb = exc_info
# figure the real context out
if tb is not None:
- real_locals = tb.tb_frame.f_locals.copy()
- ctx = real_locals.get('context')
- if ctx:
- locals = ctx.get_all()
- else:
- locals = {}
- for name, value in iteritems(real_locals):
- if name.startswith('l_') and value is not missing:
- locals[name[2:]] = value
+ locals = get_jinja_locals(tb.tb_frame.f_locals)
# if there is a local called __jinja_exception__, we get
# rid of it to not break the debug functionality.
@pytest.mark.debug
-class TestDebug():
+class TestDebug(object):
def assert_traceback_matches(self, callback, expected_tb):
try:
raise TemplateSyntaxError\('wtf', 42\)
(jinja2\.exceptions\.)?TemplateSyntaxError: wtf
line 42''')
+
+ def test_local_extraction(self):
+ from jinja2.debug import get_jinja_locals
+ from jinja2.runtime import missing
+ locals = get_jinja_locals({
+ 'l_0_foo': 42,
+ 'l_1_foo': 23,
+ 'l_2_foo': 13,
+ 'l_0_bar': 99,
+ 'l_1_bar': missing
+ })
+ assert locals == {'foo': 13}