Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f12d722
Require Pyccel version >= 2.2.3
yguclu Mar 22, 2026
030356a
Require h5py >= 3.16
yguclu Mar 22, 2026
3098869
Return error code on failure of psydac compile and test commands
yguclu Mar 22, 2026
d07ba19
Add unit tests which should always fail in CI
yguclu Mar 23, 2026
29416a9
Clean up .gitignore
yguclu Mar 23, 2026
990acca
Rename failing test to avoid automatic collection
yguclu Mar 23, 2026
7e7a289
Add useless copyright header to __init__.py for consistency
yguclu Mar 23, 2026
318a15a
Copy pytest.ini into CWD when running Pytest directly
yguclu Mar 23, 2026
561c7a1
Use pytest.ini for coverage configuration
yguclu Mar 24, 2026
42bbe0d
Check that `psydac test` command reports failures correctly
yguclu Mar 24, 2026
e8195f0
Migrate from pytest.ini to pytest.toml
yguclu Mar 24, 2026
82b568a
Require NumPy >= 2.1 to support Python >= 3.10
yguclu Mar 24, 2026
310e34c
Update psydac_test.py: pytest.ini -> pytest.toml
yguclu Mar 24, 2026
c342233
Restrict numpy version to < 2.4
yguclu Mar 24, 2026
6067a21
Replace pytest.ini w/ pytest.toml in coverage tests
yguclu Mar 24, 2026
680c7ff
Clarify version requirements in pyproject.toml
yguclu Mar 24, 2026
9ca350e
Don't run postprocessing unit tests with pytest-xdist:
yguclu Mar 24, 2026
1583bd5
Run example tests in separate folder
yguclu Mar 24, 2026
85ea890
Rename CI test directory: pytest -> scratch
yguclu Mar 24, 2026
3083bc8
Don't use nonexistent pytest.ini as test trigger
yguclu Mar 24, 2026
0be33a3
Check Pyccel flags in test folder
yguclu Mar 24, 2026
2838aa6
Install h5py from PyPI in CI
yguclu Mar 24, 2026
637a38f
Update CHANGELOG.md
yguclu Mar 24, 2026
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
26 changes: 7 additions & 19 deletions .github/actions/parallel_h5py/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,20 @@ runs:
echo $HDF5_DIR
echo "HDF5_DIR=$HDF5_DIR" >> $GITHUB_ENV

# To be deactivated when a new version of h5py is released on PyPI
- name: Install h5py in parallel mode
shell: bash
run: |
export CC="mpicc"
export HDF5_MPI="ON"
git clone https://github.com/h5py/h5py.git
cd h5py
pip install -v .
pip install h5py --no-cache-dir --no-binary h5py
pip list

# To be reactivated when a new version of h5py is released on PyPI
# - name: Install h5py in parallel mode
# shell: bash
# run: |
# export CC="mpicc"
# export HDF5_MPI="ON"
# pip install h5py --no-cache-dir --no-binary h5py
# pip list

- name: Check parallel h5py installation
shell: bash
run: |
python -c "
from mpi4py import MPI
import h5py
# This particular instantiation of h5py.File will fail if parallel h5py isn't installed
f = h5py.File('parallel_test.hdf5', 'w', driver='mpio', comm=MPI.COMM_WORLD)
print(f)"
python -c "
from mpi4py import MPI
import h5py
# This particular instantiation of h5py.File will fail if parallel h5py isn't installed
f = h5py.File('parallel_test.hdf5', 'w', driver='mpio', comm=MPI.COMM_WORLD)
print(f)"
40 changes: 26 additions & 14 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ on:
branches: [ devel, main ]
paths:
- 'psydac/**'
- 'pytest.ini'
- 'pyproject.toml'

pull_request:
Expand Down Expand Up @@ -119,27 +118,37 @@ jobs:
pip install .[test]
pip freeze

- name: Test Pyccel optimization flags
- name: Initialize test directory
run: |
mkdir scratch

- name: Test Pyccel optimization flags
working-directory: ./scratch
run: >-
cp $GITHUB_WORKSPACE/psydac/pytest.toml . &&
pytest --pyargs psydac -m pyccel --capture=no

- name: Initialize test directory
- name: Verify that 'psydac test' reports failures correctly
working-directory: ./scratch
# We run a test which is not collected by pytest by default, and we expect it to fail.
# If it fails (non-zero), the "echo" runs and the script exits with 0 (success).
# If it passes (zero), the "exit 1" runs and the GitHub Action fails.
run: |
mkdir pytest
psydac test --mod psydac.cmd.tests.failing_test && { echo "Test passed but should have failed!"; exit 1; } || echo "Test failed as expected."

- name: Run coverage tests on macOS
if: matrix.os == 'macos-14'
working-directory: ./pytest
working-directory: ./scratch
run: >-
cp $GITHUB_WORKSPACE/psydac/pytest.toml . &&
pytest -n auto
--cov psydac
--cov-config $GITHUB_WORKSPACE/pyproject.toml
--cov-report xml
--pyargs psydac -m "not mpi and not petsc" -ra

- name: Run single-process tests with Pytest on Ubuntu
if: matrix.os == 'ubuntu-24.04'
working-directory: ./pytest
working-directory: ./scratch
run: |
psydac test

Expand All @@ -148,35 +157,38 @@ jobs:
uses: codacy/codacy-coverage-reporter-action@v1.3.0
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: ./pytest/coverage.xml
coverage-reports: ./scratch/coverage.xml

- name: Print detailed coverage results on macOS
if: matrix.os == 'macos-14'
working-directory: ./pytest
working-directory: ./scratch
run: |
coverage report --ignore-errors --show-missing --sort=cover

- name: Run MPI tests with Pytest
working-directory: ./pytest
working-directory: ./scratch
run: |
psydac test --mpi

- name: Run single-process PETSc tests with Pytest
working-directory: ./pytest
working-directory: ./scratch
run: |
psydac test --petsc

- name: Run MPI PETSc tests with Pytest
working-directory: ./pytest
working-directory: ./scratch
run: |
psydac test --mpi --petsc

- name: Run single-process example tests with Pytest on Ubuntu
if: matrix.os == 'ubuntu-24.04'
run: |
working-directory: ./scratch
run: >-
cp $GITHUB_WORKSPACE/psydac/pytest.toml . &&
cp -r $GITHUB_WORKSPACE/examples . &&
python -m pytest examples/feec

- name: Remove test directory
if: always()
run: |
rm -rf pytest
rm -rf scratch
12 changes: 2 additions & 10 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,20 @@ build
*build*
*egg*
*dist*
usr
*cache*

*.swp
*.log

doc/_static
doc/_build
doc/api-python

psydac/core/bsp-f2py*
psydac/core/bspmodule.c
.env

# pytest directories
__test__/

# pycharm directory
.idea

# Visual Studio Code workspace files
# Visual Studio Code
*.code-workspace
**/.vscode/

# Meson lock files
*/.wraplock
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,24 @@ All notable changes to this project will be documented in this file.

### Fixed

- #579 : Require `h5py>=3.16` which installs correctly with `setuptools>=81.0`
- #579 : Don't run postprocessing unit tests with `pytest-xdist` because `h5py` is not thread-safe
Comment thread
campospinto marked this conversation as resolved.
- #579 : Return error code on failure of the `psydac test` and `psydac compile` commands
- #577 : Fix installation following release of Pyccel 2.2
- #571 : Fix correct application of the sum factorization algorithm
- #570 : Optimize PSYDAC logo
- #565 : Expand editable install info in `README.md`
- #566 : Fix command `psydac test --mpi` on Ubuntu machines
- [DEVELOPER] Update CI installation of `h5py` and `petsc4py` after release of `setuptools` 81.0
- [DEVELOPER] Update CI installation of `petsc4py` after release of `setuptools` 81.0
- [DEVELOPER] Check correct reporting of failure for `psydac test` command in CI testing
- [DEVELOPER] Use correct configuration file in coverage CI tests

### Changed

- #579 : Require `pyccel>=2.2.3` which can compile all kernels with C
- #579 : Require `numpy>=2.1` to support Python >= 3.10
- #579 : Require `pytest>=9.0` and use `pytest.toml` instead of `pytest.ini` for Pytest configuration
- #579 : Move coverage configuration from `pyproject.toml` to `psydac/pytest.toml`
- [DEVELOPER] Do not check file changes to trigger testing workflow on PRs
- [DEVELOPER] Run documentation workflow on pushes to `devel` whenever `README.md` is modified
- [DEVELOPER] Run testing and documentation workflows on PRs only when set to "ready for review"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ A developer wanting to modify the latest source code on GitHub should skip that
git clone --recurse-submodules https://github.com/pyccel/psydac.git
cd psydac

