anemoi-datasets 0.5.16__py3-none-any.whl → 0.5.18__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- anemoi/datasets/__init__.py +4 -1
- anemoi/datasets/__main__.py +12 -2
- anemoi/datasets/_version.py +9 -4
- anemoi/datasets/commands/cleanup.py +17 -2
- anemoi/datasets/commands/compare.py +18 -2
- anemoi/datasets/commands/copy.py +196 -14
- anemoi/datasets/commands/create.py +50 -7
- anemoi/datasets/commands/finalise-additions.py +17 -2
- anemoi/datasets/commands/finalise.py +17 -2
- anemoi/datasets/commands/init-additions.py +17 -2
- anemoi/datasets/commands/init.py +16 -2
- anemoi/datasets/commands/inspect.py +283 -62
- anemoi/datasets/commands/load-additions.py +16 -2
- anemoi/datasets/commands/load.py +16 -2
- anemoi/datasets/commands/patch.py +17 -2
- anemoi/datasets/commands/publish.py +17 -2
- anemoi/datasets/commands/scan.py +31 -3
- anemoi/datasets/compute/recentre.py +47 -11
- anemoi/datasets/create/__init__.py +612 -85
- anemoi/datasets/create/check.py +142 -20
- anemoi/datasets/create/chunks.py +64 -4
- anemoi/datasets/create/config.py +185 -21
- anemoi/datasets/create/filter.py +50 -0
- anemoi/datasets/create/filters/__init__.py +33 -0
- anemoi/datasets/create/filters/empty.py +37 -0
- anemoi/datasets/create/filters/legacy.py +93 -0
- anemoi/datasets/create/filters/noop.py +37 -0
- anemoi/datasets/create/filters/orog_to_z.py +58 -0
- anemoi/datasets/create/{functions/filters → filters}/pressure_level_relative_humidity_to_specific_humidity.py +33 -10
- anemoi/datasets/create/{functions/filters → filters}/pressure_level_specific_humidity_to_relative_humidity.py +32 -8
- anemoi/datasets/create/filters/rename.py +205 -0
- anemoi/datasets/create/{functions/filters → filters}/rotate_winds.py +43 -28
- anemoi/datasets/create/{functions/filters → filters}/single_level_dewpoint_to_relative_humidity.py +32 -9
- anemoi/datasets/create/{functions/filters → filters}/single_level_relative_humidity_to_dewpoint.py +33 -9
- anemoi/datasets/create/{functions/filters → filters}/single_level_relative_humidity_to_specific_humidity.py +55 -7
- anemoi/datasets/create/{functions/filters → filters}/single_level_specific_humidity_to_relative_humidity.py +98 -37
- anemoi/datasets/create/filters/speeddir_to_uv.py +95 -0
- anemoi/datasets/create/{functions/filters → filters}/sum.py +24 -27
- anemoi/datasets/create/filters/transform.py +53 -0
- anemoi/datasets/create/{functions/filters → filters}/unrotate_winds.py +27 -18
- anemoi/datasets/create/filters/uv_to_speeddir.py +94 -0
- anemoi/datasets/create/{functions/filters → filters}/wz_to_w.py +51 -33
- anemoi/datasets/create/input/__init__.py +76 -5
- anemoi/datasets/create/input/action.py +149 -13
- anemoi/datasets/create/input/concat.py +81 -10
- anemoi/datasets/create/input/context.py +39 -4
- anemoi/datasets/create/input/data_sources.py +72 -6
- anemoi/datasets/create/input/empty.py +21 -3
- anemoi/datasets/create/input/filter.py +60 -12
- anemoi/datasets/create/input/function.py +154 -37
- anemoi/datasets/create/input/join.py +86 -14
- anemoi/datasets/create/input/misc.py +67 -17
- anemoi/datasets/create/input/pipe.py +33 -6
- anemoi/datasets/create/input/repeated_dates.py +189 -41
- anemoi/datasets/create/input/result.py +202 -87
- anemoi/datasets/create/input/step.py +119 -22
- anemoi/datasets/create/input/template.py +100 -13
- anemoi/datasets/create/input/trace.py +62 -7
- anemoi/datasets/create/patch.py +52 -4
- anemoi/datasets/create/persistent.py +134 -17
- anemoi/datasets/create/size.py +15 -1
- anemoi/datasets/create/source.py +51 -0
- anemoi/datasets/create/sources/__init__.py +36 -0
- anemoi/datasets/create/{functions/sources → sources}/accumulations.py +296 -30
- anemoi/datasets/create/{functions/sources → sources}/constants.py +27 -2
- anemoi/datasets/create/{functions/sources → sources}/eccc_fstd.py +7 -3
- anemoi/datasets/create/sources/empty.py +37 -0
- anemoi/datasets/create/{functions/sources → sources}/forcings.py +25 -1
- anemoi/datasets/create/sources/grib.py +297 -0
- anemoi/datasets/create/{functions/sources → sources}/hindcasts.py +38 -4
- anemoi/datasets/create/sources/legacy.py +93 -0
- anemoi/datasets/create/{functions/sources → sources}/mars.py +168 -20
- anemoi/datasets/create/sources/netcdf.py +42 -0
- anemoi/datasets/create/sources/opendap.py +43 -0
- anemoi/datasets/create/{functions/sources/__init__.py → sources/patterns.py} +35 -4
- anemoi/datasets/create/sources/recentre.py +150 -0
- anemoi/datasets/create/{functions/sources → sources}/source.py +27 -5
- anemoi/datasets/create/{functions/sources → sources}/tendencies.py +64 -7
- anemoi/datasets/create/sources/xarray.py +92 -0
- anemoi/datasets/create/sources/xarray_kerchunk.py +36 -0
- anemoi/datasets/create/sources/xarray_support/README.md +1 -0
- anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/__init__.py +109 -8
- anemoi/datasets/create/sources/xarray_support/coordinates.py +442 -0
- anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/field.py +94 -16
- anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/fieldlist.py +90 -25
- anemoi/datasets/create/sources/xarray_support/flavour.py +1036 -0
- anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/grid.py +92 -31
- anemoi/datasets/create/sources/xarray_support/metadata.py +395 -0
- anemoi/datasets/create/sources/xarray_support/patch.py +91 -0
- anemoi/datasets/create/sources/xarray_support/time.py +391 -0
- anemoi/datasets/create/sources/xarray_support/variable.py +331 -0
- anemoi/datasets/create/sources/xarray_zarr.py +41 -0
- anemoi/datasets/create/{functions/sources → sources}/zenodo.py +34 -5
- anemoi/datasets/create/statistics/__init__.py +233 -44
- anemoi/datasets/create/statistics/summary.py +52 -6
- anemoi/datasets/create/testing.py +76 -0
- anemoi/datasets/create/{functions/filters/noop.py → typing.py} +6 -3
- anemoi/datasets/create/utils.py +97 -6
- anemoi/datasets/create/writer.py +26 -4
- anemoi/datasets/create/zarr.py +170 -23
- anemoi/datasets/data/__init__.py +51 -4
- anemoi/datasets/data/complement.py +191 -40
- anemoi/datasets/data/concat.py +141 -16
- anemoi/datasets/data/dataset.py +558 -62
- anemoi/datasets/data/debug.py +197 -26
- anemoi/datasets/data/ensemble.py +93 -8
- anemoi/datasets/data/fill_missing.py +165 -18
- anemoi/datasets/data/forwards.py +428 -56
- anemoi/datasets/data/grids.py +323 -97
- anemoi/datasets/data/indexing.py +112 -19
- anemoi/datasets/data/interpolate.py +92 -12
- anemoi/datasets/data/join.py +158 -19
- anemoi/datasets/data/masked.py +129 -15
- anemoi/datasets/data/merge.py +137 -23
- anemoi/datasets/data/misc.py +172 -16
- anemoi/datasets/data/missing.py +233 -29
- anemoi/datasets/data/rescale.py +111 -10
- anemoi/datasets/data/select.py +168 -26
- anemoi/datasets/data/statistics.py +67 -6
- anemoi/datasets/data/stores.py +149 -64
- anemoi/datasets/data/subset.py +159 -25
- anemoi/datasets/data/unchecked.py +168 -57
- anemoi/datasets/data/xy.py +168 -25
- anemoi/datasets/dates/__init__.py +191 -16
- anemoi/datasets/dates/groups.py +189 -47
- anemoi/datasets/grids.py +270 -31
- anemoi/datasets/testing.py +28 -1
- {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.18.dist-info}/METADATA +9 -6
- anemoi_datasets-0.5.18.dist-info/RECORD +137 -0
- {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.18.dist-info}/WHEEL +1 -1
- anemoi/datasets/create/functions/__init__.py +0 -66
- anemoi/datasets/create/functions/filters/__init__.py +0 -9
- anemoi/datasets/create/functions/filters/empty.py +0 -17
- anemoi/datasets/create/functions/filters/orog_to_z.py +0 -58
- anemoi/datasets/create/functions/filters/rename.py +0 -79
- anemoi/datasets/create/functions/filters/speeddir_to_uv.py +0 -78
- anemoi/datasets/create/functions/filters/uv_to_speeddir.py +0 -56
- anemoi/datasets/create/functions/sources/empty.py +0 -15
- anemoi/datasets/create/functions/sources/grib.py +0 -150
- anemoi/datasets/create/functions/sources/netcdf.py +0 -15
- anemoi/datasets/create/functions/sources/opendap.py +0 -15
- anemoi/datasets/create/functions/sources/recentre.py +0 -60
- anemoi/datasets/create/functions/sources/xarray/coordinates.py +0 -255
- anemoi/datasets/create/functions/sources/xarray/flavour.py +0 -472
- anemoi/datasets/create/functions/sources/xarray/metadata.py +0 -148
- anemoi/datasets/create/functions/sources/xarray/patch.py +0 -44
- anemoi/datasets/create/functions/sources/xarray/time.py +0 -177
- anemoi/datasets/create/functions/sources/xarray/variable.py +0 -188
- anemoi/datasets/create/functions/sources/xarray_kerchunk.py +0 -42
- anemoi/datasets/create/functions/sources/xarray_zarr.py +0 -15
- anemoi/datasets/utils/fields.py +0 -47
- anemoi_datasets-0.5.16.dist-info/RECORD +0 -129
- {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.18.dist-info}/entry_points.txt +0 -0
- {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.18.dist-info/licenses}/LICENSE +0 -0
- {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.18.dist-info}/top_level.txt +0 -0
|
@@ -8,11 +8,17 @@
|
|
|
8
8
|
# nor does it submit to any jurisdiction.
|
|
9
9
|
|
|
10
10
|
import logging
|
|
11
|
+
import warnings
|
|
11
12
|
from copy import deepcopy
|
|
13
|
+
from typing import Any
|
|
14
|
+
from typing import Dict
|
|
15
|
+
from typing import List
|
|
16
|
+
from typing import Optional
|
|
17
|
+
from typing import Type
|
|
12
18
|
|
|
13
19
|
from .action import Action
|
|
20
|
+
from .action import ActionContext
|
|
14
21
|
from .context import Context
|
|
15
|
-
from .misc import is_function
|
|
16
22
|
from .result import Result
|
|
17
23
|
from .template import notify_result
|
|
18
24
|
from .trace import trace_datasource
|
|
@@ -22,28 +28,75 @@ LOG = logging.getLogger(__name__)
|
|
|
22
28
|
|
|
23
29
|
|
|
24
30
|
class StepResult(Result):
|
|
25
|
-
|
|
31
|
+
"""Represents the result of a step in the data processing pipeline."""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self, context: Context, action_path: List[str], group_of_dates: Any, action: Action, upstream_result: Result
|
|
35
|
+
) -> None:
|
|
36
|
+
"""Initialize a StepResult instance.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
context
|
|
41
|
+
The context in which the step is executed.
|
|
42
|
+
action_path
|
|
43
|
+
The path of actions leading to this step.
|
|
44
|
+
group_of_dates
|
|
45
|
+
The group of dates associated with this step.
|
|
46
|
+
action
|
|
47
|
+
The action associated with this step.
|
|
48
|
+
upstream_result
|
|
49
|
+
The result of the upstream step.
|
|
50
|
+
"""
|
|
26
51
|
super().__init__(context, action_path, group_of_dates)
|
|
27
52
|
assert isinstance(upstream_result, Result), type(upstream_result)
|
|
28
|
-
self.upstream_result = upstream_result
|
|
29
|
-
self.action = action
|
|
53
|
+
self.upstream_result: Result = upstream_result
|
|
54
|
+
self.action: Action = action
|
|
30
55
|
|
|
31
56
|
@property
|
|
32
57
|
@notify_result
|
|
33
58
|
@trace_datasource
|
|
34
|
-
def datasource(self):
|
|
59
|
+
def datasource(self) -> Any:
|
|
60
|
+
"""Retrieve the datasource associated with this step result."""
|
|
35
61
|
raise NotImplementedError(f"Not implemented in {self.__class__.__name__}")
|
|
36
62
|
|
|
37
63
|
|
|
38
64
|
class StepAction(Action):
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
65
|
+
"""Represents an action that is part of a step in the data processing pipeline."""
|
|
66
|
+
|
|
67
|
+
result_class: Optional[Type[StepResult]] = None
|
|
68
|
+
|
|
69
|
+
def __init__(
|
|
70
|
+
self, context: ActionContext, action_path: List[str], previous_step: Any, *args: Any, **kwargs: Any
|
|
71
|
+
) -> None:
|
|
72
|
+
"""Initialize a StepAction instance.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
context
|
|
77
|
+
The context in which the action is executed.
|
|
78
|
+
action_path
|
|
79
|
+
The path of actions leading to this step.
|
|
80
|
+
previous_step
|
|
81
|
+
The previous step in the pipeline.
|
|
82
|
+
"""
|
|
42
83
|
super().__init__(context, action_path, *args, **kwargs)
|
|
43
|
-
self.previous_step = previous_step
|
|
84
|
+
self.previous_step: Any = previous_step
|
|
44
85
|
|
|
45
86
|
@trace_select
|
|
46
|
-
def select(self, group_of_dates):
|
|
87
|
+
def select(self, group_of_dates: Any) -> StepResult:
|
|
88
|
+
"""Select the result for a given group of dates.
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
group_of_dates
|
|
93
|
+
The group of dates to select the result for.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
unknown
|
|
98
|
+
The result of the step.
|
|
99
|
+
"""
|
|
47
100
|
return self.result_class(
|
|
48
101
|
self.context,
|
|
49
102
|
self.action_path,
|
|
@@ -52,12 +105,36 @@ class StepAction(Action):
|
|
|
52
105
|
self.previous_step.select(group_of_dates),
|
|
53
106
|
)
|
|
54
107
|
|
|
55
|
-
def __repr__(self):
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
108
|
+
def __repr__(self) -> str:
|
|
109
|
+
"""Return a string representation of the StepAction instance.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
unknown
|
|
114
|
+
String representation of the instance.
|
|
115
|
+
"""
|
|
116
|
+
return self._repr(self.previous_step, _inline_=str(self.kwargs))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def step_factory(config: Dict[str, Any], context: ActionContext, action_path: List[str], previous_step: Any) -> Any:
|
|
120
|
+
"""Factory function to create a step action based on the given configuration.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
config
|
|
125
|
+
The configuration dictionary for the step.
|
|
126
|
+
context
|
|
127
|
+
The context in which the step is executed.
|
|
128
|
+
action_path
|
|
129
|
+
The path of actions leading to this step.
|
|
130
|
+
previous_step
|
|
131
|
+
The previous step in the pipeline.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
unknown
|
|
136
|
+
An instance of a step action.
|
|
137
|
+
"""
|
|
61
138
|
|
|
62
139
|
from .filter import FilterStepAction
|
|
63
140
|
from .filter import FunctionStepAction
|
|
@@ -85,10 +162,30 @@ def step_factory(config, context, action_path, previous_step):
|
|
|
85
162
|
if isinstance(config[key], str):
|
|
86
163
|
args, kwargs = [config[key]], {}
|
|
87
164
|
|
|
88
|
-
if cls is None:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
165
|
+
if cls is not None:
|
|
166
|
+
return cls(context, action_path, previous_step, *args, **kwargs)
|
|
167
|
+
|
|
168
|
+
# Try filters from datasets filter registry
|
|
169
|
+
from anemoi.transform.filters import filter_registry as transform_filter_registry
|
|
170
|
+
|
|
171
|
+
from ..filters import create_filter as create_datasets_filter
|
|
172
|
+
from ..filters import filter_registry as datasets_filter_registry
|
|
173
|
+
|
|
174
|
+
if datasets_filter_registry.is_registered(key):
|
|
175
|
+
|
|
176
|
+
if transform_filter_registry.is_registered(key):
|
|
177
|
+
warnings.warn(f"Filter `{key}` is registered in both datasets and transform filter registries")
|
|
178
|
+
|
|
179
|
+
filter = create_datasets_filter(None, config)
|
|
180
|
+
return FunctionStepAction(context, action_path + [key], previous_step, key, filter)
|
|
181
|
+
|
|
182
|
+
# Use filters from transform registry
|
|
183
|
+
|
|
184
|
+
if transform_filter_registry.is_registered(key):
|
|
185
|
+
from ..filters.transform import TransformFilter
|
|
186
|
+
|
|
187
|
+
return FunctionStepAction(
|
|
188
|
+
context, action_path + [key], previous_step, key, TransformFilter(context, key, config)
|
|
189
|
+
)
|
|
93
190
|
|
|
94
|
-
|
|
191
|
+
raise ValueError(f"Unknown step action `{key}`")
|
|
@@ -10,35 +10,108 @@
|
|
|
10
10
|
|
|
11
11
|
import logging
|
|
12
12
|
import re
|
|
13
|
+
from abc import ABC
|
|
14
|
+
from abc import abstractmethod
|
|
13
15
|
from functools import wraps
|
|
16
|
+
from typing import Any
|
|
17
|
+
from typing import Callable
|
|
18
|
+
from typing import List
|
|
19
|
+
|
|
20
|
+
from .context import Context
|
|
14
21
|
|
|
15
22
|
LOG = logging.getLogger(__name__)
|
|
16
23
|
|
|
17
24
|
|
|
18
|
-
def notify_result(method):
|
|
25
|
+
def notify_result(method: Callable[..., Any]) -> Callable[..., Any]:
|
|
26
|
+
"""Decorator to notify the context of the result of the method call.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
method : Callable[..., Any]
|
|
31
|
+
The method to wrap.
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
Callable[..., Any]
|
|
36
|
+
The wrapped method.
|
|
37
|
+
"""
|
|
38
|
+
|
|
19
39
|
@wraps(method)
|
|
20
|
-
def wrapper(self, *args, **kwargs):
|
|
21
|
-
result = method(self, *args, **kwargs)
|
|
40
|
+
def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any:
|
|
41
|
+
result: Any = method(self, *args, **kwargs)
|
|
22
42
|
self.context.notify_result(self.action_path, result)
|
|
23
43
|
return result
|
|
24
44
|
|
|
25
45
|
return wrapper
|
|
26
46
|
|
|
27
47
|
|
|
28
|
-
class Substitution:
|
|
29
|
-
|
|
48
|
+
class Substitution(ABC):
|
|
49
|
+
"""Abstract base class for substitutions in templates."""
|
|
30
50
|
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def resolve(self, context: Context) -> Any:
|
|
53
|
+
"""Resolve the substitution using the given context.
|
|
31
54
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
context : Context
|
|
58
|
+
The context to use for resolution.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
Any
|
|
63
|
+
The resolved value.
|
|
64
|
+
"""
|
|
65
|
+
pass
|
|
36
66
|
|
|
37
|
-
|
|
67
|
+
|
|
68
|
+
class Reference(Substitution):
|
|
69
|
+
"""A class to represent a reference to another value in the context."""
|
|
70
|
+
|
|
71
|
+
def __init__(self, context: Any, action_path: List[str]) -> None:
|
|
72
|
+
"""Initialize a Reference instance.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
context : Any
|
|
77
|
+
The context in which the reference exists.
|
|
78
|
+
action_path : list of str
|
|
79
|
+
The action path to resolve.
|
|
80
|
+
"""
|
|
81
|
+
self.context: Any = context
|
|
82
|
+
self.action_path: List[str] = action_path
|
|
83
|
+
|
|
84
|
+
def resolve(self, context: Context) -> Any:
|
|
85
|
+
"""Resolve the reference using the given context.
|
|
86
|
+
|
|
87
|
+
Parameters
|
|
88
|
+
----------
|
|
89
|
+
context : Context
|
|
90
|
+
The context to use for resolution.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
Any
|
|
95
|
+
The resolved value.
|
|
96
|
+
"""
|
|
38
97
|
return context.get_result(self.action_path)
|
|
39
98
|
|
|
40
99
|
|
|
41
|
-
def resolve(context, x):
|
|
100
|
+
def resolve(context: Context, x: Any) -> Any:
|
|
101
|
+
"""Recursively resolve substitutions in the given structure using the context.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
context : Context
|
|
106
|
+
The context to use for resolution.
|
|
107
|
+
x : Union[tuple, list, dict, Substitution, Any]
|
|
108
|
+
The structure to resolve.
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
Any
|
|
113
|
+
The resolved structure.
|
|
114
|
+
"""
|
|
42
115
|
if isinstance(x, tuple):
|
|
43
116
|
return tuple([resolve(context, y) for y in x])
|
|
44
117
|
|
|
@@ -54,7 +127,21 @@ def resolve(context, x):
|
|
|
54
127
|
return x
|
|
55
128
|
|
|
56
129
|
|
|
57
|
-
def substitute(context, x):
|
|
130
|
+
def substitute(context: Context, x: Any) -> Any:
|
|
131
|
+
"""Recursively substitute references in the given structure using the context.
|
|
132
|
+
|
|
133
|
+
Parameters
|
|
134
|
+
----------
|
|
135
|
+
context : Context
|
|
136
|
+
The context to use for substitution.
|
|
137
|
+
x : Union[tuple, list, dict, str, Any]
|
|
138
|
+
The structure to substitute.
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
Any
|
|
143
|
+
The substituted structure.
|
|
144
|
+
"""
|
|
58
145
|
if isinstance(x, tuple):
|
|
59
146
|
return tuple([substitute(context, y) for y in x])
|
|
60
147
|
|
|
@@ -67,7 +154,7 @@ def substitute(context, x):
|
|
|
67
154
|
if not isinstance(x, str):
|
|
68
155
|
return x
|
|
69
156
|
|
|
70
|
-
if re.match(r"^\${[\.\w]+}$", x):
|
|
157
|
+
if re.match(r"^\${[\.\w\-]+}$", x):
|
|
71
158
|
path = x[2:-1].split(".")
|
|
72
159
|
context.will_need_reference(path)
|
|
73
160
|
return Reference(context, path)
|
|
@@ -12,6 +12,8 @@ import logging
|
|
|
12
12
|
import textwrap
|
|
13
13
|
import threading
|
|
14
14
|
from functools import wraps
|
|
15
|
+
from typing import Any
|
|
16
|
+
from typing import Callable
|
|
15
17
|
|
|
16
18
|
LOG = logging.getLogger(__name__)
|
|
17
19
|
|
|
@@ -20,17 +22,44 @@ thread_local = threading.local()
|
|
|
20
22
|
TRACE = 0
|
|
21
23
|
|
|
22
24
|
|
|
23
|
-
def enable_trace(on_off):
|
|
25
|
+
def enable_trace(on_off: int) -> None:
|
|
26
|
+
"""Enables or disables tracing.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
on_off : int
|
|
31
|
+
1 to enable tracing, 0 to disable.
|
|
32
|
+
"""
|
|
24
33
|
global TRACE
|
|
25
34
|
TRACE = on_off
|
|
26
35
|
|
|
27
36
|
|
|
28
|
-
def step(action_path):
|
|
37
|
+
def step(action_path: list[str]) -> str:
|
|
38
|
+
"""Returns a formatted string representing the action path.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
action_path : list of str
|
|
43
|
+
The action path.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
str
|
|
48
|
+
The formatted action path.
|
|
49
|
+
"""
|
|
29
50
|
return f"[{'.'.join(action_path)}]"
|
|
30
51
|
|
|
31
52
|
|
|
32
|
-
def trace(emoji, *args):
|
|
53
|
+
def trace(emoji: str, *args: Any) -> None:
|
|
54
|
+
"""Logs a trace message with an emoji.
|
|
33
55
|
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
emoji : str
|
|
59
|
+
The emoji to use.
|
|
60
|
+
*args : Any
|
|
61
|
+
The arguments to log.
|
|
62
|
+
"""
|
|
34
63
|
if not TRACE:
|
|
35
64
|
return
|
|
36
65
|
|
|
@@ -40,9 +69,22 @@ def trace(emoji, *args):
|
|
|
40
69
|
print(emoji, " " * thread_local.TRACE_INDENT, *args)
|
|
41
70
|
|
|
42
71
|
|
|
43
|
-
def trace_datasource(method):
|
|
72
|
+
def trace_datasource(method: Callable) -> Callable:
|
|
73
|
+
"""Decorator to trace the datasource method.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
method : Callable
|
|
78
|
+
The method to decorate.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
Callable
|
|
83
|
+
The wrapped method.
|
|
84
|
+
"""
|
|
85
|
+
|
|
44
86
|
@wraps(method)
|
|
45
|
-
def wrapper(self, *args, **kwargs):
|
|
87
|
+
def wrapper(self, *args: Any, **kwargs: Any) -> Any:
|
|
46
88
|
|
|
47
89
|
if not hasattr(thread_local, "TRACE_INDENT"):
|
|
48
90
|
thread_local.TRACE_INDENT = 0
|
|
@@ -67,9 +109,22 @@ def trace_datasource(method):
|
|
|
67
109
|
return wrapper
|
|
68
110
|
|
|
69
111
|
|
|
70
|
-
def trace_select(method):
|
|
112
|
+
def trace_select(method: Callable) -> Callable:
|
|
113
|
+
"""Decorator to trace the select method.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
method : Callable
|
|
118
|
+
The method to decorate.
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
Callable
|
|
123
|
+
The wrapped method.
|
|
124
|
+
"""
|
|
125
|
+
|
|
71
126
|
@wraps(method)
|
|
72
|
-
def wrapper(self, *args, **kwargs):
|
|
127
|
+
def wrapper(self, *args: Any, **kwargs: Any) -> Any:
|
|
73
128
|
if not hasattr(thread_local, "TRACE_INDENT"):
|
|
74
129
|
thread_local.TRACE_INDENT = 0
|
|
75
130
|
trace(
|
anemoi/datasets/create/patch.py
CHANGED
|
@@ -10,13 +10,26 @@
|
|
|
10
10
|
import json
|
|
11
11
|
import logging
|
|
12
12
|
import os
|
|
13
|
+
from typing import Union
|
|
13
14
|
|
|
14
15
|
import zarr
|
|
15
16
|
|
|
16
17
|
LOG = logging.getLogger(__name__)
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
def fix_order_by(order_by):
|
|
20
|
+
def fix_order_by(order_by: Union[dict, list]) -> list[dict]:
|
|
21
|
+
"""Fix the order_by attribute to ensure it is a list of dictionaries.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
order_by : dict or list
|
|
26
|
+
The order_by attribute to fix.
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
list[dict]
|
|
31
|
+
The fixed order_by attribute.
|
|
32
|
+
"""
|
|
20
33
|
if isinstance(order_by, list):
|
|
21
34
|
return order_by
|
|
22
35
|
|
|
@@ -29,14 +42,38 @@ def fix_order_by(order_by):
|
|
|
29
42
|
return lst
|
|
30
43
|
|
|
31
44
|
|
|
32
|
-
def fix_history(history):
|
|
45
|
+
def fix_history(history: list[dict]) -> list[dict]:
|
|
46
|
+
"""Fix the history attribute by removing specific actions.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
history : list[dict]
|
|
51
|
+
The history attribute to fix.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
list[dict]
|
|
56
|
+
The fixed history attribute.
|
|
57
|
+
"""
|
|
33
58
|
new = history
|
|
34
59
|
new = [d for d in new if d.get("action") != "loading_data_start"]
|
|
35
60
|
new = [d for d in new if d.get("action") != "loading_data_end"]
|
|
36
61
|
return new
|
|
37
62
|
|
|
38
63
|
|
|
39
|
-
def fix_provenance(provenance):
|
|
64
|
+
def fix_provenance(provenance: dict) -> dict:
|
|
65
|
+
"""Fix the provenance attribute by adding missing fields and removing unnecessary ones.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
provenance : dict
|
|
70
|
+
The provenance attribute to fix.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
dict
|
|
75
|
+
The fixed provenance attribute.
|
|
76
|
+
"""
|
|
40
77
|
if "python" not in provenance:
|
|
41
78
|
provenance["python"] = provenance["platform"]["python_version"]
|
|
42
79
|
|
|
@@ -79,7 +116,18 @@ def fix_provenance(provenance):
|
|
|
79
116
|
return provenance
|
|
80
117
|
|
|
81
118
|
|
|
82
|
-
def apply_patch(path, verbose=True, dry_run=False):
|
|
119
|
+
def apply_patch(path: str, verbose: bool = True, dry_run: bool = False) -> None:
|
|
120
|
+
"""Apply a patch to the dataset at the given path.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
path : str
|
|
125
|
+
The path to the dataset.
|
|
126
|
+
verbose : bool, optional
|
|
127
|
+
Whether to log detailed information. Defaults to True.
|
|
128
|
+
dry_run : bool, optional
|
|
129
|
+
If True, do not actually apply the patch. Defaults to False.
|
|
130
|
+
"""
|
|
83
131
|
LOG.debug("====================")
|
|
84
132
|
LOG.debug(f"Patching {path}")
|
|
85
133
|
LOG.debug("====================")
|