8000 Improved display of template loader postmortem on debug page. · ddriddle/django@65a7a0d · GitHub
[go: up one dir, main page]

Skip to content

Commit 65a7a0d

Browse files
Improved display of template loader postmortem on debug page.
This now works for multiple Django engines and recursive loaders. Support for non-Django engines is still pending. Refs django#15053.
1 parent fc21471 commit 65a7a0d

File tree

2 files changed

+58
-74
lines changed

2 files changed

+58
-74
lines changed

django/views/debug.py

Lines changed: 57 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import unicode_literals
22

3-
import os
43
import re
54
import sys
65
import types
@@ -10,7 +9,7 @@
109
from django.http import (
1110
HttpRequest, HttpResponse, HttpResponseNotFound, build_request_repr,
1211
)
13-
from django.template import Context, Engine, TemplateDoesNotExist
12+
from django.template import Context, Engine, TemplateDoesNotExist, engines
1413
from django.template.defaultfilters import force_escape, pprint
1514
from django.utils import lru_cache, six, timezone
1615
from django.utils.datastructures import MultiValueDict
@@ -266,61 +265,36 @@ def __init__(self, request, exc_type, exc_value, tb, is_email=False):
266265

267266
self.template_info = getattr(self.exc_value, 'template_debug', None)
268267
self.template_does_not_exist = False
269-
self.loader_debug_info = None
268+
self.postmortem = None
270269

271270
# Handle deprecated string exceptions
272271
if isinstance(self.exc_type, six.string_types):
273272
self.exc_value = Exception('Deprecated String Exception: %r' % self.exc_type)
274273
self.exc_type = type(self.exc_value)
275274

276-
def format_path_status(self, path):
277-
if not os.path.exists(path):
278-
return "File does not exist"
279-
return "File exists"
280-
281275
def get_traceback_data(self):
282276
"""Return a dictionary containing traceback information."""
283-
try:
284-
default_template_engine = Engine.get_default()
285-
except Exception:
286-
# Since the debug view must never crash, catch all exceptions.
287-
# If Django can't find a default template engine, get_default()
288-
# raises ImproperlyConfigured. If some template engines fail to
289-
# load, any exception may be raised.
290-
default_template_engine = None
291-
292-
# TODO: add support for multiple template engines (#24120).
293-
# TemplateDoesNotExist should carry all the information.
294-
# Replaying the search process isn't a good design.
295277
if self.exc_type and issubclass(self.exc_type, TemplateDoesNotExist):
296-
if default_template_engine is None:
297-
template_loaders = []
298-
else:
299-
self.template_does_not_exist = True
300-
self.loader_debug_info = []
301-
# If Django fails in get_template_loaders, provide an empty list
302-
# for the following loop to not fail.
303-
try:
304-
template_loaders = default_template_engine.template_loaders
305-
except Exception:
306-
template_loaders = []
307-
308-
for loader in template_loaders:
309-
try:
310-
source_list_func = loader.get_template_sources
311-
# NOTE: This assumes exc_value is the name of the template that
312-
# the loader attempted to load.
313-
template_list = [{
314-
'name': t,
315-
'status': self.format_path_status(t),
316-
} for t in source_list_func(str(self.exc_value))]
317-
except AttributeError:
318-
template_list = []
319-
loader_name = loader.__module__ + '.' + loader.__class__.__name__
320-
self.loader_debug_info.append({
321-
'loader': loader_name,
322-
'templates': template_list,
323-
})
278+
self.template_does_not_exist = True
279+
postmortem = []
280+
281+
# TODO: add support for multiple template engines (#24120).
282+
# TemplateDoesNotExist should carry all the information, including
283+
# the backend, rather than looping through engines.all.
284+
for engine in engines.all():
285+
if hasattr(engine, 'engine'):
286+
e = engine.engine
287+
else:
288+
e = engine
289+
290+
postmortem.append(dict(
291+
engine=engine,
292+
tried=[
293+
entry for entry in self.exc_value.tried if
294+
entry[0].loader.engine == e
295+
],
296+
))
297+
self.postmortem = postmortem
324298

