anemoi-utils 0.4.21__py3-none-any.whl → 0.4.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of anemoi-utils might be problematic. Click here for more details.
- anemoi/utils/_version.py +2 -2
- anemoi/utils/provenance.py +5 -2
- anemoi/utils/remote/s3.py +42 -9
- anemoi/utils/testing.py +29 -7
- {anemoi_utils-0.4.21.dist-info → anemoi_utils-0.4.23.dist-info}/METADATA +2 -2
- {anemoi_utils-0.4.21.dist-info → anemoi_utils-0.4.23.dist-info}/RECORD +10 -10
- {anemoi_utils-0.4.21.dist-info → anemoi_utils-0.4.23.dist-info}/WHEEL +1 -1
- {anemoi_utils-0.4.21.dist-info → anemoi_utils-0.4.23.dist-info}/entry_points.txt +0 -0
- {anemoi_utils-0.4.21.dist-info → anemoi_utils-0.4.23.dist-info}/licenses/LICENSE +0 -0
- {anemoi_utils-0.4.21.dist-info → anemoi_utils-0.4.23.dist-info}/top_level.txt +0 -0
anemoi/utils/_version.py
CHANGED
anemoi/utils/provenance.py
CHANGED
|
@@ -47,8 +47,11 @@ def lookup_git_repo(path: str) -> Optional[Any]:
|
|
|
47
47
|
Repo, optional
|
|
48
48
|
The git repository if found, otherwise None.
|
|
49
49
|
"""
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
try:
|
|
51
|
+
from git import InvalidGitRepositoryError
|
|
52
|
+
from git import Repo
|
|
53
|
+
except ImportError:
|
|
54
|
+
return None
|
|
52
55
|
|
|
53
56
|
while path != "/":
|
|
54
57
|
try:
|
anemoi/utils/remote/s3.py
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
# (C) Copyright 2024
|
|
1
|
+
# (C) Copyright 2024-2025 Anemoi contributors.
|
|
2
|
+
#
|
|
2
3
|
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
3
4
|
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
5
|
+
#
|
|
4
6
|
# In applying this licence, ECMWF does not waive the privileges and immunities
|
|
5
7
|
# granted to it by virtue of its status as an intergovernmental organisation
|
|
6
8
|
# nor does it submit to any jurisdiction.
|
|
7
9
|
|
|
10
|
+
|
|
8
11
|
"""This module provides functions to upload, download, list and delete files and folders on S3.
|
|
9
12
|
The functions of this package expect that the AWS credentials are set up in the environment
|
|
10
13
|
typicaly by setting the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables or
|
|
@@ -67,12 +70,14 @@ def s3_client(bucket: str, region: str = None) -> Any:
|
|
|
67
70
|
|
|
68
71
|
key = f"{bucket}-{region}"
|
|
69
72
|
|
|
70
|
-
boto3_config = dict(max_pool_connections=25)
|
|
71
|
-
|
|
72
73
|
if key in thread_local.s3_clients:
|
|
73
74
|
return thread_local.s3_clients[key]
|
|
74
75
|
|
|
75
|
-
boto3_config = dict(
|
|
76
|
+
boto3_config = dict(
|
|
77
|
+
max_pool_connections=25,
|
|
78
|
+
request_checksum_calculation="when_required",
|
|
79
|
+
response_checksum_validation="when_required",
|
|
80
|
+
)
|
|
76
81
|
|
|
77
82
|
if region:
|
|
78
83
|
# This is using AWS
|
|
@@ -162,7 +167,14 @@ class S3Upload(BaseUpload):
|
|
|
162
167
|
# delete(target)
|
|
163
168
|
|
|
164
169
|
def _transfer_file(
|
|
165
|
-
self,
|
|
170
|
+
self,
|
|
171
|
+
source: str,
|
|
172
|
+
target: str,
|
|
173
|
+
overwrite: bool,
|
|
174
|
+
resume: bool,
|
|
175
|
+
verbosity: int,
|
|
176
|
+
threads: int,
|
|
177
|
+
config: dict = None,
|
|
166
178
|
) -> int:
|
|
167
179
|
"""Transfer a file to S3.
|
|
168
180
|
|
|
@@ -227,7 +239,13 @@ class S3Upload(BaseUpload):
|
|
|
227
239
|
|
|
228
240
|
if verbosity > 0:
|
|
229
241
|
with tqdm.tqdm(total=size, unit="B", unit_scale=True, unit_divisor=1024, leave=False) as pbar:
|
|
230
|
-
s3.upload_file(
|
|
242
|
+
s3.upload_file(
|
|
243
|
+
source,
|
|
244
|
+
bucket,
|
|
245
|
+
key,
|
|
246
|
+
Callback=lambda x: pbar.update(x),
|
|
247
|
+
Config=config,
|
|
248
|
+
)
|
|
231
249
|
else:
|
|
232
250
|
s3.upload_file(source, bucket, key, Config=config)
|
|
233
251
|
|
|
@@ -326,7 +344,14 @@ class S3Download(BaseDownload):
|
|
|
326
344
|
return s3_object["Size"]
|
|
327
345
|
|
|
328
346
|
def _transfer_file(
|
|
329
|
-
self,
|
|
347
|
+
self,
|
|
348
|
+
source: str,
|
|
349
|
+
target: str,
|
|
350
|
+
overwrite: bool,
|
|
351
|
+
resume: bool,
|
|
352
|
+
verbosity: int,
|
|
353
|
+
threads: int,
|
|
354
|
+
config: dict = None,
|
|
330
355
|
) -> int:
|
|
331
356
|
"""Transfer a file from S3 to the local filesystem.
|
|
332
357
|
|
|
@@ -397,7 +422,13 @@ class S3Download(BaseDownload):
|
|
|
397
422
|
|
|
398
423
|
if verbosity > 0:
|
|
399
424
|
with tqdm.tqdm(total=size, unit="B", unit_scale=True, unit_divisor=1024, leave=False) as pbar:
|
|
400
|
-
s3.download_file(
|
|
425
|
+
s3.download_file(
|
|
426
|
+
bucket,
|
|
427
|
+
key,
|
|
428
|
+
target,
|
|
429
|
+
Callback=lambda x: pbar.update(x),
|
|
430
|
+
Config=config,
|
|
431
|
+
)
|
|
401
432
|
else:
|
|
402
433
|
s3.download_file(bucket, key, target, Config=config)
|
|
403
434
|
|
|
@@ -524,7 +555,9 @@ def list_folder(folder: str) -> Iterable:
|
|
|
524
555
|
|
|
525
556
|
for page in paginator.paginate(Bucket=bucket, Prefix=prefix, Delimiter="/"):
|
|
526
557
|
if "CommonPrefixes" in page:
|
|
527
|
-
yield from [folder + _["Prefix"] for _ in page.get("CommonPrefixes")]
|
|
558
|
+
yield from [folder + _["Prefix"] for _ in page.get("CommonPrefixes") if _["Prefix"] != "/"]
|
|
559
|
+
if "Contents" in page:
|
|
560
|
+
yield from [folder + _["Key"] for _ in page.get("Contents")]
|
|
528
561
|
|
|
529
562
|
|
|
530
563
|
def object_info(target: str) -> dict:
|
anemoi/utils/testing.py
CHANGED
|
@@ -68,6 +68,23 @@ def _check_path(path: str) -> None:
|
|
|
68
68
|
assert not path.startswith("."), f"Path '{path}' should not start with '.'"
|
|
69
69
|
|
|
70
70
|
|
|
71
|
+
def _temporary_directory_for_test_data(path: str) -> str:
|
|
72
|
+
"""Get the temporary directory for a test dataset.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
path : str
|
|
77
|
+
The relative path to the test data in the object store.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
str
|
|
82
|
+
The path to the temporary directory.
|
|
83
|
+
"""
|
|
84
|
+
_check_path(path)
|
|
85
|
+
return os.path.normpath(os.path.join(_temporary_directory(), path))
|
|
86
|
+
|
|
87
|
+
|
|
71
88
|
def url_for_test_data(path: str) -> str:
|
|
72
89
|
"""Generate the URL for the test data based on the given path.
|
|
73
90
|
|
|
@@ -101,12 +118,11 @@ def get_test_data(path: str, gzipped=False) -> str:
|
|
|
101
118
|
str
|
|
102
119
|
The local path to the downloaded test data.
|
|
103
120
|
"""
|
|
104
|
-
_check_path(path)
|
|
105
121
|
|
|
106
122
|
if _offline():
|
|
107
123
|
raise RuntimeError("Offline mode: cannot download test data, add @pytest.mark.skipif(not offline(),...)")
|
|
108
124
|
|
|
109
|
-
target =
|
|
125
|
+
target = _temporary_directory_for_test_data(path)
|
|
110
126
|
with lock:
|
|
111
127
|
if os.path.exists(target):
|
|
112
128
|
return target
|
|
@@ -153,12 +169,18 @@ def get_test_archive(path: str, extension=".extracted") -> str:
|
|
|
153
169
|
|
|
154
170
|
with lock:
|
|
155
171
|
|
|
172
|
+
target = _temporary_directory_for_test_data(path) + extension
|
|
173
|
+
|
|
174
|
+
if os.path.exists(target):
|
|
175
|
+
return target
|
|
176
|
+
|
|
156
177
|
archive = get_test_data(path)
|
|
157
|
-
target = archive + extension
|
|
158
178
|
|
|
159
179
|
shutil.unpack_archive(archive, os.path.dirname(target) + ".tmp")
|
|
160
180
|
os.rename(os.path.dirname(target) + ".tmp", target)
|
|
161
181
|
|
|
182
|
+
os.remove(archive)
|
|
183
|
+
|
|
162
184
|
return target
|
|
163
185
|
|
|
164
186
|
|
|
@@ -239,12 +261,12 @@ def _run_slow_tests() -> bool:
|
|
|
239
261
|
@lru_cache(maxsize=None)
|
|
240
262
|
def _offline() -> bool:
|
|
241
263
|
"""Check if we are offline."""
|
|
242
|
-
|
|
243
|
-
import socket
|
|
264
|
+
from urllib import request
|
|
244
265
|
|
|
245
266
|
try:
|
|
246
|
-
|
|
247
|
-
|
|
267
|
+
request.urlopen("https://anemoi.ecmwf.int", timeout=1)
|
|
268
|
+
return False
|
|
269
|
+
except request.URLError:
|
|
248
270
|
return True
|
|
249
271
|
|
|
250
272
|
return False
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anemoi-utils
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.23
|
|
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
|
|
@@ -252,7 +252,7 @@ Provides-Extra: provenance
|
|
|
252
252
|
Requires-Dist: gitpython; extra == "provenance"
|
|
253
253
|
Requires-Dist: nvsmi; extra == "provenance"
|
|
254
254
|
Provides-Extra: s3
|
|
255
|
-
Requires-Dist: boto3
|
|
255
|
+
Requires-Dist: boto3>1.36; extra == "s3"
|
|
256
256
|
Provides-Extra: tests
|
|
257
257
|
Requires-Dist: pytest; extra == "tests"
|
|
258
258
|
Provides-Extra: text
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
anemoi/utils/__init__.py,sha256=uVhpF-VjIl_4mMywOVtgTutgsdIsqz-xdkwxeMhzuag,730
|
|
2
2
|
anemoi/utils/__main__.py,sha256=6LlE4MYrPvqqrykxXh7XMi50UZteUY59NeM8P9Zs2dU,910
|
|
3
|
-
anemoi/utils/_version.py,sha256=
|
|
3
|
+
anemoi/utils/_version.py,sha256=AnB7uXIf9bJtYv1LZYemC9XOrzt9AeZnOcUDxAsfacA,513
|
|
4
4
|
anemoi/utils/caching.py,sha256=rXbeAmpBcMbbfN4EVblaHWKicsrtx1otER84FEBtz98,6183
|
|
5
5
|
anemoi/utils/checkpoints.py,sha256=N4WpAZXa4etrpSEKhHqUUtG2-x9w3FJMHcLO-dDAXPY,9600
|
|
6
6
|
anemoi/utils/cli.py,sha256=IyZfnSw0u0yYnrjOrzvm2RuuKvDk4cVb8pf8BkaChgA,6209
|
|
@@ -13,13 +13,13 @@ anemoi/utils/grids.py,sha256=uYgkU_KIg8FTUiuKV0Pho2swMMeXcSQ9CQe0MFlRr_I,5262
|
|
|
13
13
|
anemoi/utils/hindcasts.py,sha256=iYVIxSNFL2HJcc_k1abCFLkpJFGHT8WKRIR4wcAwA3s,2144
|
|
14
14
|
anemoi/utils/humanize.py,sha256=pjnFJAKHbEAOfcvn8c48kt-8eFy6FGW_U2ruJvfamrA,25189
|
|
15
15
|
anemoi/utils/logs.py,sha256=naTgrmPwWHD4eekFttXftS4gtcAGYHpCqG4iwYprNDA,1804
|
|
16
|
-
anemoi/utils/provenance.py,sha256=
|
|
16
|
+
anemoi/utils/provenance.py,sha256=iTsn4r-VPq2D8tSHPSuAIqG077_opkqMT42G03DRWJg,14690
|
|
17
17
|
anemoi/utils/registry.py,sha256=e3nOIRyMYQ-mpEvaHAv5tuvMYNbkJ5yz94ns7BnvkjM,9717
|
|
18
18
|
anemoi/utils/rules.py,sha256=VspUoPmw7tijrs6l_wl4vDjr_zVQsFjx9ITiBSvxgc8,6972
|
|
19
19
|
anemoi/utils/s3.py,sha256=xMT48kbcelcjjqsaU567WI3oZ5eqo88Rlgyx5ECszAU,4074
|
|
20
20
|
anemoi/utils/sanitise.py,sha256=ZYGdSX6qihQANr3pHZjbKnoapnzP1KcrWdW1Ul1mOGk,3668
|
|
21
21
|
anemoi/utils/sanitize.py,sha256=43ZKDcfVpeXSsJ9TFEc9aZnD6oe2cUh151XnDspM98M,462
|
|
22
|
-
anemoi/utils/testing.py,sha256=
|
|
22
|
+
anemoi/utils/testing.py,sha256=kwgAgLh3exYOTZSaX4xcPFjiMOyQDz-vcAlPcJqMiZk,7784
|
|
23
23
|
anemoi/utils/text.py,sha256=HkzIvi24obDceFLpJEwBJ9PmPrJUkQN2TrElJ-A87gU,14441
|
|
24
24
|
anemoi/utils/timer.py,sha256=_leKMYza2faM7JKlGE7LCNy13rbdPnwaCF7PSrI_NmI,3895
|
|
25
25
|
anemoi/utils/commands/__init__.py,sha256=5u_6EwdqYczIAgJfCwRSyQAYFEqh2ZuHHT57g9g7sdI,808
|
|
@@ -29,13 +29,13 @@ anemoi/utils/mars/__init__.py,sha256=b-Lc3L1TAQd9ODs0Z1YSJzgZCO1K_M3DSgx_yd2qXvM
|
|
|
29
29
|
anemoi/utils/mars/mars.yaml,sha256=R0dujp75lLA4wCWhPeOQnzJ45WZAYLT8gpx509cBFlc,66
|
|
30
30
|
anemoi/utils/mars/requests.py,sha256=VFMHBVAAl0_2lOcMBa1lvaKHctN0lDJsI6_U4BucGew,1142
|
|
31
31
|
anemoi/utils/remote/__init__.py,sha256=swPWHQoh-B6Xq9R489tPw0FykMue7f-bJ8enneFYSYE,20776
|
|
32
|
-
anemoi/utils/remote/s3.py,sha256=
|
|
32
|
+
anemoi/utils/remote/s3.py,sha256=dcXcgNddlgxwJ_OpgqOff8EWk-LT2mz20m7FcHHqz7w,17869
|
|
33
33
|
anemoi/utils/remote/ssh.py,sha256=xNtsawh8okytCKRehkRCVExbHZj-CRUQNormEHglfuw,8088
|
|
34
34
|
anemoi/utils/schemas/__init__.py,sha256=nkinKlsPLPXEjfTYQT1mpKC4cvs-14w_zBkDRxakwxw,698
|
|
35
35
|
anemoi/utils/schemas/errors.py,sha256=lgOXzVTYzAE0qWQf3OZ42vCWixv8lilSqLLhzARBmvI,1831
|
|
36
|
-
anemoi_utils-0.4.
|
|
37
|
-
anemoi_utils-0.4.
|
|
38
|
-
anemoi_utils-0.4.
|
|
39
|
-
anemoi_utils-0.4.
|
|
40
|
-
anemoi_utils-0.4.
|
|
41
|
-
anemoi_utils-0.4.
|
|
36
|
+
anemoi_utils-0.4.23.dist-info/licenses/LICENSE,sha256=8HznKF1Vi2IvfLsKNE5A2iVyiri3pRjRPvPC9kxs6qk,11354
|
|
37
|
+
anemoi_utils-0.4.23.dist-info/METADATA,sha256=jxTYBIvx6wzO0g8ftu2MoSPfeViRSTUrE38Zy3HUvlw,15439
|
|
38
|
+
anemoi_utils-0.4.23.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
|
39
|
+
anemoi_utils-0.4.23.dist-info/entry_points.txt,sha256=LENOkn88xzFQo-V59AKoA_F_cfYQTJYtrNTtf37YgHY,60
|
|
40
|
+
anemoi_utils-0.4.23.dist-info/top_level.txt,sha256=DYn8VPs-fNwr7fNH9XIBqeXIwiYYd2E2k5-dUFFqUz0,7
|
|
41
|
+
anemoi_utils-0.4.23.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|