Files
simple-nanoshare/my_modules/textview/view.py
T
daniel156161 73fdeacbfe
Build and Push Docker Container / build-and-push (push) Successful in 2m25s
feat!: adopt Python 3.14 and 3.15 language features
- Require Python 3.15 for the server and Python 3.14 for the CLI.
- Match the server requirement to quart_common's Python 3.15 features.
- Replace future annotations with native deferred evaluation.
- Defer CLI command dependencies and QR imports on Python 3.15.
- Enable argparse suggestions for mistyped CLI commands.
- Remove the obsolete tomllib import fallback.
- Update my_helpers and quart_common submodule references.
- Lock test dependencies and exclude them from Docker installations.
- Add regression coverage for lazy imports and deferred annotations.
- Document runtime requirements and standalone CLI validation.
- Validate 276 tests on Python 3.15 and 18 CLI tests on Python 3.14.

BREAKING CHANGE: The server now requires Python 3.15+ and the standalone CLI requires Python 3.14+.
2026-10-26 14:47:29 +01:00

41 lines
1.4 KiB
Python

from collections.abc import Awaitable, Callable
from .render import build_segments
# Text types that get the rendered viewer; anything else is served untouched.
VIEWABLE_CONTENT_TYPES = {'text/plain', 'text/markdown'}
_TRUTHY = {'1', 'true', 'yes'}
def _base_content_type(content_type: str) -> str:
return (content_type or '').split(';')[0].strip().lower()
def wants_text_view(content_type: str, accept_header: str, raw_param: str | None, force_download: bool) -> bool:
"""Only real browser navigations get HTML; curl, wget and the CLI keep the raw bytes."""
if force_download or (raw_param or '').lower() in _TRUTHY:
return False
if _base_content_type(content_type) not in VIEWABLE_CONTENT_TYPES:
return False
# Accept: */* (curl, wget, CLI clients) must not trigger the viewer.
return 'text/html' in (accept_header or '').lower()
def decode_text(raw: bytes) -> str:
"""Decode the full document; invalid bytes become replacement characters."""
return raw.decode('utf-8', errors='replace')
async def build_view_context(
raw: bytes,
file_name: str,
host: str,
root_path: str,
raw_url: str,
lookup: Callable[[str], Awaitable[dict | None]] | None,
) -> dict:
text = decode_text(raw)
segments = await build_segments(text, host=host, root_path=root_path, lookup=lookup)
return {
'file_name': file_name,
'segments': segments,
'raw_url': raw_url,
}