anemoi-utils 0.3.7__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 CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.3.7'
16
- __version_tuple__ = version_tuple = (0, 3, 7)
15
+ __version__ = version = '0.3.8'
16
+ __version_tuple__ = version_tuple = (0, 3, 8)
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.parse_args()
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
- cmd.run(args)
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())
anemoi/utils/config.py CHANGED
@@ -134,17 +134,21 @@ def config_path(name="settings.toml"):
134
134
 
135
135
 
136
136
  def _load(path):
137
- if path.endswith(".json"):
138
- with open(path, "rb") as f:
139
- return json.load(f)
140
-
141
- if path.endswith(".yaml") or path.endswith(".yml"):
142
- with open(path, "rb") as f:
143
- return yaml.safe_load(f)
144
-
145
- if path.endswith(".toml"):
146
- with open(path, "rb") as f:
147
- return tomllib.load(f)
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}]")
148
152
 
149
153
  return open(path).read()
150
154
 
@@ -224,6 +228,15 @@ def load_config(name="settings.toml"):
224
228
  return _load_config(name)
225
229
 
226
230
 
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
+
227
240
  def check_config_mode(name="settings.toml"):
228
241
  """Check that a configuration file is secure.
229
242
 
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: anemoi-utils
3
- Version: 0.3.7
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
@@ -1,13 +1,14 @@
1
1
  anemoi/utils/__init__.py,sha256=zZZpbKIoGWwdCOuo6YSruLR7C0GzvzI1Wzhyqaa0K7M,456
2
2
  anemoi/utils/__main__.py,sha256=cLA2PidDTOUHaDGzd0_E5iioKYNe-PSTv567Y2fuwQk,723
3
- anemoi/utils/_version.py,sha256=vVN20516E2VTC9JNgtvqrQNlj5XptaB_a5z2XL8NFxg,411
3
+ anemoi/utils/_version.py,sha256=FAr0t5Ub_Olk5Ke3Xi4Oeu5jcLPAvKpdk9naAtMuou8,411
4
4
  anemoi/utils/caching.py,sha256=HrC9aFHlcCTaM2Z5u0ivGIXz7eFu35UQQhUuwwuG2pk,1743
5
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
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
9
  anemoi/utils/grib.py,sha256=gVfo4KYQv31iRyoqRDwk5tiqZDUgOIvhag_kO0qjYD0,3067
10
- anemoi/utils/humanize.py,sha256=LD6dGnqChxA5j3tMhSybsAGRQzi33d_qS9pUoUHubkc,10330
10
+ anemoi/utils/hindcasts.py,sha256=X8k-81ltmkTDHdviY0SJgvMg7XDu07xoc5ALlUxyPoo,1453
11
+ anemoi/utils/humanize.py,sha256=dTbE6Hl5IdmCqfvNibw-kYAYCvK07D0lUvAsNTH_T9Q,12014
11
12
  anemoi/utils/provenance.py,sha256=v54L9jF1JgYcclOhg3iojRl1v3ajbiWz_oc289xTgO4,9574
12
13
  anemoi/utils/s3.py,sha256=icYeOlCnb0vfKDMIR_Rq6Machl-3KB67sAFSi8OmftI,15910
13
14
  anemoi/utils/text.py,sha256=4Zlc4r9dzRjkKL9xqp2vuQsoJY15bJ3y_Xv3YW_XsmU,8510
@@ -16,9 +17,9 @@ anemoi/utils/commands/__init__.py,sha256=qAybFZPBBQs0dyx7dZ3X5JsLpE90pwrqt1vSV7c
16
17
  anemoi/utils/commands/config.py,sha256=KEffXZh0ZQfn8t6LXresfd94kDY0gEyulx9Wto5ttW0,824
17
18
  anemoi/utils/mars/__init__.py,sha256=RAeY8gJ7ZvsPlcIvrQ4fy9xVHs3SphTAPw_XJDtNIKo,1750
18
19
  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,,
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,,