Refactored to sanic.pages.error module. Traceback and style tuning. Print also headers, and for other than 500 errors as well. 500 error message text UX workaround.

This commit is contained in:
L. Karkkainen 2023-01-27 18:50:35 +00:00
parent 77bdfa14ed
commit ea09906e0a
4 changed files with 54 additions and 25 deletions

View File

@ -23,7 +23,7 @@ from traceback import extract_tb
from sanic.exceptions import BadRequest, SanicException
from sanic.helpers import STATUS_CODES
from sanic.response import html, json, text
from sanic.pages.base import ErrorPage
from sanic.pages.error import ErrorPage
dumps: t.Callable[..., str]
try:
@ -160,7 +160,13 @@ class HTMLRenderer(BaseRenderer):
)
def _page(self, full: bool) -> HTTPResponse:
page = ErrorPage(super().title, super().text, sys.exc_info()[1], full=full)
page = ErrorPage(
title=super().title,
text=super().text,
request=self.request,
exc=self.exception,
full=full,
)
return html(page.render(), status=self.status, headers=self.headers)
def full(self) -> HTTPResponse:

View File

@ -24,6 +24,7 @@ class AutoIndex(BasePage):
table.autoindex td:first-child { flex: 1; }
table.autoindex td:nth-child(2) { text-align: right; }
table.autoindex td:last-child { text-align: right; }
span.icon { margin-right: 1rem; }
"""
)
TITLE = "File browser"

View File

@ -16,12 +16,15 @@ class BasePage(ABC):
display: flex; align-items: center; justify-content: space-between;
background: #555; color: #e1e1e1;
}
main { padding-bottom: 3rem; }
h2 { margin: 2rem 0 1rem 0; }
a:visited { color: inherit; }
a { text-decoration: none; color: #88f; }
a:hover, a:focus { text-decoration: underline; outline: none; }
#logo { height: 2.5rem; }
table { width: 100%; max-width: 1200px; }
span.icon { margin-right: 1rem; }
.smalltext { font-size: 1rem; }
.nobr { white-space: nowrap; }
table { width: 100%; max-width: 1200px; word-break: break-all; }
@media (prefers-color-scheme: dark) {
html { background: #111; color: #ccc; }
}
@ -50,24 +53,3 @@ class BasePage(ABC):
@abstractmethod
def _body(self) -> None:
...
class ErrorPage(BasePage):
TITLE = "Error while handling your request"
def __init__(self, title: str, text: str, exc: Exception, full: bool) -> None:
super().__init__()
self.title = title
self.text = text
self.exc = exc
self.full = full
def _body(self) -> None:
with self.doc.main:
self.doc.h1(f"⚠️ {self.title}")
if self.full and self.exc:
from niceback import html_traceback
self.doc(html_traceback(self.exc))
else:
self.doc.p(self.text)

40
sanic/pages/error.py Normal file
View File

@ -0,0 +1,40 @@
from .base import BasePage
from sanic.request import Request
from html5tagger import E
from niceback import html_traceback, inspector
# Avoid showing the request in the traceback variable inspectors
inspector.blacklist_types += Request,
class ErrorPage(BasePage):
def __init__(self, title: str, text: str, request: Request, exc: Exception, full: bool) -> None:
super().__init__()
# Internal server errors come with the text of the exception, which we don't want to show to the user.
# FIXME: This needs to be done some place else but I am not digging into that now.
if "Internal Server Error" in title:
text = "The application encountered an unexpected error and could not continue."
self.TITLE = E(f"App {request.app.name} cannot handle your request")
self.title = title
self.text = text
self.request = request
self.exc = exc
self.full = full
def _body(self) -> None:
with self.doc.main:
self.doc.h1(f"⚠️ {self.title}").p(self.text)
if not self.request.app.debug:
return
# Show additional details in debug mode, open by default for 500 errors
with self.doc.details(open=self.full, class_="smalltext"):
self.doc.summary("Details for developers (Sanic debug mode only)")
if self.exc:
self.doc.h2(f"Exception in {self.request.route.name}:")
# skip_outmost=1 to hide Sanic.handle_request
self.doc(html_traceback(self.exc, skip_outmost=1))
self.doc.h2(f"{self.request.method} {self.request.path}")
with self.doc.table(id="request-headers"):
for k, v in self.request.headers.items():
self.doc.tr.td(f"{k}:", class_="nobr").td(v)