anemoi-datasets 0.5.25__py3-none-any.whl → 0.5.27__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 (126) hide show
  1. anemoi/datasets/__init__.py +1 -2
  2. anemoi/datasets/_version.py +16 -3
  3. anemoi/datasets/commands/check.py +1 -1
  4. anemoi/datasets/commands/copy.py +1 -2
  5. anemoi/datasets/commands/create.py +1 -1
  6. anemoi/datasets/commands/grib-index.py +1 -1
  7. anemoi/datasets/commands/inspect.py +27 -35
  8. anemoi/datasets/commands/validate.py +59 -0
  9. anemoi/datasets/compute/recentre.py +3 -6
  10. anemoi/datasets/create/__init__.py +22 -25
  11. anemoi/datasets/create/check.py +10 -12
  12. anemoi/datasets/create/chunks.py +1 -2
  13. anemoi/datasets/create/config.py +3 -6
  14. anemoi/datasets/create/filter.py +21 -24
  15. anemoi/datasets/create/input/__init__.py +1 -2
  16. anemoi/datasets/create/input/action.py +3 -5
  17. anemoi/datasets/create/input/concat.py +5 -8
  18. anemoi/datasets/create/input/context.py +3 -6
  19. anemoi/datasets/create/input/data_sources.py +5 -8
  20. anemoi/datasets/create/input/empty.py +1 -2
  21. anemoi/datasets/create/input/filter.py +2 -3
  22. anemoi/datasets/create/input/function.py +1 -2
  23. anemoi/datasets/create/input/join.py +4 -5
  24. anemoi/datasets/create/input/misc.py +4 -6
  25. anemoi/datasets/create/input/repeated_dates.py +13 -18
  26. anemoi/datasets/create/input/result.py +29 -33
  27. anemoi/datasets/create/input/step.py +6 -24
  28. anemoi/datasets/create/input/template.py +3 -4
  29. anemoi/datasets/create/input/trace.py +1 -1
  30. anemoi/datasets/create/patch.py +1 -2
  31. anemoi/datasets/create/persistent.py +3 -5
  32. anemoi/datasets/create/size.py +1 -3
  33. anemoi/datasets/create/sources/accumulations.py +47 -52
  34. anemoi/datasets/create/sources/accumulations2.py +4 -8
  35. anemoi/datasets/create/sources/constants.py +1 -3
  36. anemoi/datasets/create/sources/empty.py +1 -2
  37. anemoi/datasets/create/sources/fdb.py +133 -0
  38. anemoi/datasets/create/sources/forcings.py +1 -2
  39. anemoi/datasets/create/sources/grib.py +6 -10
  40. anemoi/datasets/create/sources/grib_index.py +13 -15
  41. anemoi/datasets/create/sources/hindcasts.py +2 -5
  42. anemoi/datasets/create/sources/legacy.py +1 -1
  43. anemoi/datasets/create/sources/mars.py +17 -21
  44. anemoi/datasets/create/sources/netcdf.py +1 -2
  45. anemoi/datasets/create/sources/opendap.py +1 -3
  46. anemoi/datasets/create/sources/patterns.py +4 -6
  47. anemoi/datasets/create/sources/planetary_computer.py +44 -0
  48. anemoi/datasets/create/sources/recentre.py +8 -11
  49. anemoi/datasets/create/sources/source.py +3 -6
  50. anemoi/datasets/create/sources/tendencies.py +2 -5
  51. anemoi/datasets/create/sources/xarray.py +4 -6
  52. anemoi/datasets/create/sources/xarray_support/__init__.py +15 -32
  53. anemoi/datasets/create/sources/xarray_support/coordinates.py +16 -12
  54. anemoi/datasets/create/sources/xarray_support/field.py +17 -16
  55. anemoi/datasets/create/sources/xarray_support/fieldlist.py +11 -15
  56. anemoi/datasets/create/sources/xarray_support/flavour.py +83 -45
  57. anemoi/datasets/create/sources/xarray_support/grid.py +15 -9
  58. anemoi/datasets/create/sources/xarray_support/metadata.py +19 -128
  59. anemoi/datasets/create/sources/xarray_support/patch.py +47 -6
  60. anemoi/datasets/create/sources/xarray_support/time.py +10 -13
  61. anemoi/datasets/create/sources/xarray_support/variable.py +27 -23
  62. anemoi/datasets/create/sources/xarray_zarr.py +1 -2
  63. anemoi/datasets/create/sources/zenodo.py +3 -5
  64. anemoi/datasets/create/statistics/__init__.py +3 -6
  65. anemoi/datasets/create/testing.py +2 -74
  66. anemoi/datasets/create/typing.py +1 -2
  67. anemoi/datasets/create/utils.py +1 -2
  68. anemoi/datasets/create/zarr.py +7 -2
  69. anemoi/datasets/data/__init__.py +15 -6
  70. anemoi/datasets/data/complement.py +52 -23
  71. anemoi/datasets/data/concat.py +5 -8
  72. anemoi/datasets/data/dataset.py +42 -47
  73. anemoi/datasets/data/debug.py +7 -9
  74. anemoi/datasets/data/ensemble.py +4 -6
  75. anemoi/datasets/data/fill_missing.py +7 -10
  76. anemoi/datasets/data/forwards.py +30 -28
  77. anemoi/datasets/data/grids.py +12 -16
  78. anemoi/datasets/data/indexing.py +9 -12
  79. anemoi/datasets/data/interpolate.py +7 -15
  80. anemoi/datasets/data/join.py +8 -12
  81. anemoi/datasets/data/masked.py +6 -11
  82. anemoi/datasets/data/merge.py +5 -9
  83. anemoi/datasets/data/misc.py +41 -45
  84. anemoi/datasets/data/missing.py +11 -16
  85. anemoi/datasets/data/observations/__init__.py +8 -14
  86. anemoi/datasets/data/padded.py +3 -5
  87. anemoi/datasets/data/records/backends/__init__.py +2 -2
  88. anemoi/datasets/data/rescale.py +5 -12
  89. anemoi/datasets/data/select.py +13 -16
  90. anemoi/datasets/data/statistics.py +4 -7
  91. anemoi/datasets/data/stores.py +23 -77
  92. anemoi/datasets/data/subset.py +8 -11
  93. anemoi/datasets/data/unchecked.py +7 -11
  94. anemoi/datasets/data/xy.py +25 -21
  95. anemoi/datasets/dates/__init__.py +13 -18
  96. anemoi/datasets/dates/groups.py +7 -10
  97. anemoi/datasets/grids.py +11 -12
  98. anemoi/datasets/testing.py +93 -7
  99. anemoi/datasets/validate.py +598 -0
  100. {anemoi_datasets-0.5.25.dist-info → anemoi_datasets-0.5.27.dist-info}/METADATA +5 -4
  101. anemoi_datasets-0.5.27.dist-info/RECORD +134 -0
  102. anemoi/datasets/create/filters/__init__.py +0 -33
  103. anemoi/datasets/create/filters/empty.py +0 -37
  104. anemoi/datasets/create/filters/legacy.py +0 -93
  105. anemoi/datasets/create/filters/noop.py +0 -37
  106. anemoi/datasets/create/filters/orog_to_z.py +0 -58
  107. anemoi/datasets/create/filters/pressure_level_relative_humidity_to_specific_humidity.py +0 -83
  108. anemoi/datasets/create/filters/pressure_level_specific_humidity_to_relative_humidity.py +0 -84
  109. anemoi/datasets/create/filters/rename.py +0 -205
  110. anemoi/datasets/create/filters/rotate_winds.py +0 -105
  111. anemoi/datasets/create/filters/single_level_dewpoint_to_relative_humidity.py +0 -78
  112. anemoi/datasets/create/filters/single_level_relative_humidity_to_dewpoint.py +0 -84
  113. anemoi/datasets/create/filters/single_level_relative_humidity_to_specific_humidity.py +0 -163
  114. anemoi/datasets/create/filters/single_level_specific_humidity_to_relative_humidity.py +0 -451
  115. anemoi/datasets/create/filters/speeddir_to_uv.py +0 -95
  116. anemoi/datasets/create/filters/sum.py +0 -68
  117. anemoi/datasets/create/filters/transform.py +0 -51
  118. anemoi/datasets/create/filters/unrotate_winds.py +0 -105
  119. anemoi/datasets/create/filters/uv_to_speeddir.py +0 -94
  120. anemoi/datasets/create/filters/wz_to_w.py +0 -98
  121. anemoi/datasets/utils/__init__.py +0 -8
  122. anemoi_datasets-0.5.25.dist-info/RECORD +0 -150
  123. {anemoi_datasets-0.5.25.dist-info → anemoi_datasets-0.5.27.dist-info}/WHEEL +0 -0
  124. {anemoi_datasets-0.5.25.dist-info → anemoi_datasets-0.5.27.dist-info}/entry_points.txt +0 -0
  125. {anemoi_datasets-0.5.25.dist-info → anemoi_datasets-0.5.27.dist-info}/licenses/LICENSE +0 -0
  126. {anemoi_datasets-0.5.25.dist-info → anemoi_datasets-0.5.27.dist-info}/top_level.txt +0 -0