pip install meson-python "pyccel>=2.2.2"
pip install meson-python "pyccel>=2.2.3"
pip install --no-build-isolation --editable ".[test]"
```

Expand Down
2 changes: 1 addition & 1 deletion docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ At this point the PSYDAC library may be installed from PyPI in **standard mode**
git clone --recurse-submodules https://github.com/pyccel/psydac.git
cd psydac

pip install meson-python "pyccel>=2.1.0"
pip install meson-python "pyccel>=2.2.3"
pip install --no-build-isolation --editable ".[test]"
```
An equivalent repository address for the `clone` command is `git@github.com:pyccel/psydac.git`, which requires a GitHub account.
Expand Down
11 changes: 11 additions & 0 deletions psydac/api/tests/test_postprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def build_2_cubes():
###############################################################################
# Output Manager tests #
###############################################################################
@pytest.mark.xdist_group('h5py')
@pytest.mark.parametrize( 'dtype', ['float', 'complex'] )
def test_add_spaces(dtype):
domain = Square('D')
Expand Down Expand Up @@ -206,6 +207,7 @@ def test_add_spaces(dtype):
os.remove('test_add_spaces_single_patch.yml')


@pytest.mark.xdist_group('h5py')
@pytest.mark.parametrize( 'dtype', ['float', 'complex'] )
def test_export_fields_serial(dtype):
domain = Square('D')
Expand Down Expand Up @@ -287,6 +289,7 @@ def test_export_fields_serial(dtype):
os.remove('test_export_fields_serial.h5')


@pytest.mark.xdist_group('h5py')
@pytest.mark.mpi
def test_export_fields_parallel():
comm = MPI.COMM_WORLD
Expand Down Expand Up @@ -329,6 +332,7 @@ def test_export_fields_parallel():
###############################################################################
# Output Manager and PostProcess Manager tests #
###############################################################################
@pytest.mark.xdist_group('h5py')
@pytest.mark.parametrize('domain', [Square(), Cube()])
@pytest.mark.parametrize( 'dtype', ['float', 'complex'] )
def test_reconstruct_spaces_topological_domain(domain, dtype):
Expand Down Expand Up @@ -398,6 +402,7 @@ def test_reconstruct_spaces_topological_domain(domain, dtype):
os.remove("test_reconstruct_spaces_topological_domain_2.yml")


@pytest.mark.xdist_group('h5py')
@pytest.mark.parametrize('domain, seq', [(Square(), ['h1', 'hdiv', 'l2']), (Square(), ['h1', 'hcurl', 'l2']), (Cube(), None)])
@pytest.mark.parametrize( 'dtype', ['float', 'complex'] )
def test_reconstruct_DerhamSequence_topological_domain(domain, seq, dtype):
Expand Down Expand Up @@ -456,6 +461,7 @@ def test_reconstruct_DerhamSequence_topological_domain(domain, seq, dtype):
os.remove('test_reconstruct_DerhamSequence_topological_domain.yml')


