summaryrefslogtreecommitdiff
path: root/paste/exceptions
diff options
context:
space:
mode:
authorianb <devnull@localhost>2005-11-04 00:48:57 +0000
committerianb <devnull@localhost>2005-11-04 00:48:57 +0000
commit76c4d49ec1fa88847494dc2f7b01325a9a9dc9ca (patch)
treec9f0e06ced268f20fcc86fc5ed608ea9100d2083 /paste/exceptions
parentb9bebe8c546228dbd18fd34b46207c10d8833c53 (diff)
downloadpaste-76c4d49ec1fa88847494dc2f7b01325a9a9dc9ca.tar.gz
Improve the error output, a little more compact with expandable source
Diffstat (limited to 'paste/exceptions')
-rw-r--r--paste/exceptions/collector.py10
-rw-r--r--paste/exceptions/errormiddleware.py14
-rw-r--r--paste/exceptions/formatter.py119
3 files changed, 119 insertions, 24 deletions
diff --git a/paste/exceptions/collector.py b/paste/exceptions/collector.py
index 8a92a9c..d136a9d 100644
--- a/paste/exceptions/collector.py
+++ b/paste/exceptions/collector.py
@@ -447,15 +447,21 @@ class ExceptionFrame(Bunch):
# The value of __traceback_hide__
traceback_hide = False
- def get_source_line(self):
+ def get_source_line(self, context=0):
"""
Return the source of the current line of this frame. You
probably want to .strip() it as well, as it is likely to have
leading whitespace.
+
+ If context is given, then that many lines on either side will
+ also be returned. E.g., context=1 will give 3 lines.
"""
if not self.filename or not self.lineno:
return None
- return linecache.getline(self.filename, self.lineno)
+ lines = []
+ for lineno in range(self.lineno-context, self.lineno+context+1):
+ lines.append(linecache.getline(self.filename, lineno))
+ return ''.join(lines)
if hasattr(sys, 'tracebacklimit'):
limit = min(limit, sys.tracebacklimit)
diff --git a/paste/exceptions/errormiddleware.py b/paste/exceptions/errormiddleware.py
index 86d5d81..781efe5 100644
--- a/paste/exceptions/errormiddleware.py
+++ b/paste/exceptions/errormiddleware.py
@@ -276,10 +276,13 @@ def handle_exception(exc_info, error_stream, html=True,
exc_data.exception_type, exc_data.exception_value))
if html:
if debug_mode:
- error_html = formatter.format_html(exc_data,
- include_hidden_frames=True)
+ error_html = formatter.format_html(
+ exc_data,
+ include_hidden_frames=True,
+ include_reusable=False)
+ head_html = formatter.error_css + formatter.hide_display_js
return_error = error_template(
- error_html, extra_data)
+ head_html, error_html, extra_data)
extra_data = ''
reported = True
else:
@@ -318,15 +321,16 @@ def send_report(rep, exc_data, html=True):
else:
return ''
-def error_template(exception, extra):
+def error_template(head_html, exception, extra):
return '''
<html>
<head>
<title>Server Error</title>
+ %s
</head>
<body>
<h1>Server Error</h1>
%s
%s
</body>
- </html>''' % (exception, extra)
+ </html>''' % (head_html, exception, extra)
diff --git a/paste/exceptions/formatter.py b/paste/exceptions/formatter.py
index f34aba6..ee936df 100644
--- a/paste/exceptions/formatter.py
+++ b/paste/exceptions/formatter.py
@@ -8,6 +8,9 @@ Formatters for the exception data that comes from ExceptionCollector.
# Use this: http://www.zope.org/Members/tino/VisualTraceback/VisualTracebackNews
import cgi
+import re
+
+whitespace_re = re.compile(r' +')
def html_quote(s):
return cgi.escape(s, True)
@@ -66,11 +69,14 @@ class AbstractFormatter:
break
lines.append(self.format_source_line(
filename or '?',
+ frame.modname or '?',
frame.lineno or '?',
frame.name or '?'))
source = frame.get_source_line()
+ long_source = frame.get_source_line(2)
if source:
- lines.append(self.format_source(source))
+ lines.append(self.format_long_source(
+ source, long_source))
exc_info = self.format_exception_info(
exc_data.exception_type,
exc_data.exception_value)
@@ -176,8 +182,10 @@ class TextFormatter(AbstractFormatter):
return 'Warning: %s' % self.quote(warning)
def format_sup_info(self, info):
return [self.quote_long(info)]
- def format_source_line(self, filename, lineno, name):
+ def format_source_line(self, filename, modname, lineno, name):
return 'File %r, line %s in %s' % (filename, lineno, name)
+ def format_long_source(self, source, long_source):
+ return self.format_source(source)
def format_source(self, source_line):
return ' ' + self.quote(source_line.strip())
def format_exception_info(self, etype, evalue):
@@ -233,10 +241,29 @@ class HTMLFormatter(TextFormatter):
return 'URL: <a href="%s">%s</a>' % (url, url)
def format_combine_lines(self, lines):
return '<br>\n'.join(lines)
- def format_source_line(self, filename, lineno, name):
+ def format_source_line(self, filename, modname, lineno, name):
+ return 'Module <span class="module" title="%s">%s</span>:<b>%s</b> in <code>%s</code>' % (
+ filename, modname, lineno, name)
return 'File %r, line %s in <tt>%s</tt>' % (filename, lineno, name)
+ def format_long_source(self, source, long_source):
+ q_long_source = self.quote(long_source).rstrip()
+ #q_long_source = re.sub('^[\n\r]*', '', q_long_source)
+ lines = q_long_source.splitlines()
+ for i in range(1, len(lines)):
+ lines[i] = ' '+lines[i]
+ if lines[i].strip() == source.strip():
+ lines[i] = '<span class="source-highlight">%s</span>' % lines[i]
+ q_long_source = '<br>\n'.join(lines)
+ q_long_source = whitespace_re.sub(
+ lambda m: '&nbsp;'*(len(m.group(0))-1)+' ',
+ q_long_source)
+
+ return ('<code style="display: none" class="source" source-type="long"><a class="switch_source" onclick="return switch_source(this, \'long\')" href="#">&lt;&lt;&nbsp; </a>%s</code>'
+ '<code class="source" source-type="short"><a onclick="return switch_source(this, \'short\')" class="switch_source" href="#">&gt;&gt;&nbsp; </a>%s</code>'
+ % (q_long_source,
+ self.quote(source.strip())))
def format_source(self, source_line):
- return '&nbsp;&nbsp;<tt>%s</tt>' % self.quote(source_line.strip())
+ return '&nbsp;&nbsp;<code class="source">%s</code>' % self.quote(source_line.strip())
def format_traceback_info(self, info):
return '<pre>%s</pre>' % self.quote(info)
@@ -321,28 +348,68 @@ class HTMLFormatter(TextFormatter):
hide_display_js = r'''
<script type="text/javascript">
function hide_display(id) {
- var el = document.getElementById(id);
- if (el.className == "hidden-data") {
- el.className = "";
- return true;
- } else {
- el.className = "hidden-data";
- return false;
- }
+ var el = document.getElementById(id);
+ if (el.className == "hidden-data") {
+ el.className = "";
+ return true;
+ } else {
+ el.className = "hidden-data";
+ return false;
+ }
}
document.write('<style type="text/css">\n');
document.write('.hidden-data {display: none}\n');
document.write('</style>\n');
function show_button(toggle_id, name) {
- document.write('<a href="#' + toggle_id
- + '" onclick="javascript:hide_display(\'' + toggle_id
- + '\')" class="button">' + name + '</a><br>');
+ document.write('<a href="#' + toggle_id
+ + '" onclick="javascript:hide_display(\'' + toggle_id
+ + '\')" class="button">' + name + '</a><br>');
+}
+
+function switch_source(el, hide_type) {
+ while (el) {
+ if (el.getAttribute &&
+ el.getAttribute('source-type') == hide_type) {
+ break;
+ }
+ el = el.parentNode;
+ }
+ if (! el) {
+ return false;
+ }
+ el.style.display = 'none';
+ if (hide_type == 'long') {
+ while (el) {
+ if (el.getAttribute &&
+ el.getAttribute('source-type') == 'short') {
+ break;
+ }
+ el = el.nextSibling;
+ }
+ } else {
+ while (el) {
+ if (el.getAttribute &&
+ el.getAttribute('source-type') == 'long') {
+ break;
+ }
+ el = el.previousSibling;
+ }
+ }
+ if (el) {
+ el.style.display = '';
+ }
+ return false;
}
+
</script>'''
error_css = """
<style type="text/css">
+body {
+ font-family: Helvetica, sans-serif;
+}
+
table {
width: 100%;
}
@@ -371,6 +438,24 @@ a.button {
a.button:hover {
background-color: #ddd;
}
+
+code.source {
+ color: #006;
+}
+
+a.switch_source {
+ color: #0990;
+ text-decoration: none;
+}
+
+a.switch_source:hover {
+ background-color: #ddd;
+}
+
+.source-highlight {
+ background-color: #ff9;
+}
+
</style>
"""
@@ -380,8 +465,8 @@ def format_html(exc_data, include_hidden_frames=False, **ops):
short_er = format_html(exc_data, show_hidden_frames=False, **ops)
# @@: This should have a way of seeing if the previous traceback
# was actually trimmed at all
- long_er = format_html(exc_data, show_hidden_frames=True,
- include_reusable=False, **ops)
+ ops['include_reusable'] = False
+ long_er = format_html(exc_data, show_hidden_frames=True, **ops)
return """
%s
<br>