refactor: move in-function imports to top-level and remove keyword-only argument pattern

- Move imports from inside functions to module top-level in:
  - app/assets/database/queries/asset.py
  - app/assets/database/queries/asset_info.py
  - app/assets/database/queries/cache_state.py
  - app/assets/manager.py
  - app/assets/services/asset_management.py
  - app/assets/services/ingest.py

- Remove keyword-only argument markers (*,) from app/assets/ to match codebase conventions

Amp-Thread-ID: https://ampcode.com/threads/T-019c24eb-bfa2-727f-8212-8bc976048604
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Luke Mino-Altherr 2026-02-03 11:18:28 -08:00
parent 15ee03f65c
commit fba4570e49
10 changed files with 12 additions and 56 deletions

View File

@ -27,7 +27,6 @@ def _rows_per_stmt(cols: int) -> int:
def seed_from_paths_batch( def seed_from_paths_batch(
session: Session, session: Session,
*,
specs: list[dict], specs: list[dict],
owner_id: str = "", owner_id: str = "",
) -> dict: ) -> dict:
@ -177,7 +176,6 @@ def seed_from_paths_batch(
def bulk_insert_tags_and_meta( def bulk_insert_tags_and_meta(
session: Session, session: Session,
*,
tag_rows: list[dict], tag_rows: list[dict],
meta_rows: list[dict], meta_rows: list[dict],
max_bind_params: int, max_bind_params: int,

View File

@ -1,5 +1,6 @@
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.dialects import sqlite
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.assets.database.models import Asset from app.assets.database.models import Asset
@ -7,7 +8,6 @@ from app.assets.database.models import Asset
def asset_exists_by_hash( def asset_exists_by_hash(
session: Session, session: Session,
*,
asset_hash: str, asset_hash: str,
) -> bool: ) -> bool:
""" """
@ -23,7 +23,6 @@ def asset_exists_by_hash(
def get_asset_by_hash( def get_asset_by_hash(
session: Session, session: Session,
*,
asset_hash: str, asset_hash: str,
) -> Asset | None: ) -> Asset | None:
return ( return (
@ -33,14 +32,11 @@ def get_asset_by_hash(
def upsert_asset( def upsert_asset(
session: Session, session: Session,
*,
asset_hash: str, asset_hash: str,
size_bytes: int, size_bytes: int,
mime_type: str | None = None, mime_type: str | None = None,
) -> tuple[Asset, bool, bool]: ) -> tuple[Asset, bool, bool]:
"""Upsert an Asset by hash. Returns (asset, created, updated).""" """Upsert an Asset by hash. Returns (asset, created, updated)."""
from sqlalchemy.dialects import sqlite
vals = {"hash": asset_hash, "size_bytes": int(size_bytes)} vals = {"hash": asset_hash, "size_bytes": int(size_bytes)}
if mime_type: if mime_type:
vals["mime_type"] = mime_type vals["mime_type"] = mime_type

View File

@ -6,6 +6,7 @@ no filesystem operations, no orchestration across multiple tables.
""" """
from collections import defaultdict from collections import defaultdict
from datetime import datetime from datetime import datetime
from decimal import Decimal
from typing import Sequence from typing import Sequence
import sqlalchemy as sa import sqlalchemy as sa
@ -90,7 +91,6 @@ def _apply_metadata_filter(
if isinstance(value, bool): if isinstance(value, bool):
return _exists_for_pred(key, AssetInfoMeta.val_bool == bool(value)) return _exists_for_pred(key, AssetInfoMeta.val_bool == bool(value))
if isinstance(value, (int, float)): if isinstance(value, (int, float)):
from decimal import Decimal
num = value if isinstance(value, Decimal) else Decimal(str(value)) num = value if isinstance(value, Decimal) else Decimal(str(value))
return _exists_for_pred(key, AssetInfoMeta.val_num == num) return _exists_for_pred(key, AssetInfoMeta.val_num == num)
if isinstance(value, str): if isinstance(value, str):
@ -109,7 +109,6 @@ def _apply_metadata_filter(
def asset_info_exists_for_asset_id( def asset_info_exists_for_asset_id(
session: Session, session: Session,
*,
asset_id: str, asset_id: str,
) -> bool: ) -> bool:
q = ( q = (
@ -123,7 +122,6 @@ def asset_info_exists_for_asset_id(
def get_asset_info_by_id( def get_asset_info_by_id(
session: Session, session: Session,
*,
asset_info_id: str, asset_info_id: str,
) -> AssetInfo | None: ) -> AssetInfo | None:
return session.get(AssetInfo, asset_info_id) return session.get(AssetInfo, asset_info_id)
@ -131,7 +129,6 @@ def get_asset_info_by_id(
def insert_asset_info( def insert_asset_info(
session: Session, session: Session,
*,
asset_id: str, asset_id: str,
owner_id: str, owner_id: str,
name: str, name: str,
@ -159,7 +156,6 @@ def insert_asset_info(
def get_or_create_asset_info( def get_or_create_asset_info(
session: Session, session: Session,
*,
asset_id: str, asset_id: str,
owner_id: str, owner_id: str,
name: str, name: str,
@ -192,7 +188,6 @@ def get_or_create_asset_info(
def update_asset_info_timestamps( def update_asset_info_timestamps(
session: Session, session: Session,
*,
asset_info: AssetInfo, asset_info: AssetInfo,
preview_id: str | None = None, preview_id: str | None = None,
) -> None: ) -> None:
@ -311,7 +306,6 @@ def fetch_asset_info_asset_and_tags(
def fetch_asset_info_and_asset( def fetch_asset_info_and_asset(
session: Session, session: Session,
*,
asset_info_id: str, asset_info_id: str,
owner_id: str = "", owner_id: str = "",
) -> tuple[AssetInfo, Asset] | None: ) -> tuple[AssetInfo, Asset] | None:
@ -334,7 +328,6 @@ def fetch_asset_info_and_asset(
def touch_asset_info_by_id( def touch_asset_info_by_id(
session: Session, session: Session,
*,
asset_info_id: str, asset_info_id: str,
ts: datetime | None = None, ts: datetime | None = None,
only_if_newer: bool = True, only_if_newer: bool = True,
@ -350,7 +343,6 @@ def touch_asset_info_by_id(
def replace_asset_info_metadata_projection( def replace_asset_info_metadata_projection(
session: Session, session: Session,
*,
asset_info_id: str, asset_info_id: str,
user_metadata: dict | None = None, user_metadata: dict | None = None,
) -> None: ) -> None:
@ -389,7 +381,6 @@ def replace_asset_info_metadata_projection(
def delete_asset_info_by_id( def delete_asset_info_by_id(
session: Session, session: Session,
*,
asset_info_id: str, asset_info_id: str,
owner_id: str, owner_id: str,
) -> bool: ) -> bool:
@ -402,7 +393,6 @@ def delete_asset_info_by_id(
def set_asset_info_preview( def set_asset_info_preview(
session: Session, session: Session,
*,
asset_info_id: str, asset_info_id: str,
preview_asset_id: str | None = None, preview_asset_id: str | None = None,
) -> None: ) -> None:

View File

@ -1,8 +1,10 @@
import contextlib
import os import os
from typing import Sequence from typing import Sequence
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.dialects import sqlite
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.assets.database.models import Asset, AssetCacheState, AssetInfo from app.assets.database.models import Asset, AssetCacheState, AssetInfo
@ -23,14 +25,11 @@ def list_cache_states_by_asset_id(
def upsert_cache_state( def upsert_cache_state(
session: Session, session: Session,
*,
asset_id: str, asset_id: str,
file_path: str, file_path: str,
mtime_ns: int, mtime_ns: int,
) -> tuple[bool, bool]: ) -> tuple[bool, bool]:
"""Upsert a cache state by file_path. Returns (created, updated).""" """Upsert a cache state by file_path. Returns (created, updated)."""
from sqlalchemy.dialects import sqlite
vals = { vals = {
"asset_id": asset_id, "asset_id": asset_id,
"file_path": file_path, "file_path": file_path,
@ -101,7 +100,6 @@ def prune_orphaned_assets(session: Session, roots: tuple[str, ...], prefixes_for
def fast_db_consistency_pass( def fast_db_consistency_pass(
session: Session, session: Session,
root: str, root: str,
*,
prefixes_for_root_fn, prefixes_for_root_fn,
escape_like_prefix_fn, escape_like_prefix_fn,
fast_asset_file_check_fn, fast_asset_file_check_fn,
@ -117,8 +115,6 @@ def fast_db_consistency_pass(
- Optionally add/remove 'missing' tags based on fast-ok in this root - Optionally add/remove 'missing' tags based on fast-ok in this root
- Optionally return surviving absolute paths - Optionally return surviving absolute paths
""" """
import contextlib
prefixes = prefixes_for_root_fn(root) prefixes = prefixes_for_root_fn(root)
if not prefixes: if not prefixes:
return set() if collect_existing_paths else None return set() if collect_existing_paths else None

View File

@ -31,7 +31,7 @@ def ensure_tags_exist(session: Session, names: Iterable[str], tag_type: str = "u
session.execute(ins) session.execute(ins)
def get_asset_tags(session: Session, *, asset_info_id: str) -> list[str]: def get_asset_tags(session: Session, asset_info_id: str) -> list[str]:
return [ return [
tag_name for (tag_name,) in ( tag_name for (tag_name,) in (
session.execute( session.execute(
@ -43,7 +43,6 @@ def get_asset_tags(session: Session, *, asset_info_id: str) -> list[str]:
def set_asset_info_tags( def set_asset_info_tags(
session: Session, session: Session,
*,
asset_info_id: str, asset_info_id: str,
tags: Sequence[str], tags: Sequence[str],
origin: str = "manual", origin: str = "manual",
@ -79,7 +78,6 @@ def set_asset_info_tags(
def add_tags_to_asset_info( def add_tags_to_asset_info(
session: Session, session: Session,
*,
asset_info_id: str, asset_info_id: str,
tags: Sequence[str], tags: Sequence[str],
origin: str = "manual", origin: str = "manual",
@ -139,7 +137,6 @@ def add_tags_to_asset_info(
def remove_tags_from_asset_info( def remove_tags_from_asset_info(
session: Session, session: Session,
*,
asset_info_id: str, asset_info_id: str,
tags: Sequence[str], tags: Sequence[str],
) -> dict: ) -> dict:
@ -180,7 +177,6 @@ def remove_tags_from_asset_info(
def add_missing_tag_for_asset_id( def add_missing_tag_for_asset_id(
session: Session, session: Session,
*,
asset_id: str, asset_id: str,
origin: str = "automatic", origin: str = "automatic",
) -> None: ) -> None:
@ -210,7 +206,6 @@ def add_missing_tag_for_asset_id(
def remove_missing_tag_for_asset_id( def remove_missing_tag_for_asset_id(
session: Session, session: Session,
*,
asset_id: str, asset_id: str,
) -> None: ) -> None:
session.execute( session.execute(

View File

@ -71,7 +71,6 @@ def escape_like_prefix(s: str, escape: str = "!") -> tuple[str, str]:
return s, escape return s, escape
def fast_asset_file_check( def fast_asset_file_check(
*,
mtime_db: int | None, mtime_db: int | None,
size_db: int | None, size_db: int | None,
stat_result: os.stat_result, stat_result: os.stat_result,

View File

@ -12,6 +12,7 @@ import mimetypes
import contextlib import contextlib
from typing import Sequence from typing import Sequence
import app.assets.hashing as hashing
from app.database.db import create_session from app.database.db import create_session
from app.assets.api import schemas_out, schemas_in from app.assets.api import schemas_out, schemas_in
from app.assets.database.queries import ( from app.assets.database.queries import (
@ -64,13 +65,12 @@ def _safe_filename(name: str | None, fallback: str) -> str:
return fallback return fallback
def asset_exists(*, asset_hash: str) -> bool: def asset_exists(asset_hash: str) -> bool:
with create_session() as session: with create_session() as session:
return asset_exists_by_hash(session, asset_hash=asset_hash) return asset_exists_by_hash(session, asset_hash=asset_hash)
def list_assets( def list_assets(
*,
include_tags: Sequence[str] | None = None, include_tags: Sequence[str] | None = None,
exclude_tags: Sequence[str] | None = None, exclude_tags: Sequence[str] | None = None,
name_contains: str | None = None, name_contains: str | None = None,
@ -124,7 +124,6 @@ def list_assets(
def get_asset( def get_asset(
*,
asset_info_id: str, asset_info_id: str,
owner_id: str = "", owner_id: str = "",
) -> schemas_out.AssetDetail: ) -> schemas_out.AssetDetail:
@ -151,7 +150,6 @@ def get_asset(
def resolve_asset_content_for_download( def resolve_asset_content_for_download(
*,
asset_info_id: str, asset_info_id: str,
owner_id: str = "", owner_id: str = "",
) -> tuple[str, str, str]: ) -> tuple[str, str, str]:
@ -176,14 +174,12 @@ def resolve_asset_content_for_download(
def upload_asset_from_temp_path( def upload_asset_from_temp_path(
spec: schemas_in.UploadAssetSpec, spec: schemas_in.UploadAssetSpec,
*,
temp_path: str, temp_path: str,
client_filename: str | None = None, client_filename: str | None = None,
owner_id: str = "", owner_id: str = "",
expected_asset_hash: str | None = None, expected_asset_hash: str | None = None,
) -> schemas_out.AssetCreated: ) -> schemas_out.AssetCreated:
try: try:
import app.assets.hashing as hashing
digest = hashing.blake3_hash(temp_path) digest = hashing.blake3_hash(temp_path)
except Exception as e: except Exception as e:
raise RuntimeError(f"failed to hash uploaded file: {e}") raise RuntimeError(f"failed to hash uploaded file: {e}")
@ -297,7 +293,6 @@ def upload_asset_from_temp_path(
def update_asset( def update_asset(
*,
asset_info_id: str, asset_info_id: str,
name: str | None = None, name: str | None = None,
tags: list[str] | None = None, tags: list[str] | None = None,
@ -327,7 +322,6 @@ def update_asset(
def set_asset_preview( def set_asset_preview(
*,
asset_info_id: str, asset_info_id: str,
preview_asset_id: str | None = None, preview_asset_id: str | None = None,
owner_id: str = "", owner_id: str = "",
@ -355,7 +349,7 @@ def set_asset_preview(
) )
def delete_asset_reference(*, asset_info_id: str, owner_id: str, delete_content_if_orphan: bool = True) -> bool: def delete_asset_reference(asset_info_id: str, owner_id: str, delete_content_if_orphan: bool = True) -> bool:
return svc_delete_asset_reference( return svc_delete_asset_reference(
asset_info_id=asset_info_id, asset_info_id=asset_info_id,
owner_id=owner_id, owner_id=owner_id,
@ -364,7 +358,6 @@ def delete_asset_reference(*, asset_info_id: str, owner_id: str, delete_content_
def create_asset_from_hash( def create_asset_from_hash(
*,
hash_str: str, hash_str: str,
name: str, name: str,
tags: list[str] | None = None, tags: list[str] | None = None,
@ -406,7 +399,6 @@ def create_asset_from_hash(
def add_tags_to_asset( def add_tags_to_asset(
*,
asset_info_id: str, asset_info_id: str,
tags: list[str], tags: list[str],
origin: str = "manual", origin: str = "manual",
@ -422,7 +414,6 @@ def add_tags_to_asset(
def remove_tags_from_asset( def remove_tags_from_asset(
*,
asset_info_id: str, asset_info_id: str,
tags: list[str], tags: list[str],
owner_id: str = "", owner_id: str = "",

View File

@ -11,6 +11,7 @@ import contextlib
import os import os
from typing import Sequence from typing import Sequence
from app.assets.database.models import Asset
from app.database.db import create_session from app.database.db import create_session
from app.assets.helpers import ( from app.assets.helpers import (
compute_relative_filename, compute_relative_filename,
@ -31,7 +32,6 @@ from app.assets.database.queries import (
def get_asset_detail( def get_asset_detail(
*,
asset_info_id: str, asset_info_id: str,
owner_id: str = "", owner_id: str = "",
) -> dict | None: ) -> dict | None:
@ -57,7 +57,6 @@ def get_asset_detail(
def update_asset_metadata( def update_asset_metadata(
*,
asset_info_id: str, asset_info_id: str,
name: str | None = None, name: str | None = None,
tags: Sequence[str] | None = None, tags: Sequence[str] | None = None,
@ -136,7 +135,6 @@ def update_asset_metadata(
def delete_asset_reference( def delete_asset_reference(
*,
asset_info_id: str, asset_info_id: str,
owner_id: str, owner_id: str,
delete_content_if_orphan: bool = True, delete_content_if_orphan: bool = True,
@ -168,7 +166,6 @@ def delete_asset_reference(
states = list_cache_states_by_asset_id(session, asset_id=asset_id) states = list_cache_states_by_asset_id(session, asset_id=asset_id)
file_paths = [s.file_path for s in (states or []) if getattr(s, "file_path", None)] file_paths = [s.file_path for s in (states or []) if getattr(s, "file_path", None)]
from app.assets.database.models import Asset
asset_row = session.get(Asset, asset_id) asset_row = session.get(Asset, asset_id)
if asset_row is not None: if asset_row is not None:
session.delete(asset_row) session.delete(asset_row)
@ -185,7 +182,6 @@ def delete_asset_reference(
def set_asset_preview( def set_asset_preview(
*,
asset_info_id: str, asset_info_id: str,
preview_asset_id: str | None = None, preview_asset_id: str | None = None,
owner_id: str = "", owner_id: str = "",

View File

@ -9,6 +9,9 @@ import logging
import os import os
from typing import Sequence from typing import Sequence
from sqlalchemy import select
from app.assets.database.models import Asset, Tag
from app.database.db import create_session from app.database.db import create_session
from app.assets.helpers import ( from app.assets.helpers import (
compute_relative_filename, compute_relative_filename,
@ -33,7 +36,6 @@ from app.assets.database.queries import (
def ingest_file_from_path( def ingest_file_from_path(
*,
abs_path: str, abs_path: str,
asset_hash: str, asset_hash: str,
size_bytes: int, size_bytes: int,
@ -67,7 +69,6 @@ def ingest_file_from_path(
with create_session() as session: with create_session() as session:
# Validate preview_id if provided # Validate preview_id if provided
if preview_id: if preview_id:
from app.assets.database.models import Asset
if not session.get(Asset, preview_id): if not session.get(Asset, preview_id):
preview_id = None preview_id = None
@ -141,7 +142,6 @@ def ingest_file_from_path(
def register_existing_asset( def register_existing_asset(
*,
asset_hash: str, asset_hash: str,
name: str, name: str,
user_metadata: dict | None = None, user_metadata: dict | None = None,
@ -212,8 +212,6 @@ def register_existing_asset(
def _validate_tags_exist(session, tags: list[str]) -> None: def _validate_tags_exist(session, tags: list[str]) -> None:
"""Raise ValueError if any tags don't exist.""" """Raise ValueError if any tags don't exist."""
from sqlalchemy import select
from app.assets.database.models import Tag
existing_tag_names = set( existing_tag_names = set(
name for (name,) in session.execute(select(Tag.name).where(Tag.name.in_(tags))).all() name for (name,) in session.execute(select(Tag.name).where(Tag.name.in_(tags))).all()
) )
@ -230,7 +228,6 @@ def _compute_filename_for_asset(session, asset_id: str) -> str | None:
def _update_metadata_with_filename( def _update_metadata_with_filename(
session, session,
*,
asset_info_id: str, asset_info_id: str,
asset_id: str, asset_id: str,
info, info,

View File

@ -16,7 +16,6 @@ from app.assets.database.queries import (
def apply_tags( def apply_tags(
*,
asset_info_id: str, asset_info_id: str,
tags: list[str], tags: list[str],
origin: str = "manual", origin: str = "manual",
@ -47,7 +46,6 @@ def apply_tags(
def remove_tags( def remove_tags(
*,
asset_info_id: str, asset_info_id: str,
tags: list[str], tags: list[str],
owner_id: str = "", owner_id: str = "",