anemoi-datasets 0.5.27__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.
Files changed (61) hide show
  1. anemoi/datasets/_version.py +2 -2
  2. anemoi/datasets/commands/recipe/__init__.py +93 -0
  3. anemoi/datasets/commands/recipe/format.py +55 -0
  4. anemoi/datasets/commands/recipe/migrate.py +555 -0
  5. anemoi/datasets/create/__init__.py +42 -1
  6. anemoi/datasets/create/config.py +2 -0
  7. anemoi/datasets/create/input/__init__.py +43 -63
  8. anemoi/datasets/create/input/action.py +296 -236
  9. anemoi/datasets/create/input/context/__init__.py +71 -0
  10. anemoi/datasets/create/input/context/field.py +54 -0
  11. anemoi/datasets/create/input/data_sources.py +2 -1
  12. anemoi/datasets/create/input/misc.py +0 -71
  13. anemoi/datasets/create/input/repeated_dates.py +0 -114
  14. anemoi/datasets/create/input/result/__init__.py +17 -0
  15. anemoi/datasets/create/input/{result.py → result/field.py} +9 -89
  16. anemoi/datasets/create/sources/accumulations.py +74 -94
  17. anemoi/datasets/create/sources/accumulations2.py +16 -45
  18. anemoi/datasets/create/sources/anemoi_dataset.py +46 -42
  19. anemoi/datasets/create/sources/constants.py +39 -38
  20. anemoi/datasets/create/sources/empty.py +26 -22
  21. anemoi/datasets/create/sources/forcings.py +29 -28
  22. anemoi/datasets/create/sources/grib.py +92 -72
  23. anemoi/datasets/create/sources/grib_index.py +46 -42
  24. anemoi/datasets/create/sources/hindcasts.py +56 -55
  25. anemoi/datasets/create/sources/legacy.py +10 -62
  26. anemoi/datasets/create/sources/mars.py +107 -131
  27. anemoi/datasets/create/sources/netcdf.py +28 -24
  28. anemoi/datasets/create/sources/opendap.py +28 -24
  29. anemoi/datasets/create/sources/recentre.py +42 -41
  30. anemoi/datasets/create/sources/repeated_dates.py +44 -0
  31. anemoi/datasets/create/sources/source.py +26 -48
  32. anemoi/datasets/create/sources/tendencies.py +67 -94
  33. anemoi/datasets/create/sources/xarray_support/__init__.py +29 -24
  34. anemoi/datasets/create/sources/xarray_support/field.py +4 -4
  35. anemoi/datasets/create/sources/xarray_zarr.py +28 -24
  36. anemoi/datasets/create/sources/zenodo.py +43 -39
  37. anemoi/datasets/create/utils.py +0 -42
  38. anemoi/datasets/data/dataset.py +6 -0
  39. anemoi/datasets/data/grids.py +0 -152
  40. anemoi/datasets/data/rolling_average.py +141 -0
  41. anemoi/datasets/data/stores.py +7 -9
  42. anemoi/datasets/dates/__init__.py +2 -0
  43. anemoi/datasets/dumper.py +76 -0
  44. anemoi/datasets/grids.py +1 -178
  45. anemoi/datasets/schemas/recipe.json +131 -0
  46. {anemoi_datasets-0.5.27.dist-info → anemoi_datasets-0.5.28.dist-info}/METADATA +5 -2
  47. {anemoi_datasets-0.5.27.dist-info → anemoi_datasets-0.5.28.dist-info}/RECORD +51 -51
  48. anemoi/datasets/create/filter.py +0 -47
  49. anemoi/datasets/create/input/concat.py +0 -161
  50. anemoi/datasets/create/input/context.py +0 -86
  51. anemoi/datasets/create/input/empty.py +0 -53
  52. anemoi/datasets/create/input/filter.py +0 -117
  53. anemoi/datasets/create/input/function.py +0 -232
  54. anemoi/datasets/create/input/join.py +0 -129
  55. anemoi/datasets/create/input/pipe.py +0 -66
  56. anemoi/datasets/create/input/step.py +0 -173
  57. anemoi/datasets/create/input/template.py +0 -161
  58. {anemoi_datasets-0.5.27.dist-info → anemoi_datasets-0.5.28.dist-info}/WHEEL +0 -0
  59. {anemoi_datasets-0.5.27.dist-info → anemoi_datasets-0.5.28.dist-info}/entry_points.txt +0 -0
  60. {anemoi_datasets-0.5.27.dist-info → anemoi_datasets-0.5.28.dist-info}/licenses/LICENSE +0 -0
  61. {anemoi_datasets-0.5.27.dist-info → anemoi_datasets-0.5.28.dist-info}/top_level.txt +0 -0
