from __future__ import annotations from abc import ABC, abstractmethod from typing import Any class AdapterError(RuntimeError): pass class MarketAdapter(ABC): """Uniform adapter: probe / fetch / normalize. Realtime adapters may be stubs in P0.""" name: str = "base" @abstractmethod def probe(self) -> dict[str, Any]: """Liveness check. Must not leak credentials.""" @abstractmethod def fetch(self, dataset: str, params: dict[str, Any]) -> list[dict[str, Any]]: """Return provider-native rows (pre-canonical).""" @abstractmethod def normalize(self, dataset: str, rows: list[dict[str, Any]]) -> list[dict[str, Any]]: """Map provider-native rows onto hub canonical fields.""" class ReservedAdapter(MarketAdapter): """Placeholder for a later free/licensed source. Does not pull data in P0.""" def __init__(self, name: str) -> None: self.name = name def probe(self) -> dict[str, Any]: return { "provider": self.name, "configured": False, "state": "reserved", "message": "适配器位已预留,本阶段不接入", } def fetch(self, dataset: str, params: dict[str, Any]) -> list[dict[str, Any]]: raise AdapterError(f"{self.name} 适配器本阶段未接入") def normalize(self, dataset: str, rows: list[dict[str, Any]]) -> list[dict[str, Any]]: return []