anemoi-utils 0.4.16__tar.gz → 0.4.18__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.16 → anemoi_utils-0.4.18}/.gitignore +2 -3
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.pre-commit-config.yaml +6 -6
- anemoi_utils-0.4.18/.release-please-manifest.json +3 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/CHANGELOG.md +27 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/PKG-INFO +1 -1
- anemoi_utils-0.4.18/docs/_static/logo.png +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/conf.py +11 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/index.rst +4 -3
- anemoi_utils-0.4.18/docs/modules/testing.rst +8 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/_version.py +2 -2
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/config.py +18 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/provenance.py +2 -2
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/registry.py +4 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/remote/__init__.py +1 -1
- anemoi_utils-0.4.18/src/anemoi/utils/rules.py +218 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi_utils.egg-info/PKG-INFO +1 -1
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi_utils.egg-info/SOURCES.txt +2 -0
- anemoi_utils-0.4.16/.release-please-manifest.json +0 -3
- anemoi_utils-0.4.16/docs/_static/logo.png +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.gitattributes +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/CODEOWNERS +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/ci-hpc-config.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/dependabot.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/labeler.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/pull_request_template.md +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/release.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/workflows/downstream-ci-hpc.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/workflows/pr-conventional-commit.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/workflows/pr-label-conventional-commits.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/workflows/pr-label-file-based.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/workflows/pr-label-public.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/workflows/python-publish.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/workflows/python-pull-request.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/workflows/readthedocs-pr-update.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/workflows/release-please.yml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.readthedocs.yaml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.release-please-config.json +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/CONTRIBUTORS.md +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/LICENSE +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/README.md +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/Makefile +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/_static/style.css +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/_templates/.gitkeep +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/installing.rst +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/modules/checkpoints.rst +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/modules/config.rst +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/modules/dates.rst +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/modules/grib.rst +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/modules/humanize.rst +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/modules/provenance.rst +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/modules/s3.rst +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/docs/modules/text.rst +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/pyproject.toml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/setup.cfg +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/__init__.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/__main__.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/caching.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/checkpoints.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/cli.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/commands/__init__.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/commands/config.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/commands/requests.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/compatibility.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/dates.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/devtools.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/grib.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/grids.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/hindcasts.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/humanize.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/logs.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/mars/__init__.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/mars/mars.yaml +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/mars/requests.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/remote/s3.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/remote/ssh.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/s3.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/sanitise.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/sanitize.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/testing.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/text.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi/utils/timer.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi_utils.egg-info/dependency_links.txt +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi_utils.egg-info/entry_points.txt +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi_utils.egg-info/requires.txt +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/src/anemoi_utils.egg-info/top_level.txt +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test-transfer-data/directory/b/c/x +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test-transfer-data/directory/b/y +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/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.16 → anemoi_utils-0.4.18}/tests/test-transfer-data/directory/z +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test-transfer-data/file +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test_caching.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test_compatibility.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test_dates.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test_frequency.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test_grids.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test_provenance.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test_remote.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test_sanetise.py +0 -0
- {anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/tests/test_utils.py +0 -0
|
@@ -42,6 +42,7 @@ cover/
|
|
|
42
42
|
|
|
43
43
|
# Documentation
|
|
44
44
|
docs/_build/
|
|
45
|
+
docs/_api/
|
|
45
46
|
/site
|
|
46
47
|
*.mo
|
|
47
48
|
*.pot
|
|
@@ -119,7 +120,7 @@ tmp/
|
|
|
119
120
|
temp/
|
|
120
121
|
logs/
|
|
121
122
|
_dev/
|
|
122
|
-
outputs
|
|
123
|
+
outputs
|
|
123
124
|
*tmp_data/
|
|
124
125
|
|
|
125
126
|
# Project specific
|
|
@@ -130,9 +131,7 @@ bar
|
|
|
130
131
|
~$images.pptx
|
|
131
132
|
test.py
|
|
132
133
|
test.ipynb
|
|
133
|
-
cutout.png
|
|
134
134
|
_version.py
|
|
135
135
|
*.to_upload
|
|
136
136
|
tempCodeRunnerFile.python
|
|
137
137
|
Untitled-*.py
|
|
138
|
-
.*cache/
|
|
@@ -27,12 +27,12 @@ repos:
|
|
|
27
27
|
- id: python-check-blanket-noqa # Check for # noqa: all
|
|
28
28
|
- id: python-no-log-warn # Check for log.warn
|
|
29
29
|
- repo: https://github.com/psf/black-pre-commit-mirror
|
|
30
|
-
rev:
|
|
30
|
+
rev: 25.1.0
|
|
31
31
|
hooks:
|
|
32
32
|
- id: black
|
|
33
33
|
args: [--line-length=120]
|
|
34
34
|
- repo: https://github.com/pycqa/isort
|
|
35
|
-
rev:
|
|
35
|
+
rev: 6.0.1
|
|
36
36
|
hooks:
|
|
37
37
|
- id: isort
|
|
38
38
|
args:
|
|
@@ -40,7 +40,7 @@ repos:
|
|
|
40
40
|
- --force-single-line-imports
|
|
41
41
|
- --profile black
|
|
42
42
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
43
|
-
rev: v0.
|
|
43
|
+
rev: v0.9.9
|
|
44
44
|
hooks:
|
|
45
45
|
- id: ruff
|
|
46
46
|
args:
|
|
@@ -60,16 +60,16 @@ repos:
|
|
|
60
60
|
- id: rstfmt
|
|
61
61
|
exclude: '(cli|schemas)/.*' # Because we use argparse and pydantic sphinx directives
|
|
62
62
|
- repo: https://github.com/b8raoult/pre-commit-docconvert
|
|
63
|
-
rev: "0.1.
|
|
63
|
+
rev: "0.1.5"
|
|
64
64
|
hooks:
|
|
65
65
|
- id: docconvert
|
|
66
66
|
args: ["numpy"]
|
|
67
67
|
- repo: https://github.com/tox-dev/pyproject-fmt
|
|
68
|
-
rev: "v2.5.
|
|
68
|
+
rev: "v2.5.1"
|
|
69
69
|
hooks:
|
|
70
70
|
- id: pyproject-fmt
|
|
71
71
|
- repo: https://github.com/jshwi/docsig # Check docstrings against function sig
|
|
72
|
-
rev: v0.
|
|
72
|
+
rev: v0.69.1
|
|
73
73
|
hooks:
|
|
74
74
|
- id: docsig
|
|
75
75
|
args:
|
|
@@ -8,6 +8,33 @@ 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.18](https://github.com/ecmwf/anemoi-utils/compare/0.4.17...0.4.18) (2025-03-31)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* add matching rules ([#132](https://github.com/ecmwf/anemoi-utils/issues/132)) ([2382980](https://github.com/ecmwf/anemoi-utils/commit/2382980f4f53909a73fa0a5c8cfab108625f3c55))
|
|
17
|
+
|
|
18
|
+
## [0.4.17](https://github.com/ecmwf/anemoi-utils/compare/0.4.16...0.4.17) (2025-03-27)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
* add generic env variables to override anemoi user config ([#128](https://github.com/ecmwf/anemoi-utils/issues/128)) ([fdc7248](https://github.com/ecmwf/anemoi-utils/commit/fdc72485616a0c092356a9ffa4cdca838a0c1a9d))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Bug Fixes
|
|
27
|
+
|
|
28
|
+
* Iterate over copy of sys.modules. ([#127](https://github.com/ecmwf/anemoi-utils/issues/127)) ([7b0e7d0](https://github.com/ecmwf/anemoi-utils/commit/7b0e7d08264f7eb4c92fdcd744ff8c46eac82fb7))
|
|
29
|
+
* plugin name on error ([#120](https://github.com/ecmwf/anemoi-utils/issues/120)) ([a747f63](https://github.com/ecmwf/anemoi-utils/commit/a747f63d74bf1b108d913694915df59ffc4640c1))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Documentation
|
|
33
|
+
|
|
34
|
+
* add links to GitHub ([#123](https://github.com/ecmwf/anemoi-utils/issues/123)) ([cfe1ea2](https://github.com/ecmwf/anemoi-utils/commit/cfe1ea281e03a56b9a02108b6787c6c05b9518b0))
|
|
35
|
+
* Docathon ([#121](https://github.com/ecmwf/anemoi-utils/issues/121)) ([e1c9292](https://github.com/ecmwf/anemoi-utils/commit/e1c9292d65b1ffc8c9ce8eed41c7ffbe81f865a3))
|
|
36
|
+
* fix comment ([#125](https://github.com/ecmwf/anemoi-utils/issues/125)) ([ad3ed12](https://github.com/ecmwf/anemoi-utils/commit/ad3ed126f9a507dde7ce19064f1d32dae2cee6a3))
|
|
37
|
+
|
|
11
38
|
## [0.4.16](https://github.com/ecmwf/anemoi-utils/compare/0.4.15...0.4.16) (2025-03-22)
|
|
12
39
|
|
|
13
40
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anemoi-utils
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.18
|
|
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
|
|
Binary file
|
|
@@ -105,6 +105,10 @@ intersphinx_mapping = {
|
|
|
105
105
|
"https://anemoi-transform.readthedocs.io/en/latest/",
|
|
106
106
|
("../../anemoi-transform/docs/_build/html/objects.inv", None),
|
|
107
107
|
),
|
|
108
|
+
"anemoi-plugins": (
|
|
109
|
+
"https://anemoi-plugins.readthedocs.io/en/latest/",
|
|
110
|
+
("../../anemoi-plugins/docs/_build/html/objects.inv", None),
|
|
111
|
+
),
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
# -- Options for HTML output -------------------------------------------------
|
|
@@ -124,3 +128,10 @@ html_css_files = ["style.css"]
|
|
|
124
128
|
todo_include_todos = not read_the_docs_build
|
|
125
129
|
|
|
126
130
|
autodoc_member_order = "bysource" # Keep file order
|
|
131
|
+
|
|
132
|
+
html_context = {
|
|
133
|
+
"display_github": True,
|
|
134
|
+
"github_user": "ecmwf",
|
|
135
|
+
"github_repo": "anemoi-utils",
|
|
136
|
+
"github_version": "main/docs/",
|
|
137
|
+
}
|
|
@@ -40,9 +40,9 @@ of the *Anemoi* packages.
|
|
|
40
40
|
|
|
41
41
|
modules/*
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
Anemoi packages
|
|
45
|
-
|
|
43
|
+
***********************
|
|
44
|
+
Other Anemoi packages
|
|
45
|
+
***********************
|
|
46
46
|
|
|
47
47
|
- :ref:`anemoi-utils <anemoi-utils:index-page>`
|
|
48
48
|
- :ref:`anemoi-transform <anemoi-transform:index-page>`
|
|
@@ -52,6 +52,7 @@ of the *Anemoi* packages.
|
|
|
52
52
|
- :ref:`anemoi-training <anemoi-training:index-page>`
|
|
53
53
|
- :ref:`anemoi-inference <anemoi-inference:index-page>`
|
|
54
54
|
- :ref:`anemoi-registry <anemoi-registry:index-page>`
|
|
55
|
+
- :ref:`anemoi-plugins <anemoi-plugins:index-page>`
|
|
55
56
|
|
|
56
57
|
*********
|
|
57
58
|
License
|
|
@@ -459,6 +459,24 @@ def _load_config(
|
|
|
459
459
|
secret_config = _load_config(secret_name)
|
|
460
460
|
_merge_dicts(config, secret_config)
|
|
461
461
|
|
|
462
|
+
for env, value in os.environ.items():
|
|
463
|
+
|
|
464
|
+
if not env.startswith("ANEMOI_CONFIG_"):
|
|
465
|
+
continue
|
|
466
|
+
rest = env[len("ANEMOI_CONFIG_") :]
|
|
467
|
+
|
|
468
|
+
package = rest.split("_")[0]
|
|
469
|
+
sub = rest[len(package) + 1 :]
|
|
470
|
+
|
|
471
|
+
package = package.lower()
|
|
472
|
+
sub = sub.lower()
|
|
473
|
+
|
|
474
|
+
LOG.info(f"Using environment variable {env} to override the anemoi config key '{package}.{sub}'")
|
|
475
|
+
|
|
476
|
+
if package not in config:
|
|
477
|
+
config[package] = {}
|
|
478
|
+
config[package][sub] = value
|
|
479
|
+
|
|
462
480
|
CONFIG[key] = DotDict(config)
|
|
463
481
|
return CONFIG[key]
|
|
464
482
|
|
|
@@ -199,12 +199,12 @@ def _module_versions(full: bool) -> Tuple[Dict[str, Any], set]:
|
|
|
199
199
|
|
|
200
200
|
versions = {}
|
|
201
201
|
namespaces = set()
|
|
202
|
-
for k, v in sorted(sys.modules.items()):
|
|
202
|
+
for k, v in sorted(sys.modules.copy().items()):
|
|
203
203
|
if "." not in k:
|
|
204
204
|
version(versions, k, v, roots, namespaces, paths, full)
|
|
205
205
|
|
|
206
206
|
# Catter for modules like "earthkit.meteo"
|
|
207
|
-
for k, v in sorted(sys.modules.items()):
|
|
207
|
+
for k, v in sorted(sys.modules.copy().items()):
|
|
208
208
|
bits = k.split(".")
|
|
209
209
|
if len(bits) == 2 and bits[0] in namespaces:
|
|
210
210
|
version(versions, k, v, roots, namespaces, paths, full)
|
|
@@ -162,12 +162,16 @@ class Registry:
|
|
|
162
162
|
file : str
|
|
163
163
|
The file to load.
|
|
164
164
|
"""
|
|
165
|
+
|
|
165
166
|
name, _ = os.path.splitext(file)
|
|
167
|
+
|
|
166
168
|
try:
|
|
167
169
|
importlib.import_module(f".{name}", package=self.package)
|
|
168
170
|
except Exception as e:
|
|
169
171
|
if DEBUG_ANEMOI_REGISTRY:
|
|
170
172
|
raise
|
|
173
|
+
|
|
174
|
+
name = name.replace("_", "-")
|
|
171
175
|
self.__registered[name] = Error(e)
|
|
172
176
|
|
|
173
177
|
def is_registered(self, name: str) -> bool:
|
|
@@ -627,7 +627,7 @@ def _find_transfer_class(source: str, target: str) -> type:
|
|
|
627
627
|
raise TransferMethodNotImplementedError(f"Transfer from {source} to {target} is not implemented")
|
|
628
628
|
|
|
629
629
|
|
|
630
|
-
#
|
|
630
|
+
# This function is the main entry point for the transfer mechanism for the other anemoi packages
|
|
631
631
|
def transfer(
|
|
632
632
|
source, target, *, overwrite=False, resume=False, verbosity=1, progress=None, threads=1, temporary_target=False
|
|
633
633
|
) -> Loader:
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# (C) Copyright 2025 Anemoi contributors.
|
|
2
|
+
#
|
|
3
|
+
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
4
|
+
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
5
|
+
#
|
|
6
|
+
# In applying this licence, ECMWF does not waive the privileges and immunities
|
|
7
|
+
# granted to it by virtue of its status as an intergovernmental organisation
|
|
8
|
+
# nor does it submit to any jurisdiction.
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
from typing import Dict
|
|
12
|
+
from typing import List
|
|
13
|
+
from typing import Mapping
|
|
14
|
+
from typing import Optional
|
|
15
|
+
from typing import Union
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Rule:
|
|
19
|
+
|
|
20
|
+
def __init__(self, match: Dict[str, Any], result: Any):
|
|
21
|
+
"""Initialize a Rule object.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
match : Dict[str, Any]
|
|
26
|
+
A dictionary defining the conditions for the rule to match.
|
|
27
|
+
result : Any
|
|
28
|
+
The result to return if the rule matches.
|
|
29
|
+
"""
|
|
30
|
+
self._match = match
|
|
31
|
+
self._result = result
|
|
32
|
+
|
|
33
|
+
def match(self, obj: Mapping[str, Any]) -> bool:
|
|
34
|
+
"""Check if the rule matches the given object.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
obj : Mapping[str, Any]
|
|
39
|
+
The object to check against the rule's conditions.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
bool
|
|
44
|
+
True if the rule matches, False otherwise.
|
|
45
|
+
"""
|
|
46
|
+
for key, value in self._match.items():
|
|
47
|
+
if key not in obj or obj[key] != value:
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
return True
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def result(self) -> Any:
|
|
54
|
+
return self._result
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def condition(self) -> Dict[str, Any]:
|
|
58
|
+
return self._match
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class RuleSet:
|
|
62
|
+
|
|
63
|
+
def __init__(self, rules: List[Union[Rule, Dict[str, Any], List[Any]]]):
|
|
64
|
+
"""Initialize a RuleSet object.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
rules : List[Union[Rule, Dict[str, Any], List[Any]]]
|
|
69
|
+
A list of rules, where each rule can be a Rule object, a dictionary with
|
|
70
|
+
'match' and 'result' keys, or a list with two elements (match and result).
|
|
71
|
+
"""
|
|
72
|
+
assert isinstance(rules, list), "rules must be a list"
|
|
73
|
+
|
|
74
|
+
self.rules: List[Rule] = []
|
|
75
|
+
|
|
76
|
+
for rule in rules:
|
|
77
|
+
if isinstance(rule, Rule):
|
|
78
|
+
self.rules.append(rule)
|
|
79
|
+
continue
|
|
80
|
+
|
|
81
|
+
if isinstance(rule, dict):
|
|
82
|
+
|
|
83
|
+
assert len(rule) == 2, "Rule dictionary must contain exactly two key-value pair."
|
|
84
|
+
|
|
85
|
+
match = rule.get("match")
|
|
86
|
+
if match is None:
|
|
87
|
+
raise ValueError("Rule dictionary must contain a 'match' key.")
|
|
88
|
+
|
|
89
|
+
result = rule.get("result")
|
|
90
|
+
if result is None:
|
|
91
|
+
raise ValueError("Rule dictionary must contain a 'result' key.")
|
|
92
|
+
|
|
93
|
+
self.rules.append(Rule(match, result))
|
|
94
|
+
continue
|
|
95
|
+
|
|
96
|
+
if isinstance(rule, list):
|
|
97
|
+
assert len(rule) == 2, "Rule list must contain exactly two elements."
|
|
98
|
+
match = rule[0]
|
|
99
|
+
result = rule[1]
|
|
100
|
+
self.rules.append(Rule(match, result))
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
raise ValueError(
|
|
104
|
+
"Rule must be either a Rule object, a dictionary with 'match' and 'result' keys, or a list with two elements."
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
@classmethod
|
|
108
|
+
def from_list(cls, rules: List[Any]) -> "RuleSet":
|
|
109
|
+
"""Create a RuleSet from a list of rules.
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
rules : List[Any]
|
|
114
|
+
A list of rules to initialize the RuleSet.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
RuleSet
|
|
119
|
+
A new RuleSet object.
|
|
120
|
+
"""
|
|
121
|
+
return cls(rules)
|
|
122
|
+
|
|
123
|
+
@classmethod
|
|
124
|
+
def from_files(cls, path: str) -> "RuleSet":
|
|
125
|
+
"""Create a RuleSet from a file.
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
path : str
|
|
130
|
+
The path to the file containing the rules. Supported formats are .json and .yaml/.yml.
|
|
131
|
+
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
RuleSet
|
|
135
|
+
A new RuleSet object.
|
|
136
|
+
|
|
137
|
+
Raises
|
|
138
|
+
------
|
|
139
|
+
ValueError
|
|
140
|
+
If the file format is unsupported.
|
|
141
|
+
"""
|
|
142
|
+
if path.endswith(".json"):
|
|
143
|
+
import json
|
|
144
|
+
|
|
145
|
+
with open(path, "r") as f:
|
|
146
|
+
return cls.from_list(json.load(f))
|
|
147
|
+
|
|
148
|
+
if path.endswith(".yaml") or path.endswith(".yml"):
|
|
149
|
+
import yaml
|
|
150
|
+
|
|
151
|
+
with open(path, "r") as f:
|
|
152
|
+
return cls.from_list(yaml.safe_load(f))
|
|
153
|
+
|
|
154
|
+
raise ValueError("Unsupported file format. Supported formats are .json and .yaml/.yml.")
|
|
155
|
+
|
|
156
|
+
@classmethod
|
|
157
|
+
def from_any(cls, rules: Union[str, List[Any]]) -> "RuleSet":
|
|
158
|
+
"""Create a RuleSet from a list or a file path.
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
rules : Union[str, List[Any]]
|
|
163
|
+
The rules to initialize the RuleSet, either as a list or a file path.
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
RuleSet
|
|
168
|
+
A new RuleSet object.
|
|
169
|
+
|
|
170
|
+
Raises
|
|
171
|
+
------
|
|
172
|
+
ValueError
|
|
173
|
+
If the rules format is unsupported.
|
|
174
|
+
"""
|
|
175
|
+
if isinstance(rules, str):
|
|
176
|
+
return cls.from_files(rules)
|
|
177
|
+
|
|
178
|
+
if isinstance(rules, list):
|
|
179
|
+
return cls.from_list(rules)
|
|
180
|
+
|
|
181
|
+
raise ValueError("Unsupported rules format. Must be a list or a file path.")
|
|
182
|
+
|
|
183
|
+
def match(self, obj: Mapping[str, Any], strategy: str = "first-match") -> Optional[Rule]:
|
|
184
|
+
"""Match an object against the rules in the RuleSet.
|
|
185
|
+
|
|
186
|
+
Parameters
|
|
187
|
+
----------
|
|
188
|
+
obj : Mapping[str, Any]
|
|
189
|
+
The object to match against the rules.
|
|
190
|
+
strategy : str, optional
|
|
191
|
+
The matching strategy to use. Currently, only 'first-match' is supported.
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
Optional[Rule]
|
|
196
|
+
The first matching rule, or None if no match is found.
|
|
197
|
+
|
|
198
|
+
Raises
|
|
199
|
+
------
|
|
200
|
+
AssertionError
|
|
201
|
+
If an unsupported strategy is provided.
|
|
202
|
+
"""
|
|
203
|
+
assert strategy == "first-match", "Only 'first-match' strategy is supported for now."
|
|
204
|
+
for rule in self.rules:
|
|
205
|
+
if rule.match(obj):
|
|
206
|
+
return rule
|
|
207
|
+
|
|
208
|
+
return None
|
|
209
|
+
|
|
210
|
+
def __iter__(self) -> iter:
|
|
211
|
+
"""Return an iterator over the rules in the RuleSet.
|
|
212
|
+
|
|
213
|
+
Returns
|
|
214
|
+
-------
|
|
215
|
+
iter
|
|
216
|
+
An iterator over the Rule objects in the RuleSet.
|
|
217
|
+
"""
|
|
218
|
+
return iter(self.rules)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anemoi-utils
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.18
|
|
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
|
|
@@ -38,6 +38,7 @@ docs/modules/grib.rst
|
|
|
38
38
|
docs/modules/humanize.rst
|
|
39
39
|
docs/modules/provenance.rst
|
|
40
40
|
docs/modules/s3.rst
|
|
41
|
+
docs/modules/testing.rst
|
|
41
42
|
docs/modules/text.rst
|
|
42
43
|
src/anemoi/utils/__init__.py
|
|
43
44
|
src/anemoi/utils/__main__.py
|
|
@@ -56,6 +57,7 @@ src/anemoi/utils/humanize.py
|
|
|
56
57
|
src/anemoi/utils/logs.py
|
|
57
58
|
src/anemoi/utils/provenance.py
|
|
58
59
|
src/anemoi/utils/registry.py
|
|
60
|
+
src/anemoi/utils/rules.py
|
|
59
61
|
src/anemoi/utils/s3.py
|
|
60
62
|
src/anemoi/utils/sanitise.py
|
|
61
63
|
src/anemoi/utils/sanitize.py
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anemoi_utils-0.4.16 → anemoi_utils-0.4.18}/.github/workflows/pr-label-conventional-commits.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|