@@ -22,15 +22,10 @@ try:
22
22
  except ImportError:
23
23
  # Python 3.9
24
24
  EllipsisType = type(Ellipsis)
25
+ from collections.abc import Sequence
26
+ from collections.abc import Sized
25
27
  from typing import TYPE_CHECKING
26
28
  from typing import Any
27
- from typing import Dict
28
- from typing import List
29
- from typing import Optional
30
- from typing import Sequence
31
- from typing import Set
32
- from typing import Sized
33
- from typing import Tuple
34
29
  from typing import Union
35
30
 
36
31
  import numpy as np
@@ -48,8 +43,8 @@ if TYPE_CHECKING:
48
43
  LOG = logging.getLogger(__name__)
49
44
 
50
45
 
51
- Shape = Tuple[int, ...]
52
- TupleIndex = Tuple[Union[int, slice, EllipsisType], ...]
46
+ Shape = tuple[int, ...]
47
+ TupleIndex = tuple[Union[int, slice, EllipsisType], ...]
53
48
  FullIndex = Union[int, slice, TupleIndex]
54
49
 
55
50
 
@@ -92,8 +87,8 @@ def _tidy(v: Any) -> Any:
92
87
 
93
88
 
94
89
  class Dataset(ABC, Sized):
95
- arguments: Dict[str, Any] = {}
96
- _name: Union[str, None] = None
90
+ arguments: dict[str, Any] = {}
91
+ _name: str | None = None
97
92
 
