Source code for scitex_template.registry

"""Registry of templates vendored in this repo.

Reads ``templates/REGISTRY.yaml`` from either:
  1. the live git checkout of scitex-template (editable install), or
  2. ``~/.scitex/template/cache/templates/REGISTRY.yaml`` (shallow-clone cache,
     populated on first cloner call).

The wheel installed from PyPI intentionally does NOT ship ``templates/`` — it
contains only the cloner code. At runtime the cloner clones this repo shallowly
into ``~/.scitex/template/cache/`` and reads the registry + template payload
from there. Keeps the wheel <100KB while the git repo stays the single source
of truth.
"""

from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
from scitex_config._ecosystem import local_state
from typing import Optional

try:
    import yaml
except ImportError as _e:  # pragma: no cover
    raise ImportError(
        "scitex-template requires PyYAML. pip install scitex-template"
    ) from _e


CACHE_ROOT = local_state.runtime_path("template", "cache")


[docs] @dataclass(frozen=True) class TemplateEntry: id: str description: str version: str path: Path
def _editable_checkout_root() -> Optional[Path]: """If this module lives inside an editable scitex-template checkout, return the repo root (parent of ``src/``). Otherwise return None. """ here = Path(__file__).resolve() # .../<repo>/src/scitex_template/registry.py → repo = parents[2] candidate = here.parents[2] if (candidate / "templates" / "REGISTRY.yaml").is_file(): return candidate return None
[docs] def registry_root() -> Optional[Path]: """Return the directory that contains ``templates/REGISTRY.yaml``. Preference order: 1. Editable checkout (if we're running from ``src/scitex_template/``). 2. Cache at ``~/.scitex/template/cache/``. 3. None — caller should populate the cache. """ live = _editable_checkout_root() if live is not None: return live if (CACHE_ROOT / "templates" / "REGISTRY.yaml").is_file(): return CACHE_ROOT return None
[docs] def load_registry() -> list[TemplateEntry]: """Parse ``templates/REGISTRY.yaml`` and return every entry. Raises ``FileNotFoundError`` if neither the editable checkout nor the cache is populated — the caller is responsible for triggering a shallow-clone of the scitex-template repo into ``~/.scitex/template/cache/``. """ root = registry_root() if root is None: raise FileNotFoundError( f"no template registry found — expected either an editable " f"checkout of scitex-template or a populated cache at {CACHE_ROOT}" ) data = yaml.safe_load((root / "templates" / "REGISTRY.yaml").read_text()) or {} return [ TemplateEntry( id=item["id"], description=item["description"], version=item["version"], path=root / item["path"], ) for item in data.get("templates", []) ]
[docs] def find_template(template_id: str) -> Optional[TemplateEntry]: """Return the registry entry for ``template_id``, or None.""" for entry in load_registry(): if entry.id == template_id: return entry return None