diff -r 57b4279d8c4e -r 03e267d67478 app/django/views/debug.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/django/views/debug.py Fri Jul 18 18:22:23 2008 +0000 @@ -0,0 +1,770 @@ +import os +import re +import sys +import datetime + +from django.conf import settings +from django.template import Template, Context, TemplateDoesNotExist +from django.utils.html import escape +from django.http import HttpResponse, HttpResponseServerError, HttpResponseNotFound +from django.utils.encoding import smart_unicode + +HIDDEN_SETTINGS = re.compile('SECRET|PASSWORD|PROFANITIES_LIST') + +def linebreak_iter(template_source): + yield 0 + p = template_source.find('\n') + while p >= 0: + yield p+1 + p = template_source.find('\n', p+1) + 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 = [] + before = during = after = "" + for num, next in enumerate(linebreak_iter(template_source)): + 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]) + source_lines.append( (num, escape(template_source[upto:next])) ) + upto = next + total = len(source_lines) + + top = max(1, 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 get_safe_settings(): + "Returns a dictionary of the settings module, with sensitive settings blurred out." + settings_dict = {} + for k in dir(settings): + if k.isupper(): + if HIDDEN_SETTINGS.search(k): + settings_dict[k] = '********************' + else: + settings_dict[k] = getattr(settings, k) + return settings_dict + +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. + """ + html = get_traceback_html(request, exc_type, exc_value, tb) + return HttpResponseServerError(html, mimetype='text/html') + +def get_traceback_html(request, exc_type, exc_value, tb): + "Return HTML code for traceback." + template_info = None + template_does_not_exist = False + loader_debug_info = None + + # Handle deprecated string exceptions + if isinstance(exc_type, basestring): + exc_value = Exception('Deprecated String Exception: %r' % exc_type) + exc_type = type(exc_value) + + if issubclass(exc_type, TemplateDoesNotExist): + from django.template.loader import template_source_loaders + template_does_not_exist = True + loader_debug_info = [] + for loader in template_source_loaders: + try: + source_list_func = getattr(__import__(loader.__module__, {}, {}, ['get_template_sources']), 'get_template_sources') + # NOTE: This assumes exc_value is the name of the template that + # the loader attempted to load. + template_list = [{'name': t, 'exists': os.path.exists(t)} \ + for t in source_list_func(str(exc_value))] + except (ImportError, AttributeError): + template_list = [] + loader_debug_info.append({ + 'loader': loader.__module__ + '.' + loader.__name__, + 'templates': template_list, + }) + 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: + # support for __traceback_hide__ which is used by a few libraries + # to hide internal frames. + if tb.tb_frame.f_locals.get('__traceback_hide__'): + tb = tb.tb_next + continue + filename = tb.tb_frame.f_code.co_filename + function = tb.tb_frame.f_code.co_name + lineno = tb.tb_lineno - 1 + loader = tb.tb_frame.f_globals.get('__loader__') + module_name = tb.tb_frame.f_globals.get('__name__') + pre_context_lineno, pre_context, context_line, post_context = _get_lines_from_file(filename, lineno, 7, loader, module_name) + if pre_context_lineno is not None: + frames.append({ + 'tb': tb, + 'filename': filename, + 'function': function, + 'lineno': lineno + 1, + '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 + 1, + }) + tb = tb.tb_next + + if not frames: + frames = [{ + 'filename': '<unknown>', + 'function': '?', + 'lineno': '?', + }] + + unicode_hint = '' + if issubclass(exc_type, UnicodeError): + start = getattr(exc_value, 'start', None) + end = getattr(exc_value, 'end', None) + if start is not None and end is not None: + unicode_str = exc_value.args[1] + unicode_hint = smart_unicode(unicode_str[max(start-5, 0):min(end+5, len(unicode_str))], 'ascii', errors='replace') + from django import get_version + t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template') + c = Context({ + 'exception_type': exc_type.__name__, + 'exception_value': smart_unicode(exc_value, errors='replace'), + 'unicode_hint': unicode_hint, + 'frames': frames, + 'lastframe': frames[-1], + 'request': request, + 'request_protocol': request.is_secure() and "https" or "http", + 'settings': get_safe_settings(), + 'sys_executable': sys.executable, + 'sys_version_info': '%d.%d.%d' % sys.version_info[0:3], + 'server_time': datetime.datetime.now(), + 'django_version_info': get_version(), + 'sys_path' : sys.path, + 'template_info': template_info, + 'template_does_not_exist': template_does_not_exist, + 'loader_debug_info': loader_debug_info, + }) + return t.render(c) + +def technical_404_response(request, exception): + "Create a technical 404 error response. The exception should be the Http404." + try: + tried = exception.args[0]['tried'] + except (IndexError, TypeError): + tried = [] + else: + if not tried: + # tried exists but is an empty list. The URLconf must've been empty. + return empty_urlconf(request) + + t = Template(TECHNICAL_404_TEMPLATE, name='Technical 404 template') + c = Context({ + 'root_urlconf': settings.ROOT_URLCONF, + 'request_path': request.path[1:], # Trim leading slash + 'urlpatterns': tried, + 'reason': str(exception), + 'request': request, + 'request_protocol': request.is_secure() and "https" or "http", + 'settings': get_safe_settings(), + }) + return HttpResponseNotFound(t.render(c), mimetype='text/html') + +def empty_urlconf(request): + "Create an empty URLconf 404 error response." + t = Template(EMPTY_URLCONF_TEMPLATE, name='Empty URLConf template') + c = Context({ + 'project_name': settings.SETTINGS_MODULE.split('.')[0] + }) + return HttpResponse(t.render(c), mimetype='text/html') + +def _get_lines_from_file(filename, lineno, context_lines, loader=None, module_name=None): + """ + Returns context_lines before and after lineno from file. + Returns (pre_context_lineno, pre_context, context_line, post_context). + """ + source = None + if loader is not None and hasattr(loader, "get_source"): + source = loader.get_source(module_name) + if source is not None: + source = source.splitlines() + if source is None: + try: + f = open(filename) + try: + source = f.readlines() + finally: + f.close() + except (OSError, IOError): + pass + if source is None: + return None, [], None, [] + + encoding = 'ascii' + for line in source[:2]: + # File coding may be specified. Match pattern from PEP-263 + # (http://www.python.org/dev/peps/pep-0263/) + match = re.search(r'coding[:=]\s*([-\w.]+)', line) + if match: + encoding = match.group(1) + break + source = [unicode(sline, encoding, 'replace') for sline in source] + + lower_bound = max(0, lineno - context_lines) + upper_bound = lineno + context_lines + + pre_context = [line.strip('\n') for line in source[lower_bound:lineno]] + context_line = source[lineno].strip('\n') + post_context = [line.strip('\n') for line in source[lineno+1:upper_bound]] + + return lower_bound, pre_context, context_line, post_context + +# +# Templates are embedded in the file so that we know the error handler will +# always work even if the template loader is broken. +# + +TECHNICAL_500_TEMPLATE = """ + + + + + + {{ exception_type }} at {{ request.path|escape }} + + + + +
+

{{ exception_type }} at {{ request.path|escape }}

+

{{ exception_value|escape }}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Request Method:{{ request.META.REQUEST_METHOD }}
Request URL:{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path|escape }}
Exception Type:{{ exception_type }}
Exception Value:{{ exception_value|escape }}
Exception Location:{{ lastframe.filename|escape }} in {{ lastframe.function|escape }}, line {{ lastframe.lineno }}
Python Executable:{{ sys_executable|escape }}
Python Version:{{ sys_version_info }}
Python Path:{{ sys_path }}
Server time:{{server_time|date:"r"}}
+
+{% if unicode_hint %} +
+