@@ -14,7 +14,8 @@ from earthkit.data.core.fieldlist import MultiFieldList
14
14
 
15
15
  from anemoi.datasets.create.sources.mars import mars
16
16
 
17
- from .legacy import legacy_source
17
+ from . import source_registry
18
+ from .legacy import LegacySource
18
19
 
19
20
  LOGGER = logging.getLogger(__name__)
20
21
 
@@ -37,57 +38,57 @@ def _to_list(x: list | tuple | Any) -> list[Any]:
37
38
  return [x]
38
39
 
39
40
 
40
- @legacy_source(__file__)
41
- def hindcasts(context: Any, dates: list[Any], **request: dict[str, Any]) -> MultiFieldList:
42
- """Generates hindcast requests based on the provided dates and request parameters.
43
-
44
- Parameters
45
- ----------
46
- context : Any
47
- The context containing the dates provider and trace method.
48
- dates : List[Any]
49
- A list of dates for which to generate hindcast requests.
50
- request : Dict[str, Any]
51
- Additional request parameters.
52
-
53
- Returns
54
- -------
55
- MultiFieldList
56
- A MultiFieldList containing the hindcast data.
57
- """
58
- from anemoi.datasets.dates import HindcastsDates
59
-
60
- provider = context.dates_provider
61
- assert isinstance(provider, HindcastsDates)
62
-
63
- context.trace("H️", f"hindcasts {len(dates)=}")
64
-
65
- request["param"] = _to_list(request["param"])
66
- request["step"] = _to_list(request.get("step", 0))
67
- request["step"] = [int(_) for _ in request["step"]]
68
-
69
- context.trace("H️", f"hindcast {request}")
70
-
71
- requests = []
72
- for d in dates:
73
- r = request.copy()
74
- hindcast = provider.mapping[d]
75
- r["hdate"] = hindcast.hdate.strftime("%Y-%m-%d")
76
- r["date"] = hindcast.refdate.strftime("%Y-%m-%d")
77
- r["time"] = hindcast.refdate.strftime("%H")
78
- r["step"] = hindcast.step
79
- requests.append(r)
80
-
81
- if len(requests) == 0:
82
- return MultiFieldList([])
83
-
84
- return mars(
85
- context,
86
- dates,
87
- *requests,
88
- date_key="hdate",
89
- request_already_using_valid_datetime=True,
90
- )
91
-
92
-
93
- execute = hindcasts
41
+ @source_registry.register("hindcasts")
42
+ class HindcastsSource(LegacySource):
43
+
44
+ @staticmethod
45
+ def _execute(context: Any, dates: list[Any], **request: dict[str, Any]) -> MultiFieldList:
46
+ """Generates hindcast requests based on the provided dates and request parameters.
47
+
48
+ Parameters
49
+ ----------
50
+ context : Any
51
+ The context containing the dates provider and trace method.
52
+ dates : List[Any]
53
+ A list of dates for which to generate hindcast requests.
54
+ request : Dict[str, Any]
55
+ Additional request parameters.
56
+
57
+ Returns
58
+ -------
59
+ MultiFieldList
60
+ A MultiFieldList containing the hindcast data.
61
+ """
62
+ from anemoi.datasets.dates import HindcastsDates
63
+
64
+ provider = context.dates_provider
65
+ assert isinstance(provider, HindcastsDates)
66
+
67
+ context.trace("H️", f"hindcasts {len(dates)=}")
68
+
69
+ request["param"] = _to_list(request["param"])
70
+ request["step"] = _to_list(request.get("step", 0))
71
+ request["step"] = [int(_) for _ in request["step"]]
72
+
73
+ context.trace("H️", f"hindcast {request}")
74
+
75
+ requests = []
76
+ for d in dates:
77
+ r = request.copy()
78
+ hindcast = provider.mapping[d]
79
+ r["hdate"] = hindcast.hdate.strftime("%Y-%m-%d")
80
+ r["date"] = hindcast.refdate.strftime("%Y-%m-%d")
81
+ r["time"] = hindcast.refdate.strftime("%H")
82
+ r["step"] = hindcast.step
83
+ requests.append(r)
84
+
85
+ if len(requests) == 0:
86
+ return MultiFieldList([])
87
+
88
+ return mars(
89
+ context,
90
+ dates,
91
+ *requests,
92
+ date_key="hdate",
93
+ request_already_using_valid_datetime=True,
94
+ )
@@ -8,16 +8,13 @@
8
8
  # nor does it submit to any jurisdiction.
