"""Connector registry. Every module under `aiatlas.connectors.*` that defines `CONNECTORS = [cls, …]` is auto-registered. Add a connector: create `aiatlas/connectors//.py` with a `BaseConnector` subclass and list it in the module's `CONNECTORS`. Register its source in `registry/sources.yaml`, then `aia seed` and `aia run `. """ from __future__ import annotations import importlib import logging import pkgutil from functools import lru_cache from aiatlas.sdk.connector import BaseConnector log = logging.getLogger(__name__) @lru_cache def registry() -> dict[str, type[BaseConnector]]: import aiatlas.connectors as pkg found: dict[str, type[BaseConnector]] = {} for mod in pkgutil.walk_packages(pkg.__path__, prefix="aiatlas.connectors."): try: module = importlib.import_module(mod.name) except Exception as exc: # noqa: BLE001 log.error("cannot import connector module", extra={"module_name": mod.name, "error": str(exc)}) continue for cls in getattr(module, "CONNECTORS", []): if not cls.name: raise RuntimeError(f"{cls} has no name") if cls.name in found and found[cls.name] is not cls: raise RuntimeError(f"duplicate connector name {cls.name}") found[cls.name] = cls return dict(sorted(found.items())) def get(name: str, config: dict | None = None) -> BaseConnector: try: cls = registry()[name] except KeyError: raise KeyError(f"unknown connector {name!r}; known: {', '.join(registry())}") from None return cls(config) __all__ = ["get", "registry"]