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 %}