Skip to content

Commit c113eb0

Browse files
authored
Merge pull request #43 from ecmwf/develop
release 0.4.5
2 parents 83d521e + 6de64e7 commit c113eb0

23 files changed

+1251
-584
lines changed

Diff for: .github/workflows/changelog-pr-update.yml

+18-18
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
name: Check Changelog Update on PR
2-
on:
3-
pull_request:
4-
types: [assigned, opened, synchronize, reopened, labeled, unlabeled]
5-
branches:
6-
- main
7-
- develop
8-
paths-ignore:
9-
- .pre-commit-config.yaml
10-
- .readthedocs.yaml
11-
jobs:
12-
Check-Changelog:
13-
name: Check Changelog Action
14-
runs-on: ubuntu-20.04
15-
steps:
16-
- uses: tarides/changelog-check-action@v2
17-
with:
18-
changelog: CHANGELOG.md
1+
# name: Check Changelog Update on PR
2+
# on:
3+
# pull_request:
4+
# types: [assigned, opened, synchronize, reopened, labeled, unlabeled]
5+
# branches:
6+
# - main
7+
# - develop
8+
# paths-ignore:
9+
# - .pre-commit-config.yaml
10+
# - .readthedocs.yaml
11+
# jobs:
12+
# Check-Changelog:
13+
# name: Check Changelog Action
14+
# runs-on: ubuntu-20.04
15+
# steps:
16+
# - uses: tarides/changelog-check-action@v2
17+
# with:
18+
# changelog: CHANGELOG.md

Diff for: .github/workflows/changelog-release-update.yml

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ jobs:
2525
with:
2626
latest-version: ${{ github.event.release.tag_name }}
2727
heading-text: ${{ github.event.release.name }}
28+
release-notes: ${{ github.event.release.body }}
2829

2930
- name: Create Pull Request
3031
uses: peter-evans/create-pull-request@v6

Diff for: .pre-commit-config.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ repos:
2727
- id: python-check-blanket-noqa # Check for # noqa: all
2828
- id: python-no-log-warn # Check for log.warn
2929
- repo: https://github.com/psf/black-pre-commit-mirror
30-
rev: 24.8.0
30+
rev: 24.10.0
3131
hooks:
3232
- id: black
3333
args: [--line-length=120]
@@ -40,7 +40,7 @@ repos:
4040
- --force-single-line-imports
4141
- --profile black
4242
- repo: https://github.com/astral-sh/ruff-pre-commit
43-
rev: v0.6.9
43+
rev: v0.7.2
4444
hooks:
4545
- id: ruff
4646
args:
@@ -65,7 +65,7 @@ repos:
6565
- id: docconvert
6666
args: ["numpy"]
6767
- repo: https://github.com/tox-dev/pyproject-fmt
68-
rev: "2.2.4"
68+
rev: "v2.5.0"
6969
hooks:
7070
- id: pyproject-fmt
7171
- repo: https://github.com/jshwi/docsig # Check docstrings against function sig

Diff for: CHANGELOG.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
Please add your functional changes to the appropriate section in the PR.
99
Keep it human-readable, your future self will thank you!
1010

11-
## [Unreleased](https://github.com/ecmwf/anemoi-utils/compare/0.4.4...HEAD)
12-
1311
## [0.4.4](https://github.com/ecmwf/anemoi-utils/compare/0.4.3...0.4.4) - 2024-11-01
1412

1513
## [0.4.3](https://github.com/ecmwf/anemoi-utils/compare/0.4.1...0.4.3) - 2024-10-26
1614

1715
## [0.4.2](https://github.com/ecmwf/anemoi-utils/compare/0.4.1...0.4.2) - 2024-10-25
1816

