diff --git a/.coveragerc b/.coveragerc index 8b178e16..6c7436f6 100644 --- a/.coveragerc +++ b/.coveragerc @@ -9,6 +9,7 @@ omit = sanic/simple.py sanic/utils.py sanic/cli + sanic/pages [html] directory = coverage diff --git a/codecov.yml b/codecov.yml index bd0afc47..9b6fb373 100644 --- a/codecov.yml +++ b/codecov.yml @@ -17,7 +17,8 @@ ignore: - "sanic/compat.py" - "sanic/simple.py" - "sanic/utils.py" - - "sanic/cli" + - "sanic/cli/" + - "sanic/pages/" - ".github/" - "changelogs/" - "docker/" diff --git a/sanic/app.py b/sanic/app.py index 4c0a1fc6..a7c042a8 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -57,6 +57,7 @@ from sanic.config import SANIC_PREFIX, Config from sanic.exceptions import ( BadRequest, SanicException, + SanicIsADirectoryError, ServerError, URLBuildError, ) @@ -1578,6 +1579,10 @@ class Sanic(BaseSanic, StartupMixin, metaclass=TouchUpMeta): TouchUp.run(self) self.state.is_started = True + + self.exception(SanicIsADirectoryError)( + DirectoryHandler.default_handler + ) self.directory_handler.debug = self.debug def ack(self): diff --git a/sanic/blueprints.py b/sanic/blueprints.py index 5699d4bc..8050e1f6 100644 --- a/sanic/blueprints.py +++ b/sanic/blueprints.py @@ -304,9 +304,6 @@ class Blueprint(BaseSanic): # 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 uri = self._setup_uri(future.uri, url_prefix) diff --git a/sanic/handlers/error.py b/sanic/handlers/error.py index ad2ab5c4..e5a14de6 100644 --- a/sanic/handlers/error.py +++ b/sanic/handlers/error.py @@ -3,8 +3,6 @@ from __future__ import annotations from typing import Dict, List, Optional, Tuple, Type 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.models.handler_types import RouteHandler from sanic.response import text @@ -22,19 +20,13 @@ class ErrorHandler: realtime alerting system. """ - DEFAULT_HANDLERS = { - (SanicIsADirectoryError, None): DirectoryHandler.default_handler - } - def __init__( self, base: Type[BaseRenderer] = TextRenderer, ): self.cached_handlers: Dict[ Tuple[Type[BaseException], Optional[str]], Optional[RouteHandler] - ] = { - **self.DEFAULT_HANDLERS # type: ignore - } + ] = {} self.debug = False self.base = base diff --git a/sanic/pages/autoindex.py b/sanic/pages/autoindex.py index 79a1b968..6639fd39 100644 --- a/sanic/pages/autoindex.py +++ b/sanic/pages/autoindex.py @@ -13,23 +13,36 @@ class FileInfo(TypedDict): file_size: str -class AutoIndex(BasePage): +class AutoIndex(BasePage): # no cov EXTRA_STYLE = dedent( - """ - #breadcrumbs .path-0 a::before { content: "🏠"; } - #breadcrumbs span:has(> a:hover, > a:focus) * { - color: #ff0d68; text-shadow: 0 0 1rem; - } - main a { color: inherit; font-weight: bold; } - table.autoindex tr { display: flex; } - 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; } - span.icon { margin-right: 1rem; } + f""" + #breadcrumbs a:hover {{ text-decoration: underline; }} + #breadcrumbs .path-0 a {{ text-decoration: none; }} + #breadcrumbs span::after {{ + content: "/"; text-decoration: none; padding: 0 0.25em; + }} + #breadcrumbs .path-0 a::before {{ content: "🏠"; }} + #breadcrumbs > span > a {{ color: {BasePage.ACCENT}; }} + main a {{ color: inherit; font-weight: bold; }} + table.autoindex {{ width: 100%; font-family: monospace; }} + table.autoindex tr {{ display: flex; }} + 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__( self, files: Iterable[FileInfo], url: str, debug: bool @@ -56,11 +69,11 @@ class AutoIndex(BasePage): self.doc.span(class_=f"path-{i}").__enter__() for i, part in enumerate(p): path = "/".join(p[: i + 1]) + "/" - self.doc.a(f"{part}/", href=path) + self.doc.a(part, href=path) self.doc.__exit__(None, None, None) def _file_table(self, files: Iterable[FileInfo]): - with self.doc.table(class_="autoindex"): + with self.doc.table(class_="autoindex container"): for f in files: self._file_row(**f) diff --git a/sanic/pages/base.py b/sanic/pages/base.py index 585a1d13..f7ae4f6a 100644 --- a/sanic/pages/base.py +++ b/sanic/pages/base.py @@ -7,16 +7,26 @@ from sanic import __version__ as VERSION from sanic.application.logo import SVG_LOGO -class BasePage(ABC): +class BasePage(ABC): # no cov + ACCENT = "#ff0d68" BASE_STYLE = dedent( """ - body { margin: 0; font: 16px sans-serif; } - body > * { padding: 0 2rem; } + html { font: 16px sans-serif; background: #eee; color: #111; } + 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 { - display: flex; align-items: center; justify-content: space-between; background: #111; color: #e1e1e1; border-bottom: 1px solid #272727; } + header .container { + display: flex; align-items: center; justify-content: space-between; + } main { padding-bottom: 3rem; } + h1 { text-align: left; } h2 { margin: 2rem 0 1rem 0; } a:visited { color: inherit; } a { text-decoration: none; color: #88f; } @@ -26,7 +36,6 @@ class BasePage(ABC): #logo { height: 2.75rem; padding: 0.25rem 0; } .smalltext { font-size: 1rem; } .nobr { white-space: nowrap; } - table { width: 100%; max-width: 1200px; } span.icon { margin-right: 1rem; } @media (prefers-color-scheme: dark) { html { background: #111; color: #ccc; } @@ -51,11 +60,13 @@ class BasePage(ABC): def _head(self) -> None: self.doc.style(HTML(self.style)) - if self.debug: - with self.doc.header: - self.doc(HTML(SVG_LOGO)).div(self.TITLE, id="hdrtext").div( - f"Version {VERSION}", id="hdrver" - ) + with self.doc.header: + with self.doc.div(class_="container"): + 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 def _body(self) -> None: diff --git a/sanic/worker/container.py b/sanic/worker/container.py deleted file mode 100644 index 0d65254b..00000000 --- a/sanic/worker/container.py +++ /dev/null @@ -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)