-
-
Save fabware/305572 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Usage: | |
import debug | |
class BaseHandler(tornado.web.RequestHandler): | |
def get_error_html(self, status_code, **kwargs): | |
if self.application.settings['debug']: | |
return debug.display(self, kwargs['exception']) | |
""" | |
import datetime | |
import pprint | |
import re | |
import sys | |
import traceback | |
import tornado.template | |
from tornado.web import _O, RequestHandler | |
# Taken from django/views/debug.py | |
class ExceptionReporter: | |
def __init__(self, handler, exc_type, exc_value, tb): | |
self.exc_type = exc_type | |
self.exc_value = exc_value | |
self.tb = tb | |
self.handler = handler | |
self.template_path = handler.application.settings.get("template_path") | |
def get_traceback_frames(self): | |
frames = [] | |
tb = self.tb | |
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 = self._get_lines_from_file(filename, lineno, 7, loader, module_name) | |
if pre_context_lineno is not None: | |
vars = tb.tb_frame.f_locals.items() | |
for v in vars: | |
if v[0] == 'formatted_code': | |
vars = [v] | |
break | |
frames.append(_O({ | |
'tb': tb, | |
'filename': filename, | |
'function': function, | |
'lineno': lineno + 1, | |
'vars': vars, | |
'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 = [_O({ | |
'filename': '<unknown>', | |
'function': '?', | |
'lineno': '?', | |
'context_line': '???', | |
})] | |
return frames | |
def _get_lines_from_file(self, 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: | |
if filename.endswith('.html'): | |
t = RequestHandler._templates[self.template_path].load(filename) | |
source = t.code.rstrip().splitlines() | |
else: | |
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 | |
def display(handler, e): | |
attrs = ("protocol", "host", "method", "uri", "version", "remote_ip", | |
"remote_ip", "body") | |
req = dict([(n, getattr(handler.request, n)) for n in attrs]) | |
args = dict([(k, handler.get_argument(k)) \ | |
for k,_v in handler.request.arguments.iteritems() \ | |
if not k.startswith('_')]) | |
headers = dict(handler.request.headers) | |
files = dict([(filename, (f[0]['filename'], f[0]['content_type'])) \ | |
for filename, f in handler.request.files]) | |
frames = ExceptionReporter(handler, *sys.exc_info()).get_traceback_frames() | |
t = tornado.template.Template(TECHNICAL_500_TEMPLATE) | |
return t.generate(handler=handler, | |
e=e, | |
frames=frames, | |
sys_executable=sys.executable, | |
sys_version_info='%d.%d.%d' % sys.version_info[0:3], | |
server_time=datetime.datetime.now(), | |
sys_path=sys.path, | |
req=req, | |
args=args, | |
files=files, | |
headers=headers, | |
pprint=pprint) | |
TECHNICAL_500_TEMPLATE = """ | |
<head> | |
<title>{{ e }}</title> | |
<style type="text/css"> | |
html * { padding:0; margin:0; } | |
body * { padding:10px 20px; } | |
body * * { padding:0; } | |
body { font:small sans-serif; } | |
body>div { border-bottom:1px solid #ddd; } | |
h1 { font-weight:normal; } | |
h1, h2 { margin-bottom:.8em; } | |
h2 span, h1 span { font-size:80%; color:#666; font-weight:normal; } | |
h3 { margin:1em 0 .5em 0; } | |
h4 { margin:0 0 .5em 0; font-weight: normal; } | |
table { border:1px solid #ccc; border-collapse: collapse; width:100%; background:white; } | |
tbody td, tbody th { vertical-align:top; padding:2px 3px; } | |
thead th { padding:1px 6px 1px 3px; background:#fefefe; text-align:left; font-weight:normal; font-size:11px; border:1px solid #ddd; } | |
tbody th { width:12em; text-align:right; color:#666; padding-right:.5em; } | |
table.vars { margin:5px 0 2px 40px; } | |
table.vars td, table.req td { font-family:monospace; } | |
table td.code { width:100%; white-space: pre;} | |
table td.code div { overflow:hidden; } | |
table.source th { color:#666; } | |
table.source td { font-family:monospace; white-space:pre; border-bottom:1px solid #eee; } | |
ul.traceback { list-style-type:none; } | |
ul.traceback li.frame { margin-bottom:1em; } | |
div.context { margin: 10px 0; } | |
div.context ol { padding-left:30px; margin:0 10px; list-style-position: inside; } | |
div.context ol li { font-family:monospace; white-space:pre; color:#666; cursor:pointer; } | |
div.context ol.context-line li { color:black; background-color:#ccc; } | |
div.context ol.context-line li span { float: right; } | |
div.commands { margin-left: 40px; } | |
div.commands a { color:black; text-decoration:none; } | |
#summary { background: #ffc; } | |
#summary h2 { font-weight: normal; color: #666; } | |
#explanation { background:#eee; } | |
#template, #template-not-exist { background:#f6f6f6; } | |
#template-not-exist ul { margin: 0 0 0 20px; } | |
#unicode-hint { background:#eee; } | |
#traceback { background:#eee; } | |
#requestinfo { background:#f6f6f6;} | |
#summary table { border:none; background:transparent; } | |
.error { background: #ffc; } | |
.specific { color:#cc3300; font-weight:bold; } | |
h2 span.commands { font-size:.7em;} | |
span.commands a:link {color:#5E5694;} | |
pre.exception_value { font-family: sans-serif; color: #666; font-size: 1.5em; margin: 10px 0 10px 0; } | |
</style> | |
<script type="text/javascript"> | |
//<!-- | |
function getElementsByClassName(oElm, strTagName, strClassName){ | |
// Written by Jonathan Snook, http://www.snook.ca/jon; Add-ons by Robert Nyman, http://www.robertnyman.com | |
var arrElements = (strTagName == "*" && document.all)? document.all : | |
oElm.getElementsByTagName(strTagName); | |
var arrReturnElements = new Array(); | |
strClassName = strClassName.replace(/\-/g, "\\-"); | |
var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)"); | |
var oElement; | |
for(var i=0; i<arrElements.length; i++){ | |
oElement = arrElements[i]; | |
if(oRegExp.test(oElement.className)){ | |
arrReturnElements.push(oElement); | |
} | |
} | |
return (arrReturnElements) | |
} | |
function hideAll(elems) { | |
for (var e = 0; e < elems.length; e++) { | |
elems[e].style.display = 'none'; | |
} | |
} | |
window.onload = function() { | |
hideAll(getElementsByClassName(document, 'table', 'vars')); | |
hideAll(getElementsByClassName(document, 'ol', 'pre-context')); | |
hideAll(getElementsByClassName(document, 'ol', 'post-context')); | |
hideAll(getElementsByClassName(document, 'div', 'pastebin')); | |
} | |
function toggle() { | |
for (var i = 0; i < arguments.length; i++) { | |
var e = document.getElementById(arguments[i]); | |
if (e) { | |
e.style.display = e.style.display == 'none' ? 'block' : 'none'; | |
} | |
} | |
return false; | |
} | |
function varToggle(link, id) { | |
toggle('v' + id); | |
var s = link.getElementsByTagName('span')[0]; | |
var uarr = String.fromCharCode(0x25b6); | |
var darr = String.fromCharCode(0x25bc); | |
s.innerHTML = s.innerHTML == uarr ? darr : uarr; | |
return false; | |
} | |
function switchPastebinFriendly(link) { | |
s1 = "Switch to copy-and-paste view"; | |
s2 = "Switch back to interactive view"; | |
link.innerHTML = link.innerHTML == s1 ? s2 : s1; | |
toggle('browserTraceback', 'pastebinTraceback'); | |
return false; | |
} | |
//--> | |
</script> | |
</head> | |
<body> | |
<div id="summary"> | |
<h1>{{ e }} <span>at {{ frames[-1:][0].filename }}</span></h1> | |
<table class="meta"> | |
<tr> | |
<th>Python Executable:</th> | |
<td>{{ escape(sys_executable) }}</td> | |
</tr> | |
<tr> | |
<th>Python Version:</th> | |
<td>{{ sys_version_info }}</td> | |
</tr> | |
<!-- <tr> | |
<th>Python Path:</th> | |
<td>{{ sys_path }}</td> | |
</tr>--> | |
<tr> | |
<th>Server time:</th> | |
<td>{{server_time}}</td> | |
</tr> | |
</table> | |
</div> | |
<div id="traceback"> | |
<h2>Traceback <span class="commands"><a href="#" onclick="return switchPastebinFriendly(this);">Switch to copy-and-paste view</a></span></h2> | |
<div id="browserTraceback"> | |
<ul class="traceback"> | |
{% for frame in frames %} | |
<li class="frame"> | |
<code>{{ frame.filename }}</code> in <code>{{ frame.function}}</code> | |
{% if frame.context_line %} | |
<div class="context" id="c{{ frame.id }}"> | |
{% if frame.pre_context %} | |
<ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}"> | |
{% for line in frame.pre_context %} | |
<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ escape(line) }}</li> | |
{% end %}</ol> | |
{% end %} | |
<ol start="{{ frame.lineno }}" class="context-line"><li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ frame.context_line}} <span>...</span></li></ol> | |
{% if frame.post_context %} | |
<ol start='{{ frame.lineno }}' class="post-context" id="post{{ frame.id }}">{% for line in frame.post_context %}<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')">{{ escape(line) }}</li>{% end %}</ol> | |
{% end %} | |
</div> | |
{% end %} | |
{% if frame.vars %} | |
<div class="commands"> | |
<a href="#" onclick="return varToggle(this, '{{ frame.id }}')"><span>▶</span> Local vars</a> | |
</div> | |
<table class="vars" id="v{{ frame.id }}"> | |
<thead> | |
<tr> | |
<th>Variable</th> | |
<th>Value</th> | |
</tr> | |
</thead> | |
<tbody> | |
{% for var in frame.vars %} | |
<tr> | |
<td>{{ var[0]}}</td> | |
{% if var[0] == 'formatted_code' %} | |
<td class="code"><div>{{ escape(var[1])}}</div></td> | |
{% else %} | |
<td class="code"><div>{{ escape(pprint.pformat(var[1]))}}</div></td> | |
{% end %} | |
</tr> | |
{% end %} | |
</tbody> | |
</table> | |
{% end %} | |
</li> | |
{% end %} | |
</ul> | |
</div> | |
<form action="http://dpaste.com/" name="pasteform" id="pasteform" method="post"> | |
<div id="pastebinTraceback" class="pastebin"> | |
<input type="hidden" name="language" value="PythonConsole"> | |
<input type="hidden" name="title" value="{{ e }} at {{ handler.request.uri }}"> | |
<input type="hidden" name="source" value="Tornado Dpaste Agent"> | |
<input type="hidden" name="poster" value="Tornado"> | |
<textarea name="content" id="traceback_area" cols="140" rows="15"> | |
Traceback: | |
{% for frame in frames %}File "{{ escape(frame.filename) }}" in {{ escape(frame.function) }} | |
{% if frame.context_line %} {{ frame.lineno }}. {{ escape(frame.context_line) }}{% end %} | |
{% end %} | |
</textarea> | |
<br><br> | |
<input type="submit" value="Share this traceback on a public Web site"> | |
</div> | |
</form> | |
</div> | |
<div id="requestinfo"> | |
<h2>Request Info</h2> | |
<table class="req"> | |
<thead> | |
<tr><th width="200">Header</th><th>Value</th></tr> | |
</thead> | |
<tbody> | |
{% for k, v in req.iteritems() %} | |
<tr><td>{{ k }}</td><td>{{ escape(v) }}</td></tr> | |
{% end %} | |
<tr><td> </td><td> </td></tr> | |
{% for k, v in args.iteritems() %} | |
<tr><td>{{ k }}</td><td>{{ escape(pprint.pformat(v)) }}</td></tr> | |
{% end %} | |
</tbody> | |
</table> | |
</div> | |
<div id="headers"> | |
<h2>Headers</h2> | |
<table class="req"> | |
<thead> | |
<tr><th width="200">Header</th><th>Value</th></tr> | |
</thead> | |
<tbody> | |
{% for k, v in headers.iteritems() %} | |
<tr><td>{{ k }}</td><td>{{ v }}</td></tr> | |
{% end %} | |
</tbody> | |
</table> | |
</div> | |
<div id="explanation"> | |
<p> | |
You're seeing this error because you have <code>DEBUG = True</code> in your | |
settings file. Change that to <code>False</code>, and Tornado will | |
display a standard 500 page. | |
</p> | |
</div> | |
</body> | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment