Skip to content

Commit 0f1ee42

Browse files
committed
Integrate aicon integration test
1 parent 4ce6558 commit 0f1ee42

File tree

3 files changed

+497
-59
lines changed

3 files changed

+497
-59
lines changed

.github/workflows/python-pull-request.yml

+34-59
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ on:
44
pull_request:
55
types: [opened, synchronize, reopened]
66
push:
7-
branches:
8-
- develop
9-
schedule:
10-
- cron: "9 2 * * 0" # at 9:02 on sunday
7+
118

129
jobs:
1310
quality:
@@ -37,68 +34,46 @@ jobs:
3734
- name: Detect changed packages
3835
id: changed-packages
3936
run: |
40-
CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }})
37+
CHANGED_FILES=$(git diff --name-only ${{ github.sha }} ${{ github.sha }}) # temporarily disabled
4138
echo "training_changed=$(echo "$CHANGED_FILES" | grep -q '^training/.*\.py$' && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
4239
echo "graphs_changed=$(echo "$CHANGED_FILES" | grep -q '^graphs/.*\.py$' && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
4340
echo "models_changed=$(echo "$CHANGED_FILES" | grep -q '^models/.*\.py$' && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
4441
45-
- name: Install training package
46-
run: |
47-
if [[ ${{ steps.changed-packages.outputs.training_changed }} == 'true' ]]; then
48-
echo "Installing training from local source"
49-
pip install -e ./training[tests]
50-
else
51-
echo "Installing training from PyPI"
52-
pip install anemoi-training[tests]
53-
fi
42+
- name: Install core packages
43+
run: pip install -e ./graphs/[tests] -e ./training/[tests] -e ./models/[tests]
5444

55-
- name: Install graphs package
56-
run: |
57-
if [[ ${{ steps.changed-packages.outputs.graphs_changed }} == 'true' ]]; then
58-
echo "Installing graphs from local source"
59-
pip install -e ./graphs[tests]
60-
else
61-
echo "Installing graphs from PyPI"
62-
pip install anemoi-graphs[tests]
63-
fi
45+
- name: Run integration tests
46+
run: pytest tests
6447

65-
- name: Install models package
66-
run: |
67-
if [[ ${{ steps.changed-packages.outputs.models_changed }} == 'true' ]]; then
68-
echo "Installing models from local source"
69-
pip install -e ./models[tests]
70-
else
71-
echo "Installing models from PyPI"
72-
pip install anemoi-models[tests]
73-
fi
7448

75-
- name: Run pytest for changed training package
76-
if: steps.changed-packages.outputs.training_changed == 'true'
77-
uses: ecmwf-actions/reusable-workflows/.github/workflows/qa-pytest-pyproject.yml@v2
78-
with:
79-
python-version: ${{ matrix.python-version }}
80-
install-dependencies: false
81-
custom-pytest: pytest training/tests
49+
# - name: Run pytest for changed training package
50+
# if: steps.changed-packages.outputs.training_changed == 'true'
51+
# uses: ecmwf-actions/reusable-workflows/.github/workflows/qa-pytest-pyproject.yml@v2
52+
# with:
53+
# python-version: ${{ matrix.python-version }}
54+
# install-dependencies: false
55+
# custom-pytest: pytest training/tests
8256

83-
- name: Run pytest for changed graphs package
84-
if: steps.changed-packages.outputs.graphs_changed == 'true'
85-
uses: ecmwf-actions/reusable-workflows/.github/workflows/qa-pytest-pyproject.yml@v2
86-
with:
87-
python-version: ${{ matrix.python-version }}
88-
install-dependencies: false
89-
custom-pytest: pytest graphs/tests
57+
# - name: Run pytest for changed graphs package
58+
# if: steps.changed-packages.outputs.graphs_changed == 'true'
59+
# uses: ecmwf-actions/reusable-workflows/.github/workflows/qa-pytest-pyproject.yml@v2
60+
# with:
61+
# python-version: ${{ matrix.python-version }}
62+
# install-dependencies: false
63+
# custom-pytest: pytest graphs/tests
9064

