Source code for hydromodpy.core.workspace.path_registry
"""Canonical workspace path registry shared by runtime components."""
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING
from hydromodpy.core.state.paths import (
INTERNAL_DIRNAME,
REPORTS_DIRNAME,
scratch_dir_for,
share_dir_for,
)
#: Preprocessing intermediates go under .hmp/scratch/_preprocessing/.
#: These files are needed on disk by whitebox/rasterio during the pipeline,
#: then ingested into the project store and cleaned up.
PREPROCESSING_DIRNAME = "_preprocessing"
PREPROCESSING_DIR = f"{INTERNAL_DIRNAME}/scratch/{PREPROCESSING_DIRNAME}"
if TYPE_CHECKING:
from hydromodpy.core.workspace.config import WorkspaceConfig
[docs]
@dataclass(frozen=True)
class WorkspacePathRegistry:
"""Centralize shared data and project-local result paths."""
project_root: Path
root: Path
catalog_path: Path
data_dir: Path
runs_dir: Path
output_root: Path | None = None
[docs]
@classmethod
def from_config(cls, config: WorkspaceConfig) -> WorkspacePathRegistry:
"""Build a registry from a fully resolved workspace config."""
return cls(
project_root=Path(config.project_root),
root=Path(config.root),
catalog_path=Path(config.catalog_path),
data_dir=Path(config.data_dir),
runs_dir=Path(config.runs_dir),
output_root=Path(config.output_root) if config.output_root else None,
)
# -- Derived convenience names -----------------------------------------
@property
def _effective_output_root(self) -> Path:
"""Root for result directories: output_root if set, else project_root."""
if self.output_root is not None:
return self.output_root
return self.project_root
@property
def catch_name(self) -> str:
return self.project_root.name
@property
def solver_scratch_folder(self) -> Path:
return scratch_dir_for(self._effective_output_root)
[docs]
def solver_scratch_run_folder(self, sim_id: str) -> Path:
"""Return the scratch folder for a specific solver run."""
return self.solver_scratch_folder / sim_id
@property
def share_folder(self) -> Path:
return share_dir_for(self._effective_output_root)
@property
def reports_folder(self) -> Path:
return self.share_folder / REPORTS_DIRNAME
@property
def figures_folder(self) -> Path:
"""Figures that belong to the project, not to one run."""
return self.share_folder / "figures"
@property
def data_path(self) -> Path:
return self.data_dir
def figures_subdir(self, *parts: str) -> Path:
return self.figures_folder.joinpath(*parts)