anemoi-datasets 0.5.16__py3-none-any.whl → 0.5.17__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.
Files changed (155) hide show
  1. anemoi/datasets/__init__.py +4 -1
  2. anemoi/datasets/__main__.py +12 -2
  3. anemoi/datasets/_version.py +9 -4
  4. anemoi/datasets/commands/cleanup.py +17 -2
  5. anemoi/datasets/commands/compare.py +18 -2
  6. anemoi/datasets/commands/copy.py +196 -14
  7. anemoi/datasets/commands/create.py +50 -7
  8. anemoi/datasets/commands/finalise-additions.py +17 -2
  9. anemoi/datasets/commands/finalise.py +17 -2
  10. anemoi/datasets/commands/init-additions.py +17 -2
  11. anemoi/datasets/commands/init.py +16 -2
  12. anemoi/datasets/commands/inspect.py +283 -62
  13. anemoi/datasets/commands/load-additions.py +16 -2
  14. anemoi/datasets/commands/load.py +16 -2
  15. anemoi/datasets/commands/patch.py +17 -2
  16. anemoi/datasets/commands/publish.py +17 -2
  17. anemoi/datasets/commands/scan.py +31 -3
  18. anemoi/datasets/compute/recentre.py +47 -11
  19. anemoi/datasets/create/__init__.py +612 -85
  20. anemoi/datasets/create/check.py +142 -20
  21. anemoi/datasets/create/chunks.py +64 -4
  22. anemoi/datasets/create/config.py +185 -21
  23. anemoi/datasets/create/filter.py +50 -0
  24. anemoi/datasets/create/filters/__init__.py +33 -0
  25. anemoi/datasets/create/filters/empty.py +37 -0
  26. anemoi/datasets/create/filters/legacy.py +93 -0
  27. anemoi/datasets/create/filters/noop.py +37 -0
  28. anemoi/datasets/create/filters/orog_to_z.py +58 -0
  29. anemoi/datasets/create/{functions/filters → filters}/pressure_level_relative_humidity_to_specific_humidity.py +33 -10
  30. anemoi/datasets/create/{functions/filters → filters}/pressure_level_specific_humidity_to_relative_humidity.py +32 -8
  31. anemoi/datasets/create/filters/rename.py +205 -0
  32. anemoi/datasets/create/{functions/filters → filters}/rotate_winds.py +43 -28
  33. anemoi/datasets/create/{functions/filters → filters}/single_level_dewpoint_to_relative_humidity.py +32 -9
  34. anemoi/datasets/create/{functions/filters → filters}/single_level_relative_humidity_to_dewpoint.py +33 -9
  35. anemoi/datasets/create/{functions/filters → filters}/single_level_relative_humidity_to_specific_humidity.py +55 -7
  36. anemoi/datasets/create/{functions/filters → filters}/single_level_specific_humidity_to_relative_humidity.py +98 -37
  37. anemoi/datasets/create/filters/speeddir_to_uv.py +95 -0
  38. anemoi/datasets/create/{functions/filters → filters}/sum.py +24 -27
  39. anemoi/datasets/create/filters/transform.py +53 -0
  40. anemoi/datasets/create/{functions/filters → filters}/unrotate_winds.py +27 -18
  41. anemoi/datasets/create/filters/uv_to_speeddir.py +94 -0
  42. anemoi/datasets/create/{functions/filters → filters}/wz_to_w.py +51 -33
  43. anemoi/datasets/create/input/__init__.py +76 -5
  44. anemoi/datasets/create/input/action.py +149 -13
  45. anemoi/datasets/create/input/concat.py +81 -10
  46. anemoi/datasets/create/input/context.py +39 -4
  47. anemoi/datasets/create/input/data_sources.py +72 -6
  48. anemoi/datasets/create/input/empty.py +21 -3
  49. anemoi/datasets/create/input/filter.py +60 -12
  50. anemoi/datasets/create/input/function.py +154 -37
  51. anemoi/datasets/create/input/join.py +86 -14
  52. anemoi/datasets/create/input/misc.py +67 -17
  53. anemoi/datasets/create/input/pipe.py +33 -6
  54. anemoi/datasets/create/input/repeated_dates.py +189 -41
  55. anemoi/datasets/create/input/result.py +202 -87
  56. anemoi/datasets/create/input/step.py +119 -22
  57. anemoi/datasets/create/input/template.py +100 -13
  58. anemoi/datasets/create/input/trace.py +62 -7
  59. anemoi/datasets/create/patch.py +52 -4
  60. anemoi/datasets/create/persistent.py +134 -17
  61. anemoi/datasets/create/size.py +15 -1
  62. anemoi/datasets/create/source.py +51 -0
  63. anemoi/datasets/create/sources/__init__.py +36 -0
  64. anemoi/datasets/create/{functions/sources → sources}/accumulations.py +296 -30
  65. anemoi/datasets/create/{functions/sources → sources}/constants.py +27 -2
  66. anemoi/datasets/create/{functions/sources → sources}/eccc_fstd.py +7 -3
  67. anemoi/datasets/create/sources/empty.py +37 -0
  68. anemoi/datasets/create/{functions/sources → sources}/forcings.py +25 -1
  69. anemoi/datasets/create/sources/grib.py +297 -0
  70. anemoi/datasets/create/{functions/sources → sources}/hindcasts.py +38 -4
  71. anemoi/datasets/create/sources/legacy.py +93 -0
  72. anemoi/datasets/create/{functions/sources → sources}/mars.py +168 -20
  73. anemoi/datasets/create/sources/netcdf.py +42 -0
  74. anemoi/datasets/create/sources/opendap.py +43 -0
  75. anemoi/datasets/create/{functions/sources/__init__.py → sources/patterns.py} +35 -4
  76. anemoi/datasets/create/sources/recentre.py +150 -0
  77. anemoi/datasets/create/{functions/sources → sources}/source.py +27 -5
  78. anemoi/datasets/create/{functions/sources → sources}/tendencies.py +64 -7
  79. anemoi/datasets/create/sources/xarray.py +92 -0
  80. anemoi/datasets/create/sources/xarray_kerchunk.py +36 -0
  81. anemoi/datasets/create/sources/xarray_support/README.md +1 -0
  82. anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/__init__.py +109 -8
  83. anemoi/datasets/create/sources/xarray_support/coordinates.py +442 -0
  84. anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/field.py +94 -16
  85. anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/fieldlist.py +90 -25
  86. anemoi/datasets/create/sources/xarray_support/flavour.py +1036 -0
  87. anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/grid.py +92 -31
  88. anemoi/datasets/create/sources/xarray_support/metadata.py +395 -0
  89. anemoi/datasets/create/sources/xarray_support/patch.py +91 -0
  90. anemoi/datasets/create/sources/xarray_support/time.py +391 -0
  91. anemoi/datasets/create/sources/xarray_support/variable.py +331 -0
  92. anemoi/datasets/create/sources/xarray_zarr.py +41 -0
  93. anemoi/datasets/create/{functions/sources → sources}/zenodo.py +34 -5
  94. anemoi/datasets/create/statistics/__init__.py +233 -44
  95. anemoi/datasets/create/statistics/summary.py +52 -6
  96. anemoi/datasets/create/testing.py +76 -0
  97. anemoi/datasets/create/{functions/filters/noop.py → typing.py} +6 -3
  98. anemoi/datasets/create/utils.py +97 -6
  99. anemoi/datasets/create/writer.py +26 -4
  100. anemoi/datasets/create/zarr.py +170 -23
  101. anemoi/datasets/data/__init__.py +51 -4
  102. anemoi/datasets/data/complement.py +191 -40
  103. anemoi/datasets/data/concat.py +141 -16
  104. anemoi/datasets/data/dataset.py +552 -61
  105. anemoi/datasets/data/debug.py +197 -26
  106. anemoi/datasets/data/ensemble.py +93 -8
  107. anemoi/datasets/data/fill_missing.py +165 -18
  108. anemoi/datasets/data/forwards.py +428 -56
  109. anemoi/datasets/data/grids.py +323 -97
  110. anemoi/datasets/data/indexing.py +112 -19
  111. anemoi/datasets/data/interpolate.py +92 -12
  112. anemoi/datasets/data/join.py +158 -19
  113. anemoi/datasets/data/masked.py +129 -15
  114. anemoi/datasets/data/merge.py +137 -23
  115. anemoi/datasets/data/misc.py +172 -16
  116. anemoi/datasets/data/missing.py +233 -29
  117. anemoi/datasets/data/rescale.py +111 -10
  118. anemoi/datasets/data/select.py +168 -26
  119. anemoi/datasets/data/statistics.py +67 -6
  120. anemoi/datasets/data/stores.py +149 -64
  121. anemoi/datasets/data/subset.py +159 -25
  122. anemoi/datasets/data/unchecked.py +168 -57
  123. anemoi/datasets/data/xy.py +168 -25
  124. anemoi/datasets/dates/__init__.py +191 -16
  125. anemoi/datasets/dates/groups.py +189 -47
  126. anemoi/datasets/grids.py +270 -31
  127. anemoi/datasets/testing.py +28 -1
  128. {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.17.dist-info}/METADATA +9 -6
  129. anemoi_datasets-0.5.17.dist-info/RECORD +137 -0
  130. {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.17.dist-info}/WHEEL +1 -1
  131. anemoi/datasets/create/functions/__init__.py +0 -66
  132. anemoi/datasets/create/functions/filters/__init__.py +0 -9
  133. anemoi/datasets/create/functions/filters/empty.py +0 -17
  134. anemoi/datasets/create/functions/filters/orog_to_z.py +0 -58
  135. anemoi/datasets/create/functions/filters/rename.py +0 -79
  136. anemoi/datasets/create/functions/filters/speeddir_to_uv.py +0 -78
  137. anemoi/datasets/create/functions/filters/uv_to_speeddir.py +0 -56
  138. anemoi/datasets/create/functions/sources/empty.py +0 -15
  139. anemoi/datasets/create/functions/sources/grib.py +0 -150
  140. anemoi/datasets/create/functions/sources/netcdf.py +0 -15
  141. anemoi/datasets/create/functions/sources/opendap.py +0 -15
  142. anemoi/datasets/create/functions/sources/recentre.py +0 -60
  143. anemoi/datasets/create/functions/sources/xarray/coordinates.py +0 -255
  144. anemoi/datasets/create/functions/sources/xarray/flavour.py +0 -472
  145. anemoi/datasets/create/functions/sources/xarray/metadata.py +0 -148
  146. anemoi/datasets/create/functions/sources/xarray/patch.py +0 -44
  147. anemoi/datasets/create/functions/sources/xarray/time.py +0 -177
  148. anemoi/datasets/create/functions/sources/xarray/variable.py +0 -188
  149. anemoi/datasets/create/functions/sources/xarray_kerchunk.py +0 -42
  150. anemoi/datasets/create/functions/sources/xarray_zarr.py +0 -15
  151. anemoi/datasets/utils/fields.py +0 -47
  152. anemoi_datasets-0.5.16.dist-info/RECORD +0 -129
  153. {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.17.dist-info}/entry_points.txt +0 -0
  154. {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.17.dist-info/licenses}/LICENSE +0 -0
  155. {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.17.dist-info}/top_level.txt +0 -0
