anemoi-datasets 0.5.26__py3-none-any.whl → 0.5.28__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 +1 -2
- anemoi/datasets/_version.py +16 -3
- anemoi/datasets/commands/check.py +1 -1
- anemoi/datasets/commands/copy.py +1 -2
- anemoi/datasets/commands/create.py +1 -1
- anemoi/datasets/commands/inspect.py +27 -35
- anemoi/datasets/commands/recipe/__init__.py +93 -0
- anemoi/datasets/commands/recipe/format.py +55 -0
- anemoi/datasets/commands/recipe/migrate.py +555 -0
- anemoi/datasets/commands/validate.py +59 -0
- anemoi/datasets/compute/recentre.py +3 -6
- anemoi/datasets/create/__init__.py +64 -26
- anemoi/datasets/create/check.py +10 -12
- anemoi/datasets/create/chunks.py +1 -2
- anemoi/datasets/create/config.py +5 -6
- anemoi/datasets/create/input/__init__.py +44 -65
- anemoi/datasets/create/input/action.py +296 -238
- anemoi/datasets/create/input/context/__init__.py +71 -0
- anemoi/datasets/create/input/context/field.py +54 -0
- anemoi/datasets/create/input/data_sources.py +7 -9
- anemoi/datasets/create/input/misc.py +2 -75
- anemoi/datasets/create/input/repeated_dates.py +11 -130
- anemoi/datasets/{utils → create/input/result}/__init__.py +10 -1
- anemoi/datasets/create/input/{result.py → result/field.py} +36 -120
- anemoi/datasets/create/input/trace.py +1 -1
- anemoi/datasets/create/patch.py +1 -2
- anemoi/datasets/create/persistent.py +3 -5
- anemoi/datasets/create/size.py +1 -3
- anemoi/datasets/create/sources/accumulations.py +120 -145
- anemoi/datasets/create/sources/accumulations2.py +20 -53
- anemoi/datasets/create/sources/anemoi_dataset.py +46 -42
- anemoi/datasets/create/sources/constants.py +39 -40
- anemoi/datasets/create/sources/empty.py +22 -19
- anemoi/datasets/create/sources/fdb.py +133 -0
- anemoi/datasets/create/sources/forcings.py +29 -29
- anemoi/datasets/create/sources/grib.py +94 -78
- anemoi/datasets/create/sources/grib_index.py +57 -55
- anemoi/datasets/create/sources/hindcasts.py +57 -59
- anemoi/datasets/create/sources/legacy.py +10 -62
- anemoi/datasets/create/sources/mars.py +121 -149
- anemoi/datasets/create/sources/netcdf.py +28 -25
- anemoi/datasets/create/sources/opendap.py +28 -26
- anemoi/datasets/create/sources/patterns.py +4 -6
- anemoi/datasets/create/sources/recentre.py +46 -48
- anemoi/datasets/create/sources/repeated_dates.py +44 -0
- anemoi/datasets/create/sources/source.py +26 -51
- anemoi/datasets/create/sources/tendencies.py +68 -98
- anemoi/datasets/create/sources/xarray.py +4 -6
- anemoi/datasets/create/sources/xarray_support/__init__.py +40 -36
- anemoi/datasets/create/sources/xarray_support/coordinates.py +8 -12
- anemoi/datasets/create/sources/xarray_support/field.py +20 -16
- anemoi/datasets/create/sources/xarray_support/fieldlist.py +11 -15
- anemoi/datasets/create/sources/xarray_support/flavour.py +42 -42
- anemoi/datasets/create/sources/xarray_support/grid.py +15 -9
- anemoi/datasets/create/sources/xarray_support/metadata.py +19 -128
- anemoi/datasets/create/sources/xarray_support/patch.py +4 -6
- anemoi/datasets/create/sources/xarray_support/time.py +10 -13
- anemoi/datasets/create/sources/xarray_support/variable.py +21 -21
- anemoi/datasets/create/sources/xarray_zarr.py +28 -25
- anemoi/datasets/create/sources/zenodo.py +43 -41
- anemoi/datasets/create/statistics/__init__.py +3 -6
- anemoi/datasets/create/testing.py +4 -0
- anemoi/datasets/create/typing.py +1 -2
- anemoi/datasets/create/utils.py +0 -43
- anemoi/datasets/create/zarr.py +7 -2
- anemoi/datasets/data/__init__.py +15 -6
- anemoi/datasets/data/complement.py +7 -12
- anemoi/datasets/data/concat.py +5 -8
- anemoi/datasets/data/dataset.py +48 -47
- anemoi/datasets/data/debug.py +7 -9
- anemoi/datasets/data/ensemble.py +4 -6
- anemoi/datasets/data/fill_missing.py +7 -10
- anemoi/datasets/data/forwards.py +22 -26
- anemoi/datasets/data/grids.py +12 -168
- anemoi/datasets/data/indexing.py +9 -12
- anemoi/datasets/data/interpolate.py +7 -15
- anemoi/datasets/data/join.py +8 -12
- anemoi/datasets/data/masked.py +6 -11
- anemoi/datasets/data/merge.py +5 -9
- anemoi/datasets/data/misc.py +41 -45
- anemoi/datasets/data/missing.py +11 -16
- anemoi/datasets/data/observations/__init__.py +8 -14
- anemoi/datasets/data/padded.py +3 -5
- anemoi/datasets/data/records/backends/__init__.py +2 -2
- anemoi/datasets/data/rescale.py +5 -12
- anemoi/datasets/data/rolling_average.py +141 -0
- anemoi/datasets/data/select.py +13 -16
- anemoi/datasets/data/statistics.py +4 -7
- anemoi/datasets/data/stores.py +22 -29
- anemoi/datasets/data/subset.py +8 -11
- anemoi/datasets/data/unchecked.py +7 -11
- anemoi/datasets/data/xy.py +25 -21
- anemoi/datasets/dates/__init__.py +15 -18
- anemoi/datasets/dates/groups.py +7 -10
- anemoi/datasets/dumper.py +76 -0
- anemoi/datasets/grids.py +4 -185
- anemoi/datasets/schemas/recipe.json +131 -0
- anemoi/datasets/testing.py +93 -7
- anemoi/datasets/validate.py +598 -0
- {anemoi_datasets-0.5.26.dist-info → anemoi_datasets-0.5.28.dist-info}/METADATA +7 -4
- anemoi_datasets-0.5.28.dist-info/RECORD +134 -0
- anemoi/datasets/create/filter.py +0 -48
- anemoi/datasets/create/input/concat.py +0 -164
- anemoi/datasets/create/input/context.py +0 -89
- anemoi/datasets/create/input/empty.py +0 -54
- anemoi/datasets/create/input/filter.py +0 -118
- anemoi/datasets/create/input/function.py +0 -233
- anemoi/datasets/create/input/join.py +0 -130
- anemoi/datasets/create/input/pipe.py +0 -66
- anemoi/datasets/create/input/step.py +0 -177
- anemoi/datasets/create/input/template.py +0 -162
- anemoi_datasets-0.5.26.dist-info/RECORD +0 -131
- {anemoi_datasets-0.5.26.dist-info → anemoi_datasets-0.5.28.dist-info}/WHEEL +0 -0
- {anemoi_datasets-0.5.26.dist-info → anemoi_datasets-0.5.28.dist-info}/entry_points.txt +0 -0
- {anemoi_datasets-0.5.26.dist-info → anemoi_datasets-0.5.28.dist-info}/licenses/LICENSE +0 -0
- {anemoi_datasets-0.5.26.dist-info → anemoi_datasets-0.5.28.dist-info}/top_level.txt +0 -0
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
# (C) Copyright 2024 Anemoi contributors.
|
|
2
|
-
#
|
|
3
|
-
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
4
|
-
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
5
|
-
#
|
|
6
|
-
# In applying this licence, ECMWF does not waive the privileges and immunities
|
|
7
|
-
# granted to it by virtue of its status as an intergovernmental organisation
|
|
8
|
-
# nor does it submit to any jurisdiction.
|
|
9
|
-
|
|
10
|
-
import logging
|
|
11
|
-
from functools import cached_property
|
|
12
|
-
from typing import Any
|
|
13
|
-
from typing import Dict
|
|
14
|
-
|
|
15
|
-
from earthkit.data import FieldList
|
|
16
|
-
|
|
17
|
-
from ...dates.groups import GroupOfDates
|
|
18
|
-
from .action import Action
|
|
19
|
-
from .misc import _tidy
|
|
20
|
-
from .misc import assert_fieldlist
|
|
21
|
-
from .result import Result
|
|
22
|
-
from .template import notify_result
|
|
23
|
-
from .template import substitute
|
|
24
|
-
from .trace import trace
|
|
25
|
-
from .trace import trace_datasource
|
|
26
|
-
from .trace import trace_select
|
|
27
|
-
|
|
28
|
-
LOG = logging.getLogger(__name__)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class FunctionContext:
|
|
32
|
-
"""A FunctionContext is passed to all functions, it will be used to pass information
|
|
33
|
-
to the functions from the other actions and filters and results.
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
def __init__(self, owner: Result) -> None:
|
|
37
|
-
"""Initializes a FunctionContext instance.
|
|
38
|
-
|
|
39
|
-
Parameters
|
|
40
|
-
----------
|
|
41
|
-
owner : object
|
|
42
|
-
The owner object.
|
|
43
|
-
"""
|
|
44
|
-
self.owner = owner
|
|
45
|
-
self.use_grib_paramid: bool = owner.context.use_grib_paramid
|
|
46
|
-
|
|
47
|
-
def trace(self, emoji: str, *args: Any) -> None:
|
|
48
|
-
"""Traces the given arguments with an emoji.
|
|
49
|
-
|
|
50
|
-
Parameters
|
|
51
|
-
----------
|
|
52
|
-
emoji : str
|
|
53
|
-
The emoji to use.
|
|
54
|
-
*args : Any
|
|
55
|
-
The arguments to trace.
|
|
56
|
-
"""
|
|
57
|
-
trace(emoji, *args)
|
|
58
|
-
|
|
59
|
-
def info(self, *args: Any, **kwargs: Any) -> None:
|
|
60
|
-
"""Logs an info message.
|
|
61
|
-
|
|
62
|
-
Parameters
|
|
63
|
-
----------
|
|
64
|
-
*args : Any
|
|
65
|
-
The arguments for the log message.
|
|
66
|
-
**kwargs : Any
|
|
67
|
-
The keyword arguments for the log message.
|
|
68
|
-
"""
|
|
69
|
-
LOG.info(*args, **kwargs)
|
|
70
|
-
|
|
71
|
-
@property
|
|
72
|
-
def dates_provider(self) -> object:
|
|
73
|
-
"""Returns the dates provider."""
|
|
74
|
-
return self.owner.group_of_dates.provider
|
|
75
|
-
|
|
76
|
-
@property
|
|
77
|
-
def partial_ok(self) -> bool:
|
|
78
|
-
"""Returns whether partial results are acceptable."""
|
|
79
|
-
return self.owner.group_of_dates.partial_ok
|
|
80
|
-
|
|
81
|
-
def get_result(self, *args, **kwargs) -> Any:
|
|
82
|
-
return self.owner.context.get_result(*args, **kwargs)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
class FunctionAction(Action):
|
|
86
|
-
"""Represents an action that executes a function.
|
|
87
|
-
|
|
88
|
-
Attributes
|
|
89
|
-
----------
|
|
90
|
-
name : str
|
|
91
|
-
The name of the function.
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
def __init__(self, context: object, action_path: list, _name: str, source, **kwargs: Dict[str, Any]) -> None:
|
|
95
|
-
"""Initializes a FunctionAction instance.
|
|
96
|
-
|
|
97
|
-
Parameters
|
|
98
|
-
----------
|
|
99
|
-
context : object
|
|
100
|
-
The context object.
|
|
101
|
-
action_path : list
|
|
102
|
-
The action path.
|
|
103
|
-
_name : str
|
|
104
|
-
The name of the function.
|
|
105
|
-
**kwargs : Dict[str, Any]
|
|
106
|
-
Additional keyword arguments.
|
|
107
|
-
"""
|
|
108
|
-
super().__init__(context, action_path, **kwargs)
|
|
109
|
-
self.name: str = _name
|
|
110
|
-
self.source = source
|
|
111
|
-
|
|
112
|
-
@trace_select
|
|
113
|
-
def select(self, group_of_dates: GroupOfDates) -> "FunctionResult":
|
|
114
|
-
"""Selects the function result for the given group of dates.
|
|
115
|
-
|
|
116
|
-
Parameters
|
|
117
|
-
----------
|
|
118
|
-
group_of_dates : GroupOfDates
|
|
119
|
-
The group of dates.
|
|
120
|
-
|
|
121
|
-
Returns
|
|
122
|
-
-------
|
|
123
|
-
FunctionResult
|
|
124
|
-
The function result instance.
|
|
125
|
-
"""
|
|
126
|
-
return FunctionResult(self.context, self.action_path, group_of_dates, action=self)
|
|
127
|
-
|
|
128
|
-
def __repr__(self) -> str:
|
|
129
|
-
"""Returns a string representation of the FunctionAction instance."""
|
|
130
|
-
content: str = ""
|
|
131
|
-
content += ",".join([self._short_str(a) for a in self.args])
|
|
132
|
-
content += " ".join([self._short_str(f"{k}={v}") for k, v in self.kwargs.items()])
|
|
133
|
-
content = self._short_str(content)
|
|
134
|
-
return self._repr(_inline_=content, _indent_=" ")
|
|
135
|
-
|
|
136
|
-
def _trace_select(self, group_of_dates: GroupOfDates) -> str:
|
|
137
|
-
"""Traces the selection of the function for the given group of dates.
|
|
138
|
-
|
|
139
|
-
Parameters
|
|
140
|
-
----------
|
|
141
|
-
group_of_dates : GroupOfDates
|
|
142
|
-
The group of dates.
|
|
143
|
-
|
|
144
|
-
Returns
|
|
145
|
-
-------
|
|
146
|
-
str
|
|
147
|
-
The trace string.
|
|
148
|
-
"""
|
|
149
|
-
return f"{self.name}({group_of_dates})"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
class FunctionResult(Result):
|
|
153
|
-
"""Represents the result of executing a function.
|
|
154
|
-
|
|
155
|
-
Attributes
|
|
156
|
-
----------
|
|
157
|
-
action : Action
|
|
158
|
-
The action instance.
|
|
159
|
-
args : tuple
|
|
160
|
-
The positional arguments for the function.
|
|
161
|
-
kwargs : dict
|
|
162
|
-
The keyword arguments for the function.
|
|
163
|
-
"""
|
|
164
|
-
|
|
165
|
-
def __init__(self, context: object, action_path: list, group_of_dates: GroupOfDates, action: Action) -> None:
|
|
166
|
-
"""Initializes a FunctionResult instance.
|
|
167
|
-
|
|
168
|
-
Parameters
|
|
169
|
-
----------
|
|
170
|
-
context : object
|
|
171
|
-
The context object.
|
|
172
|
-
action_path : list
|
|
173
|
-
The action path.
|
|
174
|
-
group_of_dates : GroupOfDates
|
|
175
|
-
The group of dates.
|
|
176
|
-
action : Action
|
|
177
|
-
The action instance.
|
|
178
|
-
"""
|
|
179
|
-
super().__init__(context, action_path, group_of_dates)
|
|
180
|
-
assert isinstance(action, Action), type(action)
|
|
181
|
-
self.action: Action = action
|
|
182
|
-
|
|
183
|
-
self.args, self.kwargs = substitute(context, (self.action.args, self.action.kwargs))
|
|
184
|
-
|
|
185
|
-
def _trace_datasource(self, *args: Any, **kwargs: Any) -> str:
|
|
186
|
-
"""Traces the datasource for the given arguments.
|
|
187
|
-
|
|
188
|
-
Parameters
|
|
189
|
-
----------
|
|
190
|
-
*args : Any
|
|
191
|
-
The arguments.
|
|
192
|
-
**kwargs : Any
|
|
193
|
-
The keyword arguments.
|
|
194
|
-
|
|
195
|
-
Returns
|
|
196
|
-
-------
|
|
197
|
-
str
|
|
198
|
-
The trace string.
|
|
199
|
-
"""
|
|
200
|
-
return f"{self.action.name}({self.group_of_dates})"
|
|
201
|
-
|
|
202
|
-
@cached_property
|
|
203
|
-
@assert_fieldlist
|
|
204
|
-
@notify_result
|
|
205
|
-
@trace_datasource
|
|
206
|
-
def datasource(self) -> FieldList:
|
|
207
|
-
"""Returns the datasource for the function result."""
|
|
208
|
-
# args, kwargs = resolve(self.context, (self.args, self.kwargs))
|
|
209
|
-
self.action.source.context = FunctionContext(self)
|
|
210
|
-
|
|
211
|
-
return _tidy(
|
|
212
|
-
self.action.source.execute(
|
|
213
|
-
list(self.group_of_dates), # Will provide a list of datetime objects
|
|
214
|
-
)
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
def __repr__(self) -> str:
|
|
218
|
-
"""Returns a string representation of the FunctionResult instance."""
|
|
219
|
-
try:
|
|
220
|
-
return f"{self.action.name}({self.group_of_dates})"
|
|
221
|
-
except Exception:
|
|
222
|
-
return f"{self.__class__.__name__}(unitialised)"
|
|
223
|
-
|
|
224
|
-
@property
|
|
225
|
-
def function(self) -> None:
|
|
226
|
-
"""Raises NotImplementedError as this property is not implemented.
|
|
227
|
-
|
|
228
|
-
Raises
|
|
229
|
-
------
|
|
230
|
-
NotImplementedError
|
|
231
|
-
Always raised.
|
|
232
|
-
"""
|
|
233
|
-
raise NotImplementedError(f"Not implemented in {self.__class__.__name__}")
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
# (C) Copyright 2024 Anemoi contributors.
|
|
2
|
-
#
|
|
3
|
-
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
4
|
-
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
5
|
-
#
|
|
6
|
-
# In applying this licence, ECMWF does not waive the privileges and immunities
|
|
7
|
-
# granted to it by virtue of its status as an intergovernmental organisation
|
|
8
|
-
# nor does it submit to any jurisdiction.
|
|
9
|
-
|
|
10
|
-
import logging
|
|
11
|
-
from functools import cached_property
|
|
12
|
-
from typing import Any
|
|
13
|
-
from typing import List
|
|
14
|
-
|
|
15
|
-
from earthkit.data import FieldList
|
|
16
|
-
|
|
17
|
-
from ...dates.groups import GroupOfDates
|
|
18
|
-
from .action import Action
|
|
19
|
-
from .action import action_factory
|
|
20
|
-
from .empty import EmptyResult
|
|
21
|
-
from .misc import _tidy
|
|
22
|
-
from .misc import assert_fieldlist
|
|
23
|
-
from .result import Result
|
|
24
|
-
from .template import notify_result
|
|
25
|
-
from .trace import trace_datasource
|
|
26
|
-
from .trace import trace_select
|
|
27
|
-
|
|
28
|
-
LOG = logging.getLogger(__name__)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class JoinResult(Result):
|
|
32
|
-
"""Represents a result that combines multiple results.
|
|
33
|
-
|
|
34
|
-
Attributes
|
|
35
|
-
----------
|
|
36
|
-
context : object
|
|
37
|
-
The context object.
|
|
38
|
-
action_path : list
|
|
39
|
-
The action path.
|
|
40
|
-
group_of_dates : GroupOfDates
|
|
41
|
-
The group of dates.
|
|
42
|
-
results : List[Result]
|
|
43
|
-
The list of results.
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
def __init__(
|
|
47
|
-
self, context: object, action_path: list, group_of_dates: GroupOfDates, results: List[Result], **kwargs: Any
|
|
48
|
-
) -> None:
|
|
49
|
-
"""Initializes a JoinResult instance.
|
|
50
|
-
|
|
51
|
-
Parameters
|
|
52
|
-
----------
|
|
53
|
-
context : object
|
|
54
|
-
The context object.
|
|
55
|
-
action_path : list
|
|
56
|
-
The action path.
|
|
57
|
-
group_of_dates : GroupOfDates
|
|
58
|
-
The group of dates.
|
|
59
|
-
results : List[Result]
|
|
60
|
-
The list of results.
|
|
61
|
-
"""
|
|
62
|
-
super().__init__(context, action_path, group_of_dates)
|
|
63
|
-
self.results: List[Result] = [r for r in results if not r.empty]
|
|
64
|
-
|
|
65
|
-
@cached_property
|
|
66
|
-
@assert_fieldlist
|
|
67
|
-
@notify_result
|
|
68
|
-
@trace_datasource
|
|
69
|
-
def datasource(self) -> FieldList:
|
|
70
|
-
"""Returns the combined datasource from all results."""
|
|
71
|
-
ds: FieldList = EmptyResult(self.context, self.action_path, self.group_of_dates).datasource
|
|
72
|
-
for i in self.results:
|
|
73
|
-
ds += i.datasource
|
|
74
|
-
return _tidy(ds)
|
|
75
|
-
|
|
76
|
-
def __repr__(self) -> str:
|
|
77
|
-
"""Returns a string representation of the JoinResult instance."""
|
|
78
|
-
content: str = "\n".join([str(i) for i in self.results])
|
|
79
|
-
return self._repr(content)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
class JoinAction(Action):
|
|
83
|
-
"""Represents an action that combines multiple actions.
|
|
84
|
-
|
|
85
|
-
Attributes
|
|
86
|
-
----------
|
|
87
|
-
context : object
|
|
88
|
-
The context object.
|
|
89
|
-
action_path : list
|
|
90
|
-
The action path.
|
|
91
|
-
actions : List[Action]
|
|
92
|
-
The list of actions.
|
|
93
|
-
"""
|
|
94
|
-
|
|
95
|
-
def __init__(self, context: object, action_path: list, *configs: dict) -> None:
|
|
96
|
-
"""Initializes a JoinAction instance.
|
|
97
|
-
|
|
98
|
-
Parameters
|
|
99
|
-
----------
|
|
100
|
-
context : object
|
|
101
|
-
The context object.
|
|
102
|
-
action_path : list
|
|
103
|
-
The action path.
|
|
104
|
-
*configs : dict
|
|
105
|
-
The configuration dictionaries.
|
|
106
|
-
"""
|
|
107
|
-
super().__init__(context, action_path, *configs)
|
|
108
|
-
self.actions: List[Action] = [action_factory(c, context, action_path + [str(i)]) for i, c in enumerate(configs)]
|
|
109
|
-
|
|
110
|
-
def __repr__(self) -> str:
|
|
111
|
-
"""Returns a string representation of the JoinAction instance."""
|
|
112
|
-
content: str = "\n".join([str(i) for i in self.actions])
|
|
113
|
-
return self._repr(content)
|
|
114
|
-
|
|
115
|
-
@trace_select
|
|
116
|
-
def select(self, group_of_dates: GroupOfDates) -> JoinResult:
|
|
117
|
-
"""Selects the results for the given group of dates.
|
|
118
|
-
|
|
119
|
-
Parameters
|
|
120
|
-
----------
|
|
121
|
-
group_of_dates : GroupOfDates
|
|
122
|
-
The group of dates.
|
|
123
|
-
|
|
124
|
-
Returns
|
|
125
|
-
-------
|
|
126
|
-
JoinResult
|
|
127
|
-
The combined result for the given group of dates.
|
|
128
|
-
"""
|
|
129
|
-
results: List[Result] = [a.select(group_of_dates) for a in self.actions]
|
|
130
|
-
return JoinResult(self.context, self.action_path, group_of_dates, results)
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# (C) Copyright 2024 Anemoi contributors.
|
|
2
|
-
#
|
|
3
|
-
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
4
|
-
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
5
|
-
#
|
|
6
|
-
# In applying this licence, ECMWF does not waive the privileges and immunities
|
|
7
|
-
# granted to it by virtue of its status as an intergovernmental organisation
|
|
8
|
-
# nor does it submit to any jurisdiction.
|
|
9
|
-
|
|
10
|
-
import json
|
|
11
|
-
import logging
|
|
12
|
-
from typing import Any
|
|
13
|
-
|
|
14
|
-
from .action import Action
|
|
15
|
-
from .action import action_factory
|
|
16
|
-
from .step import step_factory
|
|
17
|
-
from .trace import trace_select
|
|
18
|
-
|
|
19
|
-
LOG = logging.getLogger(__name__)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class PipeAction(Action):
|
|
23
|
-
"""A class to represent a pipeline of actions."""
|
|
24
|
-
|
|
25
|
-
def __init__(self, context: Any, action_path: list, *configs: dict) -> None:
|
|
26
|
-
"""Initialize the PipeAction.
|
|
27
|
-
|
|
28
|
-
Parameters
|
|
29
|
-
----------
|
|
30
|
-
context : Any
|
|
31
|
-
The context for the action.
|
|
32
|
-
action_path : list
|
|
33
|
-
The path of the action.
|
|
34
|
-
configs : dict
|
|
35
|
-
The configurations for the actions.
|
|
36
|
-
"""
|
|
37
|
-
super().__init__(context, action_path, *configs)
|
|
38
|
-
if len(configs) <= 1:
|
|
39
|
-
raise ValueError(
|
|
40
|
-
f"PipeAction requires at least two actions, got {len(configs)}\n{json.dumps(configs, indent=2)}"
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
current: Any = action_factory(configs[0], context, action_path + ["0"])
|
|
44
|
-
for i, c in enumerate(configs[1:]):
|
|
45
|
-
current = step_factory(c, context, action_path + [str(i + 1)], previous_step=current)
|
|
46
|
-
self.last_step: Any = current
|
|
47
|
-
|
|
48
|
-
@trace_select
|
|
49
|
-
def select(self, group_of_dates: Any) -> Any:
|
|
50
|
-
"""Select data based on the group of dates.
|
|
51
|
-
|
|
52
|
-
Parameters
|
|
53
|
-
----------
|
|
54
|
-
group_of_dates : Any
|
|
55
|
-
The group of dates to select data for.
|
|
56
|
-
|
|
57
|
-
Returns
|
|
58
|
-
-------
|
|
59
|
-
Any
|
|
60
|
-
The selected data.
|
|
61
|
-
"""
|
|
62
|
-
return self.last_step.select(group_of_dates)
|
|
63
|
-
|
|
64
|
-
def __repr__(self) -> str:
|
|
65
|
-
"""Return a string representation of the PipeAction."""
|
|
66
|
-
return f"PipeAction({self.last_step})"
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# (C) Copyright 2024 Anemoi contributors.
|
|
2
|
-
#
|
|
3
|
-
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
4
|
-
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
5
|
-
#
|
|
6
|
-
# In applying this licence, ECMWF does not waive the privileges and immunities
|
|
7
|
-
# granted to it by virtue of its status as an intergovernmental organisation
|
|
8
|
-
# nor does it submit to any jurisdiction.
|
|
9
|
-
|
|
10
|
-
import logging
|
|
11
|
-
from copy import deepcopy
|
|
12
|
-
from typing import Any
|
|
13
|
-
from typing import Dict
|
|
14
|
-
from typing import List
|
|
15
|
-
from typing import Optional
|
|
16
|
-
from typing import Type
|
|
17
|
-
|
|
18
|
-
from .action import Action
|
|
19
|
-
from .action import ActionContext
|
|
20
|
-
from .context import Context
|
|
21
|
-
from .result import Result
|
|
22
|
-
from .template import notify_result
|
|
23
|
-
from .trace import trace_datasource
|
|
24
|
-
from .trace import trace_select
|
|
25
|
-
|
|
26
|
-
LOG = logging.getLogger(__name__)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class StepResult(Result):
|
|
30
|
-
"""Represents the result of a step in the data processing pipeline."""
|
|
31
|
-
|
|
32
|
-
def __init__(
|
|
33
|
-
self, context: Context, action_path: List[str], group_of_dates: Any, action: Action, upstream_result: Result
|
|
34
|
-
) -> None:
|
|
35
|
-
"""Initialize a StepResult instance.
|
|
36
|
-
|
|
37
|
-
Parameters
|
|
38
|
-
----------
|
|
39
|
-
context
|
|
40
|
-
The context in which the step is executed.
|
|
41
|
-
action_path
|
|
42
|
-
The path of actions leading to this step.
|
|
43
|
-
group_of_dates
|
|
44
|
-
The group of dates associated with this step.
|
|
45
|
-
action
|
|
46
|
-
The action associated with this step.
|
|
47
|
-
upstream_result
|
|
48
|
-
The result of the upstream step.
|
|
49
|
-
"""
|
|
50
|
-
super().__init__(context, action_path, group_of_dates)
|
|
51
|
-
assert isinstance(upstream_result, Result), type(upstream_result)
|
|
52
|
-
self.upstream_result: Result = upstream_result
|
|
53
|
-
self.action: Action = action
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
@notify_result
|
|
57
|
-
@trace_datasource
|
|
58
|
-
def datasource(self) -> Any:
|
|
59
|
-
"""Retrieve the datasource associated with this step result."""
|
|
60
|
-
raise NotImplementedError(f"Not implemented in {self.__class__.__name__}")
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class StepAction(Action):
|
|
64
|
-
"""Represents an action that is part of a step in the data processing pipeline."""
|
|
65
|
-
|
|
66
|
-
result_class: Optional[Type[StepResult]] = None
|
|
67
|
-
|
|
68
|
-
def __init__(
|
|
69
|
-
self, context: ActionContext, action_path: List[str], previous_step: Any, *args: Any, **kwargs: Any
|
|
70
|
-
) -> None:
|
|
71
|
-
"""Initialize a StepAction instance.
|
|
72
|
-
|
|
73
|
-
Parameters
|
|
74
|
-
----------
|
|
75
|
-
context
|
|
76
|
-
The context in which the action is executed.
|
|
77
|
-
action_path
|
|
78
|
-
The path of actions leading to this step.
|
|
79
|
-
previous_step
|
|
80
|
-
The previous step in the pipeline.
|
|
81
|
-
"""
|
|
82
|
-
super().__init__(context, action_path, *args, **kwargs)
|
|
83
|
-
self.previous_step: Any = previous_step
|
|
84
|
-
|
|
85
|
-
@trace_select
|
|
86
|
-
def select(self, group_of_dates: Any) -> StepResult:
|
|
87
|
-
"""Select the result for a given group of dates.
|
|
88
|
-
|
|
89
|
-
Parameters
|
|
90
|
-
----------
|
|
91
|
-
group_of_dates
|
|
92
|
-
The group of dates to select the result for.
|
|
93
|
-
|
|
94
|
-
Returns
|
|
95
|
-
-------
|
|
96
|
-
unknown
|
|
97
|
-
The result of the step.
|
|
98
|
-
"""
|
|
99
|
-
return self.result_class(
|
|
100
|
-
self.context,
|
|
101
|
-
self.action_path,
|
|
102
|
-
group_of_dates,
|
|
103
|
-
self,
|
|
104
|
-
self.previous_step.select(group_of_dates),
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
def __repr__(self) -> str:
|
|
108
|
-
"""Return a string representation of the StepAction instance.
|
|
109
|
-
|
|
110
|
-
Returns
|
|
111
|
-
-------
|
|
112
|
-
unknown
|
|
113
|
-
String representation of the instance.
|
|
114
|
-
"""
|
|
115
|
-
return self._repr(self.previous_step, _inline_=str(self.kwargs))
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def step_factory(config: Dict[str, Any], context: ActionContext, action_path: List[str], previous_step: Any) -> Any:
|
|
119
|
-
"""Factory function to create a step action based on the given configuration.
|
|
120
|
-
|
|
121
|
-
Parameters
|
|
122
|
-
----------
|
|
123
|
-
config
|
|
124
|
-
The configuration dictionary for the step.
|
|
125
|
-
context
|
|
126
|
-
The context in which the step is executed.
|
|
127
|
-
action_path
|
|
128
|
-
The path of actions leading to this step.
|
|
129
|
-
previous_step
|
|
130
|
-
The previous step in the pipeline.
|
|
131
|
-
|
|
132
|
-
Returns
|
|
133
|
-
-------
|
|
134
|
-
unknown
|
|
135
|
-
An instance of a step action.
|
|
136
|
-
"""
|
|
137
|
-
|
|
138
|
-
from .filter import FilterStepAction
|
|
139
|
-
from .filter import FunctionStepAction
|
|
140
|
-
|
|
141
|
-
assert isinstance(context, Context), (type, context)
|
|
142
|
-
if not isinstance(config, dict):
|
|
143
|
-
raise ValueError(f"Invalid input config {config}")
|
|
144
|
-
|
|
145
|
-
config = deepcopy(config)
|
|
146
|
-
assert len(config) == 1, config
|
|
147
|
-
|
|
148
|
-
key = list(config.keys())[0]
|
|
149
|
-
cls = dict(
|
|
150
|
-
filter=FilterStepAction,
|
|
151
|
-
# rename=RenameAction,
|
|
152
|
-
# remapping=RemappingAction,
|
|
153
|
-
).get(key)
|
|
154
|
-
|
|
155
|
-
if isinstance(config[key], list):
|
|
156
|
-
args, kwargs = config[key], {}
|
|
157
|
-
|
|
158
|
-
if isinstance(config[key], dict):
|
|
159
|
-
args, kwargs = [], config[key]
|
|
160
|
-
|
|
161
|
-
if isinstance(config[key], str):
|
|
162
|
-
args, kwargs = [config[key]], {}
|
|
163
|
-
|
|
164
|
-
if cls is not None:
|
|
165
|
-
return cls(context, action_path, previous_step, *args, **kwargs)
|
|
166
|
-
|
|
167
|
-
# Try filters from transform filter registry
|
|
168
|
-
from anemoi.transform.filters import filter_registry as transform_filter_registry
|
|
169
|
-
|
|
170
|
-
if transform_filter_registry.is_registered(key):
|
|
171
|
-
from ..filter import TransformFilter
|
|
172
|
-
|
|
173
|
-
return FunctionStepAction(
|
|
174
|
-
context, action_path + [key], previous_step, key, TransformFilter(context, key, config)
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
raise ValueError(f"Unknown step action `{key}`")
|