Update fastapi-vue-setup 1.7.1, make use of its logging facilities. Mediapreview and kanta bumped to do so too.

This commit is contained in:
2026-09-18 03:58:37 +00:00
parent 7724290921
commit 02396f4482
6 changed files with 37 additions and 19 deletions
+10
View File
@@ -55,6 +55,16 @@ def main() -> None:
default_port=DEFAULT_PORT, default_port=DEFAULT_PORT,
server_header=False, server_header=False,
reload=Path(__file__).parent if env.dev else False, reload=Path(__file__).parent if env.dev else False,
# Partial log config, merged over uvicorn's default by fastapi-vue:
# root prints at WARNING in production / INFO in dev. Keep our own
# loggers audible in production, and silence httpx's per-request INFO
# (tracking._schedule_favicon_fetch logs its own one-line summary).
log_config={
"loggers": {
"pagerite": {"level": "INFO"},
"httpx": {"level": "WARNING"},
}
},
**run_args, **run_args,
) )
-4
View File
@@ -35,10 +35,6 @@ from pagerite.state import SITE_URL, _html_response, analytics_store, data
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# httpx logs every request at INFO (e.g. the favicon fetches below); our own
# one-line summary in _schedule_favicon_fetch replaces that noise.
logging.getLogger("httpx").setLevel(logging.WARNING)
router = APIRouter() router = APIRouter()
# Live WebSocket clients for the analytics stream. # Live WebSocket clients for the analytics stream.
+3 -3
View File
@@ -17,15 +17,15 @@ readme = "README.md"
requires-python = ">=3.14" requires-python = ">=3.14"
dependencies = [ dependencies = [
"blake3>=1.0.9", "blake3>=1.0.9",
"fastapi-vue~=1.6.1", "fastapi-vue~=1.7.1",
"fastapi[standard]>=0.141.1", "fastapi[standard]>=0.141.1",
"html5tagger>=2.0.0", "html5tagger>=2.0.0",
"httpx>=0.28.1", "httpx>=0.28.1",
"kanta>=0.9.0", "kanta>=0.9.2",
"markdown-it-py>=4.2.0", "markdown-it-py>=4.2.0",
"maxminddb>=3.1.1", "maxminddb>=3.1.1",
"mdit-py-plugins>=0.6.1", "mdit-py-plugins>=0.6.1",
"mediapreview[standard]>=0.2.3", "mediapreview[standard]>=0.2.5",
"platformdirs>=4.11.5", "platformdirs>=4.11.5",
"pygments>=2.20.0", "pygments>=2.20.0",
"python-slugify>=8.0.4", "python-slugify>=8.0.4",
+1
View File
@@ -1,3 +1,4 @@
# ruff: noqa: INP001
"""Hatch build hook for building Vue frontend during package build.""" """Hatch build hook for building Vue frontend during package build."""
import sys import sys
+19 -8
View File
@@ -1,3 +1,4 @@
# ruff: noqa: INP001
"""Utilities used at build time and in devserver script. No dependencies.""" """Utilities used at build time and in devserver script. No dependencies."""
import logging import logging
@@ -9,21 +10,31 @@ from pathlib import Path
MIN_NODE_VERSION = 20 MIN_NODE_VERSION = 20
# Duplicated from fastapi_vue.logging because build environment is isolated
_LEVEL_EMOJI = {
logging.DEBUG: "🐛",
logging.INFO: "🔷",
logging.WARNING: "",
logging.ERROR: "🛑",
logging.CRITICAL: "🚨",
}
class _PrefixFormatter(logging.Formatter):
"""Formatter that adds prefix based on log level.""" class _Formatter(logging.Formatter):
"""Emoji level prefix formatter, mirroring fastapi_vue.logging.Formatter."""
def format(self, record: logging.LogRecord) -> str: def format(self, record: logging.LogRecord) -> str:
if record.levelno >= logging.WARNING: emoji = _LEVEL_EMOJI.get(record.levelno)
return f"⚠️ {record.getMessage()}" prefix = f"{emoji} " if emoji else f"{record.levelname}: "
return record.getMessage() return prefix + record.getMessage()
_handler = logging.StreamHandler() _handler = logging.StreamHandler()
_handler.setFormatter(_PrefixFormatter()) _handler.setFormatter(_Formatter())
logger = logging.getLogger("fastapi-vue") logger = logging.getLogger("fastapi-vue")
logger.addHandler(_handler) logger.addHandler(_handler)
logger.setLevel(logging.INFO) logger.setLevel(logging.INFO)
logger.propagate = False # own handler; do not double-print via a configured root
def _check_node_version(node_path: str) -> None: def _check_node_version(node_path: str) -> None:
@@ -32,7 +43,7 @@ def _check_node_version(node_path: str) -> None:
Raises RuntimeError if version is too old or cannot be determined. Raises RuntimeError if version is too old or cannot be determined.
""" """
try: try:
result = subprocess.run( result = subprocess.run( # noqa: S603
[node_path, "--version"], [node_path, "--version"],
capture_output=True, capture_output=True,
text=True, text=True,
@@ -220,7 +231,7 @@ def build(folder: str = "frontend") -> None:
def run(cmd: list[str]) -> None: def run(cmd: list[str]) -> None:
display_cmd = [Path(cmd[0]).stem, *cmd[1:]] display_cmd = [Path(cmd[0]).stem, *cmd[1:]]
logger.info("### %s", " ".join(display_cmd)) logger.info("### %s", " ".join(display_cmd))
subprocess.run(cmd, check=True, cwd=folder) subprocess.run(cmd, check=True, cwd=folder) # noqa: S603
try: try:
run(install_cmd) run(install_cmd)
+4 -4
View File
@@ -1,3 +1,4 @@
# ruff: noqa: INP001
"""Utilities meant for devserver script, used only in source repository with dev deps.""" """Utilities meant for devserver script, used only in source repository with dev deps."""
from __future__ import annotations from __future__ import annotations
@@ -11,9 +12,8 @@ from subprocess import CalledProcessError
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from urllib.parse import urlsplit from urllib.parse import urlsplit
from fastapi_vue.hostutil import parse_endpoint
from buildutil import find_dev_tool, find_install_tool, logger from buildutil import find_dev_tool, find_install_tool, logger
from fastapi_vue.hostutil import parse_endpoint
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Awaitable from collections.abc import Awaitable
@@ -67,7 +67,7 @@ class ProcessGroup(asyncio.TaskGroup):
async def wait(self, *waitables: Process | Awaitable) -> tuple[Any, ...]: async def wait(self, *waitables: Process | Awaitable) -> tuple[Any, ...]:
"""Wait concurrently and return results in argument order.""" """Wait concurrently and return results in argument order."""
async def task(w: Process | Awaitable) -> Any: async def task(w: Process | Awaitable) -> Any: # noqa: ANN401
if not isinstance(w, Process): if not isinstance(w, Process):
return await w return await w
if retcode := await w.wait(): if retcode := await w.wait():
@@ -84,7 +84,7 @@ class ProcessGroup(asyncio.TaskGroup):
return tuple(task.result() for task in tasks) return tuple(task.result() for task in tasks)
async def http_get_server(url: str, timeout: float) -> str | None: async def http_get_server(url: str, timeout: float) -> str | None: # noqa: ASYNC109
"""GET url with plain asyncio streams, return the response Server header. """GET url with plain asyncio streams, return the response Server header.
Returns an empty string when the server responds without a Server header, Returns an empty string when the server responds without a Server header,