@@ -12,6 +12,17 @@ import logging
12
12
  import os
13
13
  import textwrap
14
14
  from functools import wraps
15
+ from typing import TYPE_CHECKING
16
+ from typing import Any
17
+ from typing import Callable
18
+ from typing import List
19
+ from typing import Optional
20
+
21
+ from anemoi.utils.text import Tree
22
+ from numpy.typing import NDArray
23
+
24
+ if TYPE_CHECKING:
25
+ from .dataset import Dataset
15
26
 
16
27
  LOG = logging.getLogger(__name__)
17
28
 
@@ -24,20 +35,55 @@ DEPTH = 0
24
35
  # a.flags.writeable = False
25
36
 
26
37
 
27
- def css(name):
38
+ def css(name: str) -> str:
39
+ """Get the CSS content from a file.
40
+
41
+ Parameters
42
+ ----------
43
+ name : str
44
+ The name of the CSS file.
45
+
46
+ Returns
47
+ -------
48
+ str
49
+ The CSS content.
50
+ """
28
51
  path = os.path.join(os.path.dirname(__file__), f"{name}.css")
29
52
  with open(path) as f:
30
53
  return f"<style>{f.read()}</style>"
31
54
 
32
55
 
33
56
  class Node:
34
- def __init__(self, dataset, kids, **kwargs):
57
+ """A class to represent a node in a dataset tree."""
58
+
59
+ def __init__(self, dataset: "Dataset", kids: List[Any], **kwargs: Any) -> None:
60
+ """Initializes a Node object.
61
+
62
+ Parameters
63
+ ----------
64
+ dataset : Dataset
65
+ The dataset associated with the node.
66
+ kids : List[Any]
67
+ List of child nodes.
68
+ kwargs : Any
69
+ Additional keyword arguments.
70
+ """
35
71
  self.dataset = dataset