98
93
  def mutate(self) -> "Dataset":
99
94
  """Give an opportunity to a subclass to return a new Dataset object of a different class, if needed.
@@ -148,7 +143,7 @@ class Dataset(ABC, Sized):
148
143
  return result
149
144
 
150
145
  @property
151
- def name(self) -> Union[str, None]:
146
+ def name(self) -> str | None:
152
147
  """Return the name of the dataset."""
153
148
  return self._name
154
149
 
@@ -360,9 +355,9 @@ class Dataset(ABC, Sized):
360
355
 
361
356
  def _dates_to_indices(
362
357
  self,
363
- start: Union[None, str, datetime.datetime],
364
- end: Union[None, str, datetime.datetime],
365
- ) -> List[int]:
358
+ start: None | str | datetime.datetime,
359
+ end: None | str | datetime.datetime,
360
+ ) -> list[int]:
366
361
  """Convert date range to a list of indices.
367
362
 
368
363
  Parameters
@@ -387,7 +382,7 @@ class Dataset(ABC, Sized):
387
382
 
388
383
  return [i for i, date in enumerate(self.dates) if start <= date <= end]
389
384
 
390
- def _select_to_columns(self, vars: Union[str, List[str], Tuple[str], set]) -> List[int]:
385
+ def _select_to_columns(self, vars: str | list[str] | tuple[str] | set) -> list[int]:
391
386
  """Convert variable names to a list of column indices.
392
387
 
393
388
  Parameters
@@ -411,7 +406,7 @@ class Dataset(ABC, Sized):
411
406
 
412
407
  return [self.name_to_index[v] for v in vars]
413
408
 
414
- def _drop_to_columns(self, vars: Union[str, Sequence[str]]) -> List[int]:
409
+ def _drop_to_columns(self, vars: str | Sequence[str]) -> list[int]:
415
410
  """Convert variable names to a list of column indices to drop.
416
411
 
417
412
  Parameters
@@ -432,7 +427,7 @@ class Dataset(ABC, Sized):
432
427
 
433
428
  return sorted([v for k, v in self.name_to_index.items() if k not in vars])
434
429
 
435
- def _reorder_to_columns(self, vars: Union[str, List[str], Tuple[str], Dict[str, int]]) -> List[int]:
430
+ def _reorder_to_columns(self, vars: str | list[str] | tuple[str] | dict[str, int]) -> list[int]:
436
431
  """Convert variable names to a list of reordered column indices.
437
432
 
438
433
  Parameters
@@ -465,8 +460,8 @@ class Dataset(ABC, Sized):
465
460
  return indices
466
461
 
467
462
  def dates_interval_to_indices(
468
- self, start: Union[None, str, datetime.datetime], end: Union[None, str, datetime.datetime]
469
- ) -> List[int]:
463
+ self, start: None | str | datetime.datetime, end: None | str | datetime.datetime
464
+ ) -> list[int]:
470
465
  """Convert date interval to a list of indices.
471
466
 
472
467
  Parameters
@@ -483,7 +478,7 @@ class Dataset(ABC, Sized):
483
478
  """
484
479
  return self._dates_to_indices(start, end)
485
480
 
486
- def provenance(self) -> Dict[str, Any]:
481
+ def provenance(self) -> dict[str, Any]:
487
482
  """Return the provenance information of the dataset.
488
483
 
489
484
  Returns
@@ -511,7 +506,7 @@ class Dataset(ABC, Sized):
511
506
  return tuple(shape)
512
507
 
513
508
  @property
514
- def typed_variables(self) -> Dict[str, Any]:
509
+ def typed_variables(self) -> dict[str, Any]:
515
510
  """Return the variables with their types."""
516
511
  from anemoi.transform.variables import Variable
517
512
 
@@ -532,7 +527,7 @@ class Dataset(ABC, Sized):
532
527
 
533
528
  return result
534
529
 
535
- def _input_sources(self) -> List[Any]:
530
+ def _input_sources(self) -> list[Any]:
536
531
  """Return the input sources of the dataset.
537
532
 
538
533
  Returns
@@ -544,7 +539,7 @@ class Dataset(ABC, Sized):
544
539
  self.collect_input_sources(sources)
545
540
  return sources
546
541
 
547
- def metadata(self) -> Dict[str, Any]:
542
+ def metadata(self) -> dict[str, Any]:
548
543
  """Return the metadata of the dataset.
549
544
 
550
545
  Returns
@@ -588,7 +583,7 @@ class Dataset(ABC, Sized):
588
583
  """Return the end date of the dataset."""
589
584
  return self.dates[-1]
