Source code for hydromodpy.project.accessors
"""Helper accessors exposed on :class:`hydromodpy.project.Project`.
Split from :mod:`hydromodpy.project.facade` to keep the facade focused on the
run/lifecycle API.
"""
from __future__ import annotations
import builtins
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
import pandas as pd
from hydromodpy.project.facade import Project
from hydromodpy.results.run import Run
[docs]
class ProjectDataAccessor:
"""Helper exposed as ``project.data``.
Lists input-data cache entries used by the project, locates a specific
:class:`~hydromodpy.data.loading.entry.DataEntry`, and reports missing variables.
"""
def __init__(self, project: Project) -> None:
self._project = project
def list(self, variable: str | None = None) -> pd.DataFrame:
import pandas as pd
loaded = self._project.data_loaded
if variable is not None:
loaded = {v for v in loaded if v == variable}
return pd.DataFrame({"variable": sorted(loaded)})
def missing(self) -> builtins.list[str]:
plan_types = getattr(self._project._ctx.data_plan, "types", ()) or ()
loaded = self._project.data_loaded
return [t for t in plan_types if t not in loaded]
[docs]
class ProjectRunsAccessor:
"""Helper exposed as ``project.runs``.
Thin wrapper around :class:`~hydromodpy.results.catalog.Catalog`
that pre-filters queries by the current project name.
"""
def __init__(self, project: Project) -> None:
self._project = project
def list(self) -> pd.DataFrame:
store = self._project._store
if store is None:
import pandas as pd
return pd.DataFrame()
return store.list_simulations(project=self._project._project_name)
def find(self, **filters: Any) -> builtins.list[Run]:
store = self._project._store
if store is None:
return []
return store.find(project=self._project._project_name, **filters)
def latest(self) -> Run | None:
df = self.list()
if df.empty:
return None
return self._project._store[df.iloc[-1]["sim_id"]]
def best(self, metric: str) -> Run | None:
store = self._project._store
if store is None:
return None
return store.best(self._project._project_name, metric=metric)
[docs]
def delete(self, sim_id: str, *, remove_storage: bool = True) -> None:
"""Delete a simulation from the catalog (and optionally its artefacts)."""
store = self._project._store
if store is None:
return
store.delete(sim_id, remove_storage=remove_storage)