diff options
Diffstat (limited to 'django/views/debug.py')
| -rw-r--r-- | django/views/debug.py | 125 |
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"> |