590
585
 
591
- def dataset_metadata(self) -> Dict[str, Any]:
586
+ def dataset_metadata(self) -> dict[str, Any]:
592
587
  """Return the metadata of the dataset.
593
588
 
594
589
  Returns
@@ -608,7 +603,7 @@ class Dataset(ABC, Sized):
608
603
  name=self.name,
609
604
  )
610
605
 
611
- def _supporting_arrays(self, *path: str) -> Dict[str, NDArray[Any]]:
606
+ def _supporting_arrays(self, *path: str) -> dict[str, NDArray[Any]]:
612
607
  """Return the supporting arrays of the dataset.
613
608
 
614
609
  Parameters
@@ -646,7 +641,7 @@ class Dataset(ABC, Sized):
646
641
 
647
642
  return result
648
643
 
649
- def supporting_arrays(self) -> Dict[str, NDArray[Any]]:
644
+ def supporting_arrays(self) -> dict[str, NDArray[Any]]:
650
645
  """Return the supporting arrays to be saved in the checkpoints.
651
646
 
652
647
  Returns
@@ -657,7 +652,7 @@ class Dataset(ABC, Sized):
657
652
  arrays, _ = self._supporting_arrays_and_sources()
658
653
  return arrays
659
654
 
660
- def _supporting_arrays_and_sources(self) -> Tuple[Dict[str, NDArray], Dict[int, List[str]]]:
655
+ def _supporting_arrays_and_sources(self) -> tuple[dict[str, NDArray], dict[int, list[str]]]:
661
656
  """Return the supporting arrays and their sources.
662
657
 
663
658
  Returns
@@ -684,7 +679,7 @@ class Dataset(ABC, Sized):
684
679
 
685
680
  return result, source_to_arrays
686
681
 
687
- def collect_supporting_arrays(self, collected: List[Tuple[Tuple[str, ...], str, NDArray[Any]]], *path: str) -> None:
682
+ def collect_supporting_arrays(self, collected: list[tuple[tuple[str, ...], str, NDArray[Any]]], *path: str) -> None:
688
683
  """Collect supporting arrays.
689
684
 
690
685
  Parameters
@@ -697,7 +692,7 @@ class Dataset(ABC, Sized):
697
692
  # Override this method to add more arrays
698
693
  pass
699
694
 
700
- def metadata_specific(self, **kwargs: Any) -> Dict[str, Any]:
695
+ def metadata_specific(self, **kwargs: Any) -> dict[str, Any]:
701
696
  """Return specific metadata of the dataset.
702
697
 
703
698
  Parameters
@@ -764,7 +759,7 @@ class Dataset(ABC, Sized):
764
759
  """Return the label of the dataset."""
765
760
  return self.__class__.__name__.lower()
766
761
 
767
- def computed_constant_fields(self) -> List[str]:
762
+ def computed_constant_fields(self) -> list[str]:
768
763
  """Return the computed constant fields of the dataset.
769
764
 
770
765
  Returns
@@ -781,7 +776,7 @@ class Dataset(ABC, Sized):
781
776
 
782
777
  return sorted(self._compute_constant_fields_from_a_few_samples())
783
778
 
784
- def _compute_constant_fields_from_a_few_samples(self) -> List[str]:
779
+ def _compute_constant_fields_from_a_few_samples(self) -> list[str]:
785
780
  """Compute constant fields from a few samples.
786
781
 
787
782
  Returns
@@ -822,7 +817,7 @@ class Dataset(ABC, Sized):
822
817
 
823
818
  return [v for i, v in enumerate(self.variables) if constants[i]]
824
819
 
825
- def _compute_constant_fields_from_statistics(self) -> List[str]:
820
+ def _compute_constant_fields_from_statistics(self) -> list[str]:
826
821
  """Compute constant fields from statistics.
827
822
 
828
823
  Returns
@@ -842,8 +837,8 @@ class Dataset(ABC, Sized):
842
837
 
843
838
  def plot(
844
839
  self,
845
- date: Union[int, datetime.datetime, np.datetime64, str],
846
- variable: Union[int, str],
840
+ date: int | datetime.datetime | np.datetime64 | str,
841
+ variable: int | str,
847
842
  member: int = 0,
848
843
  **kwargs: Any,
849
844
  ) -> "matplotlib.pyplot.Axes":
@@ -873,10 +868,10 @@ class Dataset(ABC, Sized):
873
868
 
874
869
  def to_index(
875
870
  self,
876
- date: Union[int, datetime.datetime, np.datetime64, str],
877
- variable: Union[int, str],
871
+ date: int | datetime.datetime | np.datetime64 | str,
872
+ variable: int | str,
878
873
  member: int = 0,
879
- ) -> Tuple[int, int, int]:
874
+ ) -> tuple[int, int, int]:
880
875
  """Convert date, variable, and member to indices.
881
876
 
882
877
  Parameters
@@ -945,7 +940,7 @@ class Dataset(ABC, Sized):
945
940
 
946
941
  @property
947
942
  @abstractmethod
948
- def variables(self) -> List[str]:
943
+ def variables(self) -> list[str]:
949
944
  """Return the list of variables in the dataset."""
