Source code for rook.fixes.providers.base
"""Base classes for dataset fix providers."""
from abc import ABC, abstractmethod
from dataclasses import dataclass
import importlib.util
ATLAS_DATASET_PREFIXES = ("c3s-ipcc-atlas", "c3s-cica-atlas")
CMIP6_DECADAL_DATASET_PREFIX = "c3s-cmip6-decadal"
[docs]
@dataclass(frozen=True)
class FixContext:
"""Rook-side context passed to a fix provider."""
dataset_id: str | None = None
operation: str | None = None
phase: str | None = None
output_dir: str | None = None
recipe_id: str | None = None
[docs]
class FixProvider(ABC):
"""Base class for dataset fix providers."""
name = "base"
dependency_names = ()
unavailable_message = "The selected fix provider has missing dependencies."
[docs]
def missing_dependencies(self):
"""Return provider dependencies that are not importable."""
return [
dependency_name
for dependency_name in self.dependency_names
if importlib.util.find_spec(dependency_name) is None
]
[docs]
def available(self):
"""Return whether the provider dependencies are importable."""
return not self.missing_dependencies()
[docs]
def require_available(self):
"""Raise a clear error when provider dependencies are missing."""
missing = self.missing_dependencies()
if missing:
missing_names = ", ".join(missing)
raise ImportError(f"{self.unavailable_message} Missing: {missing_names}.")
[docs]
def prepare(self, ds, *, context=None):
"""Prepare a dataset before the main fix step."""
return ds
[docs]
@abstractmethod
def apply(self, ds, *, context=None):
"""Apply fixes and return the dataset."""
[docs]
def finalise(self, ds, *, context=None):
"""Finalise a dataset after the main fix step."""
return ds
DatasetFixProvider = FixProvider