Unicode error hint

+

The string that could not be encoded/decoded was: {{ unicode_hint|escape }}

+
+{% endif %} +{% if template_does_not_exist %} +
+

Template-loader postmortem

+ {% if loader_debug_info %} +

Django tried loading these templates, in this order:

+ + {% else %} +

Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty!

+ {% endif %} +
+{% endif %} +{% if template_info %} +
+

Template error

+

In template {{ template_info.name }}, error at line {{ template_info.line }}

+

{{ template_info.message }}

+ + {% for source_line in template_info.source_lines %} + {% ifequal source_line.0 template_info.line %} + + + {% else %} + + + {% endifequal %} + {% endfor %} +
{{ source_line.0 }}{{ template_info.before }}{{ template_info.during }}{{ template_info.after }}
{{ source_line.0 }}{{ source_line.1 }}
+
+{% endif %} +
+

Traceback Switch to copy-and-paste view

+ {% autoescape off %} +
+ +
+ {% endautoescape %} +
+
+ + + + + +

+ +
+
+
+ +
+

Request information

+ +

GET

+ {% if request.GET %} + + + + + + + + + {% for var in request.GET.items %} + + + + + {% endfor %} + +
VariableValue
{{ var.0 }}
{{ var.1|pprint }}
+ {% else %} +