950
945
  pass
951
946
 
@@ -969,7 +964,7 @@ class Dataset(ABC, Sized):
969
964
 
970
965
  @property
971
966
  @abstractmethod
972
- def name_to_index(self) -> Dict[str, int]:
967
+ def name_to_index(self) -> dict[str, int]:
973
968
  """Return the mapping of variable names to indices."""
974
969
  pass
975
970
 
@@ -1005,30 +1000,30 @@ class Dataset(ABC, Sized):
1005
1000
 
1006
1001
  @property
1007
1002
  @abstractmethod
1008
- def variables_metadata(self) -> Dict[str, Any]:
1003
+ def variables_metadata(self) -> dict[str, Any]:
1009
1004
  """Return the metadata of the variables in the dataset."""
1010
1005
  pass
1011
1006
 
1012
1007
  @abstractmethod
1013
1008
  @cached_property
1014
- def missing(self) -> Set[int]:
1009
+ def missing(self) -> set[int]:
1015
1010
  """Return the set of missing indices in the dataset."""
1016
1011
  pass
1017
1012
 
1018
1013
  @abstractmethod
1019
1014
  @cached_property
1020
- def constant_fields(self) -> List[str]:
1015
+ def constant_fields(self) -> list[str]:
1021
1016
  """Return the list of constant fields in the dataset."""
1022
1017
  pass
1023
1018
 
1024
1019
  @abstractmethod
1025
1020
  @cached_property
1026
- def statistics(self) -> Dict[str, NDArray[Any]]:
1021
+ def statistics(self) -> dict[str, NDArray[Any]]:
1027
1022
  """Return the statistics of the dataset."""
1028
1023
  pass
1029
1024
 
1030
1025
  @abstractmethod
1031
- def statistics_tendencies(self, delta: Optional[datetime.timedelta] = None) -> Dict[str, NDArray[Any]]:
1026
+ def statistics_tendencies(self, delta: datetime.timedelta | None = None) -> dict[str, NDArray[Any]]:
1032
1027
  """Return the tendencies of the statistics in the dataset.
1033
1028
 
1034
1029
  Parameters
@@ -1071,7 +1066,7 @@ class Dataset(ABC, Sized):
1071
1066
  pass
1072
1067
 
1073
1068
  @abstractmethod
1074
- def collect_input_sources(self, sources: List[Any]) -> None:
1069
+ def collect_input_sources(self, sources: list[Any]) -> None:
1075
1070
  """Collect the input sources of the dataset.
1076
1071
 
1077
1072
  Parameters
@@ -1082,7 +1077,7 @@ class Dataset(ABC, Sized):
1082
1077
  pass
1083
1078
 
1084
1079
  @abstractmethod
1085
- def get_dataset_names(self, names: Set[str]) -> None:
1080
+ def get_dataset_names(self, names: set[str]) -> None:
1086
1081
  """Get the names of the datasets.
1087
1082
 
1088
1083
  Parameters
@@ -11,12 +11,10 @@
11
11
  import logging
12
12
  import os
13
13
  import textwrap
14
+ from collections.abc import Callable
14
15
  from functools import wraps
15
16
  from typing import TYPE_CHECKING
16
17
  from typing import Any
17
- from typing import Callable
18
- from typing import List
19
- from typing import Optional
20
18
 
21
19
  from anemoi.utils.text import Tree
22
20
  from numpy.typing import NDArray
@@ -56,7 +54,7 @@ def css(name: str) -> str:
56
54
  class Node:
57
55
  """A class to represent a node in a dataset tree."""
58
56
 
59
- def __init__(self, dataset: "Dataset", kids: List[Any], **kwargs: Any) -> None:
57
+ def __init__(self, dataset: "Dataset", kids: list[Any], **kwargs: Any) -> None:
60
58
  """Initializes a Node object.
61
59
 
62
60
  Parameters
@@ -72,7 +70,7 @@ class Node:
72
70
  self.kids = kids
73
71
  self.kwargs = kwargs
74
72
 
75
- def _put(self, indent: int, result: List[str]) -> None:
73
+ def _put(self, indent: int, result: list[str]) -> None:
76
74
  """Helper method to add the node representation to the result list.
77
75
 
78
76
  Parameters
@@ -103,11 +101,11 @@ class Node:
103
101
  str
104
102
  String representation of the node.
105
103
  """
106
- result: List[str] = []
104
+ result: list[str] = []
107
105
  self._put(0, result)
108
106
  return "\n".join(result)
109
107
 
110
- def graph(self, digraph: List[str], nodes: dict) -> None:
108
+ def graph(self, digraph: list[str], nodes: dict) -> None:
111
109
  """Generates a graph representation of the node.
112
110
 
113
111
  Parameters
@@ -170,7 +168,7 @@ class Node:
170
168
  digraph.append("}")
171
169
  return "\n".join(digraph)
172
170
 
173
- def _html(self, indent: str, rows: List[List[str]]) -> None:
171
+ def _html(self, indent: str, rows: list[list[str]]) -> None:
174
172
  """Helper method to add the node representation to the HTML rows.
