anemoi-utils 0.4.31__tar.gz → 0.4.32__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.32/.release-please-manifest.json +3 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/CHANGELOG.md +7 -0
- {anemoi_utils-0.4.31/src/anemoi_utils.egg-info → anemoi_utils-0.4.32}/PKG-INFO +1 -1
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/pyproject.toml +3 -1
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/_version.py +3 -16
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/testing.py +54 -41
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32/src/anemoi_utils.egg-info}/PKG-INFO +1 -1
- anemoi_utils-0.4.31/.release-please-manifest.json +0 -3
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.gitattributes +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/CODEOWNERS +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/ci-hpc-config.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/dependabot.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/labeler.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/pull_request_template.md +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/workflows/downstream-ci-hpc.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/workflows/pr-conventional-commit.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/workflows/pr-label-conventional-commits.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/workflows/pr-label-file-based.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/workflows/pr-label-public.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/workflows/python-publish.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/workflows/python-pull-request.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/workflows/readthedocs-pr-update.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.github/workflows/release-please.yml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.gitignore +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.pre-commit-config.yaml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.readthedocs.yaml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/.release-please-config.json +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/CONTRIBUTORS.md +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/LICENSE +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/README.md +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/Makefile +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/_static/logo.png +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/_static/style.css +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/_templates/.gitkeep +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/_templates/apidoc/package.rst.jinja +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/conf.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/index.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/installing.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/modules/checkpoints.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/modules/config.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/modules/dates.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/modules/grib.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/modules/humanize.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/modules/provenance.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/modules/s3.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/modules/testing.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/modules/text.rst +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/docs/scripts/api_build.sh +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/setup.cfg +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/__init__.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/__main__.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/caching.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/checkpoints.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/cli.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/commands/__init__.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/commands/config.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/commands/metadata.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/commands/requests.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/commands/transfer.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/compatibility.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/config.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/dates.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/devtools.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/grib.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/grids.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/hindcasts.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/humanize.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/logs.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/mars/__init__.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/mars/mars.yaml +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/mars/requests.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/mlflow/__init__.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/mlflow/auth.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/mlflow/client.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/mlflow/utils.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/provenance.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/registry.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/remote/__init__.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/remote/s3.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/remote/ssh.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/rules.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/s3.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/sanitise.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/sanitize.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/schemas/__init__.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/schemas/errors.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/text.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi/utils/timer.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi_utils.egg-info/SOURCES.txt +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi_utils.egg-info/dependency_links.txt +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi_utils.egg-info/entry_points.txt +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi_utils.egg-info/requires.txt +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/src/anemoi_utils.egg-info/top_level.txt +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test-transfer-data/directory/b/c/x +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test-transfer-data/directory/b/y +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/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.31 → anemoi_utils-0.4.32}/tests/test-transfer-data/directory/z +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test-transfer-data/file +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test_caching.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test_compatibility.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test_dates.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test_frequency.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test_mlflow_auth.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test_mlflow_client.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test_provenance.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test_remote.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test_sanitise.py +0 -0
- {anemoi_utils-0.4.31 → anemoi_utils-0.4.32}/tests/test_utils.py +0 -0
|
@@ -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.32](https://github.com/ecmwf/anemoi-utils/compare/0.4.31...0.4.32) (2025-08-05)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* Improve types of testing ([#186](https://github.com/ecmwf/anemoi-utils/issues/186)) ([7bc7cbd](https://github.com/ecmwf/anemoi-utils/commit/7bc7cbdc1f3452e131b12067684f39dea067eed6))
|
|
17
|
+
|
|
11
18
|
## [0.4.31](https://github.com/ecmwf/anemoi-utils/compare/0.4.30...0.4.31) (2025-08-04)
|
|
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.32
|
|
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
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
3
|
|
|
4
|
-
__all__ = [
|
|
5
|
-
"__version__",
|
|
6
|
-
"__version_tuple__",
|
|
7
|
-
"version",
|
|
8
|
-
"version_tuple",
|
|
9
|
-
"__commit_id__",
|
|
10
|
-
"commit_id",
|
|
11
|
-
]
|
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
12
5
|
|
|
13
6
|
TYPE_CHECKING = False
|
|
14
7
|
if TYPE_CHECKING:
|
|
@@ -16,19 +9,13 @@ if TYPE_CHECKING:
|
|
|
16
9
|
from typing import Union
|
|
17
10
|
|
|
18
11
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
-
COMMIT_ID = Union[str, None]
|
|
20
12
|
else:
|
|
21
13
|
VERSION_TUPLE = object
|
|
22
|
-
COMMIT_ID = object
|
|
23
14
|
|
|
24
15
|
version: str
|
|
25
16
|
__version__: str
|
|
26
17
|
__version_tuple__: VERSION_TUPLE
|
|
27
18
|
version_tuple: VERSION_TUPLE
|
|
28
|
-
commit_id: COMMIT_ID
|
|
29
|
-
__commit_id__: COMMIT_ID
|
|
30
19
|
|
|
31
|
-
__version__ = version = '0.4.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 4,
|
|
33
|
-
|
|
34
|
-
__commit_id__ = commit_id = 'g2684cac7a'
|
|
20
|
+
__version__ = version = '0.4.32'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 4, 32)
|
|
@@ -11,6 +11,7 @@ import logging
|
|
|
11
11
|
import os
|
|
12
12
|
import shutil
|
|
13
13
|
import warnings
|
|
14
|
+
from collections.abc import Callable
|
|
14
15
|
from functools import lru_cache
|
|
15
16
|
from pathlib import Path
|
|
16
17
|
|
|
@@ -42,17 +43,21 @@ def _check_path(path: str) -> None:
|
|
|
42
43
|
assert not path.startswith("."), f"Path '{path}' should not start with '.'"
|
|
43
44
|
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
def
|
|
47
|
-
|
|
46
|
+
class TemporaryDirectoryForTestData:
|
|
47
|
+
def __init__(self, base_dir: Path) -> None:
|
|
48
|
+
self.base_dir = base_dir
|
|
48
49
|
|
|
49
|
-
def
|
|
50
|
+
def __call__(self, path: str = "", archive: bool = False) -> str:
|
|
50
51
|
if path == "":
|
|
51
|
-
return str(base_dir)
|
|
52
|
+
return str(self.base_dir)
|
|
52
53
|
_check_path(path)
|
|
53
|
-
return str(base_dir.joinpath(*Path(path).parts)) + (".extracted" if archive else "")
|
|
54
|
+
return str(self.base_dir.joinpath(*Path(path).parts)) + (".extracted" if archive else "")
|
|
55
|
+
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
@pytest.fixture(scope="session")
|
|
58
|
+
def temporary_directory_for_test_data(tmp_path_factory: pytest.TempPathFactory) -> TemporaryDirectoryForTestData:
|
|
59
|
+
base_dir = tmp_path_factory.mktemp("test_data_base")
|
|
60
|
+
return TemporaryDirectoryForTestData(base_dir)
|
|
56
61
|
|
|
57
62
|
|
|
58
63
|
def url_for_test_data(path: str) -> str:
|
|
@@ -73,11 +78,12 @@ def url_for_test_data(path: str) -> str:
|
|
|
73
78
|
return f"{TEST_DATA_URL}{path}"
|
|
74
79
|
|
|
75
80
|
|
|
76
|
-
|
|
77
|
-
def
|
|
78
|
-
|
|
79
|
-
"""Download the test data to a temporary directory and return the local path.
|
|
81
|
+
class GetTestData:
|
|
82
|
+
def __init__(self, temporary_directory_for_test_data: TemporaryDirectoryForTestData) -> None:
|
|
83
|
+
self.temporary_directory_for_test_data = temporary_directory_for_test_data
|
|
80
84
|
|
|
85
|
+
def __call__(self, path: str, gzipped: bool = False) -> str:
|
|
86
|
+
"""Download the test data to a temporary directory and return the local path.
|
|
81
87
|
Parameters
|
|
82
88
|
----------
|
|
83
89
|
path : str
|
|
@@ -94,7 +100,7 @@ def get_test_data(temporary_directory_for_test_data):
|
|
|
94
100
|
if _offline():
|
|
95
101
|
raise RuntimeError("Offline mode: cannot download test data, add @pytest.mark.skipif(not offline(),...)")
|
|
96
102
|
|
|
97
|
-
target = temporary_directory_for_test_data(path)
|
|
103
|
+
target = self.temporary_directory_for_test_data(path)
|
|
98
104
|
|
|
99
105
|
if os.path.exists(target):
|
|
100
106
|
return target
|
|
@@ -121,12 +127,20 @@ def get_test_data(temporary_directory_for_test_data):
|
|
|
121
127
|
|
|
122
128
|
return target
|
|
123
129
|
|
|
124
|
-
return _get_test_data
|
|
125
|
-
|
|
126
130
|
|
|
127
131
|
@pytest.fixture()
|
|
128
|
-
def
|
|
129
|
-
|
|
132
|
+
def get_test_data(temporary_directory_for_test_data: TemporaryDirectoryForTestData) -> GetTestData:
|
|
133
|
+
return GetTestData(temporary_directory_for_test_data)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class GetTestArchive:
|
|
137
|
+
def __init__(
|
|
138
|
+
self, temporary_directory_for_test_data: TemporaryDirectoryForTestData, get_test_data: GetTestData
|
|
139
|
+
) -> None:
|
|
140
|
+
self.temporary_directory_for_test_data = temporary_directory_for_test_data
|
|
141
|
+
self.get_test_data = get_test_data
|
|
142
|
+
|
|
143
|
+
def __call__(self, path: str) -> Path:
|
|
130
144
|
"""Download an archive file (.zip, .tar, .tar.gz, .tar.bz2, .tar.xz) to a temporary directory
|
|
131
145
|
unpack it, and return the local path to the directory containing the extracted files.
|
|
132
146
|
|
|
@@ -134,8 +148,6 @@ def get_test_archive(temporary_directory_for_test_data, get_test_data) -> callab
|
|
|
134
148
|
----------
|
|
135
149
|
path : str
|
|
136
150
|
The relative path to the test data.
|
|
137
|
-
extension : str, optional
|
|
138
|
-
The extension to add to the extracted directory, by default '.extracted'
|
|
139
151
|
|
|
140
152
|
Returns
|
|
141
153
|
-------
|
|
@@ -143,12 +155,12 @@ def get_test_archive(temporary_directory_for_test_data, get_test_data) -> callab
|
|
|
143
155
|
The local path to the downloaded test data.
|
|
144
156
|
"""
|
|
145
157
|
|
|
146
|
-
target = Path(temporary_directory_for_test_data(path, archive=True))
|
|
158
|
+
target = Path(self.temporary_directory_for_test_data(path, archive=True))
|
|
147
159
|
|
|
148
160
|
if os.path.exists(target):
|
|
149
161
|
return target
|
|
150
162
|
|
|
151
|
-
archive = get_test_data(path)
|
|
163
|
+
archive = self.get_test_data(path)
|
|
152
164
|
|
|
153
165
|
shutil.unpack_archive(archive, os.path.dirname(target) + ".tmp")
|
|
154
166
|
os.rename(os.path.dirname(target) + ".tmp", target)
|
|
@@ -157,7 +169,12 @@ def get_test_archive(temporary_directory_for_test_data, get_test_data) -> callab
|
|
|
157
169
|
|
|
158
170
|
return target
|
|
159
171
|
|
|
160
|
-
|
|
172
|
+
|
|
173
|
+
@pytest.fixture()
|
|
174
|
+
def get_test_archive(
|
|
175
|
+
temporary_directory_for_test_data: TemporaryDirectoryForTestData, get_test_data: GetTestData
|
|
176
|
+
) -> GetTestArchive:
|
|
177
|
+
return GetTestArchive(temporary_directory_for_test_data, get_test_data)
|
|
161
178
|
|
|
162
179
|
|
|
163
180
|
def packages_installed(*names: str) -> bool:
|
|
@@ -231,28 +248,27 @@ def _run_slow_tests() -> bool:
|
|
|
231
248
|
bool
|
|
232
249
|
True if the SLOW_TESTS environment variable is set, False otherwise.
|
|
233
250
|
"""
|
|
234
|
-
return int(os.environ.get("SLOW_TESTS", 0))
|
|
251
|
+
return bool(int(os.environ.get("SLOW_TESTS", 0)))
|
|
235
252
|
|
|
236
253
|
|
|
237
254
|
@lru_cache(maxsize=None)
|
|
238
255
|
def _offline() -> bool:
|
|
239
256
|
"""Check if we are offline."""
|
|
240
257
|
from urllib import request
|
|
258
|
+
from urllib.error import URLError
|
|
241
259
|
|
|
242
260
|
try:
|
|
243
261
|
request.urlopen("https://anemoi.ecmwf.int", timeout=1)
|
|
244
262
|
return False
|
|
245
|
-
except
|
|
263
|
+
except URLError:
|
|
246
264
|
return True
|
|
247
265
|
|
|
248
|
-
return False
|
|
249
|
-
|
|
250
266
|
|
|
251
267
|
skip_if_offline = pytest.mark.skipif(_offline(), reason="No internet connection")
|
|
252
268
|
skip_slow_tests = pytest.mark.skipif(not _run_slow_tests(), reason="Skipping slow tests")
|
|
253
269
|
|
|
254
270
|
|
|
255
|
-
def skip_missing_packages(*names: str) ->
|
|
271
|
+
def skip_missing_packages(*names: str) -> pytest.MarkDecorator:
|
|
256
272
|
"""Skip a test if any of the specified packages are missing.
|
|
257
273
|
|
|
258
274
|
Parameters
|
|
@@ -268,16 +284,17 @@ def skip_missing_packages(*names: str) -> callable:
|
|
|
268
284
|
|
|
269
285
|
missing = [f"'{p}'" for p in _missing_packages(*names)]
|
|
270
286
|
|
|
271
|
-
|
|
272
|
-
return lambda f: f
|
|
287
|
+
reason = ""
|
|
273
288
|
|
|
274
289
|
if len(missing) == 1:
|
|
275
|
-
|
|
290
|
+
reason = f"Package {missing[0]} is not installed"
|
|
291
|
+
elif len(missing):
|
|
292
|
+
reason = f"Packages {list_to_human(missing)} are not installed"
|
|
276
293
|
|
|
277
|
-
return pytest.mark.skipif(
|
|
294
|
+
return pytest.mark.skipif(len(missing) > 0, reason=reason)
|
|
278
295
|
|
|
279
296
|
|
|
280
|
-
def skip_if_missing_command(cmd: str) ->
|
|
297
|
+
def skip_if_missing_command(cmd: str) -> pytest.MarkDecorator:
|
|
281
298
|
"""Skip a test if the specified command is not available.
|
|
282
299
|
|
|
283
300
|
Parameters
|
|
@@ -293,13 +310,10 @@ def skip_if_missing_command(cmd: str) -> callable:
|
|
|
293
310
|
|
|
294
311
|
import shutil
|
|
295
312
|
|
|
296
|
-
|
|
297
|
-
return lambda f: f
|
|
313
|
+
return pytest.mark.skipif(not shutil.which(cmd), reason=f"Command '{cmd}' is not available")
|
|
298
314
|
|
|
299
|
-
return pytest.mark.skipif(True, reason=f"Command '{cmd}' is not available")
|
|
300
315
|
|
|
301
|
-
|
|
302
|
-
def cli_testing(package: str, cmd: str, *args: list[str]) -> None:
|
|
316
|
+
def cli_testing(package: str, cmd: str, *args: str) -> None:
|
|
303
317
|
"""Run a CLI command for testing purposes.
|
|
304
318
|
|
|
305
319
|
Parameters
|
|
@@ -309,7 +323,7 @@ def cli_testing(package: str, cmd: str, *args: list[str]) -> None:
|
|
|
309
323
|
Can be 'anemoi-datasets' or 'anemoi.datasets'.
|
|
310
324
|
cmd : str
|
|
311
325
|
The command to run.
|
|
312
|
-
*args :
|
|
326
|
+
*args : str
|
|
313
327
|
Additional arguments to pass to the command.
|
|
314
328
|
"""
|
|
315
329
|
|
|
@@ -323,16 +337,16 @@ def cli_testing(package: str, cmd: str, *args: list[str]) -> None:
|
|
|
323
337
|
version=version,
|
|
324
338
|
description=f"Testing the '{cmd}' CLI command from the '{package}' package.",
|
|
325
339
|
commands=COMMANDS,
|
|
326
|
-
test_arguments=
|
|
340
|
+
test_arguments=[cmd] + list(args),
|
|
327
341
|
)
|
|
328
342
|
|
|
329
343
|
|
|
330
|
-
def run_tests(globals: dict[str,
|
|
344
|
+
def run_tests(globals: dict[str, Callable[[], None]]) -> None:
|
|
331
345
|
"""Run all test functions that start with 'test_'.
|
|
332
346
|
|
|
333
347
|
Parameters
|
|
334
348
|
----------
|
|
335
|
-
globals : dict[str,
|
|
349
|
+
globals : dict[str, Callable[[], None]]
|
|
336
350
|
The global namespace containing the test functions.
|
|
337
351
|
|
|
338
352
|
Example
|
|
@@ -357,7 +371,6 @@ def run_tests(globals: dict[str, callable]) -> None:
|
|
|
357
371
|
|
|
358
372
|
for name, obj in list(globals.items()):
|
|
359
373
|
if name.startswith("test_") and callable(obj):
|
|
360
|
-
|
|
361
374
|
pytestmark = getattr(obj, "pytestmark", None)
|
|
362
375
|
if pytestmark is not None:
|
|
363
376
|
if not isinstance(pytestmark, list):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anemoi-utils
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.32
|
|
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
|
|
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.31 → anemoi_utils-0.4.32}/.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
|
|
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
|