anemoi-utils 0.1.6__py3-none-any.whl → 0.1.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.1.6'
16
- __version_tuple__ = version_tuple = (0, 1, 6)
15
+ __version__ = version = '0.1.8'
16
+ __version_tuple__ = version_tuple = (0, 1, 8)
@@ -0,0 +1,59 @@
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
+ import hashlib
9
+ import json
10
+ import os
11
+ import time
12
+
13
+
14
+ def cache(key, proc, collection="default", expires=None):
15
+ path = os.path.join(os.path.expanduser("~"), ".cache", "anemoi", collection)
16
+ os.makedirs(path, exist_ok=True)
17
+
18
+ key = json.dumps(key, sort_keys=True)
19
+ m = hashlib.md5()
20
+ m.update(key.encode("utf-8"))
21
+
22
+ filename = os.path.join(path, m.hexdigest())
23
+ if os.path.exists(filename):
24
+ with open(filename, "r") as f:
25
+ data = json.load(f)
26
+ if expires is None or data["expires"] > time.time():
27
+ if data["key"] == key:
28
+ return data["value"]
29
+
30
+ value = proc()
31
+ data = {"key": key, "value": value}
32
+ if expires is not None:
33
+ data["expires"] = time.time() + expires
34
+
35
+ with open(filename, "w") as f:
36
+ json.dump(data, f)
37
+
38
+ return value
39
+
40
+
41
+ class cached:
42
+
43
+ def __init__(self, collection="default", expires=None):
44
+ self.collection = collection
45
+ self.expires = expires
46
+
47
+ def __call__(self, func):
48
+
49
+ full = f"{func.__module__}.{func.__name__}"
50
+
51
+ def wrapped(*args, **kwargs):
52
+ return cache(
53
+ (full, args, kwargs),
54
+ lambda: func(*args, **kwargs),
55
+ self.collection,
56
+ self.expires,
57
+ )
58
+
59
+ return wrapped
@@ -6,8 +6,7 @@
6
6
  # granted to it by virtue of its status as an intergovernmental organisation
7
7
  # nor does it submit to any jurisdiction.
8
8
 
9
- """
10
- Read and write extra metadata in PyTorch checkpoints files. These files
9
+ """Read and write extra metadata in PyTorch checkpoints files. These files
11
10
  are zip archives containing the model weights.
12
11
  """
13
12
 
anemoi/utils/grib.py CHANGED
@@ -11,12 +11,26 @@ See https://codes.ecmwf.int/grib/param-db/ for more information.
11
11
 
12
12
  """
13
13
 
14
+ import logging
14
15
  import re
15
16
 
16
17
  import requests
17
18
 
19
+ from .caching import cached
18
20
 
19
- def _search(name):
21
+ LOG = logging.getLogger(__name__)
22
+
23
+
24
+ @cached(collection="grib", expires=30 * 24 * 60 * 60)
25
+ def _units():
26
+ r = requests.get("https://codes.ecmwf.int/parameter-database/api/v1/unit/")
27
+ r.raise_for_status()
28
+ units = r.json()
29
+ return {str(u["id"]): u["name"] for u in units}
30
+
31
+
32
+ @cached(collection="grib", expires=30 * 24 * 60 * 60)
33
+ def _search_param(name):
20
34
  name = re.escape(name)
21
35
  r = requests.get(f"https://codes.ecmwf.int/parameter-database/api/v1/param/?search=^{name}$&regex=true")
22
36
  r.raise_for_status()
@@ -26,7 +40,12 @@ def _search(name):
26
40
 
27
41
  if len(results) > 1:
28
42
  names = [f'{r.get("id")} ({r.get("name")})' for r in results]
29
- raise ValueError(f"{name} is ambiguous: {', '.join(names)}")
43
+ dissemination = [r for r in results if "dissemination" in r.get("access_ids", [])]
44
+ if len(dissemination) == 1:
45
+ return dissemination[0]
46
+
47
+ results = sorted(results, key=lambda x: x["id"])
48
+ LOG.warning(f"{name} is ambiguous: {', '.join(names)}. Using param_id={results[0]['id']}")
30
49
 