175
173
 
176
174
  Parameters
@@ -273,7 +271,7 @@ class Node:
273
271
  class Source:
274
272
  """A class used to follow the provenance of a data point."""
275
273
 
276
- def __init__(self, dataset: Any, index: int, source: Optional[Any] = None, info: Optional[Any] = None) -> None:
274
+ def __init__(self, dataset: Any, index: int, source: Any | None = None, info: Any | None = None) -> None:
277
275
  """Initializes a Source object.
278
276
 
279
277
  Parameters
@@ -10,8 +10,6 @@
10
10
 
11
11
  import logging
12
12
  from typing import Any
13
- from typing import Dict
14
- from typing import Tuple
15
13
 
16
14
  import numpy as np
17
15
  from numpy.typing import NDArray
@@ -105,7 +103,7 @@ class Number(Forwards):
105
103
  """
106
104
  return Node(self, [self.forward.tree()], numbers=[n + 1 for n in self.members])
107
105
 
108
- def metadata_specific(self, **kwargs: Any) -> Dict[str, Any]:
106
+ def metadata_specific(self, **kwargs: Any) -> dict[str, Any]:
109
107
  """Returns metadata specific to the Number object.
110
108
 
111
109
  Parameters
@@ -122,7 +120,7 @@ class Number(Forwards):
122
120
  "numbers": [n + 1 for n in self.members],
123
121
  }
124
122
 
125
- def forwards_subclass_metadata_specific(self) -> Dict[str, Any]:
123
+ def forwards_subclass_metadata_specific(self) -> dict[str, Any]:
126
124
  """Returns metadata specific to the Number object."""
127
125
  return {}
128
126
 
@@ -140,7 +138,7 @@ class Ensemble(GivenAxis):
140
138
  """
141
139
  return Node(self, [d.tree() for d in self.datasets])
142
140
 
143
- def forwards_subclass_metadata_specific(self) -> Dict[str, Any]:
141
+ def forwards_subclass_metadata_specific(self) -> dict[str, Any]:
144
142
  """Get the metadata specific to the forwards subclass.
145
143
 
146
144
  Returns:
@@ -149,7 +147,7 @@ class Ensemble(GivenAxis):
149
147
  return {}
150
148
 
151
149
 
152
- def ensemble_factory(args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> Ensemble:
150
+ def ensemble_factory(args: tuple[Any, ...], kwargs: dict[str, Any]) -> Ensemble:
153
151
  """Factory function to create an Ensemble object.
154
152
 
155
153
  Parameters
@@ -10,9 +10,6 @@
10
10
 
11
11
  import logging
12
12
  from typing import Any
13
- from typing import Dict
14
- from typing import Optional
15
- from typing import Set
16
13
 
17
14
  import numpy as np
18
15
  from numpy.typing import NDArray
@@ -46,7 +43,7 @@ class MissingDatesFill(Forwards):
46
43
  """
47
44
  super().__init__(dataset)
48
45
  self._missing = set(dataset.missing)
49
- self._warnings: Set[int] = set()
46
+ self._warnings: set[int] = set()
50
47
 
51
48
  @debug_indexing
52
49
  @expand_list_indexing
@@ -84,7 +81,7 @@ class MissingDatesFill(Forwards):
84
81
  return np.stack([self[i] for i in range(*s.indices(self._len))])
85
82
 
86
83
  @property
87
- def missing(self) -> Set[int]:
84
+ def missing(self) -> set[int]:
88
85
  """Get the set of missing dates."""
89
86
  return set()
90
87
 
@@ -153,7 +150,7 @@ class MissingDatesClosest(MissingDatesFill):
153
150
  self.closest = closest
154
151
  self._closest = {}
155
152
 
156
- def _fill_missing(self, n: int, a: Optional[int], b: Optional[int]) -> NDArray[Any]:
153
+ def _fill_missing(self, n: int, a: int | None, b: int | None) -> NDArray[Any]:
157
154
  """Fill the missing date at the given index.
158
155
 
159
156
  Parameters
@@ -189,7 +186,7 @@ class MissingDatesClosest(MissingDatesFill):
189
186
 
190
187
  return self.forward[self._closest[n]]
191
188
 
192
- def forwards_subclass_metadata_specific(self) -> Dict[str, Any]:
189
+ def forwards_subclass_metadata_specific(self) -> dict[str, Any]:
193
190
  """Get metadata specific to the subclass.
194
191
 
195
192
  Returns
@@ -224,7 +221,7 @@ class MissingDatesInterpolate(MissingDatesFill):
224
221
  super().__init__(dataset)
225
222
  self._alpha = {}
226
223
 
227
- def _fill_missing(self, n: int, a: Optional[int], b: Optional[int]) -> NDArray[Any]:
224
+ def _fill_missing(self, n: int, a: int | None, b: int | None) -> NDArray[Any]:
228
225
  """Fill the missing date at the given index using interpolation.
229
226
 
230
227
  Parameters
@@ -264,7 +261,7 @@ class MissingDatesInterpolate(MissingDatesFill):
264
261
  alpha = self._alpha[n]
