Made debug views not crash when there isn't a default template engine.

This commit is contained in:
Aymeric Augustin 2015-01-11 10:06:42 +01:00
parent 79deb6a071
commit 6b5113ec94
2 changed files with 64 additions and 19 deletions

View File

@ -7,12 +7,12 @@ import sys
import types
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import resolve, Resolver404
from django.http import (HttpResponse, HttpResponseNotFound, HttpRequest,
build_request_repr)
from django.template import Template, Context, TemplateDoesNotExist
from django.template import Context, Engine, TemplateDoesNotExist
from django.template.defaultfilters import force_escape, pprint
from django.template.engine import Engine
from django.utils.datastructures import MultiValueDict
from django.utils.html import escape
from django.utils.encoding import force_bytes, smart_text
@ -21,6 +21,11 @@ from django.utils.module_loading import import_string
from django.utils import six
from django.utils.translation import ugettext as _
# Minimal Django templates engine to render the error templates
# regardless of the project's TEMPLATES setting.
DEBUG_ENGINE = Engine(debug=True)
HIDDEN_SETTINGS = re.compile('API|TOKEN|KEY|SECRET|PASS|SIGNATURE')
CLEANSED_SUBSTITUTE = '********************'
@ -275,19 +280,27 @@ class ExceptionReporter(object):
def get_traceback_data(self):
"""Return a dictionary containing traceback information."""
try:
default_template_engine = Engine.get_default()
except ImproperlyConfigured:
default_template_engine = None
# TODO: handle multiple template engines.
template_engine = Engine.get_default()
# TODO: add support for multiple template engines (#24120).
# TemplateDoesNotExist should carry all the information.
# Replaying the search process isn't a good design.
if self.exc_type and issubclass(self.exc_type, TemplateDoesNotExist):
self.template_does_not_exist = True
self.loader_debug_info = []
# If Django fails in get_template_loaders, provide an empty list
# for the following loop to not fail.
try:
template_loaders = template_engine.template_loaders
except Exception:
if default_template_engine is None:
template_loaders = []
else:
self.template_does_not_exist = True
self.loader_debug_info = []
# If Django fails in get_template_loaders, provide an empty list
# for the following loop to not fail.
try:
template_loaders = default_template_engine.template_loaders
except Exception:
template_loaders = []
for loader in template_loaders:
try:
source_list_func = loader.get_template_sources
@ -304,8 +317,11 @@ class ExceptionReporter(object):
'loader': loader_name,
'templates': template_list,
})
if (template_engine.debug and
hasattr(self.exc_value, 'django_template_source')):
# TODO: add support for multiple template engines (#24119).
if (default_template_engine is not None
and default_template_engine.debug
and hasattr(self.exc_value, 'django_template_source')):
self.get_template_exception_info()
frames = self.get_traceback_frames()
@ -362,13 +378,13 @@ class ExceptionReporter(object):
def get_traceback_html(self):
"Return HTML version of debug 500 HTTP error page."
t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template')
t = DEBUG_ENGINE.from_string(TECHNICAL_500_TEMPLATE)
c = Context(self.get_traceback_data(), use_l10n=False)
return t.render(c)
def get_traceback_text(self):
"Return plain text version of debug 500 HTTP error page."
t = Template(TECHNICAL_500_TEXT_TEMPLATE, name='Technical 500 template')
t = DEBUG_ENGINE.from_string(TECHNICAL_500_TEXT_TEMPLATE)
c = Context(self.get_traceback_data(), autoescape=False, use_l10n=False)
return t.render(c)
@ -545,7 +561,7 @@ def technical_404_response(request, exception):
module = obj.__module__
caller = '%s.%s' % (module, caller)
t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template')
t = DEBUG_ENGINE.from_string(TECHNICAL_404_TEMPLATE)
c = Context({
'urlconf': urlconf,
'root_urlconf': settings.ROOT_URLCONF,
@ -561,8 +577,7 @@ def technical_404_response(request, exception):
def default_urlconf(request):
"Create an empty URLconf 404 error response."
t = Template(DEFAULT_URLCONF_TEMPLATE, name='Default URLconf template')
t = DEBUG_ENGINE.from_string(DEFAULT_URLCONF_TEMPLATE)
c = Context({
"title": _("Welcome to Django"),
"heading": _("It worked!"),

View File

@ -219,6 +219,36 @@ class DebugViewTests(TestCase):
)
@override_settings(
DEBUG=True,
ROOT_URLCONF="view_tests.urls",
# No template directories are configured, so no templates will be found.
TEMPLATES=[{
'BACKEND': 'django.template.backends.dummy.TemplateStrings',
}],
)
class NonDjangoTemplatesDebugViewTests(TestCase):
def test_400(self):
# Ensure that when DEBUG=True, technical_500_template() is called.
response = self.client.get('/raises400/')
self.assertContains(response, '<div class="context" id="', status_code=400)
def test_403(self):
response = self.client.get('/raises403/')
self.assertContains(response, '<h1>403 Forbidden</h1>', status_code=403)
def test_404(self):
response = self.client.get('/raises404/')
self.assertEqual(response.status_code, 404)
def test_template_not_found_error(self):
# Raises a TemplateDoesNotExist exception and shows the debug view.
url = reverse('raises_template_does_not_exist', kwargs={"path": "notfound.html"})
response = self.client.get(url)
self.assertContains(response, '<div class="context" id="', status_code=500)
class ExceptionReporterTests(TestCase):
rf = RequestFactory()