9
9
 
10
10
 
11
- import inspect
12
11
  import logging
13
- import os
14
- from collections.abc import Callable
12
+ from abc import abstractmethod
15
13
  from typing import Any
16
14
 
17
- from anemoi.datasets.create.input.template import resolve
15
+ from anemoi.datasets.create.input.context import Context
18
16
 
19
17
  from ..source import Source
20
- from . import source_registry
21
18
 
22
19
  LOG = logging.getLogger(__name__)
23
20
 
@@ -27,7 +24,7 @@ class LegacySource(Source):
27
24
 
28
25
  Parameters
29
26
  ----------
30
- context : Any
27
+ context : Context
31
28
  The context in which the source is created.
32
29
  *args : tuple
33
30
  Positional arguments.
@@ -35,64 +32,15 @@ class LegacySource(Source):
35
32
  Keyword arguments.
36
33
  """
37
34
 
38
- def __init__(self, context: Any, *args: Any, **kwargs: Any) -> None:
35
+ def __init__(self, context: Context, *args: Any, **kwargs: Any) -> None:
39
36
  super().__init__(context, *args, **kwargs)
40
37
  self.args = args
41
38
  self.kwargs = kwargs
42
39
 
40
+ @staticmethod
41
+ @abstractmethod
42
+ def _execute(context, *args, **kwargs):
43
+ pass
43
44
 
44
- class legacy_source:
45
- """A decorator class for legacy sources.
46
-
47
- Parameters
48
- ----------
49
- name : str
50
- The name of the legacy source.
51
- """
52
-
53
- def __init__(self, name: str) -> None:
54
- name, _ = os.path.splitext(os.path.basename(name))
55
- self.name = name
56
-
57
- def __call__(self, execute: Callable) -> Callable:
58
- """Call method to wrap the execute function.
59
-
60
- Parameters
61
- ----------
62
- execute : function
63
- The execute function to be wrapped.
64
-
65
- Returns
66
- -------
67
- function
68
- The wrapped execute function.
69
- """
70
- this = self
71
- name = f"Legacy{self.name.title()}Source"
72
- source = ".".join([execute.__module__, execute.__name__])
73
-
74
- def execute_wrapper(self, dates) -> Any:
75
- """Wrapper method to call the execute function."""
76
-
77
- args, kwargs = resolve(self.context, (self.args, self.kwargs))
78
-
79
- try:
80
- return execute(self.context, dates, *args, **kwargs)
81
- except TypeError:
82
- LOG.error(f"Error executing source {this.name} from {source}")
83
- LOG.error(f"Function signature is: {inspect.signature(execute)}")
84
- LOG.error(f"Arguments are: {args=}, {kwargs=}")
85
- raise
86
-
87
- klass = type(
88
- name,
89
- (LegacySource,),
90
- {
91
- "execute": execute_wrapper,
92
- "_source": source,
93
- },
94
- )
95
-
96
- source_registry.register(self.name)(klass)
97
-
98
- return execute
45
+ def execute(self, dates: Any) -> Any:
46
+ return self._execute(self.context, dates, *self.args, **self.kwargs)
@@ -16,9 +16,9 @@ from anemoi.utils.humanize import did_you_mean
16
16
  from earthkit.data import from_source
17
17
  from earthkit.data.utils.availability import Availability
18
18
 
19
- from anemoi.datasets.create.utils import to_datetime_list
19
+ from anemoi.datasets.create.sources import source_registry
20
20
 
21
- from .legacy import legacy_source
21
+ from .legacy import LegacySource
22
22
 
23
23
  DEBUG = False
24
24
 
@@ -358,135 +358,111 @@ MARS_KEYS = [
358
358
  ]
359
359
 
360
360
 
361
- @legacy_source(__file__)
362
- def mars(
363
- context: Any,
364
- dates: list[datetime.datetime],
365
- *requests: dict[str, Any],
366
- request_already_using_valid_datetime: bool = False,
367
- date_key: str = "date",
368
- use_cdsapi_dataset: str | None = None,
369
- **kwargs: Any,
370
- ) -> Any:
371
- """Executes MARS requests based on the given context, dates, and other parameters.
372
-
373
- Parameters
374
- ----------
375
- context : Any
376
- The context for the requests.
377
- dates : List[datetime.datetime]
378
- The list of dates to be used in the requests.
379
- requests : Dict[str, Any]
380
- The input requests to be executed.
381
- request_already_using_valid_datetime : bool, optional
382
- Flag indicating if the requests already use valid datetime.
383
- date_key : str, optional
384
- The key for the date in the requests.
385
- use_cdsapi_dataset : Optional[str], optional
386
- The dataset to be used with CDS API.
387
- kwargs : Any
388
- Additional keyword arguments for the requests.
389
-
390
- Returns
391
- -------
392
- Any
393
- The resulting dataset.
394
- """
395
-
396
- if not requests:
397
- requests = [kwargs]
398
-
399
- for r in requests:
400
- param = r.get("param", [])
401
- if not isinstance(param, (list, tuple)):
402
- param = [param]
403
- # check for "Norway bug" where yaml transforms 'no' into False, etc.
404
- for p in param:
405
- if p is False:
406
- raise ValueError(
407
- "'param' cannot be 'False'. If you wrote 'param: no' or 'param: off' in yaml, you may want to use quotes?"
408
- )
409
- if p is None:
410
- raise ValueError(
411
- "'param' cannot be 'None'. If you wrote 'param: no' in yaml, you may want to use quotes?"
412
- )
413
- if p is True:
414
- raise ValueError(
415
- "'param' cannot be 'True'. If you wrote 'param: on' in yaml, you may want to use quotes?"
416
- )
417
-
418
- if len(dates) == 0: # When using `repeated_dates`
419
- assert len(requests) == 1, requests
420
- assert "date" in requests[0], requests[0]
421
- if isinstance(requests[0]["date"], datetime.date):
422
- requests[0]["date"] = requests[0]["date"].strftime("%Y%m%d")
423
- else:
424
- requests = factorise_requests(
425
- dates,
426
- *requests,
427
- request_already_using_valid_datetime=request_already_using_valid_datetime,
428
- date_key=date_key,
429
- )
430
-
431
- requests = list(requests)
432
-
433
- ds = from_source("empty")
434
- context.trace("✅", f"{[str(d) for d in dates]}")
435
- context.trace("✅", f"Will run {len(requests)} requests")
436
- for r in requests:
437
- r = {k: v for k, v in r.items() if v != ("-",)}
438
- context.trace("✅", f"mars {r}")
439
-
440
- for r in requests:
441
- r = {k: v for k, v in r.items() if v != ("-",)}
442
-
443
- if context.use_grib_paramid and "param" in r:
444
- r = use_grib_paramid(r)
445
-
446
- for k, v in r.items():
447
- if k not in MARS_KEYS:
448
- raise ValueError(
449
- f"⚠️ Unknown key {k}={v} in MARS request. Did you mean '{did_you_mean(k, MARS_KEYS)}' ?"
450
- )
451
- try:
452
- if use_cdsapi_dataset:
453
- ds = ds + from_source("cds", use_cdsapi_dataset, r)
454
- else:
455
- ds = ds + from_source("mars", **r)
456
- except Exception as e:
457
- if "File is empty:" not in str(e):
458
- raise
459
- return ds
460
-
461
-
462
- execute = mars
463
-
464
-
465
- if __name__ == "__main__":
466
- import yaml
467
-
468
- config = yaml.safe_load(
361
+ @source_registry.register("mars")
362
+ class MarsSource(LegacySource):
363
+
364
+ @staticmethod
365
+ def _execute(
366
+ context: Any,
367
+ dates: list[datetime.datetime],
368
+ *requests: dict[str, Any],
369
+ request_already_using_valid_datetime: bool = False,
370
+ date_key: str = "date",
371
+ use_cdsapi_dataset: str | None = None,
372
+ **kwargs: Any,
373
+ ) -> Any:
374
+ """Executes MARS requests based on the given context, dates, and other parameters.
375
+
376
+ Parameters
377
+ ----------
378
+ context : Any
379
+ The context for the requests.
380
+ dates : List[datetime.datetime]
381
+ The list of dates to be used in the requests.
382
+ requests : Dict[str, Any]
383
+ The input requests to be executed.
384
+ request_already_using_valid_datetime : bool, optional
385
+ Flag indicating if the requests already use valid datetime.
386
+ date_key : str, optional
387
+ The key for the date in the requests.
388
+ use_cdsapi_dataset : Optional[str], optional
389
+ The dataset to be used with CDS API.
390
+ kwargs : Any
391
+ Additional keyword arguments for the requests.
392
+
393
+ Returns
394
+ -------
395
+ Any
396
+ The resulting dataset.
469
397
  """
470
- - class: ea
471
- expver: '0001'
472
- grid: 20.0/20.0
473
- levtype: sfc
474
- param: [2t]
475
- # param: [10u, 10v, 2d, 2t, lsm, msl, sdor, skt, slor, sp, tcw, z]
476
- number: [0, 1]
477
-
478
- # - class: ea
479
- # expver: '0001'
480
- # grid: 20.0/20.0
481
- # levtype: pl
482
- # param: [q]
483
- # levelist: [1000, 850]
484
398
 
485
- """
486
- )
487
- dates = yaml.safe_load("[2022-12-30 18:00, 2022-12-31 00:00, 2022-12-31 06:00, 2022-12-31 12:00]")
488
- dates = to_datetime_list(dates)
399
+ if not requests:
400
+ requests = [kwargs]
401
+
402
+ for r in requests:
403
+ param = r.get("param", [])
404
+ if not isinstance(param, (list, tuple)):
405
+ param = [param]
406
+ # check for "Norway bug" where yaml transforms 'no' into False, etc.
407
+ for p in param:
408
+ if p is False:
409
+ raise ValueError(
410
+ "'param' cannot be 'False'. If you wrote 'param: no' or 'param: off' in yaml, you may want to use quotes?"
411
+ )
412
+ if p is None:
413
+ raise ValueError(
414
+ "'param' cannot be 'None'. If you wrote 'param: no' in yaml, you may want to use quotes?"
415
+ )
416
+ if p is True:
417
+ raise ValueError(
418
+ "'param' cannot be 'True'. If you wrote 'param: on' in yaml, you may want to use quotes?"
419
+ )
420
+
421
+ if len(dates) == 0: # When using `repeated_dates`
422
+ assert len(requests) == 1, requests
423
+ assert "date" in requests[0], requests[0]
424
+ if isinstance(requests[0]["date"], datetime.date):
425
+ requests[0]["date"] = requests[0]["date"].strftime("%Y%m%d")
426
+ else:
427
+ requests = factorise_requests(
428
+ dates,
429
+ *requests,
430
+ request_already_using_valid_datetime=request_already_using_valid_datetime,
431
+ date_key=date_key,
432
+ )
489
433
 