265
262
  return self.forward[a] * (1 - alpha) + self.forward[b] * alpha
266
263
 
267
- def forwards_subclass_metadata_specific(self) -> Dict[str, Any]:
264
+ def forwards_subclass_metadata_specific(self) -> dict[str, Any]:
268
265
  """Get metadata specific to the subclass.
269
266
 
270
267
  Returns
@@ -285,7 +282,7 @@ class MissingDatesInterpolate(MissingDatesFill):
285
282
  return Node(self, [self.forward.tree()])
286
283
 
287
284
 
288
- def fill_missing_dates_factory(dataset: Any, method: str, kwargs: Dict[str, Any]) -> Dataset:
285
+ def fill_missing_dates_factory(dataset: Any, method: str, kwargs: dict[str, Any]) -> Dataset:
289
286
  """Factory function to create an instance of a class to fill missing dates.
290
287
 
291
288
  Parameters
@@ -14,10 +14,6 @@ import warnings
14
14
  from abc import abstractmethod
15
15
  from functools import cached_property
16
16
  from typing import Any
17
- from typing import Dict
18
- from typing import List
19
- from typing import Optional
20
- from typing import Set
21
17
 
22
18
  import numpy as np
23
19
  from numpy.typing import NDArray
@@ -75,7 +71,7 @@ class Forwards(Dataset):
75
71
  return self.forward[n]
76
72
 
77
73
  @property
78
- def name(self) -> Optional[str]:
74
+ def name(self) -> str | None:
79
75
  """Returns the name of the forward dataset."""
80
76
  if self._name is not None:
81
77
  return self._name
@@ -112,26 +108,26 @@ class Forwards(Dataset):
112
108
  return self.forward.longitudes
113
109
 
114
110
  @property
115
- def name_to_index(self) -> Dict[str, int]:
111
+ def name_to_index(self) -> dict[str, int]:
116
112
  """Returns a dictionary mapping variable names to their indices."""
117
113
  return self.forward.name_to_index
118
114
 
119
115
  @property
120
- def variables(self) -> List[str]:
116
+ def variables(self) -> list[str]:
121
117
  """Returns the variables of the forward dataset."""
122
118
  return self.forward.variables
123
119
 
124
120
  @property
125
- def variables_metadata(self) -> Dict[str, Any]:
121
+ def variables_metadata(self) -> dict[str, Any]:
126
122
  """Returns the metadata of the variables in the forward dataset."""
127
123
  return self.forward.variables_metadata
128
124
 
129
125
  @property
130
- def statistics(self) -> Dict[str, NDArray[Any]]:
126
+ def statistics(self) -> dict[str, NDArray[Any]]:
131
127
  """Returns the statistics of the forward dataset."""
132
128
  return self.forward.statistics
133
129
 
134
- def statistics_tendencies(self, delta: Optional[datetime.timedelta] = None) -> Dict[str, NDArray[Any]]:
130
+ def statistics_tendencies(self, delta: datetime.timedelta | None = None) -> dict[str, NDArray[Any]]:
135
131
  """Returns the statistics tendencies of the forward dataset.
136
132
 
137
133
  Parameters
@@ -159,7 +155,7 @@ class Forwards(Dataset):
159
155
  return self.forward.dtype
160
156
 
161
157
  @property
162
- def missing(self) -> Set[int]:
158
+ def missing(self) -> set[int]:
163
159
  """Returns the missing data information of the forward dataset."""
164
160
  return self.forward.missing
165
161
 
@@ -168,7 +164,7 @@ class Forwards(Dataset):
168
164
  """Returns the grids of the forward dataset."""
169
165
  return self.forward.grids
170
166
 
171
- def metadata_specific(self, **kwargs: Any) -> Dict[str, Any]:
167
+ def metadata_specific(self, **kwargs: Any) -> dict[str, Any]:
172
168
  """Returns metadata specific to the forward dataset.
173
169
 
174
170
  Parameters
@@ -187,7 +183,7 @@ class Forwards(Dataset):
187
183
  **kwargs,
188
184
  )
189
185
 
190
- def collect_supporting_arrays(self, collected: List[Any], *path: Any) -> None:
186
+ def collect_supporting_arrays(self, collected: list[Any], *path: Any) -> None:
191
187
  """Collects supporting arrays from the forward dataset.
192
188
 
193
189
  Parameters
@@ -199,7 +195,7 @@ class Forwards(Dataset):
199
195
  """
200
196
  self.forward.collect_supporting_arrays(collected, *path)
201
197
 
202
- def collect_input_sources(self, collected: List[Any]) -> None:
198
+ def collect_input_sources(self, collected: list[Any]) -> None:
203
199
  """Collects input sources from the forward dataset.
204
200
 
205
201
  Parameters
@@ -225,11 +221,11 @@ class Forwards(Dataset):
225
221
  return self.forward.source(index)
226
222
 
227
223
  @abstractmethod
228
- def forwards_subclass_metadata_specific(self) -> Dict[str, Any]:
224
+ def forwards_subclass_metadata_specific(self) -> dict[str, Any]:
229
225
  """Returns metadata specific to the subclass."""
230
226
  pass
231
227
 
232
- def get_dataset_names(self, names: Set[str]) -> None:
228
+ def get_dataset_names(self, names: set[str]) -> None:
233
229
  """Collects the names of the datasets.