325299
frames = self.get_traceback_frames()
326300
for i, frame in enumerate(frames):
@@ -363,7 +337,7 @@ def get_traceback_data(self):
363337
'sys_path': sys.path,
364338
'template_info': self.template_info,
365339
'template_does_not_exist': self.template_does_not_exist,
366-
'loader_debug_info': self.loader_debug_info,
340+
'postmortem': self.postmortem,
367341
}
368342
# Check whether exception info is available
369343
if self.exc_type:
@@ -634,7 +608,8 @@ def default_urlconf(request):
634608
#summary h2 { font-weight: normal; color: #666; }
635609
#explanation { background:#eee; }
636610
#template, #template-not-exist { background:#f6f6f6; }
637-
#template-not-exist ul { margin: 0 0 0 20px; }
611+
#template-not-exist ul { margin: 0 0 10px 20px; }
612+
#template-not-exist .postmortem-section { margin-bottom: 3px; }
638613
#unicode-hint { background:#eee; }
639614
#traceback { background:#eee; }
640615
#requestinfo { background:#f6f6f6; padding-left:120px; }
@@ -646,6 +621,7 @@ def default_urlconf(request):
646621
h2 span.commands { font-size:.7em;}
647622
span.commands a:link {color:#5E5694;}
648623
pre.exception_value { font-family: sans-serif; color: #666; font-size: 1.5em; margin: 10px 0 10px 0; }
624+
.append-bottom { margin-bottom: 10px; }
649625
</style>
650626
{% if not is_email %}
651627
<script type="text/javascript">
@@ -772,19 +748,23 @@ def default_urlconf(request):
772748
{% if template_does_not_exist %}
773749
<div id="template-not-exist">
774750
<h2>Template-loader postmortem</h2>
775-
{% if loader_debug_info %}
776-
<p>Django tried loading these templates, in this order:</p>
777-
<ul>
778-
{% for loader in loader_debug_info %}
779-
<li>Using loader <code>{{ loader.loader }}</code>:
780-
<ul>
781-
{% for t in loader.templates %}<li><code>{{ t.name }}</code> ({{ t.status }})</li>{% endfor %}
782-
</ul>
783-
</li>
751+
{% if postmortem %}
752+
<p class="append-bottom">Django tried loading these templates, in this order:</p>
753+
{% for entry in postmortem %}
754+
<p class="postmortem-section">Using engine <code>{{ entry.engine.name }}</code>:</p>
755+
<ul>
756+
{% if entry.tried %}
757+
{% for attempt in entry.tried %}
758+
<li><code>{{ attempt.0.loader_name }}</code>: {{ attempt.0.name }} ({{ attempt.1 }})</li>
759+
{% endfor %}
760+
</ul>
761+
{% else %}
762+
<li>This engine did not provide a list of tried templates.</li>
763+
{% endif %}
764+
</ul>
784765
{% endfor %}
785-
</ul>
786766
{% else %}
787-
<p>Django couldn't find any templates because your <code>'loaders'</code> option is empty!</p>
767+
<p>No templates were found because your 'TEMPLATES' setting is not configured.</p>
788768
{% endif %}
789769
</div>
790770
{% endif %}
@@ -907,12 +887,14 @@ def default_urlconf(request):
907887
Installed Middleware:
908888
{{ settings.MIDDLEWARE_CLASSES|pprint }}
909889
910-
{% if template_does_not_exist %}Template Loader Error:
911-
{% if loader_debug_info %}Django tried loading these templates, in this order:
912-
{% for loader in loader_debug_info %}Using loader {{ loader.loader }}:
913-
{% for t in loader.templates %}{{ t.name }} ({{ t.status }})
914-
{% endfor %}{% endfor %}
915-
{% else %}Django couldn't find any templates because your 'loaders' option is empty!
890+
{% if template_does_not_exist %}Template loader postmortem
891+
{% if postmortem %}Django tried loading these templates, in this order:
892+
{% for entry in postmortem %}
893+
Using engine {{ entry.engine.name }}:
894+
{% if entry.tried %}{% for attempt in entry.tried %} * {{ attempt.0.loader_name }}: {{ attempt.0.name }} ({{ attempt.1 }})
895+
{% endfor %}{% else %} This engine did not provide a list of tried templates.
896+
{% endif %}{% endfor %}
897+
{% else %}No templates were found because your 'TEMPLATES' setting is not configured.
916898
{% endif %}
917899
{% endif %}{% if template_info %}
918900
Template error:
@@ -1098,12 +1080,14 @@ def default_urlconf(request):
10981080
{{ settings.INSTALLED_APPS|pprint }}
10991081
Installed Middleware:
11001082
{{ settings.MIDDLEWARE_CLASSES|pprint }}
1101-
{% if template_does_not_exist %}Template loader Error:
1102-
{% if loader_debug_info %}Django tried loading these templates, in this order:
1103-
{% for loader in loader_debug_info %}Using loader {{ loader.loader }}:
1104-
{% for t in loader.templates %}{{ t.name }} ({{ t.status }})
1105-
{% endfor %}{% endfor %}
1106-
{% else %}Django couldn't find any templates because your 'loaders' option is empty!
1083+
{% if template_does_not_exist %}Template loader postmortem
1084+
{% if postmortem %}Django tried loading these templates, in this order:
1085+
{% for entry in postmortem %}
1086+
Using engine {{ entry.engine.name }}:
1087+
{% if entry.tried %}{% for attempt in entry.tried %} * {{ attempt.0.loader_name }}: {{ attempt.0.name }} ({{ attempt.1 }})
1088+
{% endfor %}{% else %} This engine did not provide a list of tried templates.
1089+
{% endif %}{% endfor %}
1090+
{% else %}No templates were found because your 'TEMPLATES' setting is not configured.
11071091
{% endif %}
11081092
{% endif %}{% if template_info %}
11091093
Template error:

tests/view_tests/tests/test_debug.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def test_template_loader_postmortem(self):
153153
'DIRS': [tempdir],
154154
}]):
155155
response = self.client.get(reverse('raises_template_does_not_exist', kwargs={"path": template_name}))
156-
self.assertContains(response, "%s (File does not exist)" % template_path, status_code=500, count=1)
156+
self.assertContains(response, "%s (Source does not exist)" % template_path, status_code=500, count=2)
157157

158158
def test_no_template_source_loaders(self):
159159
"""

0 commit comments

Comments
 (0)
0