Source code for dosho.registry

"""name -> `Cab`/`StepRef` map, registered under shinobi's `shinobi.cabs`
entry-point group (see this package's `pyproject.toml`). String-keyed
runtime lookup, for a caller that doesn't know the tool name until it
runs (`ninja cabs list/show`, `shinobi.cabs` entry-point discovery) --
for the write-time-known case, `from dosho.cabs import <tool>` (see
`dosho/cabs/__init__.py`) is the more ergonomic, direct interface.
"""

from __future__ import annotations

import importlib
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from shinobi import Cab
    from shinobi.steps.schema import StepRef

# registered name -> re-exported attribute, for the handful of tools whose
# real (possibly hyphenated) name doesn't match the identifier
# `dosho/cabs/__init__.py` re-exports it as. Every other entry in
# `dosho.cabs.__all__` registers under its own attribute name unchanged --
# see `_build_entries` below. Keeping just the exceptions here (instead of
# a full name -> attribute table) means a new cab only has to be added
# once, in `dosho/cabs/__init__.py`'s imports/`__all__`, unless its real
# name needs to differ from its attribute name.
_NAME_OVERRIDES: dict[str, str] = {
    "skysim": "simms-skysim",
    "telsim": "simms-telsim",
    "simms_classic": "simms",
    "mosaic_queen": "mosaic-queen",
}


_entries_cache: dict[str, str] | None = None


def _entries() -> dict[str, str]:
    """registered name -> "dosho.cabs:<attribute>" for every tool
    `dosho.cabs` re-exports. Every entry resolves through the same
    `dosho.cabs` module now that it re-exports everything -- `get()`
    doesn't care whether a given entry is a `Cab` (real binary-flavour
    tool) or a `StepRef` (from `@shinobi.pystep`, e.g. a CASA task) --
    `Recipe.add_step` accepts either identically.

    Computed lazily and cached: reading `dosho.cabs.__all__` requires
    importing that module, which -- per its own docstring -- eagerly
    constructs every `Cab`/`StepRef` in the repo. Deferring this to first
    use keeps `import dosho.registry` itself cheap, matching this
    module's own "lazy, string-keyed lookup" contract.
    """
    global _entries_cache
    if _entries_cache is None:
        from dosho import cabs

        _entries_cache = {
            _NAME_OVERRIDES.get(attr, attr): f"dosho.cabs:{attr}" for attr in cabs.__all__
        }
    return _entries_cache


[docs] def get(name: str) -> "Cab | StepRef": """Resolve a cab/pystep by name. Raises `KeyError` if `name` isn't one of this repo's entries -- the contract `shinobi.cabs.get` relies on to fall through to the next installed provider. """ target = _entries()[name] module_name, attr = target.split(":", 1) module = importlib.import_module(module_name) return getattr(module, attr)
[docs] def list_cabs() -> list[str]: """List every tool name registered in this repository. Returns: The registered names (may be hyphenated, e.g. `"simms-skysim"`), in no particular order. """ return list(_entries())