@pytest.mark.xdist_group('h5py')
@pytest.mark.parametrize('geometry, seq', [('identity_2d.h5', ['h1', 'hdiv', 'l2']),
('identity_2d.h5', ['h1', 'hcurl', 'l2']),
('identity_3d.h5', None),
Expand Down Expand Up @@ -521,6 +527,8 @@ def test_reconstruct_DerhamSequence_discrete_domain(geometry, seq, dtype):
os.remove('test_reconstruct_DerhamSequence_discrete_domain_2.yml')
os.remove('test_reconstruct_DerhamSequence_discrete_domain.yml')


@pytest.mark.xdist_group('h5py')
@pytest.mark.parametrize( 'dtype', ['float', 'complex'] )
def test_reconstruct_multipatch(dtype):
bounds1 = (0.5, 1.)
Expand Down Expand Up @@ -602,6 +610,7 @@ def test_reconstruct_multipatch(dtype):
assert value1 == value2


@pytest.mark.xdist_group('h5py')
def test_incorrect_arg_export_to_vtk():
domain = Square()
space = ScalarFunctionSpace('V', domain)
Expand Down Expand Up @@ -646,6 +655,7 @@ def test_incorrect_arg_export_to_vtk():
os.remove("test_incorrect_arg_export_to_vtk.h5")


@pytest.mark.xdist_group('h5py')
@pytest.mark.mpi
@pytest.mark.parametrize('geometry', ['identity_2d.h5',
'identity_3d.h5',
Expand Down Expand Up @@ -756,6 +766,7 @@ def test_parallel_export_discrete_domain(geometry, kind, space, dtype):
os.remove("test_parallel_export_discrete_domain.h5")


@pytest.mark.xdist_group('h5py')
@pytest.mark.mpi
@pytest.mark.parametrize('domain', [
Square(),
Expand Down
11 changes: 9 additions & 2 deletions psydac/cmd/psydac_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
The purpose of this module is to pyccelize all PSYDAC kernels, in the case
that these were modified after an editable installation of PSYDAC.
"""
from psydac.cmd.argparse_helpers import add_help_flag, add_version_flag
from psydac.cmd.argparse_helpers import (
add_help_flag,
add_version_flag,
exit_with_error_message,
)

__all__ = (
'setup_psydac_compile_parser',
Expand Down Expand Up @@ -72,4 +76,7 @@ def psydac_compile(*, language):

print('Executing command:')
print(f' {" ".join(cmd)}\n')
subprocess.run(cmd, shell=False)
result = subprocess.run(cmd, shell=False)

if result.returncode != 0:
exit_with_error_message('failed to compile PSYDAC kernels.')
27 changes: 18 additions & 9 deletions psydac/cmd/psydac_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
The purpose of this module is to pyccelize all PSYDAC kernels, in the case
that these were modified after an editable installation of PSYDAC.
"""
from psydac.cmd.argparse_helpers import add_help_flag, add_version_flag, exit_with_error_message
from psydac.cmd.argparse_helpers import (
add_help_flag,
add_version_flag,
exit_with_error_message,
)

__all__ = (
'setup_psydac_test_parser',
Expand Down Expand Up @@ -90,17 +94,17 @@ def psydac_test(*, mod, mpi, petsc, verbose, exitfirst):
print(f'Removing existing Pytest cache directory: {cache_dir}\n', flush=True)
shutil.rmtree(cache_dir)

# If no pytest.ini file exists in the current working directory, copy it
# If no pytest.toml file exists in the current working directory, copy it
# from the parent directory of this script (which is installed with PSYDAC)
if not os.path.isfile('pytest.ini'):
if not os.path.isfile('pytest.toml'):
script_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(script_dir)
pytest_ini = os.path.join(parent_dir, 'pytest.ini')
if not os.path.isfile(pytest_ini):
exit_with_error_message(f'could not find pytest.ini file in {parent_dir}')
pytest_cfg = os.path.join(parent_dir, 'pytest.toml')
if not os.path.isfile(pytest_cfg):
exit_with_error_message(f'could not find pytest.toml file in {parent_dir}')
else:
print(f'Copying pytest.ini from: {parent_dir}\n', flush=True)
shutil.copy(pytest_ini, os.getcwd())
print(f'Copying pytest.toml from: {parent_dir}\n', flush=True)
shutil.copy(pytest_cfg, os.getcwd())

# Build the list of flags for pytest
flags = []
Expand Down Expand Up @@ -166,4 +170,9 @@ def psydac_test(*, mod, mpi, petsc, verbose, exitfirst):
time.sleep(0.1) # ensure the print is shown before subprocess output

# Execute the command
subprocess.run(cmd, shell=False, env=os.environ)
result = subprocess.run(cmd, shell=False, env=os.environ)

if result.returncode != 0:
msg = 'the PSYDAC test suite failed. '\
'Please check the output above for details.'
exit_with_error_message(msg)
5 changes: 5 additions & 0 deletions psydac/cmd/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#---------------------------------------------------------------------------#
# This file is part of PSYDAC which is released under MIT License. See the #
# LICENSE file or go to https://github.com/pyccel/psydac/blob/devel/LICENSE #
# for full license details. #
#---------------------------------------------------------------------------#
26 changes: 26 additions & 0 deletions psydac/cmd/tests/failing_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#---------------------------------------------------------------------------#
# This file is part of PSYDAC which is released under MIT License. See the #
# LICENSE file or go to https://github.com/pyccel/psydac/blob/devel/LICENSE #
# for full license details. #
#---------------------------------------------------------------------------#
"""
This module contains only tests which are designed to fail, to check that the
error handling in the `psydac test` command works correctly. This will be used
in the CI to verify that the test suite correctly reports failures, by running
`psydac test` on this file and verifying that the CI fails as expected.
"""
import pytest


msg_tmp = "This {}test is designed to fail to check error handling in the test suite."

def test_failure():
assert False, msg_tmp.format("")

@pytest.mark.mpi
def test_failure_mpi():
assert False, msg_tmp.format("MPI ")

@pytest.mark.petsc
def test_failure_petsc():
assert False, msg_tmp.format("PETSc ")
Loading
Loading