31
50
  return results[0]
32
51
 
@@ -44,12 +63,11 @@ def shortname_to_paramid(shortname: str) -> int:
44
63
  int
45
64
  Parameter id.
46
65
 
47
-
48
66
  >>> shortname_to_paramid("2t")
49
67
  167
50
68
 
51
69
  """
52
- return _search(shortname)["id"]
70
+ return _search_param(shortname)["id"]
53
71
 
54
72
 
55
73
  def paramid_to_shortname(paramid: int) -> str:
@@ -65,9 +83,50 @@ def paramid_to_shortname(paramid: int) -> str:
65
83
  str
66
84
  Parameter shortname.
67
85
 
68
-
69
86
  >>> paramid_to_shortname(167)
70
87
  '2t'
71
88
 
72
89
  """
73
- return _search(str(paramid))["shortname"]
90
+ return _search_param(str(paramid))["shortname"]
91
+
92
+
93
+ def units(param) -> str:
94
+ """Return the units of a GRIB parameter given its name or id.
95
+
96
+ Parameters
97
+ ----------
98
+ paramid : int or str
99
+ Parameter id ir name.
100
+
101
+ Returns
102
+ -------
103
+ str
104
+ Parameter unit.
105
+
106
+ >>> unit(167)
107
+ 'K'
108
+
109
+ """
110
+
111
+ unit_id = str(_search_param(str(param))["unit_id"])
112
+ return _units()[unit_id]
113
+
114
+
115
+ def must_be_positive(param):
116
+ """Check if a parameter must be positive.
117
+
118
+ Parameters
119
+ ----------
120
+ param : int or str
121
+ Parameter id or shortname.
122
+
123
+ Returns
124
+ -------
125
+ bool
126
+ True if the parameter must be positive.
127
+
128
+ >>> must_be_positive("tp")
129
+ True
130
+
131
+ """
132
+ return units(param) in ["m", "kg kg**-1", "m of water equivalent"]
@@ -5,8 +5,7 @@
5
5
  # granted to it by virtue of its status as an intergovernmental organisation
6
6
  # nor does it submit to any jurisdiction.
7
7
 
8
- """
9
- Collect information about the current environment, like:
8
+ """Collect information about the current environment, like:
10
9
 
11
10
  - The Python version
12
11
  - The versions of the modules which are currently loaded
@@ -215,7 +214,6 @@ def git_check(*args):
215
214
  dict
216
215
  An object with the git information for the given arguments.
217
216
 
