Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
6dfd3a1
Add nox session and utilities for conditionally running tests based o…
egparedes Apr 15, 2025
5fb4a81
Add name matching mechanism for selecting which env variable are pass…
egparedes Apr 15, 2025
b032f35
Merge branch 'main' into new-conditionals
egparedes Apr 15, 2025
e24eaeb
Refactor to get conditional activation flag from the environment
egparedes Apr 15, 2025
bd66f86
WIP: fixes
egparedes Apr 15, 2025
eeb2709
More fixes
egparedes Apr 15, 2025
b945f52
Large refactoring moving all utilities to a different file
egparedes Apr 16, 2025
a74bdb6
Cleanups and fixes
egparedes Apr 16, 2025
c483e64
Test calling new nox way for eve from Github actions instead of fallback
egparedes Apr 16, 2025
f0d5c82
Cleanups and fixes
egparedes Apr 16, 2025
3fd76e8
Fix
egparedes Apr 16, 2025
4ece1f1
Try git diff changes
egparedes Apr 16, 2025
3456cb6
Print to stderr in verbose mode
egparedes Apr 16, 2025
fcc242c
Put back "origin/"
egparedes Apr 16, 2025
0a30b09
Add docstrigngs and fix verbose mode bug
egparedes Apr 16, 2025
03275fb
Use lightweight launch venv with only nox
egparedes Apr 16, 2025
b3655ca
Improve docstrings
egparedes Apr 16, 2025
b7aa661
Merge branch 'main' into new-conditionals
egparedes Apr 16, 2025
a6eed30
Fix bug
egparedes Apr 16, 2025
e8f0497
Read python versions from file
egparedes Apr 16, 2025
23980d7
Update noxfile_utils.py
egparedes Apr 16, 2025
a4be642
Update noxfile.py
egparedes Apr 16, 2025
019cf6c
Use uvx for nox
egparedes Apr 17, 2025
08ea3c5
Fixes
egparedes Apr 17, 2025
3ea0c5e
Cleanups and fixes
egparedes Apr 17, 2025
763f903
Adding unit tests
egparedes Apr 17, 2025
0001431
Tests cleanups
egparedes Apr 17, 2025
d476732
Finish unit tests
egparedes Apr 17, 2025
052bbaf
Cleanups and docs enhancements
egparedes Apr 22, 2025
bda11db
Update GitHub actions
egparedes Apr 22, 2025
ede2ad3
Missing edit from previous commit
egparedes Apr 22, 2025
48c0dd7
Fix env var names
egparedes Apr 22, 2025
7ca8037
Fix env vars prefix
egparedes Apr 22, 2025
dc06e36
Add utility to create env dicts and other cleanups
egparedes Apr 22, 2025
61643d4
Merge branch 'main' into new-conditionals
egparedes Apr 22, 2025
9c688f0
Add run_session util to create the env automatically
egparedes Apr 22, 2025
cd77635
Copilot review suggestions
egparedes Apr 23, 2025
520acf8
Merge branch 'main' into new-conditionals
egparedes Apr 23, 2025
e9fcdfd
fix
egparedes Apr 24, 2025
60ccc5b
Change development docs
egparedes Apr 24, 2025
4c4937d
Fix style
egparedes Apr 24, 2025
afe48dd
Fix noxfile calls to run_session and other cleanups
egparedes Apr 24, 2025
8d7ac17
Update nox version and remove unneeded env filtering feature from nox…
egparedes Apr 24, 2025
3b8f38b
Fix unnecessary deep clones in actions and a bug in dev-tasks.py
egparedes May 6, 2025
9477463
Merge branch 'main' into new-conditionals
egparedes May 6, 2025
641d521
Add missing changes from previous commit
egparedes May 6, 2025
7f7917a
Change import mechanism for noxfile_utils
egparedes May 6, 2025
8802cc7
More cleanups, add is_affected session and update docs.
egparedes May 7, 2025
e604f44
Replace `uvx nox` by `uv run noxfile.py` in github actions, as suppor…
egparedes May 7, 2025
3b6b25d
Doctrsing fixes
egparedes May 7, 2025
983e73d
Move noxfile_utils tests from nox to pre-commit
egparedes May 7, 2025
2312e0f
Add assert for safety
egparedes May 7, 2025
19105af
Fix noxfile tests in pre-commit
egparedes May 7, 2025
3d895d3
Update docs/development/tools/ci-infrastructure.md
egparedes May 7, 2025
ca0140f
Update docs/development/tools/ci-infrastructure.md
egparedes May 7, 2025
27a4946
Final cleanups
egparedes May 7, 2025
1911ab4
Get rid of custom NUM_PROCESSES variable and use standard PYTEST_XDIS…
egparedes May 7, 2025
c43de08
Remove unused git diff cache from noxfile_utils
egparedes May 7, 2025
3cf2b4a
Fix typos
egparedes May 7, 2025
72a1815
Merge branch 'main' into new-conditionals
egparedes May 7, 2025
c6429f4
More cleanups
egparedes May 7, 2025
cddca1a
Clean up pre-commit tests for noxfile_utils
egparedes May 8, 2025
3f8e49d
Increase slurm time limit for cscs-ci
egparedes May 8, 2025
8ed755a
Test CSCS-cI changes
egparedes May 8, 2025
53e7bb4
Try again
egparedes May 8, 2025
0124e4e
Another try following Andreas Fink tip
egparedes May 8, 2025
2c252f3
Fix typos
egparedes May 8, 2025
2033c6c
Add missing `jq` tools to base dockerfile
egparedes May 8, 2025
05b8220
Merge branch 'main' into new-conditionals
egparedes May 8, 2025
22bc05c
Add github remote in actual docker image
egparedes May 8, 2025
0dbd2ff
More fixes
egparedes May 8, 2025
21deb87
Add noxfile_utils.py to session path filters
egparedes May 8, 2025
c3453d5
Rename commit_spec variables
egparedes May 8, 2025
67ac9e0
Remove unneeded list
egparedes May 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 0 additions & 38 deletions .github/workflows/test-eve-fallback.yml