36
72
  self.kids = kids
37
73
  self.kwargs = kwargs
38
74
 
39
- def _put(self, indent, result):
40
- def _spaces(indent):
75
+ def _put(self, indent: int, result: List[str]) -> None:
76
+ """Helper method to add the node representation to the result list.
77
+
78
+ Parameters
79
+ ----------
80
+ indent : int
81
+ Indentation level.
82
+ result : List[str]
83
+ List to store the node representation.
84
+ """
85
+
86
+ def _spaces(indent: int) -> str:
41
87
  return " " * indent if indent else ""
42
88
 
43
89
  result.append(f"{_spaces(indent)}{self.dataset.__class__.__name__}")
@@ -49,12 +95,28 @@ class Node:
49
95
  for kid in self.kids:
50
96
  kid._put(indent + 2, result)
51
97
 
52
- def __repr__(self):
53
- result = []
98
+ def __repr__(self) -> str:
99
+ """Returns the string representation of the node.
100
+
101
+ Returns
102
+ -------
103
+ str
104
+ String representation of the node.
105
+ """
106
+ result: List[str] = []
54
107
  self._put(0, result)
55
108
  return "\n".join(result)
56
109
 
57
- def graph(self, digraph, nodes):
110
+ def graph(self, digraph: List[str], nodes: dict) -> None:
111
+ """Generates a graph representation of the node.
112
+
113
+ Parameters
114
+ ----------
115
+ digraph : List[str]
116
+ List to store the graph representation.
117
+ nodes : dict
118
+ Dictionary to store the node labels.
119
+ """
58
120
  label = self.dataset.label # dataset.__class__.__name__.lower()
