diff --git a/src/transcription/db/migration.py b/src/transcription/db/migration.py index af6f889..1778dc5 100644 --- a/src/transcription/db/migration.py +++ b/src/transcription/db/migration.py @@ -3,6 +3,7 @@ from __future__ import annotations import base64 import json import shutil +from collections.abc import Sequence from dataclasses import dataclass from datetime import UTC from datetime import date @@ -18,6 +19,7 @@ from sqlalchemy import Table from sqlalchemy import create_engine from sqlalchemy import inspect as sqlalchemy_inspect from sqlalchemy import select +from sqlalchemy.engine import RowMapping from sqlalchemy.engine import make_url from sqlmodel import SQLModel @@ -69,7 +71,7 @@ def export_bundle(*, source_db_url: str, source_upload_dir: Path, bundle_dir: Pa } engine = create_engine(source_db_url) - legacy_portrait_rows: list[dict[str, Any]] = [] + legacy_portrait_rows: Sequence[RowMapping] = () try: # noqa: PLR1702 inspector = sqlalchemy_inspect(engine) source_tables = set(inspector.get_table_names()) @@ -195,9 +197,10 @@ def default_sync_db_url(settings: Settings | None = None) -> str: return get_database_url(runtime_settings).replace("+aiosqlite", "").replace("+asyncpg", "").replace("+psycopg", "") -def _serialize_row(row: dict[str, Any], *, table_name: str, source_upload_dir: Path) -> dict[str, Any]: +def _serialize_row(row: RowMapping, *, table_name: str, source_upload_dir: Path) -> dict[str, Any]: serialized: dict[str, Any] = {} - for key, value in row.items(): + for raw_key, value in row.items(): + key = str(raw_key) serialized_value = _serialize_value(value) if table_name == "source" and key == "file_path" and isinstance(serialized_value, str): serialized[key] = _canonical_media_relative_path( @@ -315,7 +318,7 @@ def _prepare_photo_payload_and_uploads( # noqa: PLR0915 *, payload: dict[str, Any], uploads_bundle_dir: Path, - legacy_portrait_rows: list[dict[str, Any]], + legacy_portrait_rows: Sequence[RowMapping], ) -> None: photo_rows = payload.setdefault("tables", {}).setdefault("photo", []) photos_dir = uploads_bundle_dir / "photos" diff --git a/src/transcription/ui/pages/home_page.py b/src/transcription/ui/pages/home_page.py index a80d187..4ae47db 100644 --- a/src/transcription/ui/pages/home_page.py +++ b/src/transcription/ui/pages/home_page.py @@ -43,7 +43,7 @@ def _render_homepage_gallery( base_url: str, enable_rotation: bool = False, rotate_enabled: list[bool] | None = None, - on_change: Callable[[], None] | None = None, + on_change: Callable[[], object] | None = None, ) -> None: if not photos: render_empty_state("No homepage image uploaded yet.") diff --git a/src/transcription/ui/pages/people_page.py b/src/transcription/ui/pages/people_page.py index 194dc46..f9ba550 100644 --- a/src/transcription/ui/pages/people_page.py +++ b/src/transcription/ui/pages/people_page.py @@ -283,7 +283,10 @@ def register_page() -> None: # noqa: PLR0915 base_url=str(request.base_url), ) with ui.element("div").classes("relative w-full"): - ui.image(photo_url).classes("w-full rounded-md") + if photo_url is None: + ui.label("Image unavailable").classes("w-full text-sm ui-text-muted p-2") + else: + ui.image(photo_url).classes("w-full rounded-md") description_text = photo.description or "No description" ui.label(description_text).classes( "absolute inset-x-0 bottom-0 text-center text-white text-xs font-semibold " diff --git a/src/transcription/ui/pages/sources_page.py b/src/transcription/ui/pages/sources_page.py index 5be1baa..ca33cc3 100644 --- a/src/transcription/ui/pages/sources_page.py +++ b/src/transcription/ui/pages/sources_page.py @@ -407,7 +407,7 @@ def _render_source_metadata_column( def _resolve_source_detail_layout(*, source: Source, settings: Settings) -> str: media_type = lookup_source_mime_type(source.file_path) - if not media_type.startswith("image/"): + if media_type is None or not media_type.startswith("image/"): return "standard" absolute = (settings.upload_dir / Path(source.file_path)).resolve() dimensions = _read_image_dimensions(absolute) diff --git a/tests/test_db.py b/tests/test_db.py index a078206..b314b4f 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -141,7 +141,14 @@ async def test_create_all_declares_hot_path_indexes(tmp_path): await create_all(engine=runtime.engine) async with runtime.engine.connect() as connection: - def collect(sync_connection) -> tuple[dict[str, list[list[str]]], list[list[str]]]: + def collect( + sync_connection, + ) -> tuple[ + dict[str, list[list[str]]], + list[list[str]], + list[list[str]], + list[list[str]], + ]: database = inspect(sync_connection) indexes = { table: [index["column_names"] for index in database.get_indexes(table)]