Files
rose-ash/shared/services/registry.py
giles 382d1b7c7a
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m20s
Decouple blog models and BlogService from shared layer
Move Post/Author/Tag/PostAuthor/PostTag/PostUser models from
shared/models/ghost_content.py to blog/models/content.py so blog-domain
models no longer live in the shared layer. Replace the shared
SqlBlogService + BlogService protocol with a blog-local singleton
(blog_service), and switch entry_associations.py from direct DB access
to HTTP fetch_data("blog", "post-by-id") to respect the inter-service
boundary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:28:11 +00:00

92 lines
2.9 KiB
Python

"""Typed singleton registry for domain services.
Each app registers ONLY its own domain service. Cross-app calls go
over HTTP via ``call_action()`` (writes) and ``fetch_data()`` (reads).
Usage::
from shared.services.registry import services
# Register at app startup (own domain only)
services.calendar = SqlCalendarService()
# Use locally within the owning app
cals = await services.calendar.calendars_for_container(session, "page", page_id)
"""
from __future__ import annotations
from shared.contracts.protocols import (
CalendarService,
MarketService,
CartService,
FederationService,
)
class _ServiceRegistry:
"""Central registry holding one implementation per domain.
Properties return the registered implementation or raise
``RuntimeError`` if nothing is registered. Use ``has(name)``
to check before access when the domain might be absent.
"""
def __init__(self) -> None:
self._calendar: CalendarService | None = None
self._market: MarketService | None = None
self._cart: CartService | None = None
self._federation: FederationService | None = None
# -- calendar -------------------------------------------------------------
@property
def calendar(self) -> CalendarService:
if self._calendar is None:
raise RuntimeError("CalendarService not registered")
return self._calendar
@calendar.setter
def calendar(self, impl: CalendarService) -> None:
self._calendar = impl
# -- market ---------------------------------------------------------------
@property
def market(self) -> MarketService:
if self._market is None:
raise RuntimeError("MarketService not registered")
return self._market
@market.setter
def market(self, impl: MarketService) -> None:
self._market = impl
# -- cart -----------------------------------------------------------------
@property
def cart(self) -> CartService:
if self._cart is None:
raise RuntimeError("CartService not registered")
return self._cart
@cart.setter
def cart(self, impl: CartService) -> None:
self._cart = impl
# -- federation -----------------------------------------------------------
@property
def federation(self) -> FederationService:
if self._federation is None:
raise RuntimeError("FederationService not registered")
return self._federation
@federation.setter
def federation(self, impl: FederationService) -> None:
self._federation = impl
# -- introspection --------------------------------------------------------
def has(self, name: str) -> bool:
"""Check whether a domain service is registered."""
return getattr(self, f"_{name}", None) is not None
# Module-level singleton — import this everywhere.
services = _ServiceRegistry()