anemoi-utils 0.3.7__py3-none-any.whl → 0.3.9__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/cli.py +11 -2
- anemoi/utils/commands/config.py +2 -2
- anemoi/utils/config.py +120 -27
- anemoi/utils/dates.py +2 -31
- anemoi/utils/hindcasts.py +40 -0
- anemoi/utils/humanize.py +60 -2
- anemoi/utils/s3.py +12 -7
- {anemoi_utils-0.3.7.dist-info → anemoi_utils-0.3.9.dist-info}/METADATA +1 -1
- anemoi_utils-0.3.9.dist-info/RECORD +25 -0
- {anemoi_utils-0.3.7.dist-info → anemoi_utils-0.3.9.dist-info}/WHEEL +1 -1
- anemoi_utils-0.3.7.dist-info/RECORD +0 -24
- {anemoi_utils-0.3.7.dist-info → anemoi_utils-0.3.9.dist-info}/LICENSE +0 -0
- {anemoi_utils-0.3.7.dist-info → anemoi_utils-0.3.9.dist-info}/entry_points.txt +0 -0
- {anemoi_utils-0.3.7.dist-info → anemoi_utils-0.3.9.dist-info}/top_level.txt +0 -0
anemoi/utils/_version.py
CHANGED
anemoi/utils/cli.py
CHANGED
|
@@ -16,6 +16,8 @@ LOG = logging.getLogger(__name__)
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class Command:
|
|
19
|
+
accept_unknown_args = False
|
|
20
|
+
|
|
19
21
|
def run(self, args):
|
|
20
22
|
raise NotImplementedError(f"Command not implemented: {args.command}")
|
|
21
23
|
|
|
@@ -97,7 +99,7 @@ def register_commands(here, package, select, fail=None):
|
|
|
97
99
|
|
|
98
100
|
def cli_main(version, description, commands):
|
|
99
101
|
parser = make_parser(description, commands)
|
|
100
|
-
args = parser.
|
|
102
|
+
args, unknown = parser.parse_known_args()
|
|
101
103
|
|
|
102
104
|
if args.version:
|
|
103
105
|
print(version)
|
|
@@ -115,8 +117,15 @@ def cli_main(version, description, commands):
|
|
|
115
117
|
level=logging.DEBUG if args.debug else logging.INFO,
|
|
116
118
|
)
|
|
117
119
|
|
|
120
|
+
if unknown and not cmd.accept_unknown_args:
|
|
121
|
+
# This should trigger an error
|
|
122
|
+
parser.parse_args()
|
|
123
|
+
|
|
118
124
|
try:
|
|
119
|
-
|
|
125
|
+
if unknown:
|
|
126
|
+
cmd.run(args, unknown)
|
|
127
|
+
else:
|
|
128
|
+
cmd.run(args)
|
|
120
129
|
except ValueError as e:
|
|
121
130
|
traceback.print_exc()
|
|
122
131
|
LOG.error("\n💣 %s", str(e).lstrip())
|
anemoi/utils/commands/config.py
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import json
|
|
13
13
|
|
|
14
|
-
from ..config import
|
|
14
|
+
from ..config import _config_path
|
|
15
15
|
from ..config import load_config
|
|
16
16
|
from . import Command
|
|
17
17
|
|
|
@@ -23,7 +23,7 @@ class Config(Command):
|
|
|
23
23
|
|
|
24
24
|
def run(self, args):
|
|
25
25
|
if args.path:
|
|
26
|
-
print(
|
|
26
|
+
print(_config_path())
|
|
27
27
|
else:
|
|
28
28
|
print(json.dumps(load_config(), indent=4))
|
|
29
29
|
|
anemoi/utils/config.py
CHANGED
|
@@ -104,12 +104,54 @@ class DotDict(dict):
|
|
|
104
104
|
|
|
105
105
|
CONFIG = {}
|
|
106
106
|
CHECKED = {}
|
|
107
|
-
CONFIG_LOCK = threading.
|
|
107
|
+
CONFIG_LOCK = threading.RLock()
|
|
108
108
|
QUIET = False
|
|
109
109
|
|
|
110
110
|
|
|
111
|
-
def
|
|
111
|
+
def _find(config, what, result=None):
|
|
112
|
+
if result is None:
|
|
113
|
+
result = []
|
|
114
|
+
|
|
115
|
+
if isinstance(config, list):
|
|
116
|
+
for i in config:
|
|
117
|
+
_find(i, what, result)
|
|
118
|
+
return result
|
|
119
|
+
|
|
120
|
+
if isinstance(config, dict):
|
|
121
|
+
if what in config:
|
|
122
|
+
result.append(config[what])
|
|
123
|
+
|
|
124
|
+
for k, v in config.items():
|
|
125
|
+
_find(v, what, result)
|
|
126
|
+
|
|
127
|
+
return result
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _merge_dicts(a, b):
|
|
131
|
+
for k, v in b.items():
|
|
132
|
+
if k in a and isinstance(a[k], dict) and isinstance(v, dict):
|
|
133
|
+
_merge_dicts(a[k], v)
|
|
134
|
+
else:
|
|
135
|
+
a[k] = v
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _set_defaults(a, b):
|
|
139
|
+
for k, v in b.items():
|
|
140
|
+
if k in a and isinstance(a[k], dict) and isinstance(v, dict):
|
|
141
|
+
_set_defaults(a[k], v)
|
|
142
|
+
else:
|
|
143
|
+
a.setdefault(k, v)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _config_path(name="settings.toml"):
|
|
112
147
|
global QUIET
|
|
148
|
+
|
|
149
|
+
if name.startswith("/") or name.startswith("."):
|
|
150
|
+
return name
|
|
151
|
+
|
|
152
|
+
if name.startswith("~"):
|
|
153
|
+
return os.path.expanduser(name)
|
|
154
|
+
|
|
113
155
|
full = os.path.join(os.path.expanduser("~"), ".config", "anemoi", name)
|
|
114
156
|
os.makedirs(os.path.dirname(full), exist_ok=True)
|
|
115
157
|
|
|
@@ -133,46 +175,77 @@ def config_path(name="settings.toml"):
|
|
|
133
175
|
return full
|
|
134
176
|
|
|
135
177
|
|
|
136
|
-
def
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
178
|
+
def load_any_dict_format(path):
|
|
179
|
+
"""Load a configuration file in any supported format: JSON, YAML and TOML.
|
|
180
|
+
|
|
181
|
+
Returns
|
|
182
|
+
-------
|
|
183
|
+
dict
|
|
184
|
+
The decoded configuration file.
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
if path.endswith(".json"):
|
|
189
|
+
with open(path, "rb") as f:
|
|
190
|
+
return json.load(f)
|
|
140
191
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
192
|
+
if path.endswith(".yaml") or path.endswith(".yml"):
|
|
193
|
+
with open(path, "rb") as f:
|
|
194
|
+
return yaml.safe_load(f)
|
|
144
195
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
196
|
+
if path.endswith(".toml"):
|
|
197
|
+
with open(path, "rb") as f:
|
|
198
|
+
return tomllib.load(f)
|
|
199
|
+
except (json.JSONDecodeError, yaml.YAMLError, tomllib.TOMLDecodeError) as e:
|
|
200
|
+
LOG.warning(f"Failed to parse config file {path}", exc_info=e)
|
|
201
|
+
return ValueError(f"Failed to parse config file {path} [{e}]")
|
|
148
202
|
|
|
149
203
|
return open(path).read()
|
|
150
204
|
|
|
151
205
|
|
|
152
|
-
def _load_config(name="settings.toml"):
|
|
206
|
+
def _load_config(name="settings.toml", secrets=None, defaults=None):
|
|
153
207
|
|
|
154
208
|
if name in CONFIG:
|
|
155
209
|
return CONFIG[name]
|
|
156
210
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
config = _load(conf)
|
|
211
|
+
path = _config_path(name)
|
|
212
|
+
if os.path.exists(path):
|
|
213
|
+
config = load_any_dict_format(path)
|
|
161
214
|
else:
|
|
162
215
|
config = {}
|
|
163
216
|
|
|
164
|
-
if
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
217
|
+
if defaults is not None:
|
|
218
|
+
if isinstance(defaults, str):
|
|
219
|
+
defaults = load_raw_config(defaults)
|
|
220
|
+
_set_defaults(config, defaults)
|
|
221
|
+
|
|
222
|
+
if secrets is not None:
|
|
223
|
+
if isinstance(secrets, str):
|
|
224
|
+
secrets = [secrets]
|
|
225
|
+
|
|
226
|
+
base, ext = os.path.splitext(path)
|
|
227
|
+
secret_name = base + ".secrets" + ext
|
|
228
|
+
|
|
229
|
+
found = set()
|
|
230
|
+
for secret in secrets:
|
|
231
|
+
if _find(config, secret):
|
|
232
|
+
found.add(secret)
|
|
233
|
+
|
|
234
|
+
if found:
|
|
235
|
+
check_config_mode(name, secret_name, found)
|
|
236
|
+
|
|
237
|
+
check_config_mode(secret_name, None)
|
|
238
|
+
secret_config = _load_config(secret_name)
|
|
239
|
+
_merge_dicts(config, secret_config)
|
|
168
240
|
|
|
241
|
+
CONFIG[name] = DotDict(config)
|
|
169
242
|
return CONFIG[name]
|
|
170
243
|
|
|
171
244
|
|
|
172
245
|
def _save_config(name, data):
|
|
173
246
|
CONFIG.pop(name, None)
|
|
174
247
|
|
|
175
|
-
conf =
|
|
248
|
+
conf = _config_path(name)
|
|
176
249
|
|
|
177
250
|
if conf.endswith(".json"):
|
|
178
251
|
with open(conf, "w") as f:
|
|
@@ -207,7 +280,7 @@ def save_config(name, data):
|
|
|
207
280
|
_save_config(name, data)
|
|
208
281
|
|
|
209
282
|
|
|
210
|
-
def load_config(name="settings.toml"):
|
|
283
|
+
def load_config(name="settings.toml", secrets=None, defaults=None):
|
|
211
284
|
"""Read a configuration file.
|
|
212
285
|
|
|
213
286
|
Parameters
|
|
@@ -220,11 +293,21 @@ def load_config(name="settings.toml"):
|
|
|
220
293
|
DotDict or str
|
|
221
294
|
Return DotDict if it is a dictionary, otherwise the raw data
|
|
222
295
|
"""
|
|
296
|
+
|
|
223
297
|
with CONFIG_LOCK:
|
|
224
|
-
return _load_config(name)
|
|
298
|
+
return _load_config(name, secrets, defaults)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def load_raw_config(name, default=None):
|
|
302
|
+
|
|
303
|
+
path = _config_path(name)
|
|
304
|
+
if os.path.exists(path):
|
|
305
|
+
return load_any_dict_format(path)
|
|
306
|
+
|
|
307
|
+
return default
|
|
225
308
|
|
|
226
309
|
|
|
227
|
-
def check_config_mode(name="settings.toml"):
|
|
310
|
+
def check_config_mode(name="settings.toml", secrets_name=None, secrets=None):
|
|
228
311
|
"""Check that a configuration file is secure.
|
|
229
312
|
|
|
230
313
|
Parameters
|
|
@@ -240,8 +323,18 @@ def check_config_mode(name="settings.toml"):
|
|
|
240
323
|
with CONFIG_LOCK:
|
|
241
324
|
if name in CHECKED:
|
|
242
325
|
return
|
|
243
|
-
|
|
326
|
+
|
|
327
|
+
conf = _config_path(name)
|
|
328
|
+
if not os.path.exists(conf):
|
|
329
|
+
return
|
|
244
330
|
mode = os.stat(conf).st_mode
|
|
245
331
|
if mode & 0o777 != 0o600:
|
|
246
|
-
|
|
332
|
+
if secrets_name:
|
|
333
|
+
secret_path = _config_path(secrets_name)
|
|
334
|
+
raise SystemError(
|
|
335
|
+
f"Configuration file {conf} should not hold entries {secrets}.\n"
|
|
336
|
+
f"Please move them to {secret_path}."
|
|
337
|
+
)
|
|
338
|
+
raise SystemError(f"Configuration file {conf} is not secure.\n" f"Please run `chmod 600 {conf}`.")
|
|
339
|
+
|
|
247
340
|
CHECKED[name] = True
|
anemoi/utils/dates.py
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
import calendar
|
|
10
10
|
import datetime
|
|
11
11
|
|
|
12
|
+
from .hindcasts import HindcastDatesTimes
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
def normalise_frequency(frequency):
|
|
14
16
|
if isinstance(frequency, int):
|
|
@@ -158,37 +160,6 @@ class DateTimes:
|
|
|
158
160
|
date += self.increment
|
|
159
161
|
|
|
160
162
|
|
|
161
|
-
class HindcastDatesTimes:
|
|
162
|
-
"""The HindcastDatesTimes class is an iterator that generates datetime objects within a given range."""
|
|
163
|
-
|
|
164
|
-
def __init__(self, reference_dates, years=20):
|
|
165
|
-
"""_summary_
|
|
166
|
-
|
|
167
|
-
Parameters
|
|
168
|
-
----------
|
|
169
|
-
reference_dates : _type_
|
|
170
|
-
_description_
|
|
171
|
-
years : int, optional
|
|
172
|
-
_description_, by default 20
|
|
173
|
-
"""
|
|
174
|
-
|
|
175
|
-
self.reference_dates = reference_dates
|
|
176
|
-
|
|
177
|
-
if isinstance(years, list):
|
|
178
|
-
self.years = years
|
|
179
|
-
else:
|
|
180
|
-
self.years = range(1, years + 1)
|
|
181
|
-
|
|
182
|
-
def __iter__(self):
|
|
183
|
-
for reference_date in self.reference_dates:
|
|
184
|
-
for year in self.years:
|
|
185
|
-
if reference_date.month == 2 and reference_date.day == 29:
|
|
186
|
-
date = datetime.datetime(reference_date.year - year, 2, 28)
|
|
187
|
-
else:
|
|
188
|
-
date = datetime.datetime(reference_date.year - year, reference_date.month, reference_date.day)
|
|
189
|
-
yield (date, reference_date)
|
|
190
|
-
|
|
191
|
-
|
|
192
163
|
class Year(DateTimes):
|
|
193
164
|
"""Year is defined as the months of January to December."""
|
|
194
165
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# (C) Copyright 2024 European Centre for Medium-Range Weather Forecasts.
|
|
2
|
+
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
3
|
+
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
4
|
+
# In applying this licence, ECMWF does not waive the privileges and immunities
|
|
5
|
+
# granted to it by virtue of its status as an intergovernmental organisation
|
|
6
|
+
# nor does it submit to any jurisdiction.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
import datetime
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class HindcastDatesTimes:
|
|
13
|
+
"""The HindcastDatesTimes class is an iterator that generates datetime objects within a given range."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, reference_dates, years=20):
|
|
16
|
+
"""_summary_
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
reference_dates : _type_
|
|
21
|
+
_description_
|
|
22
|
+
years : int, optional
|
|
23
|
+
_description_, by default 20
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
self.reference_dates = reference_dates
|
|
27
|
+
|
|
28
|
+
if isinstance(years, list):
|
|
29
|
+
self.years = years
|
|
30
|
+
else:
|
|
31
|
+
self.years = range(1, years + 1)
|
|
32
|
+
|
|
33
|
+
def __iter__(self):
|
|
34
|
+
for reference_date in self.reference_dates:
|
|
35
|
+
for year in self.years:
|
|
36
|
+
if reference_date.month == 2 and reference_date.day == 29:
|
|
37
|
+
date = datetime.datetime(reference_date.year - year, 2, 28)
|
|
38
|
+
else:
|
|
39
|
+
date = datetime.datetime(reference_date.year - year, reference_date.month, reference_date.day)
|
|
40
|
+
yield (date, reference_date)
|
anemoi/utils/humanize.py
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"""Generate human readable strings"""
|
|
11
11
|
|
|
12
12
|
import datetime
|
|
13
|
+
import json
|
|
13
14
|
import re
|
|
14
15
|
from collections import defaultdict
|
|
15
16
|
|
|
@@ -189,7 +190,7 @@ def __(n):
|
|
|
189
190
|
return "th"
|
|
190
191
|
|
|
191
192
|
|
|
192
|
-
def when(then, now=None, short=True):
|
|
193
|
+
def when(then, now=None, short=True, use_utc=False):
|
|
193
194
|
"""Generate a human readable string for a date, relative to now
|
|
194
195
|
|
|
195
196
|
>>> when(datetime.datetime.now() - datetime.timedelta(hours=2))
|
|
@@ -225,7 +226,10 @@ def when(then, now=None, short=True):
|
|
|
225
226
|
last = "last"
|
|
226
227
|
|
|
227
228
|
if now is None:
|
|
228
|
-
|
|
229
|
+
if use_utc:
|
|
230
|
+
now = datetime.datetime.utcnow()
|
|
231
|
+
else:
|
|
232
|
+
now = datetime.datetime.now()
|
|
229
233
|
|
|
230
234
|
diff = (now - then).total_seconds()
|
|
231
235
|
|
|
@@ -472,3 +476,57 @@ def rounded_datetime(d):
|
|
|
472
476
|
d = d + datetime.timedelta(seconds=1)
|
|
473
477
|
d = d.replace(microsecond=0)
|
|
474
478
|
return d
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def json_pretty_dump(obj, max_line_length=120, default=str):
|
|
482
|
+
"""Custom JSON dump function that keeps dicts and lists on one line if they are short enough.
|
|
483
|
+
|
|
484
|
+
Parameters
|
|
485
|
+
----------
|
|
486
|
+
obj
|
|
487
|
+
The object to be dumped as JSON.
|
|
488
|
+
max_line_length
|
|
489
|
+
Maximum allowed line length for pretty-printing.
|
|
490
|
+
|
|
491
|
+
Returns
|
|
492
|
+
-------
|
|
493
|
+
unknown
|
|
494
|
+
JSON string.
|
|
495
|
+
"""
|
|
496
|
+
|
|
497
|
+
def _format_json(obj, indent_level=0):
|
|
498
|
+
"""Helper function to format JSON objects with custom pretty-print rules.
|
|
499
|
+
|
|
500
|
+
Parameters
|
|
501
|
+
----------
|
|
502
|
+
obj
|
|
503
|
+
The object to format.
|
|
504
|
+
indent_level
|
|
505
|
+
Current indentation level.
|
|
506
|
+
|
|
507
|
+
Returns
|
|
508
|
+
-------
|
|
509
|
+
unknown
|
|
510
|
+
Formatted JSON string.
|
|
511
|
+
"""
|
|
512
|
+
indent = " " * 4 * indent_level
|
|
513
|
+
if isinstance(obj, dict):
|
|
514
|
+
items = []
|
|
515
|
+
for key, value in obj.items():
|
|
516
|
+
items.append(f'"{key}": {_format_json(value, indent_level + 1)}')
|
|
517
|
+
line = "{" + ", ".join(items) + "}"
|
|
518
|
+
if len(line) <= max_line_length:
|
|
519
|
+
return line
|
|
520
|
+
else:
|
|
521
|
+
return "{\n" + ",\n".join([f"{indent} {item}" for item in items]) + "\n" + indent + "}"
|
|
522
|
+
elif isinstance(obj, list):
|
|
523
|
+
items = [_format_json(item, indent_level + 1) for item in obj]
|
|
524
|
+
line = "[" + ", ".join(items) + "]"
|
|
525
|
+
if len(line) <= max_line_length:
|
|
526
|
+
return line
|
|
527
|
+
else:
|
|
528
|
+
return "[\n" + ",\n".join([f"{indent} {item}" for item in items]) + "\n" + indent + "]"
|
|
529
|
+
else:
|
|
530
|
+
return json.dumps(obj, default=default)
|
|
531
|
+
|
|
532
|
+
return _format_json(obj)
|
anemoi/utils/s3.py
CHANGED
|
@@ -18,7 +18,7 @@ to use a different S3 compatible service::
|
|
|
18
18
|
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
-
import concurrent
|
|
21
|
+
import concurrent.futures
|
|
22
22
|
import logging
|
|
23
23
|
import os
|
|
24
24
|
import threading
|
|
@@ -26,7 +26,6 @@ from copy import deepcopy
|
|
|
26
26
|
|
|
27
27
|
import tqdm
|
|
28
28
|
|
|
29
|
-
from .config import check_config_mode
|
|
30
29
|
from .config import load_config
|
|
31
30
|
from .humanize import bytes
|
|
32
31
|
|
|
@@ -41,9 +40,7 @@ thread_local = threading.local()
|
|
|
41
40
|
def s3_client(bucket):
|
|
42
41
|
import boto3
|
|
43
42
|
|
|
44
|
-
config = load_config()
|
|
45
|
-
if "object-storage" in config:
|
|
46
|
-
check_config_mode()
|
|
43
|
+
config = load_config(secrets=["aws_access_key_id", "aws_secret_access_key"])
|
|
47
44
|
|
|
48
45
|
if not hasattr(thread_local, "s3_clients"):
|
|
49
46
|
thread_local.s3_clients = {}
|
|
@@ -51,8 +48,14 @@ def s3_client(bucket):
|
|
|
51
48
|
if bucket not in thread_local.s3_clients:
|
|
52
49
|
|
|
53
50
|
options = {}
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
cfg = config.get("object-storage", {})
|
|
52
|
+
for k, v in cfg.items():
|
|
53
|
+
if isinstance(v, (str, int, float, bool)):
|
|
54
|
+
options[k] = v
|
|
55
|
+
|
|
56
|
+
for k, v in cfg.get(bucket, {}).items():
|
|
57
|
+
if isinstance(v, (str, int, float, bool)):
|
|
58
|
+
options[k] = v
|
|
56
59
|
|
|
57
60
|
type = options.pop("type", "s3")
|
|
58
61
|
if type != "s3":
|
|
@@ -420,11 +423,13 @@ def list_folder(folder):
|
|
|
420
423
|
A list of the subfolders names in the folder.
|
|
421
424
|
"""
|
|
422
425
|
|
|
426
|
+
print(folder)
|
|
423
427
|
assert folder.startswith("s3://")
|
|
424
428
|
if not folder.endswith("/"):
|
|
425
429
|
folder += "/"
|
|
426
430
|
|
|
427
431
|
_, _, bucket, prefix = folder.split("/", 3)
|
|
432
|
+
print(bucket, prefix)
|
|
428
433
|
|
|
429
434
|
s3 = s3_client(bucket)
|
|
430
435
|
paginator = s3.get_paginator("list_objects_v2")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: anemoi-utils
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
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
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
anemoi/utils/__init__.py,sha256=zZZpbKIoGWwdCOuo6YSruLR7C0GzvzI1Wzhyqaa0K7M,456
|
|
2
|
+
anemoi/utils/__main__.py,sha256=cLA2PidDTOUHaDGzd0_E5iioKYNe-PSTv567Y2fuwQk,723
|
|
3
|
+
anemoi/utils/_version.py,sha256=nV2HEiFwTdaOZoFEyVxxG_D8Oq_nlSmX2vHL4jK4h6w,411
|
|
4
|
+
anemoi/utils/caching.py,sha256=HrC9aFHlcCTaM2Z5u0ivGIXz7eFu35UQQhUuwwuG2pk,1743
|
|
5
|
+
anemoi/utils/checkpoints.py,sha256=1_3mg4B-ykTVfIvIUEv7IxGyREx_ZcilVbB3U-V6O6I,5165
|
|
6
|
+
anemoi/utils/cli.py,sha256=4uMy6LyL9VPg9ZVNKsimahT5BBVPQgWWk7LUel5dQZE,3545
|
|
7
|
+
anemoi/utils/config.py,sha256=_Kzvu69_XlXRDh1Ane_VJ52z-3oyJ4DVXczBycvOGuY,8798
|
|
8
|
+
anemoi/utils/dates.py,sha256=P-AW-dViogxn4t8Q10sO1HldJ2-lez6ILrx6z59tA10,7454
|
|
9
|
+
anemoi/utils/grib.py,sha256=gVfo4KYQv31iRyoqRDwk5tiqZDUgOIvhag_kO0qjYD0,3067
|
|
10
|
+
anemoi/utils/hindcasts.py,sha256=X8k-81ltmkTDHdviY0SJgvMg7XDu07xoc5ALlUxyPoo,1453
|
|
11
|
+
anemoi/utils/humanize.py,sha256=v5fRfrEJduVDhre3TPRLYyYAcYmuUvVMoINtElu0YYU,12112
|
|
12
|
+
anemoi/utils/provenance.py,sha256=v54L9jF1JgYcclOhg3iojRl1v3ajbiWz_oc289xTgO4,9574
|
|
13
|
+
anemoi/utils/s3.py,sha256=lSJc0Oepl3qqwyiDW9ACf320VfPidncwTkIYAmDU754,16087
|
|
14
|
+
anemoi/utils/text.py,sha256=4Zlc4r9dzRjkKL9xqp2vuQsoJY15bJ3y_Xv3YW_XsmU,8510
|
|
15
|
+
anemoi/utils/timer.py,sha256=JKOgFkpJxmVRn57DEBolmTGwr25P-ePTWASBd8CLeqM,972
|
|
16
|
+
anemoi/utils/commands/__init__.py,sha256=qAybFZPBBQs0dyx7dZ3X5JsLpE90pwrqt1vSV7cqEIw,706
|
|
17
|
+
anemoi/utils/commands/config.py,sha256=lXbbP4HrNez0wh0Fa2eLmTpA3le0EGNLPO4g3JkcGxQ,826
|
|
18
|
+
anemoi/utils/mars/__init__.py,sha256=RAeY8gJ7ZvsPlcIvrQ4fy9xVHs3SphTAPw_XJDtNIKo,1750
|
|
19
|
+
anemoi/utils/mars/mars.yaml,sha256=R0dujp75lLA4wCWhPeOQnzJ45WZAYLT8gpx509cBFlc,66
|
|
20
|
+
anemoi_utils-0.3.9.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
21
|
+
anemoi_utils-0.3.9.dist-info/METADATA,sha256=mDJUF1ukIQDF47RGDT-epp3pKMeN-Qf6O0-wPyGHS54,15513
|
|
22
|
+
anemoi_utils-0.3.9.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
|
|
23
|
+
anemoi_utils-0.3.9.dist-info/entry_points.txt,sha256=LENOkn88xzFQo-V59AKoA_F_cfYQTJYtrNTtf37YgHY,60
|
|
24
|
+
anemoi_utils-0.3.9.dist-info/top_level.txt,sha256=DYn8VPs-fNwr7fNH9XIBqeXIwiYYd2E2k5-dUFFqUz0,7
|
|
25
|
+
anemoi_utils-0.3.9.dist-info/RECORD,,
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
anemoi/utils/__init__.py,sha256=zZZpbKIoGWwdCOuo6YSruLR7C0GzvzI1Wzhyqaa0K7M,456
|
|
2
|
-
anemoi/utils/__main__.py,sha256=cLA2PidDTOUHaDGzd0_E5iioKYNe-PSTv567Y2fuwQk,723
|
|
3
|
-
anemoi/utils/_version.py,sha256=vVN20516E2VTC9JNgtvqrQNlj5XptaB_a5z2XL8NFxg,411
|
|
4
|
-
anemoi/utils/caching.py,sha256=HrC9aFHlcCTaM2Z5u0ivGIXz7eFu35UQQhUuwwuG2pk,1743
|
|
5
|
-
anemoi/utils/checkpoints.py,sha256=1_3mg4B-ykTVfIvIUEv7IxGyREx_ZcilVbB3U-V6O6I,5165
|
|
6
|
-
anemoi/utils/cli.py,sha256=w6YVYfJV-50Zm9FrO0KNrrIWDdgj5hPjxJvgAh391NY,3308
|
|
7
|
-
anemoi/utils/config.py,sha256=BKH-ZOIVZWhuvKxmhK33JVpIr3q7Tdx-tI8kwd4SvgA,6175
|
|
8
|
-
anemoi/utils/dates.py,sha256=Ot9OTY1uFvHxW1EU4DPv3oUqmzvkXTwKuwhlfVlY788,8426
|
|
9
|
-
anemoi/utils/grib.py,sha256=gVfo4KYQv31iRyoqRDwk5tiqZDUgOIvhag_kO0qjYD0,3067
|
|
10
|
-
anemoi/utils/humanize.py,sha256=LD6dGnqChxA5j3tMhSybsAGRQzi33d_qS9pUoUHubkc,10330
|
|
11
|
-
anemoi/utils/provenance.py,sha256=v54L9jF1JgYcclOhg3iojRl1v3ajbiWz_oc289xTgO4,9574
|
|
12
|
-
anemoi/utils/s3.py,sha256=icYeOlCnb0vfKDMIR_Rq6Machl-3KB67sAFSi8OmftI,15910
|
|
13
|
-
anemoi/utils/text.py,sha256=4Zlc4r9dzRjkKL9xqp2vuQsoJY15bJ3y_Xv3YW_XsmU,8510
|
|
14
|
-
anemoi/utils/timer.py,sha256=JKOgFkpJxmVRn57DEBolmTGwr25P-ePTWASBd8CLeqM,972
|
|
15
|
-
anemoi/utils/commands/__init__.py,sha256=qAybFZPBBQs0dyx7dZ3X5JsLpE90pwrqt1vSV7cqEIw,706
|
|
16
|
-
anemoi/utils/commands/config.py,sha256=KEffXZh0ZQfn8t6LXresfd94kDY0gEyulx9Wto5ttW0,824
|
|
17
|
-
anemoi/utils/mars/__init__.py,sha256=RAeY8gJ7ZvsPlcIvrQ4fy9xVHs3SphTAPw_XJDtNIKo,1750
|
|
18
|
-
anemoi/utils/mars/mars.yaml,sha256=R0dujp75lLA4wCWhPeOQnzJ45WZAYLT8gpx509cBFlc,66
|
|
19
|
-
anemoi_utils-0.3.7.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
20
|
-
anemoi_utils-0.3.7.dist-info/METADATA,sha256=TR-5CWm6hwvgDbTyu-P4cIoobZOBJmWWdrrdfQSu3eY,15513
|
|
21
|
-
anemoi_utils-0.3.7.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
|
|
22
|
-
anemoi_utils-0.3.7.dist-info/entry_points.txt,sha256=LENOkn88xzFQo-V59AKoA_F_cfYQTJYtrNTtf37YgHY,60
|
|
23
|
-
anemoi_utils-0.3.7.dist-info/top_level.txt,sha256=DYn8VPs-fNwr7fNH9XIBqeXIwiYYd2E2k5-dUFFqUz0,7
|
|
24
|
-
anemoi_utils-0.3.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|