fix(dispatch): resolve native ingester class at call time (test monkeypatch)
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 19s
CI / backend-lint-and-test (push) Successful in 34s
CI / integration (push) Successful in 3m22s

The _NATIVE_INGESTERS dict captured PatreonIngester/SubscribeStarIngester at
import, so test_download_service's monkeypatch.setattr(db_mod, "PatreonIngester",
_FakeIngester) no longer affected dispatch → the fake's run() never ran →
KeyError 'campaign_id' on empty run_kwargs (integration run 1215). Replace the
dict with a _native_ingester_cls() call-time lookup that reads the module globals,
so monkeypatching the class names works again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 12:09:40 -04:00
parent d8d8ecd78f
commit d526447496
+13 -9
View File
@@ -34,18 +34,22 @@ from .subscribestar_ingester import SubscribeStarIngester
# deviantart) until they migrate too.
NATIVE_INGESTER_PLATFORMS = frozenset({"patreon", "subscribestar"})
# Native ingester classes keyed by platform (uniform constructor signature, so
# _run_native_ingester / preview build whichever the source needs).
_NATIVE_INGESTERS = {
"patreon": PatreonIngester,
"subscribestar": SubscribeStarIngester,
}
# Mirrors patreon_resolver._CAMPAIGNS_URL — surfaced in resolution-failure
# messages so the operator sees the exact lookup endpoint that was hit.
_CAMPAIGNS_API = "https://www.patreon.com/api/campaigns"
def _native_ingester_cls(platform: str):
"""The native ingester class for `platform` (uniform constructor signature).
A call-time lookup (not a module-level dict captured at import) so tests can
monkeypatch db_mod.PatreonIngester / SubscribeStarIngester and have the
dispatch pick up the replacement."""
return {
"patreon": PatreonIngester,
"subscribestar": SubscribeStarIngester,
}[platform]
def uses_native_ingester(platform: str) -> bool:
"""True when `platform` is served by the native ingester (not gallery-dl).
The single predicate the download path and verify both route on."""
@@ -150,7 +154,7 @@ async def _run_native_ingester(
if source_config.sleep_request is not None
else max(0.5, rate_limit / 4)
)
ingester = _NATIVE_INGESTERS[platform](
ingester = _native_ingester_cls(platform)(
images_root=gdl.images_root,
cookies_path=ctx["cookies_path"],
session_factory=sync_session_factory,
@@ -209,7 +213,7 @@ async def preview_source(
"(cookies expired, or the creator moved/renamed?)."
)
}
ingester = _NATIVE_INGESTERS[platform](
ingester = _native_ingester_cls(platform)(
images_root=images_root,
cookies_path=cookies_path,
session_factory=sync_session_factory,