59
121
  if self.kwargs:
60
122
  param = []
@@ -88,7 +150,14 @@ class Node:
88
150
  digraph.append(f"N{id(self)} -> N{id(kid)}")
89
151
  kid.graph(digraph, nodes)
90
152
 
91
- def digraph(self):
153
+ def digraph(self) -> str:
154
+ """Returns the graph representation of the node.
155
+
156
+ Returns
157
+ -------
158
+ str
159
+ Graph representation of the node.
160
+ """
92
161
  digraph = ["digraph {"]
93
162
  digraph.append("node [shape=box];")
94
163
  nodes = {}
@@ -101,8 +170,16 @@ class Node:
101
170
  digraph.append("}")
102
171
  return "\n".join(digraph)
103
172
 
104
- def _html(self, indent, rows):
173
+ def _html(self, indent: str, rows: List[List[str]]) -> None:
174
+ """Helper method to add the node representation to the HTML rows.
105
175
 
176
+ Parameters
177
+ ----------
178
+ indent : str
179
+ Indentation level.
180
+ rows : List[List[str]]
181
+ List to store the HTML rows.
182
+ """
106
183
  kwargs = {}
107
184
 
108
185
  for k, v in self.kwargs.items():
@@ -130,7 +207,14 @@ class Node:
130
207
  for kid in self.kids:
