"""Solution type registry.
All subclasses of ``SolutionBase`` that declare a ``solution_type`` class
variable are registered automatically via ``__init_subclass__``. Adding a
new solution type requires only creating a new file in ``maya/solutions/``
— no manual registration.
Usage (from the build pipeline)::
from openrig.maya.core.registry import get, all_types
cls = get("Arm") # → ArmSolution
cls = get("Spine") # → SpineSolution
known = all_types() # → {"Arm": ArmSolution, "Spine": SpineSolution}
"""
import logging
logger = logging.getLogger(__name__)
_REGISTRY: dict[str, type[object]] = {}
[docs]
def register(solution_type: str, cls: type[object]) -> None:
"""Register a solution class under its type string.
Called automatically by ``SolutionBase.__init_subclass__``. Logs a
warning if the type string is already taken (the new class wins).
Args:
solution_type: The type string declared on the class
(e.g. ``"Arm"``).
cls: The solution class to register.
"""
if solution_type in _REGISTRY:
existing = _REGISTRY[solution_type]
logger.warning(
"Solution type '%s' is already registered by '%s'. "
"Overwriting with '%s'.",
solution_type,
existing.__qualname__,
cls.__qualname__,
)
_REGISTRY[solution_type] = cls
logger.debug("Registered solution type '%s' → %s.", solution_type, cls.__qualname__)
[docs]
def get(solution_type: str) -> type[object]:
"""Return the solution class registered under the given type string.
Args:
solution_type: The type string to look up (e.g. ``"Arm"``).
Returns:
The registered solution class.
Raises:
KeyError: If no solution is registered under ``solution_type``.
"""
try:
return _REGISTRY[solution_type]
except KeyError:
known = sorted(_REGISTRY)
raise KeyError(
f"No solution registered for type '{solution_type}'. "
f"Known types: {known!r}."
) from None
[docs]
def all_types() -> dict[str, type[object]]:
"""Return a snapshot of all currently registered solution types.
Returns:
A dict mapping type strings to their solution classes.
"""
return dict(_REGISTRY)