Python 49.6%
TypeScript 25.5%
CSS 24.1%
1# -----------------------------------------------------------------------------2# Home-Ka — US real-estate aggregator (Groupe KA)3# Author: Simon-Pierre Boucher — contact@spboucher.ai4# connectors/__init__.py : AUTO-DISCOVERING connector registry (recursive).5#6# Same principle as immo-ka, extended with connector FAMILIES:7# - FAMILIES: {"reso": RESOConnector, "xml": XMLFeedConnector, ...}8# generic config-driven classes (class attribute `family`), instantiated9# per source from the `sources` table — a new source of a known family10# is a DB row, zero code.11# - CUSTOM: {"acme_realty": AcmeRealtyConnector, ...}12# one-site classes (class attribute `source_id`), like immo-ka.13# Every module under this package (subpackages included) is imported; a broken14# connector never blocks the others.15# -----------------------------------------------------------------------------16from __future__ import annotations1718import importlib19import pkgutil20import sys2122from .base import BaseConnector2324FAMILIES: dict[str, type[BaseConnector]] = {}25CUSTOM: dict[str, type[BaseConnector]] = {}262728def _register(module) -> None:29 for obj in vars(module).values():30 if not (isinstance(obj, type) and issubclass(obj, BaseConnector)31 and obj is not BaseConnector):32 continue33 fam = getattr(obj, "family", "")34 sid = getattr(obj, "source_id", "")35 if fam and obj.__dict__.get("family"):36 FAMILIES[fam] = obj37 if sid and obj.__dict__.get("source_id"):38 CUSTOM[sid] = obj394041def _walk(package_name: str, path) -> None:42 for mod in pkgutil.iter_modules(path):43 if mod.name in ("base", "__init__"):44 continue45 full = f"{package_name}.{mod.name}"46 try:47 module = importlib.import_module(full)48 except Exception as exc: # a broken connector never blocks the others49 print(f"[home-ka] connector '{full}' skipped: {exc}", file=sys.stderr)50 continue51 _register(module)52 if mod.ispkg:53 _walk(full, module.__path__)545556_walk(__name__, __path__)575859def build(source_id: str, connector_type: str,60 config: dict | None = None) -> BaseConnector | None:61 """Instantiate the connector for a `sources` row (or a custom class)."""62 if source_id in CUSTOM:63 return CUSTOM[source_id]()64 cls = FAMILIES.get(connector_type)65 if cls is None:66 return None67 return cls(source_id, config or {})68