diff --git a/AUTHORS b/AUTHORS index 7fa7981aab..9f36d49d10 100644 --- a/AUTHORS +++ b/AUTHORS @@ -180,6 +180,7 @@ answer newbie questions, and generally made Django that much better: Brian Ray remco@diji.biz rhettg@gmail.com + Armin Ronacher Oliver Rutherfurd Ivan Sagalaev (Maniac) David Schein diff --git a/django/views/debug.py b/django/views/debug.py index b49a98a864..2530350e26 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -90,11 +90,18 @@ def technical_500_response(request, exc_type, exc_value, tb): 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 - pre_context_lineno, pre_context, context_line, post_context = _get_lines_from_file(filename, lineno, 7) - if pre_context_lineno: + 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, @@ -161,24 +168,35 @@ def empty_urlconf(request): }) return HttpResponseNotFound(t.render(c), mimetype='text/html') -def _get_lines_from_file(filename, lineno, context_lines): +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). """ - try: - source = open(filename).readlines() - 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 - except (OSError, IOError): + source = None + if loader is not None: + source = loader.get_source(module_name).splitlines() + else: + try: + f = open(filename) + try: + source = f.readlines() + finally: + f.close() + except (OSError, IOError): + pass + if source is None: return None, [], None, [] + 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. @@ -314,7 +332,7 @@ TECHNICAL_500_TEMPLATE = """ Exception Location: - {{ lastframe.filename }} in {{ lastframe.function }}, line {{ lastframe.lineno }} + {{ lastframe.filename|escape }} in {{ lastframe.function|escape }}, line {{ lastframe.lineno }} @@ -361,7 +379,7 @@ TECHNICAL_500_TEMPLATE = """
    {% for frame in frames %}
  • - {{ frame.filename }} in {{ frame.function }} + {{ frame.filename|escape }} in {{ frame.function|escape }} {% if frame.context_line %}