This file was deleted.

13 changes: 5 additions & 8 deletions .github/workflows/test-eve.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@ on:
pull_request:
branches:
- main
paths: # Run when gt4py.eve files (or package settings) are changed
- "src/gt4py/eve/**"
- "tests/eve_tests/**"
- ".github/workflows/**"
- "*.lock"
- "*.toml"
- "*.yml"

jobs:
# First job to read Python versions from .python-versions file
Expand All @@ -37,6 +30,8 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Use a deep clone to get target PR zbranch

- name: Install uv and set the python version
uses: astral-sh/setup-uv@v5
Expand All @@ -48,5 +43,7 @@ jobs:
- name: Run 'eve' tests with nox
env:
NUM_PROCESSES: auto
GT4PY_CI_NOX_RUN_ONLY_IF_CHANGED_FROM: "origin/${{ github.base_ref }}"
GT4PY_CI_NOX_VERBOSE: 1
shell: bash
run: uv run nox -s test_eve-${{ matrix.python-version }}
run: uvx nox -s test_eve-${{ matrix.python-version }}
118 changes: 70 additions & 48 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@

import os
import pathlib
import sys
import types
from collections.abc import Sequence
from typing import Final, Literal, TypeAlias
from collections.abc import Callable, Sequence
from unittest import mock
from typing import Any, Final, Literal, TypeAlias, TypeVar

import nox

with mock.patch("sys.path", [".", *sys.path]):
import noxfile_utils as nox_utils

#: This should just be `pytest.ExitCode.NO_TESTS_COLLECTED` but `pytest`
#: is not guaranteed to be available in the venv where `nox` is running.
NO_TESTS_COLLECTED_EXIT_CODE: Final = 5
Expand All @@ -39,6 +44,9 @@
"test_storage-3.11(cpu)",
]


PYTHON_VERSIONS: Final[list[str]] = pathlib.Path(".python-versions").read_text().splitlines()

# -- Parameter sets --
DeviceOption: TypeAlias = Literal["cpu", "cuda11", "cuda12", "rocm4_3", "rocm5_0"]
DeviceNoxParam: Final = types.SimpleNamespace(
Expand Down Expand Up @@ -69,8 +77,13 @@
}


