from __future__ import annotations import importlib from pathlib import Path def repository_root() -> Path: """Absolute path to the repository root (the directory that contains ``src/``).""" return Path(__file__).resolve().parent.parent.parent def resolve_repo_path(path: str | Path) -> Path: """ Resolve *path* against the repository root when it is relative; absolute paths are only ``.resolve()``-ed. Use this so ``cache/...`` and ``configs/...`` work no matter the process working directory. """ p = Path(path) if p.is_absolute(): return p.resolve() return (repository_root() / p).resolve() def import_from_path(path: str): if ":" not in path: raise ValueError("Expected class path format 'module.submodule:ClassName'.") module_name, symbol_name = path.split(":", maxsplit=1) module = importlib.import_module(module_name) return getattr(module, symbol_name)