Tighten provider normalization contract and fallback semantics

This commit is contained in:
Alfredo Di Stasio
2026-03-10 16:47:39 +01:00
parent 2252821daf
commit e0e75cfb0c
11 changed files with 340 additions and 59 deletions

View File

@ -6,6 +6,15 @@ from pathlib import Path
from django.conf import settings
from apps.providers.contracts import (
CompetitionPayload,
NormalizedSyncPayload,
PlayerCareerPayload,
PlayerPayload,
PlayerStatsPayload,
SeasonPayload,
TeamPayload,
)
from apps.providers.exceptions import ProviderRateLimitError, ProviderTransientError
from apps.providers.interfaces import BaseProviderAdapter
@ -50,38 +59,38 @@ class MvpDemoProviderAdapter(BaseProviderAdapter):
value = payload.get(key, [])
return value if isinstance(value, list) else []
def search_players(self, *, query: str = "", limit: int = 50, offset: int = 0) -> list[dict]:
def search_players(self, *, query: str = "", limit: int = 50, offset: int = 0) -> list[PlayerPayload]:
players = self.fetch_players()
if query:
query_lower = query.lower()
players = [p for p in players if query_lower in p.get("full_name", "").lower()]
return players[offset : offset + limit]
def fetch_player(self, *, external_player_id: str) -> dict | None:
def fetch_player(self, *, external_player_id: str) -> PlayerPayload | None:
for payload in self.fetch_players():
if payload.get("external_id") == external_player_id:
return payload
return None
def fetch_players(self) -> list[dict]:
return self._payload_list("players")
def fetch_players(self) -> list[PlayerPayload]:
return self._payload_list("players") # type: ignore[return-value]
def fetch_competitions(self) -> list[dict]:
return self._payload_list("competitions")
def fetch_competitions(self) -> list[CompetitionPayload]:
return self._payload_list("competitions") # type: ignore[return-value]
def fetch_teams(self) -> list[dict]:
return self._payload_list("teams")
def fetch_teams(self) -> list[TeamPayload]:
return self._payload_list("teams") # type: ignore[return-value]
def fetch_seasons(self) -> list[dict]:
return self._payload_list("seasons")
def fetch_seasons(self) -> list[SeasonPayload]:
return self._payload_list("seasons") # type: ignore[return-value]
def fetch_player_stats(self) -> list[dict]:
return self._payload_list("player_stats")
def fetch_player_stats(self) -> list[PlayerStatsPayload]:
return self._payload_list("player_stats") # type: ignore[return-value]
def fetch_player_careers(self) -> list[dict]:
return self._payload_list("player_careers")
def fetch_player_careers(self) -> list[PlayerCareerPayload]:
return self._payload_list("player_careers") # type: ignore[return-value]
def sync_all(self) -> dict:
def sync_all(self) -> NormalizedSyncPayload:
return {
"players": self.fetch_players(),
"competitions": self.fetch_competitions(),
@ -92,7 +101,7 @@ class MvpDemoProviderAdapter(BaseProviderAdapter):
"cursor": None,
}
def sync_incremental(self, *, cursor: str | None = None) -> dict:
def sync_incremental(self, *, cursor: str | None = None) -> NormalizedSyncPayload:
payload = self.sync_all()
# MVP source has no change feed yet; returns full snapshot.
payload["cursor"] = cursor