Files
romm/backend/handler/streaming/background.py
T
Sam DornanandClaude Opus 5.5 5a6c895d33 chore(mypy): give every generic its type arguments (#4818)
* chore(mypy): switch to strict mode with listed exceptions

Replace the hand-picked flags with `strict = True`, turning off only the
four flags that aren't clean yet (disallow_any_generics,
warn_return_any, disallow_untyped_calls, disallow_untyped_decorators).
Any other strict flag, including those future mypy releases add to the
preset, is on by default.

That turns on no_implicit_reexport, strict_equality and extra_checks:
- Import each name from the module that defines it. About 240 test
  sites patched a dependency through the module that imported it
  (`scan_module.fs_rom_handler`); they now import the same object from
  its source, so every patch targets what it did before. Tests that
  replace a module attribute are unchanged.
- handler.streaming.memory_cards re-exports store_memory_card_version
  explicitly, since endpoints call it there and tests patch it there.
- mutagen gets implicit_reexport, as it re-exports without __all__.
- Test comparisons build typed values (CoverResult, a typed expected
  dict, enum .value) and the CORS lookup casts for its identity check.
- One ss_handler ** spread keeps a coded ignore: extra_checks wants its
  NotRequired dump_* keys spelled out, and the media dict never has them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PLzXae5up2pYXRoBjfjn2G

* chore(mypy): give every generic its type arguments

Drop disallow_any_generics from the strict-mode exceptions and fix the
347 bare generics it reports, 230 of them in app code.

- Bare `dict` becomes `dict[str, Any]`: update payloads, raw provider
  JSON and endpoint bodies map string keys to mixed values, so the Any is
  real and now written down. The OpenAPI document is unchanged.
- Rom query filters take and return RomSelect; _music_facet_joins and
  _exclude_hidden are generic over the Select they're given, and
  _build_hash_selects returns id-only selects.
- Redis clients are typed by what they return: the decoding caches are
  Redis[str], the RQ connection and binary cache Redis[bytes].
- The rest get explicit parameters: Row, Pattern, ColumnElement,
  QueryableAttribute, SpooledTemporaryFile, Task, Future and friends.

Precise types reached callers that had been getting Any, which surfaced:
- The LaunchBox cache writer is fed binary-cache pipelines.
- The flashpoint and IGDB request helpers return raw JSON of varying
  shape, not always a dict.
- The rom search endpoint returned dicts under a list[SearchRomSchema]
  annotation; it now validates them into that schema.
- The audit filter's id subquery selects strings.
- In tests the binary cache is the non-decoding fake shared with
  async_cache, so it is cast to Redis[bytes] rather than changed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PLzXae5up2pYXRoBjfjn2G

* test(upload): assert cleanup against the patched upload directory

The 409 test checked config's ROM_UPLOAD_TMP_BASE while the fixture patches
the endpoint's copy to tmp_path/uploads, so it passed even if cleanup failed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PLzXae5up2pYXRoBjfjn2G

* chore(mypy): keep the row type through the ROM filter helpers

filter_roms and its helpers also receive select(Rom.id) membership queries,
so they now take and return the caller's Select type instead of narrowing to
RomSelect. merged_ra_metadata mixes scalar and list values.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01PLzXae5up2pYXRoBjfjn2G

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-09-26 16:32:29 -05:00

11 lines
254 B
Python

"""Fire-and-forget sync tasks, held so the event loop keeps them alive."""
import asyncio
from typing import Any
from utils.background_tasks import fire_and_forget
def spawn_sync_task(coro: Any) -> asyncio.Task[Any]:
return fire_and_forget(coro)