234
230
 
235
231
  Parameters
@@ -240,7 +236,7 @@ class Forwards(Dataset):
240
236
  self.forward.get_dataset_names(names)
241
237
 
242
238
  @property
243
- def constant_fields(self) -> List[str]:
239
+ def constant_fields(self) -> list[str]:
244
240
  """Returns the constant fields of the forward dataset."""
245
241
  return self.forward.constant_fields
246
242
 
@@ -248,7 +244,7 @@ class Forwards(Dataset):
248
244
  class Combined(Forwards):
249
245
  """A class to combine multiple datasets into a single dataset."""
250
246
 
251
- def __init__(self, datasets: List[Dataset]) -> None:
247
+ def __init__(self, datasets: list[Dataset]) -> None:
252
248
  """Initializes a Combined object.
253
249
 
254
250
  Parameters
@@ -330,8 +326,14 @@ class Combined(Forwards):
330
326
  ValueError
331
327
  If the grids are not the same.
332
328
  """
333
- if (d1.latitudes != d2.latitudes).any() or (d1.longitudes != d2.longitudes).any():
334
- raise ValueError(f"Incompatible grid ({d1} {d2})")
329
+
330
+ # note: not a proper implementation, should be handled
331
+ # in a more consolidated way ...
332
+ rtol = 1.0e-7
333
+ if not np.allclose(d1.latitudes, d2.latitudes, rtol=rtol) or not np.allclose(
334
+ d1.longitudes, d2.longitudes, rtol=rtol
335
+ ):
336
+ raise ValueError(f"Incompatible grid ({d1.longitudes} {d2.longitudes})")
335
337
 
336
338
  def check_same_shape(self, d1: Dataset, d2: Dataset) -> None:
337
339
  """Checks if the shapes of two datasets are the same.
@@ -460,7 +462,7 @@ class Combined(Forwards):
460
462
  self.check_same_variables(d1, d2)
461
463
  self.check_same_dates(d1, d2)
462
464
 
463
- def provenance(self) -> List[Any]:
465
+ def provenance(self) -> list[Any]:
464
466
  """Returns the provenance of the combined datasets.
465
467
 
466
468
  Returns
@@ -481,7 +483,7 @@ class Combined(Forwards):
481
483
  lst = ", ".join(repr(d) for d in self.datasets)
482
484
  return f"{self.__class__.__name__}({lst})"
483
485
 
484
- def metadata_specific(self, **kwargs: Any) -> Dict[str, Any]:
486
+ def metadata_specific(self, **kwargs: Any) -> dict[str, Any]:
485
487
  """Returns metadata specific to the combined datasets.
486
488
 
487
489
  Parameters
@@ -502,7 +504,7 @@ class Combined(Forwards):
502
504
  **kwargs,
503
505
  )
504
506
 
505
- def collect_supporting_arrays(self, collected: List[Any], *path: Any) -> None:
507
+ def collect_supporting_arrays(self, collected: list[Any], *path: Any) -> None:
506
508
  """Collects supporting arrays from the combined datasets.
507
509
 
508
510
  Parameters
@@ -518,7 +520,7 @@ class Combined(Forwards):
518
520
  d.collect_supporting_arrays(collected, *path, name)
519
521
 
520
522
  @property
521
- def missing(self) -> Set[int]:
523
+ def missing(self) -> set[int]:
522
524
  """Returns the missing data information of the combined datasets.
523
525
 
524
526
  Raises
@@ -528,7 +530,7 @@ class Combined(Forwards):
528
530
  """
529
531
  raise NotImplementedError("missing() not implemented for Combined")
530
532
 
531
- def get_dataset_names(self, names: Set[str]) -> None:
533
+ def get_dataset_names(self, names: set[str]) -> None:
532
534
  """Collects the names of the combined datasets.
533
535
 
534
536
  Parameters
@@ -543,7 +545,7 @@ class Combined(Forwards):
543
545
  class GivenAxis(Combined):
544
546
  """A class to combine datasets along a given axis."""
545
547
 
546
- def __init__(self, datasets: List[Any], axis: int) -> None:
548
+ def __init__(self, datasets: list[Any], axis: int) -> None:
547
549
  """Initializes a GivenAxis object.
548
550
 
549
551
  Parameters
@@ -650,10 +652,10 @@ class GivenAxis(Combined):
650
652
  return np.concatenate([d[n] for d in self.datasets], axis=self.axis - 1)
651
653
 
652
654
  @cached_property
653
- def missing(self) -> Set[int]:
655
+ def missing(self) -> set[int]:
654
656
  """Returns the missing data information of the combined dataset along the given axis."""
655
657
  offset = 0
656
- result: Set[int] = set()
658
+ result: set[int] = set()
657
659
  for d in self.datasets:
658
660
  result.update(offset + m for m in d.missing)
659
661
  if self.axis == 0: # Advance if axis is time