anemoi-utils 0.4.29__tar.gz → 0.4.31__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.31}/.github/workflows/python-pull-request.yml +1 -1
- anemoi_utils-0.4.31/.release-please-manifest.json +3 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/CHANGELOG.md +14 -0
- {anemoi_utils-0.4.29/src/anemoi_utils.egg-info → anemoi_utils-0.4.31}/PKG-INFO +2 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/conf.py +2 -2
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/pyproject.toml +1 -2
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/_version.py +16 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/caching.py +4 -5
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/checkpoints.py +1 -1
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/cli.py +2 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/commands/metadata.py +1 -2
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/compatibility.py +2 -6
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/config.py +44 -21
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/dates.py +17 -24
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/grib.py +4 -6
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/grids.py +2 -5
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/hindcasts.py +3 -5
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/humanize.py +33 -40
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/mars/__init__.py +4 -7
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/mars/requests.py +1 -2
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/provenance.py +13 -18
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/registry.py +6 -11
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/remote/__init__.py +2 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/remote/s3.py +1 -1
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/rules.py +10 -14
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/s3.py +2 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/text.py +6 -9
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31/src/anemoi_utils.egg-info}/PKG-INFO +2 -3
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/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.31}/.gitattributes +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/CODEOWNERS +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/ci-hpc-config.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/dependabot.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/labeler.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/pull_request_template.md +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/workflows/downstream-ci-hpc.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/workflows/pr-conventional-commit.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/workflows/pr-label-conventional-commits.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/workflows/pr-label-file-based.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/workflows/pr-label-public.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/workflows/python-publish.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/workflows/readthedocs-pr-update.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.github/workflows/release-please.yml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.gitignore +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.pre-commit-config.yaml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.readthedocs.yaml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/.release-please-config.json +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/CONTRIBUTORS.md +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/LICENSE +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/README.md +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/Makefile +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/_static/logo.png +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/_static/style.css +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/_templates/.gitkeep +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/_templates/apidoc/package.rst.jinja +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/index.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/installing.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/modules/checkpoints.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/modules/config.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/modules/dates.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/modules/grib.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/modules/humanize.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/modules/provenance.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/modules/s3.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/modules/testing.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/modules/text.rst +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/docs/scripts/api_build.sh +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/setup.cfg +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/__init__.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/__main__.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/commands/__init__.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/commands/config.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/commands/requests.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/commands/transfer.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/devtools.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/logs.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/mars/mars.yaml +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/mlflow/__init__.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/mlflow/auth.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/mlflow/client.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/mlflow/utils.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/remote/ssh.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/sanitise.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/sanitize.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/schemas/__init__.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/schemas/errors.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/testing.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi/utils/timer.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi_utils.egg-info/SOURCES.txt +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi_utils.egg-info/dependency_links.txt +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi_utils.egg-info/entry_points.txt +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi_utils.egg-info/requires.txt +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/src/anemoi_utils.egg-info/top_level.txt +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test-transfer-data/directory/b/c/x +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test-transfer-data/directory/b/y +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/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.31}/tests/test-transfer-data/directory/z +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test-transfer-data/file +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test_caching.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test_compatibility.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test_dates.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test_frequency.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test_mlflow_auth.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test_mlflow_client.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test_provenance.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/tests/test_remote.py +0 -0
- {anemoi_utils-0.4.29 → anemoi_utils-0.4.31}/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,20 @@ 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.31](https://github.com/ecmwf/anemoi-utils/compare/0.4.30...0.4.31) (2025-08-04)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* Remove too many warnings ([#193](https://github.com/ecmwf/anemoi-utils/issues/193)) ([df6862b](https://github.com/ecmwf/anemoi-utils/commit/df6862bf829e67651ccc97cbaac9f38096ad4d34))
|
|
17
|
+
|
|
18
|
+
## [0.4.30](https://github.com/ecmwf/anemoi-utils/compare/0.4.29...0.4.30) (2025-07-31)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* 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))
|
|
24
|
+
|
|
11
25
|
## [0.4.29](https://github.com/ecmwf/anemoi-utils/compare/0.4.28...0.4.29) (2025-07-22)
|
|
12
26
|
|
|
13
27
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anemoi-utils
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.31
|
|
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",
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
3
|
|
|
4
|
-
__all__ = [
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
5
12
|
|
|
6
13
|
TYPE_CHECKING = False
|
|
7
14
|
if TYPE_CHECKING:
|
|
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
|
|
|
9
16
|
from typing import Union
|
|
10
17
|
|
|
11
18
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
12
20
|
else:
|
|
13
21
|
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
14
23
|
|
|
15
24
|
version: str
|
|
16
25
|
__version__: str
|
|
17
26
|
__version_tuple__: VERSION_TUPLE
|
|
18
27
|
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
19
30
|
|
|
20
|
-
__version__ = version = '0.4.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 4,
|
|
31
|
+
__version__ = version = '0.4.31'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 4, 31)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = 'g2684cac7a'
|
|
@@ -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.
|
|
@@ -15,9 +15,8 @@ import json
|
|
|
15
15
|
import logging
|
|
16
16
|
import os
|
|
17
17
|
import threading
|
|
18
|
+
import warnings
|
|
18
19
|
from typing import Any
|
|
19
|
-
from typing import Optional
|
|
20
|
-
from typing import Union
|
|
21
20
|
|
|
22
21
|
import yaml
|
|
23
22
|
|
|
@@ -62,14 +61,20 @@ class DotDict(dict):
|
|
|
62
61
|
super().__init__(*args, **kwargs)
|
|
63
62
|
|
|
64
63
|
for k, v in self.items():
|
|
65
|
-
|
|
66
|
-
self[k] = DotDict(v)
|
|
64
|
+
self[k] = self.convert_to_nested_dot_dict(v)
|
|
67
65
|
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
@staticmethod
|
|
67
|
+
def convert_to_nested_dot_dict(value):
|
|
68
|
+
if isinstance(value, dict) or is_omegaconf_dict(value):
|
|
69
|
+
return DotDict(value)
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
if isinstance(value, list) or is_omegaconf_list(value):
|
|
72
|
+
return [DotDict(i) if isinstance(i, dict) or is_omegaconf_dict(i) else i for i in value]
|
|
73
|
+
|
|
74
|
+
if isinstance(value, tuple):
|
|
75
|
+
return [DotDict(i) if isinstance(i, dict) or is_omegaconf_dict(i) else i for i in value]
|
|
76
|
+
|
|
77
|
+
return value
|
|
73
78
|
|
|
74
79
|
@classmethod
|
|
75
80
|
def from_file(cls, path: str) -> DotDict:
|
|
@@ -109,7 +114,7 @@ class DotDict(dict):
|
|
|
109
114
|
DotDict
|
|
110
115
|
The created DotDict.
|
|
111
116
|
"""
|
|
112
|
-
with open(path
|
|
117
|
+
with open(path) as file:
|
|
113
118
|
data = yaml.safe_load(file)
|
|
114
119
|
|
|
115
120
|
return cls(data)
|
|
@@ -128,7 +133,7 @@ class DotDict(dict):
|
|
|
128
133
|
DotDict
|
|
129
134
|
The created DotDict.
|
|
130
135
|
"""
|
|
131
|
-
with open(path
|
|
136
|
+
with open(path) as file:
|
|
132
137
|
data = json.load(file)
|
|
133
138
|
|
|
134
139
|
return cls(data)
|
|
@@ -147,7 +152,7 @@ class DotDict(dict):
|
|
|
147
152
|
DotDict
|
|
148
153
|
The created DotDict.
|
|
149
154
|
"""
|
|
150
|
-
with open(path
|
|
155
|
+
with open(path) as file:
|
|
151
156
|
data = tomllib.load(file)
|
|
152
157
|
return cls(data)
|
|
153
158
|
|
|
@@ -179,9 +184,27 @@ class DotDict(dict):
|
|
|
179
184
|
value : Any
|
|
180
185
|
The attribute value.
|
|
181
186
|
"""
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
187
|
+
|
|
188
|
+
self.warn_on_mutation(attr)
|
|
189
|
+
value = self.convert_to_nested_dot_dict(value)
|
|
190
|
+
super().__setitem__(attr, value)
|
|
191
|
+
|
|
192
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
193
|
+
"""Set an item in the dictionary.
|
|
194
|
+
|
|
195
|
+
Parameters
|
|
196
|
+
----------
|
|
197
|
+
key : str
|
|
198
|
+
The key to set.
|
|
199
|
+
value : Any
|
|
200
|
+
The value to set.
|
|
201
|
+
"""
|
|
202
|
+
self.warn_on_mutation(key)
|
|
203
|
+
value = self.convert_to_nested_dot_dict(value)
|
|
204
|
+
super().__setitem__(key, value)
|
|
205
|
+
|
|
206
|
+
def warn_on_mutation(self, key):
|
|
207
|
+
warnings.warn("Mofifying and instance of DotDict(). This class is intended to be immutable.")
|
|
185
208
|
|
|
186
209
|
def __repr__(self) -> str:
|
|
187
210
|
"""Return a string representation of the DotDict.
|
|
@@ -243,7 +266,7 @@ QUIET = False
|
|
|
243
266
|
CONFIG_PATCH = None
|
|
244
267
|
|
|
245
268
|
|
|
246
|
-
def _find(config:
|
|
269
|
+
def _find(config: dict | list, what: str, result: list = None) -> list:
|
|
247
270
|
"""Find all occurrences of a key in a nested dictionary or list.
|
|
248
271
|
|
|
249
272
|
Parameters
|
|
@@ -408,8 +431,8 @@ def load_any_dict_format(path: str) -> dict:
|
|
|
408
431
|
|
|
409
432
|
def _load_config(
|
|
410
433
|
name: str = "settings.toml",
|
|
411
|
-
secrets:
|
|
412
|
-
defaults:
|
|
434
|
+
secrets: str | list[str] | None = None,
|
|
435
|
+
defaults: str | dict | None = None,
|
|
413
436
|
) -> DotDict:
|
|
414
437
|
"""Load a configuration file.
|
|
415
438
|
|
|
@@ -531,8 +554,8 @@ def save_config(name: str, data: Any) -> None:
|
|
|
531
554
|
|
|
532
555
|
def load_config(
|
|
533
556
|
name: str = "settings.toml",
|
|
534
|
-
secrets:
|
|
535
|
-
defaults:
|
|
557
|
+
secrets: str | list[str] | None = None,
|
|
558
|
+
defaults: str | dict | None = None,
|
|
536
559
|
) -> DotDict | str:
|
|
537
560
|
"""Read a configuration file.
|
|
538
561
|
|
|
@@ -558,7 +581,7 @@ def load_config(
|
|
|
558
581
|
return config
|
|
559
582
|
|
|
560
583
|
|
|
561
|
-
def load_raw_config(name: str, default: Any = None) ->
|
|
584
|
+
def load_raw_config(name: str, default: Any = None) -> DotDict | str:
|
|
562
585
|
"""Load a raw configuration file.
|
|
563
586
|
|
|
564
587
|
Parameters
|
|
@@ -617,7 +640,7 @@ def check_config_mode(name: str = "settings.toml", secrets_name: str = None, sec
|
|
|
617
640
|
CHECKED[name] = True
|
|
618
641
|
|
|
619
642
|
|
|
620
|
-
def find(metadata:
|
|
643
|
+
def find(metadata: dict | list, what: str, result: list = None, *, select: callable = None) -> list:
|
|
621
644
|
"""Find all occurrences of a key in a nested dictionary or list with an optional selector.
|
|
622
645
|
|
|
623
646
|
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
|