91-
- name: Run pytest for changed models package
92-
if: steps.changed-packages.outputs.models_changed == 'true'
93-
uses: ecmwf-actions/reusable-workflows/.github/workflows/qa-pytest-pyproject.yml@v2
94-
with:
95-
python-version: ${{ matrix.python-version }}
96-
install-dependencies: false
97-
custom-pytest: pytest models/tests
65+
# - name: Run pytest for changed models package
66+
# if: steps.changed-packages.outputs.models_changed == 'true'
67+
# uses: ecmwf-actions/reusable-workflows/.github/workflows/qa-pytest-pyproject.yml@v2
68+
# with:
69+
# python-version: ${{ matrix.python-version }}
70+
# install-dependencies: false
71+
# custom-pytest: pytest models/tests
9872

99-
- name: Run integration tests
100-
if: success()
101-
uses: ecmwf-actions/reusable-workflows/.github/workflows/qa-pytest-pyproject.yml@v2
102-
with:
103-
python-version: ${{ matrix.python-version }}
104-
install-dependencies: false
73+
# - name: Run integration tests
74+
# if: success()
75+
# uses: ecmwf-actions/reusable-workflows/.github/workflows/qa-pytest-pyproject.yml@v2
76+
# with:
77+
# python-version: ${{ matrix.python-version }}
78+
# install-dependencies: false
79+
# custom-pytest: pytest tests
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# (C) Copyright 2025 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+
# Various tests of the Anemoi components using a sample data set.
10+
#
11+
# This script is not part of a productive ML workflow, but is
12+
# used for CI/CD!
13+
import datetime
14+
import os
15+
import pathlib
16+
import platform
17+
import tempfile
18+
19+
import matplotlib as mpl
20+
import pytest
21+
import torch
22+
from hydra import compose
23+
from hydra import initialize
24+
25+
import anemoi.training
26+
from anemoi.training.train.train import AnemoiTrainer
27+
28+
os.environ["ANEMOI_BASE_SEED"] = "42"
29+
os.environ["ANEMOI_CONFIG_PATH"] = str(pathlib.Path(anemoi.training.__file__).parent / "config")
30+
mpl.use("agg")
31+
32+
33+
def trainer(shorten: bool = True) -> AnemoiTrainer:
34+
with initialize(version_base=None, config_path="./"):
35+
config = compose(config_name="test_cicd_aicon_04_icon-dream_medium")
36+
37+
if shorten:
38+
date = datetime.datetime.fromisoformat(config.dataloader.training.start)
39+
date = date + datetime.timedelta(days=3)
40+
config.dataloader.training.end = date.isoformat()
41+
date = date + datetime.timedelta(hours=6)
42+
config.dataloader.validation.start = date.isoformat()
43+
date = date + datetime.timedelta(days=2)
44+
config.dataloader.validation.end = date.isoformat()
45+
46+
grid_filename = config.graph.nodes.icon_mesh.node_builder.grid_filename
47+
with tempfile.NamedTemporaryFile(suffix=".nc") as grid_fp:
48+
if grid_filename.startswith(("http://", "https://")):
49+
import urllib.request
50+
51+
urllib.request.urlretrieve(grid_filename, grid_fp.name) # noqa: S310
52+
config.graph.nodes.icon_mesh.node_builder.grid_filename = grid_fp.name
53+
54+
trainer = AnemoiTrainer(config)
55+
initial_sum = torch.tensor(list(map(torch.sum, trainer.model.parameters()))).sum()
56+
trainer.train()
57+
final_sum = torch.tensor(list(map(torch.sum, trainer.model.parameters()))).sum()
58+
return trainer, initial_sum, final_sum
59+
60+
61+
@pytest.fixture
62+
def get_trainer() -> tuple:
63+
return trainer()
64+
65+
66+
@pytest.mark.skipif(
67+
platform.system() == "Darwin",
68+
reason="We set strategy=DDP but strategies from the DDP family are not supported on the MPS,"
69+
" which is the accelerator of the M1 Mac.",
70+
)
71+
def test_main(get_trainer: tuple) -> None:
72+
trainer, initial_sum, final_sum = get_trainer
73+
assert trainer
74+
assert initial_sum != final_sum
75+
76+
77+
if __name__ == "__main__":
78+
test_main(trainer(shorten=True))

0 commit comments

Comments
 (0)