1917
### Added
20-
2118
- Add supporting_arrays to checkpoints
2219
- Add factories registry
2320
- Optional renaming of subcommands via `command` attribute [#34](https://github.com/ecmwf/anemoi-utils/pull/34)
@@ -53,7 +50,9 @@ Keep it human-readable, your future self will thank you!
5350
- Changelog merge strategy- Codeowners file
5451
- Create dependency on wcwidth. MIT licence.
5552
- Add distribution name dictionary to provenance [#15](https://github.com/ecmwf/anemoi-utils/pull/15) & [#19](https://github.com/ecmwf/anemoi-utils/pull/19)
56-
- Add anonimize() function.
53+
- Add anonymize() function.
54+
- Add transfer to ssh:// target (experimental)
55+
- Deprecated 'anemoi.utils.s3'
5756

5857
### Changed
5958

Diff for: pyproject.toml

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
#!/usr/bin/env python
2-
# (C) Copyright 2024 ECMWF.
1+
# (C) Copyright 2024 Anemoi contributors.
32
#
43
# This software is licensed under the terms of the Apache Licence Version 2.0
54
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5+
#
66
# In applying this licence, ECMWF does not waive the privileges and immunities
77
# granted to it by virtue of its status as an intergovernmental organisation
88
# nor does it submit to any jurisdiction.
99

10-
# https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
11-
1210
[build-system]
1311
requires = [ "setuptools>=60", "setuptools-scm>=8" ]
1412

@@ -35,6 +33,7 @@ classifiers = [
3533
"Programming Language :: Python :: 3.10",
3634
"Programming Language :: Python :: 3.11",
3735
"Programming Language :: Python :: 3.12",
36+
"Programming Language :: Python :: 3.13",
3837
"Programming Language :: Python :: Implementation :: CPython",
3938
"Programming Language :: Python :: Implementation :: PyPy",
4039
]

Diff for: src/anemoi/utils/__main__.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
#!/usr/bin/env python
2-
# (C) Copyright 2024 ECMWF.
1+
# (C) Copyright 2024 Anemoi contributors.
32
#
43
# This software is licensed under the terms of the Apache Licence Version 2.0
54
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5+
#
66
# In applying this licence, ECMWF does not waive the privileges and immunities
77
# granted to it by virtue of its status as an intergovernmental organisation
88
# nor does it submit to any jurisdiction.
9-
#
109

1110
from anemoi.utils.cli import cli_main
1211
from anemoi.utils.cli import make_parser

Diff for: src/anemoi/utils/checkpoints.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ def load_metadata(path: str, *, supporting_arrays=False, name: str = DEFAULT_NAM
9494
with zipfile.ZipFile(path, "r") as f:
9595
metadata = json.load(f.open(metadata, "r"))
9696
if supporting_arrays:
97-
metadata["supporting_arrays"] = load_supporting_arrays(f, metadata.get("supporting_arrays", {}))
98-
return metadata, supporting_arrays
97+
arrays = load_supporting_arrays(f, metadata.get("supporting_arrays_paths", {}))
98+
return metadata, arrays
9999

100100
return metadata
101101
else:

Diff for: src/anemoi/utils/commands/__init__.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
#!/usr/bin/env python
2-
# (C) Copyright 2024 ECMWF.
1+
# (C) Copyright 2024 Anemoi contributors.
32
#
43
# This software is licensed under the terms of the Apache Licence Version 2.0
54
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5+
#
66
# In applying this licence, ECMWF does not waive the privileges and immunities
77
# granted to it by virtue of its status as an intergovernmental organisation
88
# nor does it submit to any jurisdiction.
9-
#
109

1110
import os
1211

Diff for: src/anemoi/utils/commands/config.py

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#!/usr/bin/env python3
21
# (C) Copyright 2024 Anemoi contributors.
32
#
43
# This software is licensed under the terms of the Apache Licence Version 2.0

Diff for: src/anemoi/utils/compatibility.py

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# (C) Copyright 2024 Anemoi contributors.
2+
#
3+
# This software is licensed under the terms of the Apache Licence Version 2.0
4+
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5+
#
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+
from __future__ import annotations
11+
12+
import functools
13+
from typing import Any
14+
from typing import Callable
15+
16+
17+
def aliases(
18+
aliases: dict[str, str | list[str]] | None = None, **kwargs: str | list[str]
19+
) -> Callable[[Callable], Callable]:
20+
"""Alias keyword arguments in a function call.
21+
22+
Allows for dynamically renaming keyword arguments in a function call.
23+
24+
Parameters
25+
----------
26+
aliases : dict[str, str | list[str]] | None, optional
27+
Key, value pair of aliases, with keys being the true name, and value being a str or list of aliases,
28+
by default None
29+
**kwargs : str | list[str]
30+
Kwargs form of aliases
31+
32+
Returns
33+
-------
34+
Callable
35+
Decorator function that renames keyword arguments in a function call.
36+
37+
Raises
38+
------
39+
ValueError
40+
If the aliasing would result in duplicate keys.
41+
42+
Examples
43+
--------
44+
```python
45+
@aliases(a="b", c=["d", "e"])
46+
def func(a, c):
47+
return a, c
48+
49+
func(a=1, c=2) # (1, 2)
50+
func(b=1, d=2) # (1, 2)
51+
```
52+
53+
"""
54+
55+
if aliases is None:
56+
aliases = {}
57+
aliases.update(kwargs)
58+
59+
aliases = {v: k for k, vs in aliases.items() for v in (vs if isinstance(vs, list) else [vs])}
60+
61+
def decorator(func: Callable) -> Callable:
62+
@functools.wraps(func)
63+
def wrapper(*args, **kwargs) -> Any:
64+
keys = kwargs.keys()
65+
for k in set(keys).intersection(set(aliases.keys())):
66+
if aliases[k] in keys:
67+
raise ValueError(
68+
f"When aliasing {k} with {aliases[k]} duplicate keys were present. Cannot include both."
69+
)
70+
kwargs[aliases[k]] = kwargs.pop(k)
71+
72+
return func(*args, **kwargs)
73+
74+
return wrapper
75+
76+
return decorator

Diff for: src/anemoi/utils/mars/__init__.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
# (C) Copyright 2024 European Centre for Medium-Range Weather Forecasts.
1+
# (C) Copyright 2024 Anemoi contributors.
2+
#
23
# This software is licensed under the terms of the Apache Licence Version 2.0
34
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5+
#
46
# In applying this licence, ECMWF does not waive the privileges and immunities
57
# granted to it by virtue of its status as an intergovernmental organisation
68
# nor does it submit to any jurisdiction.

Diff for: src/anemoi/utils/registry.py

+32-1
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ def __call__(self, factory):
3333
class Registry:
3434
"""A registry of factories"""
3535

36-
def __init__(self, package):
36+
def __init__(self, package, key="_type"):
3737

3838
self.package = package
3939
self.registered = {}
4040
self.kind = package.split(".")[-1]
41+
self.key = key
4142

4243
def register(self, name: str, factory: callable = None):
4344

@@ -86,6 +87,8 @@ def lookup(self, name: str) -> callable:
8687
self.registered[name] = entry_point.load()
8788

8889
if name not in self.registered:
90+
for e in self.registered:
91+
LOG.info(f"Registered: {e}")
8992
raise ValueError(f"Cannot load '{name}' from {self.package}")
9093

9194
return self.registered[name]
@@ -96,3 +99,31 @@ def create(self, name: str, *args, **kwargs):
9699

97100
def __call__(self, name: str, *args, **kwargs):
98101
return self.create(name, *args, **kwargs)
102+
103+
def from_config(self, config, *args, **kwargs):
104+
if isinstance(config, str):
105+
config = {config: {}}
106+
107+
if not isinstance(config, dict):
108+
raise ValueError(f"Invalid config: {config}")
109+
110+
if self.key in config:
111+
config = config.copy()
112+
key = config.pop(self.key)
113+
return self.create(key, *args, **config, **kwargs)
114+
115+
if len(config) == 1:
116+
key = list(config.keys())[0]
117+
value = config[key]
118+
119+
if isinstance(value, dict):
120+
return self.create(key, *args, **value, **kwargs)
121+
122+
if isinstance(value, list):
123+
return self.create(key, *args, *value, **kwargs)
124+
125+
return self.create(key, *args, value, **kwargs)
126+
127+
raise ValueError(
128+
f"Entry '{config}' must either be a string, a dictionray with a single entry, or a dictionary with a '{self.key}' key"
129+
)

0 commit comments

Comments
 (0)