"""Demo adapters behind the frozen integration Protocols (SPEC §9, #14). `setup()` runs when the package is first imported. Every consumer imports `app.integrations.base`, which initialises this package first, and `app/main.py` is a frozen contract — so the registry is wired before any request or job without a startup hook. Setup only constructs objects: data files and DB sessions are opened lazily on the first call, so importing the package never fails on I/O. Registry after setup: - `prescriptions` — `MisMock`: clinical DB `prescriptions`, then `data/meds/mis_prescriptions.json`; - `identity` — `ConnectCodeIdentity`: one-time connect code from the doctor (ЕСИА stand-in); - `drug_info` — `GrlsExcerpts`: `data/meds/grls/*.yaml`; - `notifier` — `CompositeNotifier`: in-memory dashboard feed + optional Telegram doctor chat; - `outbox` — unchanged `MemoryOutbox` (the web console drains it; the Telegram channel wraps it at start). """ from app.integrations.base import ( EmptyPrescriptions, MemoryNotifier, NoDrugInfo, RejectIdentity, integrations, ) from app.integrations.connect_code import ConnectCodeIdentity from app.integrations.grls import GrlsExcerpts from app.integrations.mis_mock import MisMock from app.integrations.notify import CompositeNotifier, NotificationFeed __all__ = ["CompositeNotifier", "ConnectCodeIdentity", "GrlsExcerpts", "MisMock", "NotificationFeed", "setup"] _done = False def setup(*, force: bool = False) -> None: """Register the demo adapters. Idempotent; never replaces an adapter someone already swapped in (a test fake, the Telegram outbox), only the in-memory defaults from `base.py` — unless `force`.""" global _done if _done and not force: return if force or isinstance(integrations.prescriptions, EmptyPrescriptions): integrations.prescriptions = MisMock() if force or isinstance(integrations.identity, RejectIdentity): integrations.identity = ConnectCodeIdentity() if force or isinstance(integrations.drug_info, NoDrugInfo): integrations.drug_info = GrlsExcerpts() # Exact type check: MemoryNotifier subclasses used as test sinks must stay in place. if force or type(integrations.notifier) is MemoryNotifier: integrations.notifier = CompositeNotifier() _done = True setup()