490
- DEBUG = True
491
- for f in mars(None, dates, *config):
492
- print(f, f.to_numpy().mean())
434
+ requests = list(requests)
435
+
436
+ ds = from_source("empty")
437
+ context.trace("✅", f"{[str(d) for d in dates]}")
438
+ context.trace("✅", f"Will run {len(requests)} requests")
439
+ for r in requests:
440
+ r = {k: v for k, v in r.items() if v != ("-",)}
441
+ context.trace("✅", f"mars {r}")
442
+
443
+ for r in requests:
444
+ r = {k: v for k, v in r.items() if v != ("-",)}
445
+
446
+ if context.use_grib_paramid and "param" in r:
447
+ r = use_grib_paramid(r)
448
+
449
+ for k, v in r.items():
450
+ if k not in MARS_KEYS:
451
+ raise ValueError(
452
+ f"⚠️ Unknown key {k}={v} in MARS request. Did you mean '{did_you_mean(k, MARS_KEYS)}' ?"
453
+ )
454
+ try:
455
+ if use_cdsapi_dataset:
456
+ ds = ds + from_source("cds", use_cdsapi_dataset, r)
457
+ else:
458
+ ds = ds + from_source("mars", **r)
459
+ except Exception as e:
460
+ if "File is empty:" not in str(e):
461
+ raise
462
+ return ds
463
+
464
+
465
+ # TODO: make clearer the interface between sources that use mars.
466
+ # Currently some sources use mars as a function rather than through the registry,
467
+ # e.g. accumulations, accumulations2, hindcasts, recentre, tendencies
468
+ mars = MarsSource._execute
@@ -12,30 +12,34 @@ from typing import Any
12
12
 