131
208
  kid._html(indent + "&nbsp;&nbsp;&nbsp;", rows)
132
209
 
133
- def html(self):
210
+ def html(self) -> str:
211
+ """Returns the HTML representation of the node.
212
+
213
+ Returns
214
+ -------
215
+ str
216
+ HTML representation of the node.
217
+ """
134
218
  result = [css("debug")]
135
219
 
136
220
  result.append('<table class="dataset">')
@@ -145,37 +229,78 @@ class Node:
145
229
  result.append("</table>")
146
230
  return "\n".join(result)
147
231
 
148
- def _as_tree(self, tree):
232
+ def _as_tree(self, tree: Any) -> None:
233
+ """Helper method to add the node representation to the tree.
149
234
 
235
+ Parameters
236
+ ----------
237
+ tree : Any
238
+ Tree object to store the node representation.
239
+ """
150
240
  for kid in self.kids:
151
241
  n = tree.node(kid)
152
242
  kid._as_tree(n)
153
243
 
154
- def as_tree(self):
155
- from anemoi.utils.text import Tree
244
+ def as_tree(self) -> Tree:
245
+ """Returns the tree representation of the node.
246
+
247
+ Returns
248
+ -------
249
+ Tree
250
+ Tree representation of the node.
251
+ """
156
252
 
157
253
  tree = Tree(self)
158
254
  self._as_tree(tree)
159
255
  return tree
160
256
 
161
257
  @property
162
- def summary(self):
258
+ def summary(self) -> str:
259
+ """Returns the summary of the node."""
163
260
  return self.dataset.label
164
261
 
165
- def as_dict(self):
262
+ def as_dict(self) -> dict:
263
+ """Returns the dictionary representation of the node.
264
+
265
+ Returns
266
+ -------
267
+ dict
268
+ Dictionary representation of the node.
269
+ """
166
270
  return {}
167
271
 
168
272
 
169
273
  class Source:
170
- """Class used to follow the provenance of a data point."""
171
-
172
- def __init__(self, dataset, index, source=None, info=None):
274
+ """A class used to follow the provenance of a data point."""
275
+
276
+ def __init__(self, dataset: Any, index: int, source: Optional[Any] = None, info: Optional[Any] = None) -> None:
277
+ """Initializes a Source object.
278
+
279
+ Parameters
280
+ ----------
281
+ dataset : Any
282
+ The dataset associated with the source.
283
+ index : int
284
+ Index of the data point.
285
+ source : Optional[Any], optional
286
+ Source of the data point, by default None.
287
+ info : Optional[Any], optional
288
+ Additional information, by default None.
289
+ """
173
290
  self.dataset = dataset
291
+
174
292
  self.index = index
175
293
  self.source = source
176
294
  self.info = info
177
295
 
178
- def __repr__(self):
296
+ def __repr__(self) -> str:
297
+ """Returns the string representation of the source.
298
+
299
+ Returns
300
+ -------
301
+ str
302
+ String representation of the source.
303
+ """
179
304
  p = s = self.source
180
305
  while s is not None:
181
306
  p = s
@@ -183,22 +308,49 @@ class Source:
183
308
 
184
309
  return f"{self.dataset}[{self.index}, {self.dataset.variables[self.index]}] ({p})"
185
310
 
