Fixed #30425 -- Handled jinja2.TemplateSyntaxError when rendering a template.
Jinja raises jinja2.TemplateSyntaxError in render() not in get_template() when it's in an included template.
This commit is contained in:
parent
1f817daa20
commit
8d32290279
|
@ -1,3 +1,5 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import jinja2
|
import jinja2
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -68,7 +70,12 @@ class Template:
|
||||||
context['csrf_token'] = csrf_token_lazy(request)
|
context['csrf_token'] = csrf_token_lazy(request)
|
||||||
for context_processor in self.backend.template_context_processors:
|
for context_processor in self.backend.template_context_processors:
|
||||||
context.update(context_processor(request))
|
context.update(context_processor(request))
|
||||||
return self.template.render(context)
|
try:
|
||||||
|
return self.template.render(context)
|
||||||
|
except jinja2.TemplateSyntaxError as exc:
|
||||||
|
new = TemplateSyntaxError(exc.args)
|
||||||
|
new.template_debug = get_exception_info(exc)
|
||||||
|
raise new from exc
|
||||||
|
|
||||||
|
|
||||||
class Origin:
|
class Origin:
|
||||||
|
@ -88,12 +95,22 @@ def get_exception_info(exception):
|
||||||
"""
|
"""
|
||||||
context_lines = 10
|
context_lines = 10
|
||||||
lineno = exception.lineno
|
lineno = exception.lineno
|
||||||
lines = list(enumerate(exception.source.strip().split("\n"), start=1))
|
source = exception.source
|
||||||
during = lines[lineno - 1][1]
|
if source is None:
|
||||||
total = len(lines)
|
exception_file = Path(exception.filename)
|
||||||
top = max(0, lineno - context_lines - 1)
|
if exception_file.exists():
|
||||||
bottom = min(total, lineno + context_lines)
|
with open(exception_file, 'r') as fp:
|
||||||
|
source = fp.read()
|
||||||
|
if source is not None:
|
||||||
|
lines = list(enumerate(source.strip().split('\n'), start=1))
|
||||||
|
during = lines[lineno - 1][1]
|
||||||
|
total = len(lines)
|
||||||
|
top = max(0, lineno - context_lines - 1)
|
||||||
|
bottom = min(total, lineno + context_lines)
|
||||||
|
else:
|
||||||
|
during = ''
|
||||||
|
lines = []
|
||||||
|
total = top = bottom = 0
|
||||||
return {
|
return {
|
||||||
'name': exception.filename,
|
'name': exception.filename,
|
||||||
'message': exception.message,
|
'message': exception.message,
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{% include "template_backends/syntax_error.html" %}
|
|
@ -1,5 +1,5 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import skipIf
|
from unittest import mock, skipIf
|
||||||
|
|
||||||
from django.template import TemplateSyntaxError
|
from django.template import TemplateSyntaxError
|
||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
|
@ -96,3 +96,39 @@ class Jinja2Tests(TemplateStringsTests):
|
||||||
})
|
})
|
||||||
template = engine.get_template('hello.html')
|
template = engine.get_template('hello.html')
|
||||||
self.assertEqual(template.render({'name': 'Joe'}), 'Hello Joe!')
|
self.assertEqual(template.render({'name': 'Joe'}), 'Hello Joe!')
|
||||||
|
|
||||||
|
def test_template_render_nested_error(self):
|
||||||
|
template = self.engine.get_template('template_backends/syntax_error_include.html')
|
||||||
|
with self.assertRaises(TemplateSyntaxError) as e:
|
||||||
|
template.render(context={})
|
||||||
|
debug = e.exception.template_debug
|
||||||
|
self.assertEqual(debug['after'], '')
|
||||||
|
self.assertEqual(debug['before'], '')
|
||||||
|
self.assertEqual(debug['during'], '{% block %}')
|
||||||
|
self.assertEqual(debug['bottom'], 1)
|
||||||
|
self.assertEqual(debug['top'], 0)
|
||||||
|
self.assertEqual(debug['line'], 1)
|
||||||
|
self.assertEqual(debug['total'], 1)
|
||||||
|
self.assertEqual(len(debug['source_lines']), 1)
|
||||||
|
self.assertTrue(debug['name'].endswith('syntax_error.html'))
|
||||||
|
self.assertIn('message', debug)
|
||||||
|
|
||||||
|
def test_template_render_error_nonexistent_source(self):
|
||||||
|
template = self.engine.get_template('template_backends/hello.html')
|
||||||
|
with mock.patch(
|
||||||
|
'jinja2.environment.Template.render',
|
||||||
|
side_effect=jinja2.TemplateSyntaxError('', 1, filename='nonexistent.html'),
|
||||||
|
):
|
||||||
|
with self.assertRaises(TemplateSyntaxError) as e:
|
||||||
|
template.render(context={})
|
||||||
|
debug = e.exception.template_debug
|
||||||
|
self.assertEqual(debug['after'], '')
|
||||||
|
self.assertEqual(debug['before'], '')
|
||||||
|
self.assertEqual(debug['during'], '')
|
||||||
|
self.assertEqual(debug['bottom'], 0)
|
||||||
|
self.assertEqual(debug['top'], 0)
|
||||||
|
self.assertEqual(debug['line'], 1)
|
||||||
|
self.assertEqual(debug['total'], 0)
|
||||||
|
self.assertEqual(len(debug['source_lines']), 0)
|
||||||
|
self.assertTrue(debug['name'].endswith('nonexistent.html'))
|
||||||
|
self.assertIn('message', debug)
|
||||||
|
|
Loading…
Reference in New Issue