summaryrefslogtreecommitdiff
path: root/django/views/debug.py
diff options
context:
space:
mode:
authorAdrian Holovaty <adrian@holovaty.com>2005-11-23 23:10:17 +0000
committerAdrian Holovaty <adrian@holovaty.com>2005-11-23 23:10:17 +0000
commit5d863f1fbd26537a8bca2920bc591279d15fbdf1 (patch)
tree44c640a364e95274e67a9555752b4561def7571a /django/views/debug.py
parentcfc5786d03f3dc190f3ed1606edc3a196f16915e (diff)
Fixed #603 -- Added template debugging errors to pretty error-page output, if TEMPLATE_DEBUG setting is True. Also refactored FilterParser for a significant speed increase and changed the template_loader interface so that it returns information about the loader. Taken from new-admin. Thanks rjwittams and crew
git-svn-id: http://code.djangoproject.com/svn/django/trunk@1379 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/views/debug.py')
-rw-r--r--django/views/debug.py125
1 files changed, 95 insertions, 30 deletions
diff --git a/django/views/debug.py b/django/views/debug.py
index 189b244af2..012d7f9a75 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -1,19 +1,64 @@
-import re
-import os
-import sys
-import inspect
from django.conf import settings
-from os.path import dirname, join as pathjoin
from django.core.template import Template, Context
+from django.utils.html import escape
from django.utils.httpwrappers import HttpResponseServerError, HttpResponseNotFound
+import inspect, os, re, sys
+from itertools import count, izip
+from os.path import dirname, join as pathjoin
HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD')
+def linebreak_iter(template_source):
+ newline_re = re.compile("^", re.M)
+ for match in newline_re.finditer(template_source):
+ yield match.start()
+ yield len(template_source) + 1
+
+def get_template_exception_info(exc_type, exc_value, tb):
+ origin, (start, end) = exc_value.source
+ template_source = origin.reload()
+ context_lines = 10
+ line = 0
+ upto = 0
+ source_lines = []
+ linebreaks = izip(count(0), linebreak_iter(template_source))
+ linebreaks.next() # skip the nothing before initial line start
+ for num, next in linebreaks:
+ if start >= upto and end <= next:
+ line = num
+ before = escape(template_source[upto:start])
+ during = escape(template_source[start:end])
+ after = escape(template_source[end:next - 1])
+ source_lines.append( (num, escape(template_source[upto:next - 1])) )
+ upto = next
+ total = len(source_lines)
+
+ top = max(0, line - context_lines)
+ bottom = min(total, line + 1 + context_lines)
+
+ template_info = {
+ 'message': exc_value.args[0],
+ 'source_lines': source_lines[top:bottom],
+ 'before': before,
+ 'during': during,
+ 'after': after,
+ 'top': top ,
+ 'bottom': bottom ,
+ 'total': total,
+ 'line': line,
+ 'name': origin.name,
+ }
+ exc_info = hasattr(exc_value, 'exc_info') and exc_value.exc_info or (exc_type, exc_value, tb)
+ return exc_info + (template_info,)
+
def technical_500_response(request, exc_type, exc_value, tb):
"""
Create a technical server error response. The last three arguments are
the values returned from sys.exc_info() and friends.
"""
+ template_info = None
+ if settings.TEMPLATE_DEBUG and hasattr(exc_value, 'source'):
+ exc_type, exc_value, tb, template_info = get_template_exception_info(exc_type, exc_value, tb)
frames = []
while tb is not None:
filename = tb.tb_frame.f_code.co_filename
@@ -21,16 +66,16 @@ def technical_500_response(request, exc_type, exc_value, tb):
lineno = tb.tb_lineno - 1
pre_context_lineno, pre_context, context_line, post_context = _get_lines_from_file(filename, lineno, 7)
frames.append({
- 'tb' : tb,
- 'filename' : filename,
- 'function' : function,
- 'lineno' : lineno,
- 'vars' : tb.tb_frame.f_locals.items(),
- 'id' : id(tb),
- 'pre_context' : pre_context,
- 'context_line' : context_line,
- 'post_context' : post_context,
- 'pre_context_lineno' : pre_context_lineno,
+ 'tb': tb,
+ 'filename': filename,
+ 'function': function,
+ 'lineno': lineno,
+ 'vars': tb.tb_frame.f_locals.items(),
+ 'id': id(tb),
+ 'pre_context': pre_context,
+ 'context_line': context_line,
+ 'post_context': post_context,
+ 'pre_context_lineno': pre_context_lineno,
})
tb = tb.tb_next
@@ -46,14 +91,14 @@ def technical_500_response(request, exc_type, exc_value, tb):
t = Template(TECHNICAL_500_TEMPLATE)
c = Context({
- 'exception_type' : exc_type.__name__,
- 'exception_value' : exc_value,
- 'frames' : frames,
- 'lastframe' : frames[-1],
- 'request' : request,
- 'request_protocol' : os.environ.get("HTTPS") == "on" and "https" or "http",
- 'settings' : settings_dict,
-
+ 'exception_type': exc_type.__name__,
+ 'exception_value': exc_value,
+ 'frames': frames,
+ 'lastframe': frames[-1],
+ 'request': request,
+ 'request_protocol': os.environ.get("HTTPS") == "on" and "https" or "http",
+ 'settings': settings_dict,
+ 'template_info': template_info,
})
return HttpResponseServerError(t.render(c), mimetype='text/html')
@@ -69,12 +114,12 @@ def technical_404_response(request, exception):
t = Template(TECHNICAL_404_TEMPLATE)
c = Context({
- 'root_urlconf' : settings.ROOT_URLCONF,
- 'urlpatterns' : tried,
- 'reason' : str(exception),
- 'request' : request,
- 'request_protocol' : os.environ.get("HTTPS") == "on" and "https" or "http",
- 'settings' : dict([(k, getattr(settings, k)) for k in dir(settings) if k.isupper()]),
+ 'root_urlconf': settings.ROOT_URLCONF,
+ 'urlpatterns': tried,
+ 'reason': str(exception),
+ 'request': request,
+ 'request_protocol': os.environ.get("HTTPS") == "on" and "https" or "http",
+ 'settings': dict([(k, getattr(settings, k)) for k in dir(settings) if k.isupper()]),
})
return HttpResponseNotFound(t.render(c), mimetype='text/html')
@@ -144,6 +189,9 @@ TECHNICAL_500_TEMPLATE = """
#summary table { border:none; background:transparent; }
#requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
#requestinfo h3 { margin-bottom:-1em; }
+ table.source td { font-family: monospace; white-space: pre; }
+ span.specific { background:#ffcab7; }
+ .error { background: #ffc; }
</style>
<script type="text/javascript">
//<!--
@@ -221,7 +269,24 @@ TECHNICAL_500_TEMPLATE = """
</tr>
</table>
</div>
-
+{% if template_info %}
+<div id="template">
+ <h2>Template</h2>
+ In template {{ template_info.name }}, error at line {{ template_info.line }}
+ <div>{{ template_info.message|escape }}</div>
+ <table class="source{% if template_info.top %} cut-top{% endif %}{% ifnotequal template_info.bottom template_info.total %} cut-bottom{% endifnotequal %}">
+ {% for source_line in template_info.source_lines %}
+ {% ifequal source_line.0 template_info.line %}
+ <tr class="error"><td>{{ source_line.0 }}</td>
+ <td>{{ template_info.before }}<span class="specific">{{ template_info.during }}</span>{{ template_info.after }}</td></tr>
+ {% else %}
+ <tr><td>{{ source_line.0 }}</td>
+ <td> {{ source_line.1 }}</td></tr>
+ {% endifequal %}
+ {% endfor %}
+ </table>
+</div>
+{% endif %}
<div id="traceback">
<h2>Traceback <span>(innermost last)</span></h2>
<ul class="traceback">