186
- def target(self):
311
+ def target(self) -> Any:
312
+ """Returns the target source.
313
+
314
+ Returns
315
+ -------
316
+ Any
317
+ Target source.
318
+ """
187
319
  p = s = self.source
188
320
  while s is not None:
189
321
  p = s
190
322
  s = s.source
191
323
  return p
192
324
 
193
- def dump(self, depth=0):
325
+ def dump(self, depth: int = 0) -> None:
326
+ """Dumps the source information.
327
+
328
+ Parameters
329
+ ----------
330
+ depth : int, optional
331
+ Indentation level, by default 0.
332
+ """
194
333
  print(" " * depth, self)
195
334
  if self.source is not None:
196
335
  self.source.dump(depth + 1)
197
336
 
198
337
 
199
- def _debug_indexing(method):
338
+ def _debug_indexing(method: Callable[..., NDArray[Any]]) -> Callable[..., NDArray[Any]]:
339
+ """Decorator to debug indexing methods.
340
+
341
+ Parameters
342
+ ----------
343
+ method : Callable[..., NDArray[Any]]
344
+ The method to be decorated.
345
+
346
+ Returns
347
+ -------
348
+ Callable[..., NDArray[Any]]
349
+ The decorated method.
350
+ """
351
+
200
352
  @wraps(method)
201
- def wrapper(self, index):
353
+ def wrapper(self: Any, index: Any) -> NDArray[Any]:
202
354
  global DEPTH
203
355
  # if isinstance(index, tuple):
204
356
  print(" " * DEPTH, "->", self, method.__name__, index)
@@ -212,8 +364,20 @@ def _debug_indexing(method):
212
364
  return wrapper
213
365
 
214
366
 
215
- def _identity(x):
216
- return x
367
+ def _identity(method: Callable[..., NDArray[Any]]) -> Callable[..., NDArray[Any]]:
368
+ """Identity function.
369
+
370
+ Parameters
371
+ ----------
372
+ method : Callable[..., NDArray[Any]]
373
+ Input method.
374
+
375
+ Returns
376
+ -------
377
+ Callable[..., NDArray[Any]]
378
+ The input method.
379
+ """
380
+ return method
217
381
 
218
382
 
219
383
  if DEBUG_ZARR_INDEXING:
@@ -222,6 +386,13 @@ else:
222
386
  debug_indexing = _identity
223
387
 
224
388
 
225
- def debug_zarr_loading(on_off):
389
+ def debug_zarr_loading(on_off: int) -> None:
390
+ """Enables or disables Zarr loading debugging.
391
+
392
+ Parameters
393
+ ----------
394
+ on_off : int
395
+ 1 to enable debugging, 0 to disable.
396
+ """
226
397
  global DEBUG_ZARR_LOADING
227
398
  DEBUG_ZARR_LOADING = on_off
@@ -9,9 +9,16 @@
9
9
 
10
10
 
11
11
  import logging
12
+ from typing import Any
13
+ from typing import Dict
14
+ from typing import Tuple
12
15
 
13
16
  import numpy as np
17
+ from numpy.typing import NDArray
14
18
 
19
+ from .dataset import Dataset
20
+ from .dataset import FullIndex
21
+ from .dataset import Shape
15
22
  from .debug import Node
16
23
  from .forwards import Forwards
17
24
  from .forwards import GivenAxis
@@ -27,7 +34,18 @@ OFFSETS = dict(number=1, numbers=1, member=0, members=0)
27
34
 
28
35
 
29
36
  class Number(Forwards):
30
- def __init__(self, forward, **kwargs):
37
+ """A class to represent a subset of ensemble members from a dataset."""
38
+
39
+ def __init__(self, forward: Dataset, **kwargs: Any) -> None:
40
+ """Initializes a Number object.
41
+
42
+ Parameters
43
+ ----------
44
+ forward : Any
45
+ The dataset to forward.
46
+ kwargs : Any
47
+ Additional keyword arguments specifying the members.
48
+ """
31
49
  super().__init__(forward)