No GET data

+ {% endif %} + +

POST

+ {% if request.POST %} + + + + + + + + + {% for var in request.POST.items %} + + + + + {% endfor %} + +
VariableValue
{{ var.0 }}
{{ var.1|pprint }}
+ {% else %} +

No POST data

+ {% endif %} + + + {% if request.COOKIES %} + + + + + + + + + {% for var in request.COOKIES.items %} + + + + + {% endfor %} + +
VariableValue
{{ var.0 }}
{{ var.1|pprint }}
+ {% else %} +

No cookie data

+ {% endif %} + +

META

+ + + + + + + + + {% for var in request.META.items|dictsort:"0" %} + + + + + {% endfor %} + +
VariableValue
{{ var.0 }}
{{ var.1|pprint }}
+ +

Settings

+

Using settings module {{ settings.SETTINGS_MODULE }}

+ + + + + + + + + {% for var in settings.items|dictsort:"0" %} + + + + + {% endfor %} + +
SettingValue
{{ var.0 }}
{{ var.1|pprint }}
+ +
+ +
+

+ You're seeing this error because you have DEBUG = True in your + Django settings file. Change that to False, and Django will + display a standard 500 page. +

+
+ + +""" + +TECHNICAL_404_TEMPLATE = """ + + + + + Page not found at {{ request.path|escape }} + + + + +
+

Page not found (404)

+ + + + + + + + + +
Request Method:{{ request.META.REQUEST_METHOD }}
Request URL:{{ request_protocol }}://{{ request.META.HTTP_HOST }}{{ request.path|escape }}
+
+
+ {% if urlpatterns %} +

+ Using the URLconf defined in {{ settings.ROOT_URLCONF }}, + Django tried these URL patterns, in this order: +

+
    + {% for pattern in urlpatterns %} +
  1. {{ pattern }}
  2. + {% endfor %} +
+

The current URL, {{ request_path|escape }}, didn't match any of these.

+ {% else %} +

{{ reason }}

+ {% endif %} +
+ +
+

+ You're seeing this error because you have DEBUG = True in + your Django settings file. Change that to False, and Django + will display a standard 404 page. +

+
+ + +""" + +EMPTY_URLCONF_TEMPLATE = """ + + + + Welcome to Django + + + + +
+

It worked!

+

Congratulations on your first Django-powered page.

+
+ +
+

Of course, you haven't actually done any work yet. Here's what to do next:

+ +
+ +
+

+ You're seeing this message because you have DEBUG = True in your + Django settings file and you haven't configured any URLs. Get to work! +

+
+ +"""