Skip to content

Commit 5ed47d1

Browse files
authored
Merge pull request #50 from ecmwf/develop
releasing 0.4.6
2 parents c113eb0 + 6c7bb41 commit 5ed47d1

File tree

8 files changed

+83
-62
lines changed

8 files changed

+83
-62
lines changed

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

+12-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
name: "Update Changelog"
33

44
on:
5-
release:
6-
types: [released]
7-
workflow_dispatch: ~
5+
workflow_run:
6+
workflows:
7+
- Upload Python Package
8+
types:
9+
- completed
810

911
permissions:
1012
pull-requests: write
@@ -13,6 +15,7 @@ permissions:
1315
jobs:
1416
update:
1517
runs-on: ubuntu-latest
18+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
1619

1720
steps:
1821
- name: Checkout code
@@ -31,6 +34,12 @@ jobs:
3134
uses: peter-evans/create-pull-request@v6
3235
with:
3336
branch: docs/changelog-update-${{ github.event.release.tag_name }}
37+
base: develop
3438
title: '[Changelog] Update to ${{ github.event.release.tag_name }}'
39+
body: |
40+
This PR updates the changelog to include the changes in the latest release.
41+
42+
> [!CAUTION]
43+
> Merge DO NOT squash to correctly update the tag version of `develop` branch.
3544
add-paths: |
3645
CHANGELOG.md

Diff for: .github/workflows/ci.yml

+23-8
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,28 @@ jobs:
3131
with:
3232
anemoi-utils: ecmwf/anemoi-utils@${{ github.event.pull_request.head.sha || github.sha }}
3333
codecov_upload: true
34+
skip_matrix_jobs: |
35+
gnu@debian-11
36+
37+
gnu@debian-11
38+
39+
40+
gnu@fedora-37
3441
secrets: inherit
3542

36-
# Build downstream packages on HPC
37-
downstream-ci-hpc:
38-
name: downstream-ci-hpc
39-
if: ${{ !github.event.pull_request.head.repo.fork && github.event.action != 'labeled' || github.event.label.name == 'approved-for-ci' }}
40-
uses: ecmwf-actions/downstream-ci/.github/workflows/downstream-ci-hpc.yml@main
41-
with:
42-
anemoi-utils: ecmwf/anemoi-utils@${{ github.event.pull_request.head.sha || github.sha }}
43-
secrets: inherit
43+
# # Build downstream packages on HPC
44+
# downstream-ci-hpc:
45+
# name: downstream-ci-hpc
46+
# if: ${{ !github.event.pull_request.head.repo.fork && github.event.action != 'labeled' || github.event.label.name == 'approved-for-ci' }}
47+
# uses: ecmwf-actions/downstream-ci/.github/workflows/downstream-ci.yml@main
48+
# with:
49+
# anemoi-utils: ecmwf/anemoi-utils@${{ github.event.pull_request.head.sha || github.sha }}
50+
# codecov_upload: true
51+
# skip_matrix_jobs: |
52+
# gnu@debian-11
53+
54+
# gnu@debian-11
55+
56+
57+
# gnu@fedora-37
58+
# secrets: inherit

Diff for: .github/workflows/python-pull-request.yml

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
# This workflow will upload a Python Package using Twine when a release is created
22
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
33

4-
name: Code Quality checks for PRs
4+
name: Test PR
55

66
on:
7-
push:
87
pull_request:
98
types: [opened, synchronize, reopened]
9+
push:
10+
branches:
11+
- develop
12+
schedule:
13+
- cron: "9 2 * * 0" # at 9:02 on sunday
14+
1015

1116
jobs:
1217
quality:
@@ -17,7 +22,7 @@ jobs:
1722
checks:
1823
strategy:
1924
matrix:
20-
python-version: ["3.9", "3.10", "3.11", "3.12"]
25+
python-version: ["3.11"]
2126
uses: ecmwf-actions/reusable-workflows/.github/workflows/qa-pytest-pyproject.yml@v2
2227
with:
2328
python-version: ${{ matrix.python-version }}

Diff for: .pre-commit-config.yaml

-5
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,6 @@ repos:
5959
hooks:
6060
- id: rstfmt
6161
exclude: 'cli/.*' # Because we use argparse
62-
- repo: https://github.com/b8raoult/pre-commit-docconvert
63-
rev: "0.1.5"
64-
hooks:
65-
- id: docconvert
66-
args: ["numpy"]
6762
- repo: https://github.com/tox-dev/pyproject-fmt
6863
rev: "v2.5.0"
6964
hooks:

Diff for: CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,23 @@ 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+
## [0.4.5](https://github.com/ecmwf/anemoi-utils/compare/0.4.4...0.4.5) - 2024-11-06
12+
13+
### What's Changed
14+
15+
* upload with ssh by @floriankrb in https://github.com/ecmwf/anemoi-utils/pull/25
16+
* feat: Add aliases decorator by @HCookie in https://github.com/ecmwf/anemoi-utils/pull/40
17+
18+
**Full Changelog**: https://github.com/ecmwf/anemoi-utils/compare/0.4.4...0.4.5
19+
1120
## [0.4.4](https://github.com/ecmwf/anemoi-utils/compare/0.4.3...0.4.4) - 2024-11-01
1221

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

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

