added exception chain rendering in debug #675
This commit is contained in:
parent
158a94d34c
commit
69511c2783
|
@ -47,6 +47,10 @@ TRACEBACK_STYLE = '''
|
|||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.tb-border {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.frame-descriptor {
|
||||
background-color: #e2eafb;
|
||||
}
|
||||
|
@ -63,12 +67,9 @@ TRACEBACK_WRAPPER_HTML = '''
|
|||
{style}
|
||||
</head>
|
||||
<body>
|
||||
<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}
|
||||
<p class="summary">
|
||||
{inner_html}
|
||||
<div class="summary">
|
||||
<p>
|
||||
<b>{exc_name}: {exc_value}</b>
|
||||
while handling path <code>{path}</code>
|
||||
</p>
|
||||
|
@ -77,6 +78,24 @@ TRACEBACK_WRAPPER_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 = '''
|
||||
<div class="frame-line">
|
||||
<p class="frame-descriptor">
|
||||
|
|
|
@ -9,7 +9,9 @@ from sanic.exceptions import (
|
|||
SanicException,
|
||||
TRACEBACK_LINE_HTML,
|
||||
TRACEBACK_STYLE,
|
||||
TRACEBACK_WRAPPER_HTML)
|
||||
TRACEBACK_WRAPPER_HTML,
|
||||
TRACEBACK_WRAPPER_INNER_HTML,
|
||||
TRACEBACK_BORDER)
|
||||
from sanic.log import log
|
||||
from sanic.response import text, html
|
||||
|
||||
|
@ -24,19 +26,31 @@ class ErrorHandler:
|
|||
self.cached_handlers = {}
|
||||
self.debug = False
|
||||
|
||||
def _render_traceback_html(self, exception, request):
|
||||
exc_type, exc_value, tb = sys.exc_info()
|
||||
frames = extract_tb(tb)
|
||||
def _render_exception(self, exception):
|
||||
frames = extract_tb(exception.__traceback__)
|
||||
|
||||
frame_html = []
|
||||
for frame in frames:
|
||||
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(
|
||||
style=TRACEBACK_STYLE,
|
||||
exc_name=exc_type.__name__,
|
||||
exc_value=exc_value,
|
||||
frame_html=''.join(frame_html),
|
||||
exc_name=exception.__class__.__name__,
|
||||
exc_value=exception,
|
||||
inner_html=TRACEBACK_BORDER.join(reversed(exceptions)),
|
||||
path=request.path)
|
||||
|
||||
def add(self, exception, handler):
|
||||
|
|
|
@ -35,6 +35,15 @@ def handler_5(request):
|
|||
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)
|
||||
def handler_exception(request, exception):
|
||||
return text("OK")
|
||||
|
@ -84,6 +93,26 @@ def test_inherited_exception_handler():
|
|||
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():
|
||||
class CustomError(Exception):
|
||||
pass
|
||||
|
|
Loading…
Reference in New Issue
Block a user