anemoi-utils 0.3.6__py3-none-any.whl → 0.3.8__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 +9 -2
- anemoi/utils/commands/config.py +31 -0
- anemoi/utils/config.py +138 -20
- anemoi/utils/dates.py +2 -31
- anemoi/utils/hindcasts.py +40 -0
- anemoi/utils/humanize.py +55 -0
- anemoi/utils/s3.py +16 -0
- {anemoi_utils-0.3.6.dist-info → anemoi_utils-0.3.8.dist-info}/METADATA +1 -1
- anemoi_utils-0.3.8.dist-info/RECORD +25 -0
- anemoi/utils/commands/checkpoint.py +0 -61
- anemoi_utils-0.3.6.dist-info/RECORD +0 -24
- {anemoi_utils-0.3.6.dist-info → anemoi_utils-0.3.8.dist-info}/LICENSE +0 -0
- {anemoi_utils-0.3.6.dist-info → anemoi_utils-0.3.8.dist-info}/WHEEL +0 -0
- {anemoi_utils-0.3.6.dist-info → anemoi_utils-0.3.8.dist-info}/entry_points.txt +0 -0
- {anemoi_utils-0.3.6.dist-info → anemoi_utils-0.3.8.dist-info}/top_level.txt +0 -0
anemoi/utils/_version.py
CHANGED
anemoi/utils/cli.py
CHANGED
|
@@ -97,7 +97,7 @@ def register_commands(here, package, select, fail=None):
|
|
|
97
97
|
|
|
98
98
|
def cli_main(version, description, commands):
|
|
99
99
|
parser = make_parser(description, commands)
|
|
100
|
-
args = parser.
|
|
100
|
+
args, unknown = parser.parse_known_args()
|
|
101
101
|
|
|
102
102
|
if args.version:
|
|
103
103
|
print(version)
|
|
@@ -115,8 +115,15 @@ def cli_main(version, description, commands):
|
|
|
115
115
|
level=logging.DEBUG if args.debug else logging.INFO,
|
|
116
116
|
)
|
|
117
117
|
|
|
118
|
+
if unknown and not cmd.accept_unknown_args:
|
|
119
|
+
# This should trigger an error
|
|
120
|
+
parser.parse_args()
|
|
121
|
+
|
|
118
122
|
try:
|
|
119
|
-
|
|
123
|
+
if unknown:
|
|
124
|
+
cmd.run(args, unknown)
|
|
125
|
+
else:
|
|
126
|
+
cmd.run(args)
|
|
120
127
|
except ValueError as e:
|
|
121
128
|
traceback.print_exc()
|
|
122
129
|
LOG.error("\n💣 %s", str(e).lstrip())
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# (C) Copyright 2024 ECMWF.
|
|
3
|
+
#
|
|
4
|
+
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
5
|
+
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
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
|
+
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
|
|
14
|
+
from ..config import config_path
|
|
15
|
+
from ..config import load_config
|
|
16
|
+
from . import Command
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Config(Command):
|
|
20
|
+
|
|
21
|
+
def add_arguments(self, command_parser):
|
|
22
|
+
command_parser.add_argument("--path", help="Print path to config file")
|
|
23
|
+
|
|
24
|
+
def run(self, args):
|
|
25
|
+
if args.path:
|
|
26
|
+
print(config_path())
|
|
27
|
+
else:
|
|
28
|
+
print(json.dumps(load_config(), indent=4))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
command = Config
|
anemoi/utils/config.py
CHANGED
|
@@ -102,41 +102,159 @@ class DotDict(dict):
|
|
|
102
102
|
return f"DotDict({super().__repr__()})"
|
|
103
103
|
|
|
104
104
|
|
|
105
|
-
CONFIG =
|
|
105
|
+
CONFIG = {}
|
|
106
|
+
CHECKED = {}
|
|
106
107
|
CONFIG_LOCK = threading.Lock()
|
|
108
|
+
QUIET = False
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def config_path(name="settings.toml"):
|
|
112
|
+
global QUIET
|
|
113
|
+
full = os.path.join(os.path.expanduser("~"), ".config", "anemoi", name)
|
|
114
|
+
os.makedirs(os.path.dirname(full), exist_ok=True)
|
|
115
|
+
|
|
116
|
+
if name == "settings.toml":
|
|
117
|
+
old = os.path.join(os.path.expanduser("~"), ".anemoi.toml")
|
|
118
|
+
if not os.path.exists(full) and os.path.exists(old):
|
|
119
|
+
if not QUIET:
|
|
120
|
+
LOG.warning(
|
|
121
|
+
"Configuration file found at ~/.anemoi.toml. Please move it to ~/.config/anemoi/settings.toml"
|
|
122
|
+
)
|
|
123
|
+
QUIET = True
|
|
124
|
+
return old
|
|
125
|
+
else:
|
|
126
|
+
if os.path.exists(old):
|
|
127
|
+
if not QUIET:
|
|
128
|
+
LOG.warning(
|
|
129
|
+
"Configuration file found at ~/.anemoi.toml and ~/.config/anemoi/settings.toml, ignoring the former"
|
|
130
|
+
)
|
|
131
|
+
QUIET = True
|
|
132
|
+
|
|
133
|
+
return full
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _load(path):
|
|
137
|
+
try:
|
|
138
|
+
if path.endswith(".json"):
|
|
139
|
+
with open(path, "rb") as f:
|
|
140
|
+
return json.load(f)
|
|
141
|
+
|
|
142
|
+
if path.endswith(".yaml") or path.endswith(".yml"):
|
|
143
|
+
with open(path, "rb") as f:
|
|
144
|
+
return yaml.safe_load(f)
|
|
145
|
+
|
|
146
|
+
if path.endswith(".toml"):
|
|
147
|
+
with open(path, "rb") as f:
|
|
148
|
+
return tomllib.load(f)
|
|
149
|
+
except (json.JSONDecodeError, yaml.YAMLError, tomllib.TOMLDecodeError) as e:
|
|
150
|
+
LOG.warning(f"Failed to parse config file {path}", exc_info=e)
|
|
151
|
+
return ValueError(f"Failed to parse config file {path} [{e}]")
|
|
152
|
+
|
|
153
|
+
return open(path).read()
|
|
154
|
+
|
|
107
155
|
|
|
156
|
+
def _load_config(name="settings.toml"):
|
|
108
157
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if CONFIG is not None:
|
|
112
|
-
return CONFIG
|
|
158
|
+
if name in CONFIG:
|
|
159
|
+
return CONFIG[name]
|
|
113
160
|
|
|
114
|
-
conf =
|
|
161
|
+
conf = config_path(name)
|
|
115
162
|
|
|
116
163
|
if os.path.exists(conf):
|
|
164
|
+
config = _load(conf)
|
|
165
|
+
else:
|
|
166
|
+
config = {}
|
|
117
167
|
|
|
118
|
-
|
|
119
|
-
|
|
168
|
+
if isinstance(config, dict):
|
|
169
|
+
CONFIG[name] = DotDict(config)
|
|
120
170
|
else:
|
|
121
|
-
CONFIG =
|
|
171
|
+
CONFIG[name] = config
|
|
172
|
+
|
|
173
|
+
return CONFIG[name]
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _save_config(name, data):
|
|
177
|
+
CONFIG.pop(name, None)
|
|
178
|
+
|
|
179
|
+
conf = config_path(name)
|
|
180
|
+
|
|
181
|
+
if conf.endswith(".json"):
|
|
182
|
+
with open(conf, "w") as f:
|
|
183
|
+
json.dump(data, f, indent=4)
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
if conf.endswith(".yaml") or conf.endswith(".yml"):
|
|
187
|
+
with open(conf, "w") as f:
|
|
188
|
+
yaml.dump(data, f)
|
|
189
|
+
return
|
|
190
|
+
|
|
191
|
+
if conf.endswith(".toml"):
|
|
192
|
+
raise NotImplementedError("Saving to TOML is not implemented yet")
|
|
122
193
|
|
|
123
|
-
|
|
194
|
+
with open(conf, "w") as f:
|
|
195
|
+
f.write(data)
|
|
124
196
|
|
|
125
197
|
|
|
126
|
-
def
|
|
127
|
-
"""
|
|
198
|
+
def save_config(name, data):
|
|
199
|
+
"""Save a configuration file.
|
|
200
|
+
|
|
201
|
+
Parameters
|
|
202
|
+
----------
|
|
203
|
+
name : str
|
|
204
|
+
The name of the configuration file to save.
|
|
205
|
+
|
|
206
|
+
data : Any
|
|
207
|
+
The data to save.
|
|
208
|
+
|
|
209
|
+
"""
|
|
210
|
+
with CONFIG_LOCK:
|
|
211
|
+
_save_config(name, data)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def load_config(name="settings.toml"):
|
|
215
|
+
"""Read a configuration file.
|
|
216
|
+
|
|
217
|
+
Parameters
|
|
218
|
+
----------
|
|
219
|
+
name : str, optional
|
|
220
|
+
The name of the config file to read, by default "settings.toml"
|
|
128
221
|
|
|
129
222
|
Returns
|
|
130
223
|
-------
|
|
131
|
-
DotDict
|
|
132
|
-
|
|
224
|
+
DotDict or str
|
|
225
|
+
Return DotDict if it is a dictionary, otherwise the raw data
|
|
133
226
|
"""
|
|
134
227
|
with CONFIG_LOCK:
|
|
135
|
-
return _load_config()
|
|
228
|
+
return _load_config(name)
|
|
136
229
|
|
|
137
230
|
|
|
138
|
-
def
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if
|
|
142
|
-
|
|
231
|
+
def load_raw_config(name, default=None):
|
|
232
|
+
|
|
233
|
+
path = config_path(name)
|
|
234
|
+
if os.path.exists(path):
|
|
235
|
+
return _load(path)
|
|
236
|
+
|
|
237
|
+
return default
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def check_config_mode(name="settings.toml"):
|
|
241
|
+
"""Check that a configuration file is secure.
|
|
242
|
+
|
|
243
|
+
Parameters
|
|
244
|
+
----------
|
|
245
|
+
name : str, optional
|
|
246
|
+
The name of the configuration file, by default "settings.toml"
|
|
247
|
+
|
|
248
|
+
Raises
|
|
249
|
+
------
|
|
250
|
+
SystemError
|
|
251
|
+
If the configuration file is not secure.
|
|
252
|
+
"""
|
|
253
|
+
with CONFIG_LOCK:
|
|
254
|
+
if name in CHECKED:
|
|
255
|
+
return
|
|
256
|
+
conf = config_path(name)
|
|
257
|
+
mode = os.stat(conf).st_mode
|
|
258
|
+
if mode & 0o777 != 0o600:
|
|
259
|
+
raise SystemError(f"Configuration file {conf} is not secure. " "Please run `chmod 600 {conf}`.")
|
|
260
|
+
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
|
|
|
@@ -472,3 +473,57 @@ def rounded_datetime(d):
|
|
|
472
473
|
d = d + datetime.timedelta(seconds=1)
|
|
473
474
|
d = d.replace(microsecond=0)
|
|
474
475
|
return d
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def json_pretty_dump(obj, max_line_length=120, default=str):
|
|
479
|
+
"""Custom JSON dump function that keeps dicts and lists on one line if they are short enough.
|
|
480
|
+
|
|
481
|
+
Parameters
|
|
482
|
+
----------
|
|
483
|
+
obj
|
|
484
|
+
The object to be dumped as JSON.
|
|
485
|
+
max_line_length
|
|
486
|
+
Maximum allowed line length for pretty-printing.
|
|
487
|
+
|
|
488
|
+
Returns
|
|
489
|
+
-------
|
|
490
|
+
unknown
|
|
491
|
+
JSON string.
|
|
492
|
+
"""
|
|
493
|
+
|
|
494
|
+
def _format_json(obj, indent_level=0):
|
|
495
|
+
"""Helper function to format JSON objects with custom pretty-print rules.
|
|
496
|
+
|
|
497
|
+
Parameters
|
|
498
|
+
----------
|
|
499
|
+
obj
|
|
500
|
+
The object to format.
|
|
501
|
+
indent_level
|
|
502
|
+
Current indentation level.
|
|
503
|
+
|
|
504
|
+
Returns
|
|
505
|
+
-------
|
|
506
|
+
unknown
|
|
507
|
+
Formatted JSON string.
|
|
508
|
+
"""
|
|
509
|
+
indent = " " * 4 * indent_level
|
|
510
|
+
if isinstance(obj, dict):
|
|
511
|
+
items = []
|
|
512
|
+
for key, value in obj.items():
|
|
513
|
+
items.append(f'"{key}": {_format_json(value, indent_level + 1)}')
|
|
514
|
+
line = "{" + ", ".join(items) + "}"
|
|
515
|
+
if len(line) <= max_line_length:
|
|
516
|
+
return line
|
|
517
|
+
else:
|
|
518
|
+
return "{\n" + ",\n".join([f"{indent} {item}" for item in items]) + "\n" + indent + "}"
|
|
519
|
+
elif isinstance(obj, list):
|
|
520
|
+
items = [_format_json(item, indent_level + 1) for item in obj]
|
|
521
|
+
line = "[" + ", ".join(items) + "]"
|
|
522
|
+
if len(line) <= max_line_length:
|
|
523
|
+
return line
|
|
524
|
+
else:
|
|
525
|
+
return "[\n" + ",\n".join([f"{indent} {item}" for item in items]) + "\n" + indent + "]"
|
|
526
|
+
else:
|
|
527
|
+
return json.dumps(obj, default=default)
|
|
528
|
+
|
|
529
|
+
return _format_json(obj)
|
anemoi/utils/s3.py
CHANGED
|
@@ -146,6 +146,14 @@ class Upload(Transfer):
|
|
|
146
146
|
return os.path.getsize(local_path)
|
|
147
147
|
|
|
148
148
|
def transfer_file(self, source, target, overwrite, resume, verbosity, config=None):
|
|
149
|
+
try:
|
|
150
|
+
return self._transfer_file(source, target, overwrite, resume, verbosity, config=config)
|
|
151
|
+
except Exception as e:
|
|
152
|
+
LOGGER.exception(f"Error transferring {source} to {target}")
|
|
153
|
+
LOGGER.error(e)
|
|
154
|
+
raise
|
|
155
|
+
|
|
156
|
+
def _transfer_file(self, source, target, overwrite, resume, verbosity, config=None):
|
|
149
157
|
|
|
150
158
|
from botocore.exceptions import ClientError
|
|
151
159
|
|
|
@@ -208,6 +216,14 @@ class Download(Transfer):
|
|
|
208
216
|
return s3_object["Size"]
|
|
209
217
|
|
|
210
218
|
def transfer_file(self, source, target, overwrite, resume, verbosity, config=None):
|
|
219
|
+
try:
|
|
220
|
+
return self._transfer_file(source, target, overwrite, resume, verbosity, config=config)
|
|
221
|
+
except Exception as e:
|
|
222
|
+
LOGGER.exception(f"Error transferring {source} to {target}")
|
|
223
|
+
LOGGER.error(e)
|
|
224
|
+
raise
|
|
225
|
+
|
|
226
|
+
def _transfer_file(self, source, target, overwrite, resume, verbosity, config=None):
|
|
211
227
|
# from boto3.s3.transfer import TransferConfig
|
|
212
228
|
|
|
213
229
|
_, _, bucket, key = source.split("/", 3)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: anemoi-utils
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
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=FAr0t5Ub_Olk5Ke3Xi4Oeu5jcLPAvKpdk9naAtMuou8,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=qPfByejFODsD1qBFxT8675AU9mu0-3V1Z1ePWIiZAFw,3512
|
|
7
|
+
anemoi/utils/config.py,sha256=hmZPU1ZFHrZ6UPWg4VybJ7cWPiBdkyHWQjFiL1ZcVYU,6592
|
|
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=dTbE6Hl5IdmCqfvNibw-kYAYCvK07D0lUvAsNTH_T9Q,12014
|
|
12
|
+
anemoi/utils/provenance.py,sha256=v54L9jF1JgYcclOhg3iojRl1v3ajbiWz_oc289xTgO4,9574
|
|
13
|
+
anemoi/utils/s3.py,sha256=icYeOlCnb0vfKDMIR_Rq6Machl-3KB67sAFSi8OmftI,15910
|
|
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=KEffXZh0ZQfn8t6LXresfd94kDY0gEyulx9Wto5ttW0,824
|
|
18
|
+
anemoi/utils/mars/__init__.py,sha256=RAeY8gJ7ZvsPlcIvrQ4fy9xVHs3SphTAPw_XJDtNIKo,1750
|
|
19
|
+
anemoi/utils/mars/mars.yaml,sha256=R0dujp75lLA4wCWhPeOQnzJ45WZAYLT8gpx509cBFlc,66
|
|
20
|
+
anemoi_utils-0.3.8.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
21
|
+
anemoi_utils-0.3.8.dist-info/METADATA,sha256=8BOhK6TNwiE_jBCATqFzVnSLZmT5LGbEFJJztDCrimc,15513
|
|
22
|
+
anemoi_utils-0.3.8.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
|
|
23
|
+
anemoi_utils-0.3.8.dist-info/entry_points.txt,sha256=LENOkn88xzFQo-V59AKoA_F_cfYQTJYtrNTtf37YgHY,60
|
|
24
|
+
anemoi_utils-0.3.8.dist-info/top_level.txt,sha256=DYn8VPs-fNwr7fNH9XIBqeXIwiYYd2E2k5-dUFFqUz0,7
|
|
25
|
+
anemoi_utils-0.3.8.dist-info/RECORD,,
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# (C) Copyright 2024 ECMWF.
|
|
3
|
-
#
|
|
4
|
-
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
5
|
-
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
import json
|
|
13
|
-
|
|
14
|
-
from . import Command
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def visit(x, path, name, value):
|
|
18
|
-
if isinstance(x, dict):
|
|
19
|
-
for k, v in x.items():
|
|
20
|
-
if k == name:
|
|
21
|
-
print(".".join(path), k, v)
|
|
22
|
-
|
|
23
|
-
if v == value:
|
|
24
|
-
print(".".join(path), k, v)
|
|
25
|
-
|
|
26
|
-
path.append(k)
|
|
27
|
-
visit(v, path, name, value)
|
|
28
|
-
path.pop()
|
|
29
|
-
|
|
30
|
-
if isinstance(x, list):
|
|
31
|
-
for i, v in enumerate(x):
|
|
32
|
-
path.append(str(i))
|
|
33
|
-
visit(v, path, name, value)
|
|
34
|
-
path.pop()
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class Checkpoint(Command):
|
|
38
|
-
|
|
39
|
-
def add_arguments(self, command_parser):
|
|
40
|
-
command_parser.add_argument("path", help="Path to the checkpoint.")
|
|
41
|
-
command_parser.add_argument("--name", help="Search for a specific name.")
|
|
42
|
-
command_parser.add_argument("--value", help="Search for a specific value.")
|
|
43
|
-
|
|
44
|
-
def run(self, args):
|
|
45
|
-
from anemoi.utils.checkpoints import load_metadata
|
|
46
|
-
|
|
47
|
-
checkpoint = load_metadata(args.path, "*.json")
|
|
48
|
-
|
|
49
|
-
if args.name or args.value:
|
|
50
|
-
visit(
|
|
51
|
-
checkpoint,
|
|
52
|
-
[],
|
|
53
|
-
args.name if args.name is not None else object(),
|
|
54
|
-
args.value if args.value is not None else object(),
|
|
55
|
-
)
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
-
print(json.dumps(checkpoint, sort_keys=True, indent=4))
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
command = Checkpoint
|
|
@@ -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=IKAQ4gPrCQ2FWMXOFRqouULC2EQI1zCb4iXHsnfbmTQ,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=HBU8UbT0ZSFVSgpQGY42bXukrGIJBPbdqsqK1Btx97A,3475
|
|
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=OEZGm85gzWfZ29OuCx-A2dczC00XKM_SYnkGv9vgs14,15204
|
|
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/checkpoint.py,sha256=SEnAizU3WklqMXUjmIh4eNrgBVwmheKG9gEBS90zwYU,1741
|
|
17
|
-
anemoi/utils/mars/__init__.py,sha256=RAeY8gJ7ZvsPlcIvrQ4fy9xVHs3SphTAPw_XJDtNIKo,1750
|
|
18
|
-
anemoi/utils/mars/mars.yaml,sha256=R0dujp75lLA4wCWhPeOQnzJ45WZAYLT8gpx509cBFlc,66
|
|
19
|
-
anemoi_utils-0.3.6.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
20
|
-
anemoi_utils-0.3.6.dist-info/METADATA,sha256=DHKiN2X6h1APP0fFqHPHGN6TNWv7X65V85PPHX5ghac,15513
|
|
21
|
-
anemoi_utils-0.3.6.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
|
|
22
|
-
anemoi_utils-0.3.6.dist-info/entry_points.txt,sha256=LENOkn88xzFQo-V59AKoA_F_cfYQTJYtrNTtf37YgHY,60
|
|
23
|
-
anemoi_utils-0.3.6.dist-info/top_level.txt,sha256=DYn8VPs-fNwr7fNH9XIBqeXIwiYYd2E2k5-dUFFqUz0,7
|
|
24
|
-
anemoi_utils-0.3.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|