1726
### Added
27+
1828
- Add supporting_arrays to checkpoints
1929
- Add factories registry
2030
- Optional renaming of subcommands via `command` attribute [#34](https://github.com/ecmwf/anemoi-utils/pull/34)

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

+9-9
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ def __init__(self, reference_dates, years=20):
2727

2828
self.reference_dates = reference_dates
2929

30-
if isinstance(years, list):
31-
self.years = years
32-
else:
33-
self.years = range(1, years + 1)
30+
assert isinstance(years, int), f"years must be an integer, got {years}"
31+
assert years > 0, f"years must be greater than 0, got {years}"
32+
self.years = years
3433

3534
def __iter__(self):
3635
for reference_date in self.reference_dates:
37-
for year in self.years:
38-
if reference_date.month == 2 and reference_date.day == 29:
39-
date = datetime.datetime(reference_date.year - year, 2, 28)
40-
else:
41-
date = datetime.datetime(reference_date.year - year, reference_date.month, reference_date.day)
36+
year, month, day = reference_date.year, reference_date.month, reference_date.day
37+
if (month, day) == (2, 29):
38+
day = 28
39+
40+
for i in range(1, self.years + 1):
41+
date = datetime.datetime(year - i, month, day)
4242
yield (date, reference_date)

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

+21-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ def __call__(self, factory):
3030
return factory
3131

3232

33+
_BY_KIND = {}
34+
35+
3336
class Registry:
3437
"""A registry of factories"""
3538

@@ -39,6 +42,11 @@ def __init__(self, package, key="_type"):
3942
self.registered = {}
4043
self.kind = package.split(".")[-1]
4144
self.key = key
45+
_BY_KIND[self.kind] = self
46+
47+
@classmethod
48+
def lookup_kind(cls, kind: str):
49+
return _BY_KIND.get(kind)
4250

4351
def register(self, name: str, factory: callable = None):
4452

@@ -47,14 +55,19 @@ def register(self, name: str, factory: callable = None):
4755

4856
self.registered[name] = factory
4957

58+
# def registered(self, name: str):
59+
# return name in self.registered
60+
5061
def _load(self, file):
5162
name, _ = os.path.splitext(file)
5263
try:
5364
importlib.import_module(f".{name}", package=self.package)
5465
except Exception:
5566
LOG.warning(f"Error loading filter '{self.package}.{name}'", exc_info=True)
5667

57-
def lookup(self, name: str) -> callable:
68+
def lookup(self, name: str, *, return_none=False) -> callable:
69+
70+
# print('✅✅✅✅✅✅✅✅✅✅✅✅✅', name, self.registered)
5871
if name in self.registered:
5972
return self.registered[name]
6073

@@ -87,8 +100,12 @@ def lookup(self, name: str) -> callable:
87100
self.registered[name] = entry_point.load()
88101

89102
if name not in self.registered:
103+
if return_none:
104+
return None
105+
90106
for e in self.registered:
91107
LOG.info(f"Registered: {e}")
108+
92109
raise ValueError(f"Cannot load '{name}' from {self.package}")
93110

94111
return self.registered[name]
@@ -97,8 +114,8 @@ def create(self, name: str, *args, **kwargs):
97114
factory = self.lookup(name)
98115
return factory(*args, **kwargs)
99116

100-
def __call__(self, name: str, *args, **kwargs):
101-
return self.create(name, *args, **kwargs)
117+
# def __call__(self, name: str, *args, **kwargs):
118+
# return self.create(name, *args, **kwargs)
102119

103120
def from_config(self, config, *args, **kwargs):
104121
if isinstance(config, str):
@@ -125,5 +142,5 @@ def from_config(self, config, *args, **kwargs):
125142
return self.create(key, *args, value, **kwargs)
126143

127144
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"
145+
f"Entry '{config}' must either be a string, a dictionary with a single entry, or a dictionary with a '{self.key}' key"
129146
)

Diff for: tests/test_dates.py

-30
Original file line numberDiff line numberDiff line change
@@ -83,36 +83,6 @@ def test_date_hindcast_1():
8383
assert len(list(d)) == 60
8484

8585

86-
def test_date_hindcast_2():
87-
d = _(
88-
"""
89-
- name: hindcast
90-
reference_dates:
91-
start: 2023-01-01
92-
end: 2023-01-03
93-
frequency: 24
94-
years: [2018, 2019, 2020, 2021]
95-
"""
96-
)
97-
assert len(list(d)) == 12
98-
99-
100-
def test_date_hindcast_3():
101-
d = _(
102-
"""
103-
- name: hindcast
104-
reference_dates:
105-
start: 2022-12-25 00:00:00
106-
end: 2022-12-31 12:00:00
107-
frequency: 12h
108-
day_of_week: tuesday
109-
years: [2018, 2019, 2020, 2021]
110-
"""
111-
)
112-
print(list(d))
113-
assert len(list(d)) == 8
114-
115-
11686
if __name__ == "__main__":
11787
for name, obj in list(globals().items()):
11888
if name.startswith("test_") and callable(obj):

0 commit comments

Comments
 (0)