checking system…
Docs / back / src/maf/sources/base.py · line 46
Python · 78 lines
 1"""Base source abstraction for data adapters."""
 2
 3from __future__ import annotations
 4
 5from abc import ABC, abstractmethod
 6from typing import Any
 7
 8
 9class BaseSource(ABC):
10    """Abstract base for all data source adapters.
11
12    Each adapter wraps a specific data provider (QuestDB, fomo2 stream,
13    web search, etc.) and returns structured data for agent consumption.
14    """
15
16    adapter_name: str = ""
17
18    def __init__(self, config: dict[str, Any]) -> None:
19        self.config = config
20
21    @abstractmethod
22    async def fetch(self, params: dict[str, Any] | None = None) -> dict[str, Any]:
23        """Fetch data from this source.
24
25        Parameters
26        ----------
27        params:
28            Runtime parameters that override/extend the static config.
29            E.g. {"symbols": ["AAPL"], "start": "2024-01-01"}.
30
31        Returns
32        -------
33        Dict with the fetched data. Structure depends on adapter type.
34        """
35        ...
36
37    async def check_health(self) -> bool:
38        """Check if this source is available."""
39        try:
40            await self.fetch()
41            return True
42        except Exception:
43            return False
44
45    @classmethod
46    def freshness_spec(cls, binding_config: dict[str, Any]) -> dict[str, Any]:
47        """Declare where this adapter's data lives so the dashboard can
48        render a "live · stale · empty" badge next to each binding.
49
50        Subclasses override this to point at the Redis stream/key they
51        consume. The default ``{"type": "unknown"}`` keeps the dashboard
52        honest — badges will say "unknown" rather than fabricating an age.
53
54        Supported types:
55            * ``stream``           — single Redis Stream; report XLEN + last-id age.
56                Required key: ``stream`` (str).
57            * ``key``              — one or more Redis string keys (TTL'd cache).
58                Required key: ``key_pattern`` (str, may contain {placeholders}).
59                Optional: ``emit_stream`` (str) — gives an accurate "last refreshed" age.
60            * ``scan``             — pattern scan only; reports key count.
61                Required key: ``scan_pattern``.
62                Optional: ``emit_stream``.
63            * ``external``         — external HTTP/SQL, no caching.
64                Optional key: ``detail`` (str) — shown in tooltip.
65            * ``request_response`` — round-trips through a Redis Stream.
66                Required key: ``out_stream``.
67            * ``unknown``          — default; dashboard renders "unknown".
68
69        Placeholders in ``key_pattern`` / ``stream`` / ``scan_pattern`` are
70        resolved against ``binding_config`` (e.g. ``"trtools2:bars:{timeframe}"``).
71
72        Implementations must be cheap — this runs on every Setup-tab poll.
73        """
74        return {"type": "unknown"}
75
76    def __repr__(self) -> str:
77        return f"<{self.__class__.__name__} adapter={self.adapter_name!r}>"