Source code for rook.fixes.providers.woodpecker

"""Woodpecker-backed dataset fix provider."""

import importlib
from functools import cached_property

from rook.fixes.providers.base import (
    ATLAS_DATASET_PREFIXES,
    CMIP6_DECADAL_DATASET_PREFIX,
    FixContext,
    FixProvider,
)

WOODPECKER_CMIP6_DECADAL_RECIPE_ID = "c3s.cmip6_decadal"
WOODPECKER_ATLAS_RECIPE_ID = "c3s.atlas"
WOODPECKER_PREPARE_PHASE = "prepare"
WOODPECKER_APPLY_PHASE = "apply"


[docs] class WoodpeckerDatasetFixProvider(FixProvider): """Woodpecker-backed dataset fix provider.""" name = "woodpecker" dependency_names = ( "woodpecker", "woodpecker_atlas_plugin", "woodpecker_cmip6_decadal_plugin", ) unavailable_message = ( "Woodpecker is required to apply fixes with the woodpecker backend. " "Install woodpecker, the woodpecker-atlas plugin, and the " "woodpecker-cmip6-decadal plugin, or use the legacy backend." ) @cached_property def woodpecker(self): """Return the Woodpecker module after checking provider dependencies.""" self.require_available() return importlib.import_module("woodpecker")
[docs] def prepare(self, ds, *, context=None): context = context or FixContext() return self._apply_recipe( ds, recipe_id=context.recipe_id or WOODPECKER_CMIP6_DECADAL_RECIPE_ID, phase=context.phase or WOODPECKER_PREPARE_PHASE, )
[docs] def apply(self, ds, *, context=None): context = context or FixContext() dataset_id = context.dataset_id or "" if dataset_id.startswith(ATLAS_DATASET_PREFIXES): return self._apply_atlas_recipe( ds, dataset_id=dataset_id, recipe_id=context.recipe_id or WOODPECKER_ATLAS_RECIPE_ID, ) if dataset_id.startswith(CMIP6_DECADAL_DATASET_PREFIX): return self._apply_recipe( ds, recipe_id=context.recipe_id or WOODPECKER_CMIP6_DECADAL_RECIPE_ID, phase=context.phase or WOODPECKER_APPLY_PHASE, ) return ds
def _apply_atlas_recipe(self, ds, *, dataset_id, recipe_id): previous_dataset_id = ds.attrs.get("dataset_id") previous_source_name = ds.attrs.get("source_name") # TODO: clean up this temporary attribute workaround when revisiting # c3s-atlas fix handling in Woodpecker. ds.attrs["dataset_id"] = dataset_id ds.attrs["source_name"] = f"{dataset_id}.nc" try: self._apply_recipe( ds, recipe_id=recipe_id, phase=WOODPECKER_APPLY_PHASE, ) finally: if previous_dataset_id is None: ds.attrs.pop("dataset_id", None) else: ds.attrs["dataset_id"] = previous_dataset_id if previous_source_name is None: ds.attrs.pop("source_name", None) else: ds.attrs["source_name"] = previous_source_name return ds def _apply_recipe(self, ds, *, recipe_id, phase=None): recipe = self.woodpecker.recipe.get(recipe_id) self.woodpecker.recipe.apply(ds, recipe, phase=phase, dry_run=False) return ds