anemoi-utils 0.4.29__tar.gz → 0.4.30__tar.gz
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.
Potentially problematic release.
This version of anemoi-utils might be problematic. Click here for more details.
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/workflows/python-pull-request.yml +1 -1
- anemoi_utils-0.4.30/.release-please-manifest.json +3 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/CHANGELOG.md +7 -0
- {anemoi_utils-0.4.29/src/anemoi_utils.egg-info → anemoi_utils-0.4.30}/PKG-INFO +2 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/conf.py +2 -2
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/pyproject.toml +1 -2
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/_version.py +2 -2
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/caching.py +4 -5
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/checkpoints.py +1 -1
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/cli.py +2 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/commands/metadata.py +1 -2
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/compatibility.py +2 -6
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/config.py +47 -21
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/dates.py +17 -24
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/grib.py +4 -6
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/grids.py +2 -5
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/hindcasts.py +3 -5
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/humanize.py +33 -40
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/mars/__init__.py +4 -7
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/mars/requests.py +1 -2
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/provenance.py +13 -18
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/registry.py +6 -11
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/remote/__init__.py +2 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/remote/s3.py +1 -1
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/rules.py +10 -14
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/s3.py +2 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/text.py +6 -9
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30/src/anemoi_utils.egg-info}/PKG-INFO +2 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test_utils.py +34 -0
- anemoi_utils-0.4.29/.release-please-manifest.json +0 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.gitattributes +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/CODEOWNERS +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/ci-hpc-config.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/dependabot.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/labeler.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/pull_request_template.md +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/workflows/downstream-ci-hpc.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/workflows/pr-conventional-commit.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/workflows/pr-label-conventional-commits.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/workflows/pr-label-file-based.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/workflows/pr-label-public.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/workflows/python-publish.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/workflows/readthedocs-pr-update.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.github/workflows/release-please.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.gitignore +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.pre-commit-config.yaml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.readthedocs.yaml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/.release-please-config.json +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/CONTRIBUTORS.md +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/LICENSE +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/README.md +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/Makefile +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/_static/logo.png +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/_static/style.css +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/_templates/.gitkeep +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/_templates/apidoc/package.rst.jinja +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/index.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/installing.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/modules/checkpoints.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/modules/config.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/modules/dates.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/modules/grib.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/modules/humanize.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/modules/provenance.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/modules/s3.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/modules/testing.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/modules/text.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/docs/scripts/api_build.sh +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/setup.cfg +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/__init__.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/__main__.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/commands/__init__.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/commands/config.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/commands/requests.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/commands/transfer.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/devtools.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/logs.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/mars/mars.yaml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/mlflow/__init__.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/mlflow/auth.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/mlflow/client.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/mlflow/utils.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/remote/ssh.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/sanitise.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/sanitize.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/schemas/__init__.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/schemas/errors.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/testing.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi/utils/timer.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi_utils.egg-info/SOURCES.txt +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi_utils.egg-info/dependency_links.txt +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi_utils.egg-info/entry_points.txt +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi_utils.egg-info/requires.txt +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/src/anemoi_utils.egg-info/top_level.txt +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test-transfer-data/directory/b/c/x +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test-transfer-data/directory/b/y +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test-transfer-data/directory/exotic filename ;^/"'[=.,#]()/303/252/303/274/303/247/303/262/342/234/205.txt" +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test-transfer-data/directory/z +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test-transfer-data/file +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test_caching.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test_compatibility.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test_dates.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test_frequency.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test_mlflow_auth.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test_mlflow_client.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test_provenance.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test_remote.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.30}/tests/test_sanitise.py +0 -0
|
@@ -19,7 +19,7 @@ jobs:
|
|
|
19
19
|
checks:
|
|
20
20
|
strategy:
|
|
21
21
|
matrix:
|
|
22
|
-
python-version: ["3.
|
|
22
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
23
23
|
uses: ecmwf/reusable-workflows/.github/workflows/qa-pytest-pyproject.yml@v2
|
|
24
24
|
with:
|
|
25
25
|
python-version: ${{ matrix.python-version }}
|
|
@@ -8,6 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
Please add your functional changes to the appropriate section in the PR.
|
|
9
9
|
Keep it human-readable, your future self will thank you!
|
|
10
10
|
|
|
11
|
+
## [0.4.30](https://github.com/ecmwf/anemoi-utils/compare/0.4.29...0.4.30) (2025-07-31)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* Refactor code for casting dotdicts and apply this in getitem and setitem methods ([#169](https://github.com/ecmwf/anemoi-utils/issues/169)) ([e91aecf](https://github.com/ecmwf/anemoi-utils/commit/e91aecf6699a0daaed6f79e92b4ebc57cd4abe36))
|
|
17
|
+
|
|
11
18
|
## [0.4.29](https://github.com/ecmwf/anemoi-utils/compare/0.4.28...0.4.29) (2025-07-22)
|
|
12
19
|
|
|
13
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anemoi-utils
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.30
|
|
4
4
|
Summary: A package to hold various functions to support training of ML models on ECMWF data.
|
|
5
5
|
Author-email: "European Centre for Medium-Range Weather Forecasts (ECMWF)" <software.support@ecmwf.int>
|
|
6
6
|
License: Apache License
|
|
@@ -215,14 +215,13 @@ Classifier: Intended Audience :: Developers
|
|
|
215
215
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
216
216
|
Classifier: Operating System :: OS Independent
|
|
217
217
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
218
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
219
218
|
Classifier: Programming Language :: Python :: 3.10
|
|
220
219
|
Classifier: Programming Language :: Python :: 3.11
|
|
221
220
|
Classifier: Programming Language :: Python :: 3.12
|
|
222
221
|
Classifier: Programming Language :: Python :: 3.13
|
|
223
222
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
224
223
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
225
|
-
Requires-Python: >=3.
|
|
224
|
+
Requires-Python: >=3.10
|
|
226
225
|
License-File: LICENSE
|
|
227
226
|
Requires-Dist: aniso8601
|
|
228
227
|
Requires-Dist: deprecation
|
|
@@ -35,9 +35,9 @@ year = datetime.datetime.now().year
|
|
|
35
35
|
if year == 2024:
|
|
36
36
|
years = "2024"
|
|
37
37
|
else:
|
|
38
|
-
years = "2024
|
|
38
|
+
years = f"2024-{year}"
|
|
39
39
|
|
|
40
|
-
copyright = "
|
|
40
|
+
copyright = f"{years}, Anemoi contributors"
|
|
41
41
|
|
|
42
42
|
try:
|
|
43
43
|
from anemoi.utils._version import __version__
|
|
@@ -21,7 +21,7 @@ authors = [
|
|
|
21
21
|
{ name = "European Centre for Medium-Range Weather Forecasts (ECMWF)", email = "software.support@ecmwf.int" },
|
|
22
22
|
]
|
|
23
23
|
|
|
24
|
-
requires-python = ">=3.
|
|
24
|
+
requires-python = ">=3.10"
|
|
25
25
|
|
|
26
26
|
classifiers = [
|
|
27
27
|
"Development Status :: 4 - Beta",
|
|
@@ -29,7 +29,6 @@ classifiers = [
|
|
|
29
29
|
"License :: OSI Approved :: Apache Software License",
|
|
30
30
|
"Operating System :: OS Independent",
|
|
31
31
|
"Programming Language :: Python :: 3 :: Only",
|
|
32
|
-
"Programming Language :: Python :: 3.9",
|
|
33
32
|
"Programming Language :: Python :: 3.10",
|
|
34
33
|
"Programming Language :: Python :: 3.11",
|
|
35
34
|
"Programming Language :: Python :: 3.12",
|
|
@@ -12,10 +12,9 @@ import hashlib
|
|
|
12
12
|
import json
|
|
13
13
|
import os
|
|
14
14
|
import time
|
|
15
|
+
from collections.abc import Callable
|
|
15
16
|
from threading import Lock
|
|
16
17
|
from typing import Any
|
|
17
|
-
from typing import Callable
|
|
18
|
-
from typing import Optional
|
|
19
18
|
|
|
20
19
|
import numpy as np
|
|
21
20
|
|
|
@@ -61,7 +60,7 @@ class Cacher:
|
|
|
61
60
|
Private class, do not use directly.
|
|
62
61
|
"""
|
|
63
62
|
|
|
64
|
-
def __init__(self, collection: str, expires:
|
|
63
|
+
def __init__(self, collection: str, expires: int | None):
|
|
65
64
|
"""Initialize the Cacher.
|
|
66
65
|
|
|
67
66
|
Parameters
|
|
@@ -181,7 +180,7 @@ class JsonCacher(Cacher):
|
|
|
181
180
|
dict
|
|
182
181
|
The loaded data
|
|
183
182
|
"""
|
|
184
|
-
with open(path
|
|
183
|
+
with open(path) as f:
|
|
185
184
|
return json.load(f)
|
|
186
185
|
|
|
187
186
|
|
|
@@ -226,7 +225,7 @@ class NpzCacher(Cacher):
|
|
|
226
225
|
|
|
227
226
|
|
|
228
227
|
# This function is the main entry point for the caching mechanism for the other anemoi packages
|
|
229
|
-
def cached(collection: str = "default", expires:
|
|
228
|
+
def cached(collection: str = "default", expires: int | None = None, encoding: str = "json") -> Callable:
|
|
230
229
|
"""Decorator to cache the result of a function.
|
|
231
230
|
|
|
232
231
|
Default is to use a json file to store the cache, but you can also use npz files
|
|
@@ -14,8 +14,7 @@ import logging
|
|
|
14
14
|
import os
|
|
15
15
|
import sys
|
|
16
16
|
import traceback
|
|
17
|
-
from
|
|
18
|
-
from typing import Optional
|
|
17
|
+
from collections.abc import Callable
|
|
19
18
|
|
|
20
19
|
try:
|
|
21
20
|
import argcomplete
|
|
@@ -187,7 +186,7 @@ def register_commands(here: str, package: str, select: Callable, fail: Callable
|
|
|
187
186
|
|
|
188
187
|
|
|
189
188
|
def cli_main(
|
|
190
|
-
version: str, description: str, commands: dict[str, Command], test_arguments:
|
|
189
|
+
version: str, description: str, commands: dict[str, Command], test_arguments: list[str] | None = None
|
|
191
190
|
) -> None:
|
|
192
191
|
"""Main entry point for the CLI.
|
|
193
192
|
|
|
@@ -17,7 +17,6 @@ from argparse import ArgumentParser
|
|
|
17
17
|
from argparse import Namespace
|
|
18
18
|
from tempfile import TemporaryDirectory
|
|
19
19
|
from typing import Any
|
|
20
|
-
from typing import Dict
|
|
21
20
|
|
|
22
21
|
import yaml
|
|
23
22
|
|
|
@@ -213,7 +212,7 @@ class Metadata(Command):
|
|
|
213
212
|
from anemoi.utils.checkpoints import load_metadata
|
|
214
213
|
from anemoi.utils.checkpoints import replace_metadata
|
|
215
214
|
|
|
216
|
-
kwargs:
|
|
215
|
+
kwargs: dict[str, Any] = {}
|
|
217
216
|
|
|
218
217
|
if args.json:
|
|
219
218
|
ext = "json"
|
|
@@ -10,15 +10,11 @@
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import functools
|
|
13
|
+
from collections.abc import Callable
|
|
13
14
|
from typing import Any
|
|
14
|
-
from typing import Callable
|
|
15
|
-
from typing import Optional
|
|
16
|
-
from typing import Union
|
|
17
15
|
|
|
18
16
|
|
|
19
|
-
def aliases(
|
|
20
|
-
aliases: Optional[dict[str, Union[str, list[str]]]] = None, **kwargs: Any
|
|
21
|
-
) -> Callable[[Callable], Callable]:
|
|
17
|
+
def aliases(aliases: dict[str, str | list[str]] | None = None, **kwargs: Any) -> Callable[[Callable], Callable]:
|
|
22
18
|
"""Alias keyword arguments in a function call.
|
|
23
19
|
|
|
24
20
|
Allows for dynamically renaming keyword arguments in a function call.
|
|
@@ -16,8 +16,6 @@ import logging
|
|
|
16
16
|
import os
|
|
17
17
|
import threading
|
|
18
18
|
from typing import Any
|
|
19
|
-
from typing import Optional
|
|
20
|
-
from typing import Union
|
|
21
19
|
|
|
22
20
|
import yaml
|
|
23
21
|
|
|
@@ -62,14 +60,20 @@ class DotDict(dict):
|
|
|
62
60
|
super().__init__(*args, **kwargs)
|
|
63
61
|
|
|
64
62
|
for k, v in self.items():
|
|
65
|
-
|
|
66
|
-
self[k] = DotDict(v)
|
|
63
|
+
self[k] = self.convert_to_nested_dot_dict(v)
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
@staticmethod
|
|
66
|
+
def convert_to_nested_dot_dict(value):
|
|
67
|
+
if isinstance(value, dict) or is_omegaconf_dict(value):
|
|
68
|
+
return DotDict(value)
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
if isinstance(value, list) or is_omegaconf_list(value):
|
|
71
|
+
return [DotDict(i) if isinstance(i, dict) or is_omegaconf_dict(i) else i for i in value]
|
|
72
|
+
|
|
73
|
+
if isinstance(value, tuple):
|
|
74
|
+
return [DotDict(i) if isinstance(i, dict) or is_omegaconf_dict(i) else i for i in value]
|
|
75
|
+
|
|
76
|
+
return value
|
|
73
77
|
|
|
74
78
|
@classmethod
|
|
75
79
|
def from_file(cls, path: str) -> DotDict:
|
|
@@ -109,7 +113,7 @@ class DotDict(dict):
|
|
|
109
113
|
DotDict
|
|
110
114
|
The created DotDict.
|
|
111
115
|
"""
|
|
112
|
-
with open(path
|
|
116
|
+
with open(path) as file:
|
|
113
117
|
data = yaml.safe_load(file)
|
|
114
118
|
|
|
115
119
|
return cls(data)
|
|
@@ -128,7 +132,7 @@ class DotDict(dict):
|
|
|
128
132
|
DotDict
|
|
129
133
|
The created DotDict.
|
|
130
134
|
"""
|
|
131
|
-
with open(path
|
|
135
|
+
with open(path) as file:
|
|
132
136
|
data = json.load(file)
|
|
133
137
|
|
|
134
138
|
return cls(data)
|
|
@@ -147,7 +151,7 @@ class DotDict(dict):
|
|
|
147
151
|
DotDict
|
|
148
152
|
The created DotDict.
|
|
149
153
|
"""
|
|
150
|
-
with open(path
|
|
154
|
+
with open(path) as file:
|
|
151
155
|
data = tomllib.load(file)
|
|
152
156
|
return cls(data)
|
|
153
157
|
|
|
@@ -179,9 +183,31 @@ class DotDict(dict):
|
|
|
179
183
|
value : Any
|
|
180
184
|
The attribute value.
|
|
181
185
|
"""
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
|
|
187
|
+
self.warn_on_mutation(attr)
|
|
188
|
+
value = self.convert_to_nested_dot_dict(value)
|
|
189
|
+
super().__setitem__(attr, value)
|
|
190
|
+
|
|
191
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
192
|
+
"""Set an item in the dictionary.
|
|
193
|
+
|
|
194
|
+
Parameters
|
|
195
|
+
----------
|
|
196
|
+
key : str
|
|
197
|
+
The key to set.
|
|
198
|
+
value : Any
|
|
199
|
+
The value to set.
|
|
200
|
+
"""
|
|
201
|
+
self.warn_on_mutation(key)
|
|
202
|
+
value = self.convert_to_nested_dot_dict(value)
|
|
203
|
+
super().__setitem__(key, value)
|
|
204
|
+
|
|
205
|
+
@staticmethod
|
|
206
|
+
def warn_on_mutation(key):
|
|
207
|
+
LOG.warning(
|
|
208
|
+
f"Config key '{key}' was modified after instantiation. "
|
|
209
|
+
"This is bad practice — configs are intended to be immutable. "
|
|
210
|
+
)
|
|
185
211
|
|
|
186
212
|
def __repr__(self) -> str:
|
|
187
213
|
"""Return a string representation of the DotDict.
|
|
@@ -243,7 +269,7 @@ QUIET = False
|
|
|
243
269
|
CONFIG_PATCH = None
|
|
244
270
|
|
|
245
271
|
|
|
246
|
-
def _find(config:
|
|
272
|
+
def _find(config: dict | list, what: str, result: list = None) -> list:
|
|
247
273
|
"""Find all occurrences of a key in a nested dictionary or list.
|
|
248
274
|
|
|
249
275
|
Parameters
|
|
@@ -408,8 +434,8 @@ def load_any_dict_format(path: str) -> dict:
|
|
|
408
434
|
|
|
409
435
|
def _load_config(
|
|
410
436
|
name: str = "settings.toml",
|
|
411
|
-
secrets:
|
|
412
|
-
defaults:
|
|
437
|
+
secrets: str | list[str] | None = None,
|
|
438
|
+
defaults: str | dict | None = None,
|
|
413
439
|
) -> DotDict:
|
|
414
440
|
"""Load a configuration file.
|
|
415
441
|
|
|
@@ -531,8 +557,8 @@ def save_config(name: str, data: Any) -> None:
|
|
|
531
557
|
|
|
532
558
|
def load_config(
|
|
533
559
|
name: str = "settings.toml",
|
|
534
|
-
secrets:
|
|
535
|
-
defaults:
|
|
560
|
+
secrets: str | list[str] | None = None,
|
|
561
|
+
defaults: str | dict | None = None,
|
|
536
562
|
) -> DotDict | str:
|
|
537
563
|
"""Read a configuration file.
|
|
538
564
|
|
|
@@ -558,7 +584,7 @@ def load_config(
|
|
|
558
584
|
return config
|
|
559
585
|
|
|
560
586
|
|
|
561
|
-
def load_raw_config(name: str, default: Any = None) ->
|
|
587
|
+
def load_raw_config(name: str, default: Any = None) -> DotDict | str:
|
|
562
588
|
"""Load a raw configuration file.
|
|
563
589
|
|
|
564
590
|
Parameters
|
|
@@ -617,7 +643,7 @@ def check_config_mode(name: str = "settings.toml", secrets_name: str = None, sec
|
|
|
617
643
|
CHECKED[name] = True
|
|
618
644
|
|
|
619
645
|
|
|
620
|
-
def find(metadata:
|
|
646
|
+
def find(metadata: dict | list, what: str, result: list = None, *, select: callable = None) -> list:
|
|
621
647
|
"""Find all occurrences of a key in a nested dictionary or list with an optional selector.
|
|
622
648
|
|
|
623
649
|
Parameters
|
|
@@ -12,16 +12,11 @@ import calendar
|
|
|
12
12
|
import datetime
|
|
13
13
|
import re
|
|
14
14
|
from typing import Any
|
|
15
|
-
from typing import List
|
|
16
|
-
from typing import Optional
|
|
17
|
-
from typing import Set
|
|
18
|
-
from typing import Tuple
|
|
19
|
-
from typing import Union
|
|
20
15
|
|
|
21
16
|
import aniso8601
|
|
22
17
|
|
|
23
18
|
|
|
24
|
-
def normalise_frequency(frequency:
|
|
19
|
+
def normalise_frequency(frequency: int | str) -> int:
|
|
25
20
|
"""Normalise frequency to hours.
|
|
26
21
|
|
|
27
22
|
Parameters
|
|
@@ -61,7 +56,7 @@ def _no_time_zone(date: datetime.datetime) -> datetime.datetime:
|
|
|
61
56
|
|
|
62
57
|
|
|
63
58
|
# this function is use in anemoi-datasets
|
|
64
|
-
def as_datetime(date:
|
|
59
|
+
def as_datetime(date: datetime.date | datetime.datetime | str, keep_time_zone: bool = False) -> datetime.datetime:
|
|
65
60
|
"""Convert a date to a datetime object, removing any time zone information.
|
|
66
61
|
|
|
67
62
|
Parameters
|
|
@@ -91,9 +86,7 @@ def as_datetime(date: Union[datetime.date, datetime.datetime, str], keep_time_zo
|
|
|
91
86
|
raise ValueError(f"Invalid date type: {type(date)}")
|
|
92
87
|
|
|
93
88
|
|
|
94
|
-
def _as_datetime_list(
|
|
95
|
-
date: Union[datetime.date, datetime.datetime, str], default_increment: datetime.timedelta
|
|
96
|
-
) -> iter:
|
|
89
|
+
def _as_datetime_list(date: datetime.date | datetime.datetime | str, default_increment: datetime.timedelta) -> iter:
|
|
97
90
|
"""Convert a date to a list of datetime objects.
|
|
98
91
|
|
|
99
92
|
Parameters
|
|
@@ -137,7 +130,7 @@ def _as_datetime_list(
|
|
|
137
130
|
|
|
138
131
|
|
|
139
132
|
def as_datetime_list(
|
|
140
|
-
date:
|
|
133
|
+
date: datetime.date | datetime.datetime | str, default_increment: int = 1
|
|
141
134
|
) -> list[datetime.datetime]:
|
|
142
135
|
"""Convert a date to a list of datetime objects.
|
|
143
136
|
|
|
@@ -157,7 +150,7 @@ def as_datetime_list(
|
|
|
157
150
|
return list(_as_datetime_list(date, default_increment))
|
|
158
151
|
|
|
159
152
|
|
|
160
|
-
def as_timedelta(frequency:
|
|
153
|
+
def as_timedelta(frequency: int | str | datetime.timedelta) -> datetime.timedelta:
|
|
161
154
|
"""Convert anything to a timedelta object.
|
|
162
155
|
|
|
163
156
|
Parameters
|
|
@@ -237,7 +230,7 @@ def as_timedelta(frequency: Union[int, str, datetime.timedelta]) -> datetime.tim
|
|
|
237
230
|
raise ValueError(f"Cannot convert frequency {frequency} to timedelta")
|
|
238
231
|
|
|
239
232
|
|
|
240
|
-
def frequency_to_timedelta(frequency:
|
|
233
|
+
def frequency_to_timedelta(frequency: int | str | datetime.timedelta) -> datetime.timedelta:
|
|
241
234
|
"""Convert a frequency to a timedelta object.
|
|
242
235
|
|
|
243
236
|
Parameters
|
|
@@ -302,7 +295,7 @@ def frequency_to_string(frequency: datetime.timedelta) -> str:
|
|
|
302
295
|
return str(frequency)
|
|
303
296
|
|
|
304
297
|
|
|
305
|
-
def frequency_to_seconds(frequency:
|
|
298
|
+
def frequency_to_seconds(frequency: int | str | datetime.timedelta) -> int:
|
|
306
299
|
"""Convert a frequency to seconds.
|
|
307
300
|
|
|
308
301
|
Parameters
|
|
@@ -347,7 +340,7 @@ MONTH = {
|
|
|
347
340
|
}
|
|
348
341
|
|
|
349
342
|
|
|
350
|
-
def _make_day(day:
|
|
343
|
+
def _make_day(day: tuple[int, list[int]] | None) -> set[int]:
|
|
351
344
|
"""Create a set of days.
|
|
352
345
|
|
|
353
346
|
Parameters
|
|
@@ -367,7 +360,7 @@ def _make_day(day: Optional[Tuple[int, List[int]]]) -> Set[int]:
|
|
|
367
360
|
return {int(d) for d in day}
|
|
368
361
|
|
|
369
362
|
|
|
370
|
-
def _make_week(week:
|
|
363
|
+
def _make_week(week: tuple[str, list[str]] | None) -> set[int]:
|
|
371
364
|
"""Create a set of weekdays.
|
|
372
365
|
|
|
373
366
|
Parameters
|
|
@@ -387,7 +380,7 @@ def _make_week(week: Optional[Tuple[str, List[str]]]) -> Set[int]:
|
|
|
387
380
|
return {DOW[w.lower()] for w in week}
|
|
388
381
|
|
|
389
382
|
|
|
390
|
-
def _make_months(months:
|
|
383
|
+
def _make_months(months: int | str | list[int | str] | None) -> set[int]:
|
|
391
384
|
"""Create a set of months.
|
|
392
385
|
|
|
393
386
|
Parameters
|
|
@@ -414,13 +407,13 @@ class DateTimes:
|
|
|
414
407
|
|
|
415
408
|
def __init__(
|
|
416
409
|
self,
|
|
417
|
-
start:
|
|
418
|
-
end:
|
|
410
|
+
start: datetime.date | datetime.datetime | str,
|
|
411
|
+
end: datetime.date | datetime.datetime | str,
|
|
419
412
|
increment: int = 24,
|
|
420
413
|
*,
|
|
421
|
-
day_of_month:
|
|
422
|
-
day_of_week:
|
|
423
|
-
calendar_months:
|
|
414
|
+
day_of_month: tuple[int, list[int]] | None = None,
|
|
415
|
+
day_of_week: tuple[str, list[str]] | None = None,
|
|
416
|
+
calendar_months: int | str | list[int | str] | None = None,
|
|
424
417
|
):
|
|
425
418
|
"""Initialize the DateTimes iterator.
|
|
426
419
|
|
|
@@ -571,7 +564,7 @@ class ConcatDateTimes:
|
|
|
571
564
|
class EnumDateTimes:
|
|
572
565
|
"""EnumDateTimes is an iterator that generates datetime objects from a list of dates."""
|
|
573
566
|
|
|
574
|
-
def __init__(self, dates: list[
|
|
567
|
+
def __init__(self, dates: list[datetime.date | datetime.datetime | str]):
|
|
575
568
|
"""Initialize the EnumDateTimes iterator.
|
|
576
569
|
|
|
577
570
|
Parameters
|
|
@@ -593,7 +586,7 @@ class EnumDateTimes:
|
|
|
593
586
|
yield as_datetime(date)
|
|
594
587
|
|
|
595
588
|
|
|
596
|
-
def datetimes_factory(*args: Any, **kwargs: Any) ->
|
|
589
|
+
def datetimes_factory(*args: Any, **kwargs: Any) -> DateTimes | ConcatDateTimes | EnumDateTimes:
|
|
597
590
|
"""Create a DateTimes, ConcatDateTimes, or EnumDateTimes object.
|
|
598
591
|
|
|
599
592
|
Parameters
|
|
@@ -15,8 +15,6 @@ See https://codes.ecmwf.int/grib/param-db/ for more information.
|
|
|
15
15
|
|
|
16
16
|
import logging
|
|
17
17
|
import re
|
|
18
|
-
from typing import Dict
|
|
19
|
-
from typing import Union
|
|
20
18
|
|
|
21
19
|
import requests
|
|
22
20
|
|
|
@@ -26,7 +24,7 @@ LOG = logging.getLogger(__name__)
|
|
|
26
24
|
|
|
27
25
|
|
|
28
26
|
@cached(collection="grib", expires=30 * 24 * 60 * 60)
|
|
29
|
-
def _units() ->
|
|
27
|
+
def _units() -> dict[str, str]:
|
|
30
28
|
"""Fetch and cache GRIB parameter units.
|
|
31
29
|
|
|
32
30
|
Returns
|
|
@@ -41,7 +39,7 @@ def _units() -> Dict[str, str]:
|
|
|
41
39
|
|
|
42
40
|
|
|
43
41
|
@cached(collection="grib", expires=30 * 24 * 60 * 60)
|
|
44
|
-
def _search_param(name: str) ->
|
|
42
|
+
def _search_param(name: str) -> dict[str, str | int]:
|
|
45
43
|
"""Search for a GRIB parameter by name.
|
|
46
44
|
|
|
47
45
|
Parameters
|
|
@@ -116,7 +114,7 @@ def paramid_to_shortname(paramid: int) -> str:
|
|
|
116
114
|
return _search_param(str(paramid))["shortname"]
|
|
117
115
|
|
|
118
116
|
|
|
119
|
-
def units(param:
|
|
117
|
+
def units(param: int | str) -> str:
|
|
120
118
|
"""Return the units of a GRIB parameter given its name or id.
|
|
121
119
|
|
|
122
120
|
Parameters
|
|
@@ -137,7 +135,7 @@ def units(param: Union[int, str]) -> str:
|
|
|
137
135
|
return _units()[unit_id]
|
|
138
136
|
|
|
139
137
|
|
|
140
|
-
def must_be_positive(param:
|
|
138
|
+
def must_be_positive(param: int | str) -> bool:
|
|
141
139
|
"""Check if a parameter must be positive.
|
|
142
140
|
|
|
143
141
|
Parameters
|
|
@@ -13,9 +13,6 @@
|
|
|
13
13
|
import logging
|
|
14
14
|
import os
|
|
15
15
|
from io import BytesIO
|
|
16
|
-
from typing import List
|
|
17
|
-
from typing import Tuple
|
|
18
|
-
from typing import Union
|
|
19
16
|
|
|
20
17
|
import deprecation
|
|
21
18
|
import numpy as np
|
|
@@ -145,7 +142,7 @@ def nearest_grid_points(
|
|
|
145
142
|
|
|
146
143
|
|
|
147
144
|
@cached(collection="grids", encoding="npz")
|
|
148
|
-
def _grids(name:
|
|
145
|
+
def _grids(name: str | list[float] | tuple[float, ...]) -> bytes:
|
|
149
146
|
"""Get grid data by name.
|
|
150
147
|
|
|
151
148
|
Parameters
|
|
@@ -196,7 +193,7 @@ def _grids(name: Union[str, List[float], Tuple[float, ...]]) -> bytes:
|
|
|
196
193
|
current_version=__version__,
|
|
197
194
|
details="Use anemoi.transform.grids.named.lookup instead.",
|
|
198
195
|
)
|
|
199
|
-
def grids(name:
|
|
196
|
+
def grids(name: str | list[float] | tuple[float, ...]) -> dict:
|
|
200
197
|
"""Load grid data by name.
|
|
201
198
|
|
|
202
199
|
Parameters
|
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
import datetime
|
|
12
|
-
from
|
|
13
|
-
from typing import List
|
|
14
|
-
from typing import Tuple
|
|
12
|
+
from collections.abc import Iterator
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
class HindcastDatesTimes:
|
|
@@ -25,7 +23,7 @@ class HindcastDatesTimes:
|
|
|
25
23
|
Number of years to go back from each reference date.
|
|
26
24
|
"""
|
|
27
25
|
|
|
28
|
-
def __init__(self, reference_dates:
|
|
26
|
+
def __init__(self, reference_dates: list[datetime.datetime], years: int = 20):
|
|
29
27
|
"""Initialize the HindcastDatesTimes iterator.
|
|
30
28
|
|
|
31
29
|
Parameters
|
|
@@ -41,7 +39,7 @@ class HindcastDatesTimes:
|
|
|
41
39
|
assert years > 0, f"years must be greater than 0, got {years}"
|
|
42
40
|
self.years = years
|
|
43
41
|
|
|
44
|
-
def __iter__(self) -> Iterator[
|
|
42
|
+
def __iter__(self) -> Iterator[tuple[datetime.datetime, datetime.datetime]]:
|
|
45
43
|
"""Generate tuples of past dates and their corresponding reference dates.
|
|
46
44
|
|
|
47
45
|
Yields
|