Merge pull request #677 from abuckenheimer/master
added exception chain rendering in debug #675
This commit is contained in:
commit
7f3c417078
|
@ -47,6 +47,10 @@ TRACEBACK_STYLE = '''
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tb-border {
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.frame-descriptor {
|
.frame-descriptor {
|
||||||
background-color: #e2eafb;
|
background-color: #e2eafb;
|
||||||
}
|
}
|
||||||
|
@ -63,12 +67,9 @@ TRACEBACK_WRAPPER_HTML = '''
|
||||||
{style}
|
{style}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>{exc_name}</h1>
|
{inner_html}
|
||||||
<h3><code>{exc_value}</code></h3>
|
<div class="summary">
|
||||||
<div class="tb-wrapper">
|
<p>
|
||||||
<p class="tb-header">Traceback (most recent call last):</p>
|
|
||||||
{frame_html}
|
|
||||||
<p class="summary">
|
|
||||||
<b>{exc_name}: {exc_value}</b>
|
<b>{exc_name}: {exc_value}</b>
|
||||||
while handling path <code>{path}</code>
|
while handling path <code>{path}</code>
|
||||||
</p>
|
</p>
|
||||||
|
@ -77,6 +78,24 @@ TRACEBACK_WRAPPER_HTML = '''
|
||||||
</html>
|
</html>
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
TRACEBACK_WRAPPER_INNER_HTML = '''
|
||||||
|
<h1>{exc_name}</h1>
|
||||||
|
<h3><code>{exc_value}</code></h3>
|
||||||
|
<div class="tb-wrapper">
|
||||||
|
<p class="tb-header">Traceback (most recent call last):</p>
|
||||||
|
{frame_html}
|
||||||
|
</div>
|
||||||
|
'''
|
||||||
|
|
||||||
|
TRACEBACK_BORDER = '''
|
||||||
|
<div class="tb-border">
|
||||||
|
<b><i>
|
||||||
|
The above exception was the direct cause of the
|
||||||
|
following exception:
|
||||||
|
</i></b>
|
||||||
|
</div>
|
||||||
|
'''
|
||||||
|
|
||||||
TRACEBACK_LINE_HTML = '''
|
TRACEBACK_LINE_HTML = '''
|
||||||
<div class="frame-line">
|
<div class="frame-line">
|
||||||
<p class="frame-descriptor">
|
<p class="frame-descriptor">
|
||||||
|
|
|
@ -9,7 +9,9 @@ from sanic.exceptions import (
|
||||||
SanicException,
|
SanicException,
|
||||||
TRACEBACK_LINE_HTML,
|
TRACEBACK_LINE_HTML,
|
||||||
TRACEBACK_STYLE,
|
TRACEBACK_STYLE,
|
||||||
TRACEBACK_WRAPPER_HTML)
|
TRACEBACK_WRAPPER_HTML,
|
||||||
|
TRACEBACK_WRAPPER_INNER_HTML,
|
||||||
|
TRACEBACK_BORDER)
|
||||||
from sanic.log import log
|
from sanic.log import log
|
||||||
from sanic.response import text, html
|
from sanic.response import text, html
|
||||||
|
|
||||||
|
@ -24,19 +26,31 @@ class ErrorHandler:
|
||||||
self.cached_handlers = {}
|
self.cached_handlers = {}
|
||||||
self.debug = False
|
self.debug = False
|
||||||
|
|
||||||
def _render_traceback_html(self, exception, request):
|
def _render_exception(self, exception):
|
||||||
exc_type, exc_value, tb = sys.exc_info()
|
frames = extract_tb(exception.__traceback__)
|
||||||
frames = extract_tb(tb)
|
|
||||||
|
|
||||||
frame_html = []
|
frame_html = []
|
||||||
for frame in frames:
|
for frame in frames:
|
||||||
frame_html.append(TRACEBACK_LINE_HTML.format(frame))
|
frame_html.append(TRACEBACK_LINE_HTML.format(frame))
|
||||||
|
|
||||||
|
return TRACEBACK_WRAPPER_INNER_HTML.format(
|
||||||
|
exc_name=exception.__class__.__name__,
|
||||||
|
exc_value=exception,
|
||||||
|
frame_html=''.join(frame_html))
|
||||||
|
|
||||||
|
def _render_traceback_html(self, exception, request):
|
||||||
|
exc_type, exc_value, tb = sys.exc_info()
|
||||||
|
exceptions = []
|
||||||
|
|
||||||
|
while exc_value:
|
||||||
|
exceptions.append(self._render_exception(exc_value))
|
||||||
|
exc_value = exc_value.__cause__
|
||||||
|
|
||||||
return TRACEBACK_WRAPPER_HTML.format(
|
return TRACEBACK_WRAPPER_HTML.format(
|
||||||
style=TRACEBACK_STYLE,
|
style=TRACEBACK_STYLE,
|
||||||
exc_name=exc_type.__name__,
|
exc_name=exception.__class__.__name__,
|
||||||
exc_value=exc_value,
|
exc_value=exception,
|
||||||
frame_html=''.join(frame_html),
|
inner_html=TRACEBACK_BORDER.join(reversed(exceptions)),
|
||||||
path=request.path)
|
path=request.path)
|
||||||
|
|
||||||
def add(self, exception, handler):
|
def add(self, exception, handler):
|
||||||
|
|
|
@ -35,6 +35,15 @@ def handler_5(request):
|
||||||
raise CustomServerError('Custom server error')
|
raise CustomServerError('Custom server error')
|
||||||
|
|
||||||
|
|
||||||
|
@exception_handler_app.route('/6/<arg:int>')
|
||||||
|
def handler_6(request, arg):
|
||||||
|
try:
|
||||||
|
foo = 1 / arg
|
||||||
|
except Exception as e:
|
||||||
|
raise e from ValueError("{}".format(arg))
|
||||||
|
return text(foo)
|
||||||
|
|
||||||
|
|
||||||
@exception_handler_app.exception(NotFound, ServerError)
|
@exception_handler_app.exception(NotFound, ServerError)
|
||||||
def handler_exception(request, exception):
|
def handler_exception(request, exception):
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
@ -84,6 +93,26 @@ def test_inherited_exception_handler():
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_chained_exception_handler():
|
||||||
|
request, response = exception_handler_app.test_client.get(
|
||||||
|
'/6/0', debug=True)
|
||||||
|
assert response.status == 500
|
||||||
|
|
||||||
|
soup = BeautifulSoup(response.body, 'html.parser')
|
||||||
|
html = str(soup)
|
||||||
|
|
||||||
|
assert 'response = handler(request, *args, **kwargs)' in html
|
||||||
|
assert 'handler_6' in html
|
||||||
|
assert 'foo = 1 / arg' in html
|
||||||
|
assert 'ValueError' in html
|
||||||
|
assert 'The above exception was the direct cause' in html
|
||||||
|
|
||||||
|
summary_text = " ".join(soup.select('.summary')[0].text.split())
|
||||||
|
assert (
|
||||||
|
"ZeroDivisionError: division by zero "
|
||||||
|
"while handling path /6/0") == summary_text
|
||||||
|
|
||||||
|
|
||||||
def test_exception_handler_lookup():
|
def test_exception_handler_lookup():
|
||||||
class CustomError(Exception):
|
class CustomError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Reference in New Issue
Block a user