13
13
  import earthkit.data as ekd
14
14
 
15
- from .legacy import legacy_source
15
+ from . import source_registry
16
+ from .legacy import LegacySource
16
17
  from .xarray import load_many
17
18
 
18
19
 
19
- @legacy_source(__file__)
20
- def execute(context: Any, dates: list[str], path: str, *args: Any, **kwargs: Any) -> ekd.FieldList:
21
- """Execute the loading of multiple NetCDF files.
22
-
23
- Parameters
24
- ----------
25
- context : object
26
- The context in which the function is executed.
27
- dates : list
28
- List of dates for which data is to be loaded.
29
- path : str
30
- Path to the directory containing the NetCDF files.
31
- *args : tuple
32
- Additional positional arguments.
33
- **kwargs : dict
34
- Additional keyword arguments.
35
-
36
- Returns
37
- -------
38
- object
39
- The loaded data.
40
- """
41
- return load_many("📁", context, dates, path, *args, **kwargs)
20
+ @source_registry.register("netcdf")
21
+ class NetCDFSource(LegacySource):
22
+
23
+ @staticmethod
24
+ def _execute(context: Any, dates: list[str], path: str, *args: Any, **kwargs: Any) -> ekd.FieldList:
25
+ """Execute the loading of multiple NetCDF files.
26
+
27
+ Parameters
28
+ ----------
29
+ context : object
30
+ The context in which the function is executed.
31
+ dates : list
32
+ List of dates for which data is to be loaded.
33
+ path : str
34
+ Path to the directory containing the NetCDF files.
35
+ *args : tuple
36
+ Additional positional arguments.
37
+ **kwargs : dict
38
+ Additional keyword arguments.
39
+
40
+ Returns
41
+ -------
42
+ object
43
+ The loaded data.
44
+ """
45
+ return load_many("📁", context, dates, path, *args, **kwargs)
@@ -12,30 +12,34 @@ from typing import Any
12
12
 