32
50
 
33
51
  self.members = []
@@ -45,10 +63,23 @@ class Number(Forwards):
45
63
  self._shape, _ = update_tuple(forward.shape, 2, len(self.members))
46
64
 
47
65
  @property
48
- def shape(self):
66
+ def shape(self) -> Shape:
67
+ """Returns the shape of the dataset."""
49
68
  return self._shape
50
69
 
51
- def __getitem__(self, index):
70
+ def __getitem__(self, index: FullIndex) -> NDArray[Any]:
71
+ """Retrieves data from the dataset based on the given index.
72
+
73
+ Parameters
74
+ ----------
75
+ index : FullIndex
76
+ Index specifying the data to retrieve.
77
+
78
+ Returns
79
+ -------
80
+ NDArray[Any]
81
+ Data array from the dataset based on the index.
82
+ """
52
83
  if isinstance(index, int):
53
84
  result = self.forward[index]
54
85
  result = result[:, self.mask, :]
@@ -59,26 +90,80 @@ class Number(Forwards):
59
90
  result = result[:, :, self.mask, :]
60
91
  return result
61
92
 
62
- index, changes = index_to_slices(index, self.shape)
93
+ index, changes = index_to_slices(index, self.forward.shape)
63
94
  result = self.forward[index]
64
95
  result = result[:, :, self.mask, :]
65
96
  return apply_index_to_slices_changes(result, changes)
66
97
 
67
- def tree(self):
98
+ def tree(self) -> Node:
99
+ """Generates a hierarchical tree structure for the dataset.
100
+
101
+ Returns
102
+ -------
103
+ Node
104
+ A Node object representing the dataset.
105
+ """
68
106
  return Node(self, [self.forward.tree()], numbers=[n + 1 for n in self.members])
69
107
 
70
- def metadata_specific(self):
108
+ def metadata_specific(self, **kwargs: Any) -> Dict[str, Any]:
109
+ """Returns metadata specific to the Number object.
110
+
111
+ Parameters
112
+ ----------
113
+ kwargs : Any
114
+ Additional keyword arguments.
115
+
116
+ Returns
117
+ -------
118
+ Dict[str, Any]
119
+ Metadata specific to the Number object.
120
+ """
71
121
  return {
72
122
  "numbers": [n + 1 for n in self.members],
73
123
  }
74
124
 
125
+ def forwards_subclass_metadata_specific(self) -> Dict[str, Any]:
126
+ """Returns metadata specific to the Number object."""
127
+ return {}
128
+
75
129
 
76
130
  class Ensemble(GivenAxis):
77
- def tree(self):
131
+ """A class to represent an ensemble of datasets combined along a given axis."""
132
+
133
+ def tree(self) -> Node:
134
+ """Generates a hierarchical tree structure for the ensemble datasets.
135
+
136
+ Returns
137
+ -------
138
+ Node
139
+ A Node object representing the ensemble datasets.
140
+ """
78
141
  return Node(self, [d.tree() for d in self.datasets])
79
142
 
143
+ def forwards_subclass_metadata_specific(self) -> Dict[str, Any]:
144
+ """Get the metadata specific to the forwards subclass.
145
+
146
+ Returns:
147
+ Dict[str, Any]: The metadata specific to the forwards subclass.
148
+ """
149
+ return {}
150
+
151
+
152
+ def ensemble_factory(args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> Ensemble:
153
+ """Factory function to create an Ensemble object.
154
+
155
+ Parameters
156
+ ----------
157
+ args : Tuple[Any, ...]
158
+ Positional arguments.
159
+ kwargs : dict
160
+ Keyword arguments.
80
161
 
81
- def ensemble_factory(args, kwargs):
162
+ Returns
163
+ -------
164
+ Ensemble
165
+ An Ensemble object.
166
+ """
82
167
  if "grids" in kwargs:
83
168
  raise NotImplementedError("Cannot use both 'ensemble' and 'grids'")
84
169