# -- nox sessions --
@nox.session(python=["3.10", "3.11"], tags=["cartesian"])
# -- Sessions --
@nox_utils.customize_session(
python=PYTHON_VERSIONS,
tags=["cartesian"],
env_vars=["NUM_PROCESSES"],
ignore_paths=["src/gt4py/next/*", "tests/next_tests/**", "examples/**", "*.md", "*.rst"],
)
@nox.parametrize("device", [DeviceNoxParam.cpu, DeviceNoxParam.cuda12])
@nox.parametrize("codegen", [CodeGenNoxParam.internal, CodeGenNoxParam.dace])
def test_cartesian(
Expand All @@ -83,13 +96,13 @@ def test_cartesian(
codegen_settings = CodeGenTestSettings[codegen]
device_settings = DeviceTestSettings[device]

_install_session_venv(
nox_utils.install_session_venv(
session,
extras=["performance", "testing", *codegen_settings["extras"], *device_settings["extras"]],
groups=["test"],
)

num_processes = os.environ.get("NUM_PROCESSES", "auto")
num_processes = session.env.get("NUM_PROCESSES", "auto")
markers = " and ".join(codegen_settings["markers"] + device_settings["markers"])

session.run(
Expand All @@ -104,13 +117,26 @@ def test_cartesian(
)


@nox.session(python=["3.10", "3.11"], tags=["cartesian", "next", "cpu"])
@nox_utils.customize_session(
python=PYTHON_VERSIONS,
tags=["cartesian", "next", "cpu"],
env_vars=["NUM_PROCESSES"],
paths=[ # Run when gt4py.eve files (or package settings) are changed
"src/gt4py/eve/*",
"tests/eve_tests/*",
".github/workflows/*",
"*.lock",
"*.toml",
"*.yml",
"noxfile.py",
],
)
def test_eve(session: nox.Session) -> None:
"""Run 'gt4py.eve' tests."""

_install_session_venv(session, groups=["test"])
nox_utils.install_session_venv(session, groups=["test"])

num_processes = os.environ.get("NUM_PROCESSES", "auto")
num_processes = session.env.get("NUM_PROCESSES", "auto")

session.run(
*f"pytest --cache-clear -sv -n {num_processes}".split(),
Expand All @@ -123,11 +149,11 @@ def test_eve(session: nox.Session) -> None:
)


@nox.session(python=["3.10", "3.11"])
@nox.session(python=PYTHON_VERSIONS)
def test_examples(session: nox.Session) -> None:
"""Run and test documentation workflows."""

_install_session_venv(session, extras=["testing"], groups=["docs", "test"])
nox_utils.install_session_venv(session, extras=["testing"], groups=["docs", "test"])

session.run(*"jupytext docs/user/next/QuickstartGuide.md --to .ipynb".split())
session.run(*"jupytext docs/user/next/advanced/*.md --to .ipynb".split())
Expand All @@ -145,7 +171,18 @@ def test_examples(session: nox.Session) -> None:
)


@nox.session(python=["3.10", "3.11"], tags=["next"])
@nox_utils.customize_session(
python=PYTHON_VERSIONS,
tags=["next"],
env_vars=["NUM_PROCESSES"],
ignore_paths=[ # Skip when only gt4py.cartesian or doc files have been updated
"src/gt4py/cartesian/**",
"tests/cartesian_tests/**",
"examples/**",
"*.md",
"*.rst",
],
)
@nox.parametrize(
"meshlib",
[
Expand Down Expand Up @@ -175,13 +212,13 @@ def test_next(
mesh_markers.append("requires_atlas")
groups.append("frameworks")

_install_session_venv(
nox_utils.install_session_venv(
session,
extras=["performance", "testing", *codegen_settings["extras"], *device_settings["extras"]],
groups=groups,
)

num_processes = os.environ.get("NUM_PROCESSES", "auto")
num_processes = session.env.get("NUM_PROCESSES", "auto")
markers = " and ".join(codegen_settings["markers"] + device_settings["markers"] + mesh_markers)

session.run(
Expand All @@ -198,14 +235,14 @@ def test_next(
)


@nox.session(python=["3.10", "3.11"], tags=["cartesian", "next", "cpu"])
@nox.session(python=PYTHON_VERSIONS, tags=["cartesian", "next", "cpu"])
def test_package(session: nox.Session) -> None:
"""Run 'gt4py' package level tests."""

_install_session_venv(session, groups=["test"])
nox_utils.install_session_venv(session, groups=["test"])

session.run(
*f"pytest --cache-clear -sv".split(),
*"pytest --cache-clear -sv".split(),
str(pathlib.Path("tests") / "package_tests"),
*session.posargs,
)
Expand All @@ -218,7 +255,20 @@ def test_package(session: nox.Session) -> None:
)


@nox.session(python=["3.10", "3.11"], tags=["cartesian", "next"])
@nox_utils.customize_session(
python=PYTHON_VERSIONS,
tags=["cartesian", "next"],
env_vars=["NUM_PROCESSES"],
paths=[ # Run when gt4py.storage files (or package settings) are changed
"src/gt4py/storage/**",
"src/gt4py/cartesian/backend/**", # For DaCe storages
"tests/storage_tests/**",
".github/workflows/**",
"*.lock", "*.toml",
"*.yml",
"noxfile.py",
],
)
@nox.parametrize("device", [DeviceNoxParam.cpu, DeviceNoxParam.cuda12])
def test_storage(
session: nox.Session,
Expand All @@ -228,11 +278,11 @@ def test_storage(

device_settings = DeviceTestSettings[device]

_install_session_venv(
nox_utils.install_session_venv(
session, extras=["performance", "testing", *device_settings["extras"]], groups=["test"]
)

num_processes = os.environ.get("NUM_PROCESSES", "auto")
num_processes = session.env.get("NUM_PROCESSES", "auto")
Copy link
Copy Markdown
Contributor

@edopao edopao May 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We changed session.env.get("NUM_PROCESSES", "auto") to os.environ.get("NUM_PROCESSES", "auto") because we saw problems in the CI pipelines, in #1869.
It seems like the problem is back with this change, see the CI log: 288 workers [168 items]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right, reading from session.env at this point was always a bug from our side. I was fooled by the include_outer_env option of session.run() but it doesn't apply here because we are not running a command in the session, only reading the environment.

The solution I've implemented now is to get rid of our custom NUM_PROCESSES variable and use instead PYTEST_XDIST_AUTO_NUM_WORKERS as documented in pytest-xdist docs: https://pytest-xdist.readthedocs.io/en/stable/distribution.html#running-tests-across-multiple-cpus

Do you agree @edopao ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this solution. However, I see that you also added --dist loadgroup and I don't understand the need for that. We do not use the xdist_group mark in our tests, right?

Tests are grouped by the xdist_group mark. Groups are distributed to available workers as whole units. This guarantees that all tests with same xdist_group name run in the same worker.

@pytest.mark.xdist_group(name="group1")
def test1():
    pass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, this is a way to allow to serialize some tests. We maybe need this for the tests with SDFGConvertible. I see that one test is failing in https://github.com/GridTools/gt4py/actions/runs/14888031268/job/41812791488 but the log does not show the reason.

Copy link
Copy Markdown
Contributor Author

@egparedes egparedes May 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this option allows to group together tests that should be executed by the same process. It was already used in cartesian and I adopted it now for all other sessions, since when groups are not used in the tests, it just falls back to the default behavior.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, we added the option in cartesian to mitigate an issue (test dependencies) in our test setup. See #1849 for more details.

If your tests don't have implicit test dependencies, the default way of scheduling should work out just fine. I'd stick with the default if you can.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If your tests don't have implicit test dependencies, the default way of scheduling should work out just fine. I'd stick with the default if you can.

The loadgroup setting uses the default load policy for unmarked tests, which I think it is exactly the behavior we want:

Tests without the xdist_group mark are distributed normally as in the --dist=load mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right - I forgot about that part. All good then. I agree, that is a good default behavior.

markers = " and ".join(device_settings["markers"])

session.run(
Expand All @@ -246,31 +296,3 @@ def test_storage(
str(pathlib.Path("src") / "gt4py" / "storage"),
success_codes=[0, NO_TESTS_COLLECTED_EXIT_CODE],
)


# -- utils --
def _install_session_venv(
session: nox.Session,
*args: str | Sequence[str],
extras: Sequence[str] = (),
groups: Sequence[str] = (),
) -> None:
"""Install session packages using uv."""
session.run_install(
"uv",
"sync",
*("--python", session.python),
"--no-dev",
*(f"--extra={e}" for e in extras),
*(f"--group={g}" for g in groups),
env={key: value for key, value in os.environ.items()}
| {"UV_PROJECT_ENVIRONMENT": session.virtualenv.location},
)
for item in args:
session.run_install(
"uv",
"pip",
"install",
*((item,) if isinstance(item, str) else item),
env={"UV_PROJECT_ENVIRONMENT": session.virtualenv.location},
)
Loading
Loading