Atlas recipe example¶
Shows a bundled Atlas plugin recipe on a tiny synthetic dataset.
Flow: create data -> load recipe -> check -> dry-run -> apply -> re-check.
In [1]:
Copied!
import woodpecker_atlas_plugin # noqa: F401 - imports plugin fixes for editable installs
import woodpecker
from woodpecker.testing import make_atlas
import woodpecker_atlas_plugin # noqa: F401 - imports plugin fixes for editable installs
import woodpecker
from woodpecker.testing import make_atlas
Create an Atlas-like dataset with missing project_id metadata and overly strong compression.
In [2]:
Copied!
dataset = make_atlas(missing=["project_id"], seed=7)
dataset["pr"].encoding["complevel"] = 5
dataset
dataset = make_atlas(missing=["project_id"], seed=7)
dataset["pr"].encoding["complevel"] = 5
dataset
Out[2]:
<xarray.Dataset> Size: 32kB
Dimensions: (time: 12, lat: 18, lon: 36)
Coordinates:
* time (time) datetime64[s] 96B 2000-01-01 2000-02-01 ... 2000-12-01
* lat (lat) float64 144B -85.0 -75.0 -65.0 -55.0 ... 55.0 65.0 75.0 85.0
* lon (lon) float64 288B 0.0 10.0 20.0 30.0 ... 320.0 330.0 340.0 350.0
Data variables:
pr (time, lat, lon) float32 31kB 2.131 2.146 2.117 ... 1.967 1.959
Attributes:
dataset_id: c3s-ipcc-atlas.cmip6.historical.ssp245.pr.monthly.global
ds_id: c3s-ipcc-atlas.cmip6.historical.ssp245.pr.monthly.global
source_name: c3s-ipcc-atlas.cmip6.historical.ssp245.pr.monthly.global.nc
experiment_id: ssp245
variable_id: pr
table_id: Amon
units: kg m-2 s-1
frequency: mon
grid_label: gr
atlas_region: globalLoad the bundled Atlas recipe and inspect its match rules and fix steps.
In [3]:
Copied!
recipe = woodpecker.recipe.get("c3s.atlas")
recipe.model_dump()
recipe = woodpecker.recipe.get("c3s.atlas")
recipe.model_dump()
Out[3]:
{'id': 'c3s.atlas',
'aliases': [],
'description': 'C3S/CDS adaptation recipe for Atlas NetCDF datasets',
'match': {'attrs': {},
'dataset_id_patterns': [],
'path_patterns': ['*atlas*.nc']},
'steps': [{'id': 'atlas.encoding_cleanup',
'phase': 'apply',
'options': {},
'links': []},
{'id': 'atlas.project_id_normalization',
'phase': 'apply',
'options': {},
'links': []}],
'links': [{'rel': 'self',
'href': 'https://github.com/roocs/woodpecker/blob/main/plugins/woodpecker-atlas-plugin/src/woodpecker_atlas_plugin/recipes/atlas_basic_recipe.json',
'title': 'Source recipe document'}]}
In [4]:
Copied!
recipe.match.model_dump(), [step.id for step in recipe.steps]
recipe.match.model_dump(), [step.id for step in recipe.steps]
Out[4]:
({'attrs': {}, 'dataset_id_patterns': [], 'path_patterns': ['*atlas*.nc']},
['atlas.encoding_cleanup', 'atlas.project_id_normalization'])
In [5]:
Copied!
findings = woodpecker.recipe.check(dataset, recipe)
findings.fix_ids
findings = woodpecker.recipe.check(dataset, recipe)
findings.fix_ids
Out[5]:
('atlas.encoding_cleanup',
'atlas.encoding_cleanup',
'atlas.project_id_normalization')
Dry-run previews the repair without changing the dataset.
In [6]:
Copied!
result = woodpecker.recipe.apply(dataset, recipe, dry_run=True)
result.stats, result.preview, dataset.attrs.get("project_id"), dataset["pr"].encoding["complevel"]
result = woodpecker.recipe.apply(dataset, recipe, dry_run=True)
result.stats, result.preview, dataset.attrs.get("project_id"), dataset["pr"].encoding["complevel"]
Out[6]:
({'attempted': 2,
'changed': 2,
'persist_attempted': 0,
'persisted': 0,
'persist_failed': 0,
'preview': [{'path': 'c3s-ipcc-atlas.cmip6.historical.ssp245.pr.monthly.global.nc',
'fix_id': 'atlas.encoding_cleanup',
'name': 'ATLAS encoding cleanup',
'labels': ['risk.encoding_metadata'],
'label_titles': ['safe: encoding metadata'],
'label_metadata': [{'id': 'risk.encoding_metadata',
'title': 'safe: encoding metadata',
'description': 'Changes encoding or persistence metadata without changing data values.',
'category': 'risk-low'}],
'changed': True},
{'path': 'c3s-ipcc-atlas.cmip6.historical.ssp245.pr.monthly.global.nc',
'fix_id': 'atlas.project_id_normalization',
'name': 'ATLAS project_id normalization',
'labels': ['risk.metadata_only'],
'label_titles': ['safe: metadata only'],
'label_metadata': [{'id': 'risk.metadata_only',
'title': 'safe: metadata only',
'description': 'Changes metadata without changing data values.',
'category': 'risk-low'}],
'changed': True}]},
({'path': 'c3s-ipcc-atlas.cmip6.historical.ssp245.pr.monthly.global.nc',
'fix_id': 'atlas.encoding_cleanup',
'name': 'ATLAS encoding cleanup',
'labels': ['risk.encoding_metadata'],
'label_titles': ['safe: encoding metadata'],
'label_metadata': [{'id': 'risk.encoding_metadata',
'title': 'safe: encoding metadata',
'description': 'Changes encoding or persistence metadata without changing data values.',
'category': 'risk-low'}],
'changed': True},
{'path': 'c3s-ipcc-atlas.cmip6.historical.ssp245.pr.monthly.global.nc',
'fix_id': 'atlas.project_id_normalization',
'name': 'ATLAS project_id normalization',
'labels': ['risk.metadata_only'],
'label_titles': ['safe: metadata only'],
'label_metadata': [{'id': 'risk.metadata_only',
'title': 'safe: metadata only',
'description': 'Changes metadata without changing data values.',
'category': 'risk-low'}],
'changed': True}),
None,
5)
Apply the recipe in memory and re-check.
In [7]:
Copied!
write = woodpecker.recipe.apply(dataset, recipe, dry_run=False)
(
write.stats,
dataset.attrs["project_id"],
dataset["pr"].encoding["complevel"],
dataset["pr"].encoding["zlib"],
dataset["pr"].encoding["shuffle"],
)
write = woodpecker.recipe.apply(dataset, recipe, dry_run=False)
(
write.stats,
dataset.attrs["project_id"],
dataset["pr"].encoding["complevel"],
dataset["pr"].encoding["zlib"],
dataset["pr"].encoding["shuffle"],
)
Out[7]:
({'attempted': 2,
'changed': 2,
'persist_attempted': 1,
'persisted': 1,
'persist_failed': 0,
'preview': [{'path': 'c3s-ipcc-atlas.cmip6.historical.ssp245.pr.monthly.global.nc',
'fix_id': 'atlas.encoding_cleanup',
'name': 'ATLAS encoding cleanup',
'labels': ['risk.encoding_metadata'],
'label_titles': ['safe: encoding metadata'],
'label_metadata': [{'id': 'risk.encoding_metadata',
'title': 'safe: encoding metadata',
'description': 'Changes encoding or persistence metadata without changing data values.',
'category': 'risk-low'}],
'changed': True},
{'path': 'c3s-ipcc-atlas.cmip6.historical.ssp245.pr.monthly.global.nc',
'fix_id': 'atlas.project_id_normalization',
'name': 'ATLAS project_id normalization',
'labels': ['risk.metadata_only'],
'label_titles': ['safe: metadata only'],
'label_metadata': [{'id': 'risk.metadata_only',
'title': 'safe: metadata only',
'description': 'Changes metadata without changing data values.',
'category': 'risk-low'}],
'changed': True}]},
'c3s-ipcc-atlas',
1,
True,
True)
In [8]:
Copied!
recheck = woodpecker.recipe.check(dataset, recipe)
bool(recheck)
recheck = woodpecker.recipe.check(dataset, recipe)
bool(recheck)
Out[8]:
False