Merge branch 'issue2661' into niceback-error-handling
This commit is contained in:
commit
ff47448585
@ -9,6 +9,7 @@ omit =
|
|||||||
sanic/simple.py
|
sanic/simple.py
|
||||||
sanic/utils.py
|
sanic/utils.py
|
||||||
sanic/cli
|
sanic/cli
|
||||||
|
sanic/pages
|
||||||
|
|
||||||
[html]
|
[html]
|
||||||
directory = coverage
|
directory = coverage
|
||||||
|
@ -17,7 +17,8 @@ ignore:
|
|||||||
- "sanic/compat.py"
|
- "sanic/compat.py"
|
||||||
- "sanic/simple.py"
|
- "sanic/simple.py"
|
||||||
- "sanic/utils.py"
|
- "sanic/utils.py"
|
||||||
- "sanic/cli"
|
- "sanic/cli/"
|
||||||
|
- "sanic/pages/"
|
||||||
- ".github/"
|
- ".github/"
|
||||||
- "changelogs/"
|
- "changelogs/"
|
||||||
- "docker/"
|
- "docker/"
|
||||||
|
@ -57,6 +57,7 @@ from sanic.config import SANIC_PREFIX, Config
|
|||||||
from sanic.exceptions import (
|
from sanic.exceptions import (
|
||||||
BadRequest,
|
BadRequest,
|
||||||
SanicException,
|
SanicException,
|
||||||
|
SanicIsADirectoryError,
|
||||||
ServerError,
|
ServerError,
|
||||||
URLBuildError,
|
URLBuildError,
|
||||||
)
|
)
|
||||||
@ -1578,6 +1579,10 @@ class Sanic(BaseSanic, StartupMixin, metaclass=TouchUpMeta):
|
|||||||
TouchUp.run(self)
|
TouchUp.run(self)
|
||||||
|
|
||||||
self.state.is_started = True
|
self.state.is_started = True
|
||||||
|
|
||||||
|
self.exception(SanicIsADirectoryError)(
|
||||||
|
DirectoryHandler.default_handler
|
||||||
|
)
|
||||||
self.directory_handler.debug = self.debug
|
self.directory_handler.debug = self.debug
|
||||||
|
|
||||||
def ack(self):
|
def ack(self):
|
||||||
|
@ -304,9 +304,6 @@ class Blueprint(BaseSanic):
|
|||||||
|
|
||||||
# Routes
|
# Routes
|
||||||
for future in self._future_routes:
|
for future in self._future_routes:
|
||||||
# attach the blueprint name to the handler so that it can be
|
|
||||||
# prefixed properly in the router
|
|
||||||
future.handler.__blueprintname__ = self.name
|
|
||||||
# Prepend the blueprint URI prefix if available
|
# Prepend the blueprint URI prefix if available
|
||||||
uri = self._setup_uri(future.uri, url_prefix)
|
uri = self._setup_uri(future.uri, url_prefix)
|
||||||
|
|
||||||
|
@ -3,8 +3,6 @@ from __future__ import annotations
|
|||||||
from typing import Dict, List, Optional, Tuple, Type
|
from typing import Dict, List, Optional, Tuple, Type
|
||||||
|
|
||||||
from sanic.errorpages import BaseRenderer, TextRenderer, exception_response
|
from sanic.errorpages import BaseRenderer, TextRenderer, exception_response
|
||||||
from sanic.exceptions import SanicIsADirectoryError
|
|
||||||
from sanic.handlers.directory import DirectoryHandler
|
|
||||||
from sanic.log import deprecation, error_logger
|
from sanic.log import deprecation, error_logger
|
||||||
from sanic.models.handler_types import RouteHandler
|
from sanic.models.handler_types import RouteHandler
|
||||||
from sanic.response import text
|
from sanic.response import text
|
||||||
@ -22,19 +20,13 @@ class ErrorHandler:
|
|||||||
realtime alerting system.
|
realtime alerting system.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DEFAULT_HANDLERS = {
|
|
||||||
(SanicIsADirectoryError, None): DirectoryHandler.default_handler
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
base: Type[BaseRenderer] = TextRenderer,
|
base: Type[BaseRenderer] = TextRenderer,
|
||||||
):
|
):
|
||||||
self.cached_handlers: Dict[
|
self.cached_handlers: Dict[
|
||||||
Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler]
|
Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler]
|
||||||
] = {
|
] = {}
|
||||||
**self.DEFAULT_HANDLERS # type: ignore
|
|
||||||
}
|
|
||||||
self.debug = False
|
self.debug = False
|
||||||
self.base = base
|
self.base = base
|
||||||
|
|
||||||
|
@ -13,23 +13,36 @@ class FileInfo(TypedDict):
|
|||||||
file_size: str
|
file_size: str
|
||||||
|
|
||||||
|
|
||||||
class AutoIndex(BasePage):
|
class AutoIndex(BasePage): # no cov
|
||||||
EXTRA_STYLE = dedent(
|
EXTRA_STYLE = dedent(
|
||||||
"""
|
f"""
|
||||||
#breadcrumbs .path-0 a::before { content: "🏠"; }
|
#breadcrumbs a:hover {{ text-decoration: underline; }}
|
||||||
#breadcrumbs span:has(> a:hover, > a:focus) * {
|
#breadcrumbs .path-0 a {{ text-decoration: none; }}
|
||||||
color: #ff0d68; text-shadow: 0 0 1rem;
|
#breadcrumbs span::after {{
|
||||||
}
|
content: "/"; text-decoration: none; padding: 0 0.25em;
|
||||||
main a { color: inherit; font-weight: bold; }
|
}}
|
||||||
table.autoindex tr { display: flex; }
|
#breadcrumbs .path-0 a::before {{ content: "🏠"; }}
|
||||||
table.autoindex td { margin: 0 0.5rem; }
|
#breadcrumbs > span > a {{ color: {BasePage.ACCENT}; }}
|
||||||
table.autoindex td:first-child { flex: 1; }
|
main a {{ color: inherit; font-weight: bold; }}
|
||||||
table.autoindex td:nth-child(2) { text-align: right; }
|
table.autoindex {{ width: 100%; font-family: monospace; }}
|
||||||
table.autoindex td:last-child { text-align: right; }
|
table.autoindex tr {{ display: flex; }}
|
||||||
span.icon { margin-right: 1rem; }
|
table.autoindex tr:hover {{ background-color: #ddd; }}
|
||||||
|
table.autoindex td {{ margin: 0 0.5rem; }}
|
||||||
|
table.autoindex td:first-child {{ flex: 1; }}
|
||||||
|
table.autoindex td:nth-child(2) {{ text-align: right; }}
|
||||||
|
table.autoindex td:last-child {{ text-align: right; }}
|
||||||
|
@media (min-width: 915px) {{
|
||||||
|
table.autoindex {{ font-size: 1.75vw; }}
|
||||||
|
}}
|
||||||
|
@media (min-width: 1600px) {{
|
||||||
|
table.autoindex {{ font-size: 1.75rem; }}
|
||||||
|
}}
|
||||||
|
@media (prefers-color-scheme: dark) {{
|
||||||
|
table.autoindex tr:hover {{ background-color: #222; }}
|
||||||
|
}}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
TITLE = "File browser"
|
TITLE = "File Browser"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, files: Iterable[FileInfo], url: str, debug: bool
|
self, files: Iterable[FileInfo], url: str, debug: bool
|
||||||
@ -56,11 +69,11 @@ class AutoIndex(BasePage):
|
|||||||
self.doc.span(class_=f"path-{i}").__enter__()
|
self.doc.span(class_=f"path-{i}").__enter__()
|
||||||
for i, part in enumerate(p):
|
for i, part in enumerate(p):
|
||||||
path = "/".join(p[: i + 1]) + "/"
|
path = "/".join(p[: i + 1]) + "/"
|
||||||
self.doc.a(f"{part}/", href=path)
|
self.doc.a(part, href=path)
|
||||||
self.doc.__exit__(None, None, None)
|
self.doc.__exit__(None, None, None)
|
||||||
|
|
||||||
def _file_table(self, files: Iterable[FileInfo]):
|
def _file_table(self, files: Iterable[FileInfo]):
|
||||||
with self.doc.table(class_="autoindex"):
|
with self.doc.table(class_="autoindex container"):
|
||||||
for f in files:
|
for f in files:
|
||||||
self._file_row(**f)
|
self._file_row(**f)
|
||||||
|
|
||||||
|
@ -7,16 +7,26 @@ from sanic import __version__ as VERSION
|
|||||||
from sanic.application.logo import SVG_LOGO
|
from sanic.application.logo import SVG_LOGO
|
||||||
|
|
||||||
|
|
||||||
class BasePage(ABC):
|
class BasePage(ABC): # no cov
|
||||||
|
ACCENT = "#ff0d68"
|
||||||
BASE_STYLE = dedent(
|
BASE_STYLE = dedent(
|
||||||
"""
|
"""
|
||||||
body { margin: 0; font: 16px sans-serif; }
|
html { font: 16px sans-serif; background: #eee; color: #111; }
|
||||||
body > * { padding: 0 2rem; }
|
body { margin: 0; font-size: 1.25rem; }
|
||||||
|
body > * { padding: 1rem 2vw; }
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
body > * { padding: 0.5rem 1.5vw;}
|
||||||
|
body { font-size: 1rem; }
|
||||||
|
}
|
||||||
|
.container { min-width: 600px; max-width: 1600px; }
|
||||||
header {
|
header {
|
||||||
display: flex; align-items: center; justify-content: space-between;
|
|
||||||
background: #111; color: #e1e1e1; border-bottom: 1px solid #272727;
|
background: #111; color: #e1e1e1; border-bottom: 1px solid #272727;
|
||||||
}
|
}
|
||||||
|
header .container {
|
||||||
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
|
}
|
||||||
main { padding-bottom: 3rem; }
|
main { padding-bottom: 3rem; }
|
||||||
|
h1 { text-align: left; }
|
||||||
h2 { margin: 2rem 0 1rem 0; }
|
h2 { margin: 2rem 0 1rem 0; }
|
||||||
a:visited { color: inherit; }
|
a:visited { color: inherit; }
|
||||||
a { text-decoration: none; color: #88f; }
|
a { text-decoration: none; color: #88f; }
|
||||||
@ -26,7 +36,6 @@ class BasePage(ABC):
|
|||||||
#logo { height: 2.75rem; padding: 0.25rem 0; }
|
#logo { height: 2.75rem; padding: 0.25rem 0; }
|
||||||
.smalltext { font-size: 1rem; }
|
.smalltext { font-size: 1rem; }
|
||||||
.nobr { white-space: nowrap; }
|
.nobr { white-space: nowrap; }
|
||||||
table { width: 100%; max-width: 1200px; }
|
|
||||||
span.icon { margin-right: 1rem; }
|
span.icon { margin-right: 1rem; }
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
html { background: #111; color: #ccc; }
|
html { background: #111; color: #ccc; }
|
||||||
@ -51,11 +60,13 @@ class BasePage(ABC):
|
|||||||
|
|
||||||
def _head(self) -> None:
|
def _head(self) -> None:
|
||||||
self.doc.style(HTML(self.style))
|
self.doc.style(HTML(self.style))
|
||||||
if self.debug:
|
|
||||||
with self.doc.header:
|
with self.doc.header:
|
||||||
self.doc(HTML(SVG_LOGO)).div(self.TITLE, id="hdrtext").div(
|
with self.doc.div(class_="container"):
|
||||||
f"Version {VERSION}", id="hdrver"
|
if self.debug:
|
||||||
)
|
self.doc(HTML(SVG_LOGO))
|
||||||
|
self.doc.div(self.TITLE, id="hdrtext")
|
||||||
|
if self.debug:
|
||||||
|
self.doc.div(f"Version {VERSION}", id="hdrver")
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _body(self) -> None:
|
def _body(self) -> None:
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
from sanic.worker.loader import AppLoader
|
|
||||||
|
|
||||||
|
|
||||||
class AppContainer:
|
|
||||||
def __init__(self, loader: AppLoader) -> None:
|
|
||||||
self.loader = loader
|
|
||||||
|
|
||||||
def prepare(self, *apps) -> None:
|
|
||||||
for app in apps:
|
|
||||||
app.prepare(**app._early_prepare)
|
|
||||||
|
|
||||||
def serve(self) -> None:
|
|
||||||
from sanic import Sanic
|
|
||||||
|
|
||||||
primary = self.loader.load()
|
|
||||||
self.prepare(primary)
|
|
||||||
Sanic.serve(primary=primary, app_loader=self.loader)
|
|
Loading…
x
Reference in New Issue
Block a user