13
13
  import earthkit.data as ekd
14
14
 
15
- from .legacy import legacy_source
15
+ from . import source_registry
16
+ from .legacy import LegacySource
16
17
  from .xarray import load_many
17
18
 
18
19
 
19
- @legacy_source(__file__)
20
- def execute(context: dict[str, Any], dates: list[str], url: str, *args: Any, **kwargs: Any) -> ekd.FieldList:
21
- """Execute the data loading process from an OpenDAP source.
22
-
23
- Parameters
24
- ----------
25
- context : dict
26
- The context in which the function is executed.
27
- dates : list
28
- List of dates for which data is to be loaded.
29
- url : str
30
- The URL of the OpenDAP source.
31
- *args : tuple
32
- Additional positional arguments.
33
- **kwargs : dict
34
- Additional keyword arguments.
35
-
36
- Returns
37
- -------
38
- xarray.Dataset
39
- The loaded dataset.
40
- """
41
- return load_many("🌐", context, dates, url, *args, **kwargs)
20
+ @source_registry.register("opendap")
21
+ class OpenDAPSource(LegacySource):
22
+
23
+ @staticmethod
24
+ def _execute(context: dict[str, Any], dates: list[str], url: str, *args: Any, **kwargs: Any) -> ekd.FieldList:
25
+ """Execute the data loading process from an OpenDAP source.
26
+
27
+ Parameters
28
+ ----------
29
+ context : dict
30
+ The context in which the function is executed.
31
+ dates : list
32
+ List of dates for which data is to be loaded.
33
+ url : str
34
+ The URL of the OpenDAP source.
35
+ *args : tuple
36
+ Additional positional arguments.
37
+ **kwargs : dict
38
+ Additional keyword arguments.
39
+
40
+ Returns
41
+ -------
42
+ xarray.Dataset
43
+ The loaded dataset.
44
+ """
45
+ return load_many("🌐", context, dates, url, *args, **kwargs)