218
-
219
217
  >>> {
220
218
  "anemoi.utils": {
221
219
  "sha1": "c999d83ae283bcbb99f68d92c42d24315922129f",
anemoi/utils/text.py CHANGED
@@ -5,9 +5,7 @@
5
5
  # granted to it by virtue of its status as an intergovernmental organisation
6
6
  # nor does it submit to any jurisdiction.
7
7
 
8
- """
9
- Text utilities
10
- """
8
+ """Text utilities"""
11
9
 
12
10
  import sys
13
11
  from collections import defaultdict
@@ -58,9 +56,6 @@ def boxed(text, min_width=80, max_width=80) -> str:
58
56
  str
59
57
  A boxed version of the input text
60
58
 
61
-
62
-
63
-
64
59
  """
65
60
 
66
61
  lines = text.split("\n")
@@ -266,7 +261,6 @@ def table(rows, header, align, margin=0):
266
261
  margin : int, optional
267
262
  Extra spaces on the left side of the table, by default 0
268
263
 
269
-
270
264
  Returns
271
265
  -------
272
266
  str
@@ -339,7 +333,6 @@ def progress(done, todo, width=80) -> str:
339
333
  str
340
334
  _description_
341
335
 
342
-
343
336
  """
344
337
  done = min(int(done / todo * width + 0.5), width)
345
338
  return green("█" * done) + red("█" * (width - done))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: anemoi-utils
3
- Version: 0.1.6
3
+ Version: 0.1.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,15 @@
1
+ anemoi/utils/__init__.py,sha256=zZZpbKIoGWwdCOuo6YSruLR7C0GzvzI1Wzhyqaa0K7M,456
2
+ anemoi/utils/_version.py,sha256=PdJ7dZoz_SyEgX0MdrMfQYBFlGcwpemv6ibF8NKALBY,411
3
+ anemoi/utils/caching.py,sha256=HrC9aFHlcCTaM2Z5u0ivGIXz7eFu35UQQhUuwwuG2pk,1743
4
+ anemoi/utils/checkpoints.py,sha256=IR86FFNh5JR_uQVlgybnZG74PyU0CNLhyocqARwZIrs,2069
5
+ anemoi/utils/config.py,sha256=XEesqODvkuE3ZA7dnEnZ-ooBRtU6ecPmkfP65FtialA,2147
6
+ anemoi/utils/dates.py,sha256=ZabXLecHMio9ecIJbUxNcfOFoGfkcotSwy_xw1kNQ9w,6474
7
+ anemoi/utils/grib.py,sha256=gVfo4KYQv31iRyoqRDwk5tiqZDUgOIvhag_kO0qjYD0,3067
8
+ anemoi/utils/humanize.py,sha256=LD6dGnqChxA5j3tMhSybsAGRQzi33d_qS9pUoUHubkc,10330
9
+ anemoi/utils/provenance.py,sha256=v54L9jF1JgYcclOhg3iojRl1v3ajbiWz_oc289xTgO4,9574
10
+ anemoi/utils/text.py,sha256=pGWtDvRFoDxAnSuZJiA-GOGJOJLHsw2dAm0tfVvPKno,8599
11
+ anemoi_utils-0.1.8.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
12
+ anemoi_utils-0.1.8.dist-info/METADATA,sha256=bEA_bMbWJubncfBmc6tMi6cJLtFgZrgth899Z60i5Yg,15079
13
+ anemoi_utils-0.1.8.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
14
+ anemoi_utils-0.1.8.dist-info/top_level.txt,sha256=DYn8VPs-fNwr7fNH9XIBqeXIwiYYd2E2k5-dUFFqUz0,7
15
+ anemoi_utils-0.1.8.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- anemoi/utils/__init__.py,sha256=zZZpbKIoGWwdCOuo6YSruLR7C0GzvzI1Wzhyqaa0K7M,456
2
- anemoi/utils/_version.py,sha256=L9DFp_i-1xztMRdin6ZHqLFMlDKUn5bsVgheqXFwTTc,411
3
- anemoi/utils/checkpoints.py,sha256=j1QMmffpo6Blo6kmAJDdUzK3dqq30UWIsWghFqsY4QU,2070
4
- anemoi/utils/config.py,sha256=XEesqODvkuE3ZA7dnEnZ-ooBRtU6ecPmkfP65FtialA,2147
5
- anemoi/utils/dates.py,sha256=ZabXLecHMio9ecIJbUxNcfOFoGfkcotSwy_xw1kNQ9w,6474
6
- anemoi/utils/grib.py,sha256=8fxp2O7tXrFvvp0h68IZ0OhDkyH7GQFTX_6qwJ-hzBs,1692
7
- anemoi/utils/humanize.py,sha256=LD6dGnqChxA5j3tMhSybsAGRQzi33d_qS9pUoUHubkc,10330
8
- anemoi/utils/provenance.py,sha256=RiDpevwTbCzTAkU0oL7pNwST37xt4W9GOkeNNDqbAgk,9576
9
- anemoi/utils/text.py,sha256=mBCPH9NwLyWCU9GkXzB0K4xiDN6UQ1XGlD4T5d8x8Vk,8606
10
- anemoi_utils-0.1.6.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
11
- anemoi_utils-0.1.6.dist-info/METADATA,sha256=gGK2zftLCNffyYnA0FhMXja0k5MOKzoixlL24O29dhk,15079
12
- anemoi_utils-0.1.6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
13
- anemoi_utils-0.1.6.dist-info/top_level.txt,sha256=DYn8VPs-fNwr7fNH9XIBqeXIwiYYd2E2k5-dUFFqUz0,7
14
- anemoi_utils-0.1.6.dist-info/RECORD,,