"""Canonical registry slot for the wizard-flow catalogue.Domain modules that need to inspect ``SETUP_FLOW`` or ``WIZARD_FLOWS``import from here, never from ``application.wizard._catalogue``. Thismodule is the core slot that holds already-built descriptors; it does not buildwizard sections, render prompts, compile profile keys, persist answers, orown the :mod:`core.setup_answers` typed answer model.The application layer registers the concrete descriptors at startup via:func:`register_wizard_catalogue`. Until registration, the accessors:func:`get_setup_flow` and :func:`get_wizard_flows` raise:class:`WizardCatalogueNotRegisteredError` so any premature domain accesssurfaces immediately rather than silently falling back to an upward dependency.The protocol this module defines (:class:`WizardFlowProtocol`) is satisfied by:class:`application.wizard._models.WizardFlow`. Domain code depends only on thestructural slot and the accessor functions; the concrete descriptor class staysowned by the application wizard package."""from__future__importannotationsfromtypingimportAny,Protocol,runtime_checkablefrom.errorsimportCoreErrorfrom.loggingimportget_logger_log=get_logger(__name__)
[docs]classWizardCatalogueNotRegisteredError(CoreError):"""Raised when a domain consumer accesses the catalogue before registration."""def__init__(self)->None:"""Initialise with a fixed message directing the caller to register the catalogue."""super().__init__("Wizard catalogue has not been registered. ""Call register_wizard_catalogue() at application startup before ""any domain module accesses SETUP_FLOW or WIZARD_FLOWS.",)
[docs]classWizardCatalogueAlreadyRegisteredError(CoreError):"""Raised when :func:`register_wizard_catalogue` receives different objects after registration."""
[docs]@runtime_checkableclassWizardFlowProtocol(Protocol):"""Structural type satisfied by WizardFlow descriptors. The protocol captures the smallest attribute core consumers need for diagnostics. Accessors still return the concrete descriptor object, but domain code reaches it through this core slot and never imports the application-layer ``WizardFlow`` class directly. """@propertydefid(self)->str:"""The canonical flow identifier (e.g. ``"setup"``)."""...# pragma: no cover
# Module-level registry slot: a list is used so the presence check is# a single ``if _SETUP_FLOW_SLOT`` rather than ``if _SETUP_FLOW_SLOT[0] is not None``._SETUP_FLOW_SLOT:list[Any]=[]_WIZARD_FLOWS_SLOT:list[tuple[Any,...]]=[]# KWARGS-ANY-RATIONALE-CATALOGUE-WIZARD-FLOW-CIRCULAR:# Same circular-import rationale as core/profile.py KWARGS-ANY markers.
[docs]defregister_wizard_catalogue(setup_flow:Any,wizard_flows:tuple[Any,...],)->None:"""Register the concrete wizard-flow descriptors from the application layer. Call this exactly once at application startup (e.g. in the ``application.wizard._catalogue`` module body, after the ``SETUP_FLOW`` / ``WIZARD_FLOWS`` constants are built). Calling with identical objects a second time is a no-op. Calling with *different* objects raises :class:`WizardCatalogueAlreadyRegisteredError` to prevent accidental re-registration from a different source. The function stores object identity only; it does not copy, validate, or normalise the application-owned descriptors. """if_SETUP_FLOW_SLOT:if_SETUP_FLOW_SLOT[0]issetup_flowand_WIZARD_FLOWS_SLOT[0]iswizard_flows:returnraiseWizardCatalogueAlreadyRegisteredError("register_wizard_catalogue() called a second time with different objects. ""The catalogue must be registered exactly once.",)_SETUP_FLOW_SLOT.append(setup_flow)_WIZARD_FLOWS_SLOT.append(wizard_flows)_log.debug("wizard catalogue registered: setup_flow=%r flows=%d",setup_flow.id,len(wizard_flows))
# ANY-RETURN-RATIONALE-CATALOGUE-SLOT:# Concrete wizard-flow type registered at runtime; not importable from aeat.core# without circular import.
[docs]defget_setup_flow()->Any:# ANY-RETURN-RATIONALE-CATALOGUE-SLOT"""Return the registered ``SETUP_FLOW`` descriptor. Returns: The concrete ``SETUP_FLOW`` descriptor registered by the application layer. Callers should treat it as the canonical setup-flow descriptor and should not import ``application.wizard._catalogue`` as a fallback. Raises: WizardCatalogueNotRegisteredError: When the application layer has not yet called :func:`register_wizard_catalogue`. """ifnot_SETUP_FLOW_SLOT:raiseWizardCatalogueNotRegisteredError()return_SETUP_FLOW_SLOT[0]
# ANY-RETURN-RATIONALE-CATALOGUE-SLOT:# Concrete wizard-flow type registered at runtime; not importable from aeat.core# without circular import.
[docs]defget_wizard_flows()->tuple[Any,...]:# ANY-RETURN-RATIONALE-CATALOGUE-SLOT"""Return the registered ``WIZARD_FLOWS`` tuple. Returns: Tuple of concrete wizard-flow descriptors registered by the application layer. The tuple identity is preserved so downstream consumers inspect the same catalogue object the application registered. Raises: WizardCatalogueNotRegisteredError: When the application layer has not yet called :func:`register_wizard_catalogue`. """ifnot_WIZARD_FLOWS_SLOT:raiseWizardCatalogueNotRegisteredError()return_WIZARD_FLOWS_SLOT[0]