| 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) | |