From e115e2b55cdf768bccde0ec9f5ee367e617ad805 Mon Sep 17 00:00:00 2001 From: Lisandro Dalcin Date: Thu, 5 Oct 2023 14:16:28 +0300 Subject: [PATCH] Refactor wheel testing --- .cibw/test-Linux-debian.sh | 16 ++ .cibw/test-Linux-fedora.sh | 25 +++ .cibw/test-Linux-ubuntu.sh | 17 ++ .cibw/test-Windows.sh | 5 + .cibw/test-basic.sh | 104 +++++++++ .cibw/test-macOS.sh | 27 +++ .github/workflows/cd-wheel.yml | 378 +++++++++++++++++++++++---------- 7 files changed, 464 insertions(+), 108 deletions(-) create mode 100755 .cibw/test-Linux-debian.sh create mode 100755 .cibw/test-Linux-fedora.sh create mode 100755 .cibw/test-Linux-ubuntu.sh create mode 100755 .cibw/test-Windows.sh create mode 100755 .cibw/test-basic.sh create mode 100755 .cibw/test-macOS.sh diff --git a/.cibw/test-Linux-debian.sh b/.cibw/test-Linux-debian.sh new file mode 100755 index 0000000..40975fb --- /dev/null +++ b/.cibw/test-Linux-debian.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -euo pipefail + +packages=( + python3.11-venv + pypy3 + libmpich12 + libopenmpi3 +) +sudo=$(command -v sudo || true) +$sudo apt update -y +$sudo apt install -y ${packages[@]} +$sudo ln -sr /usr/lib/$(arch)-linux-gnu/libmpi{ch,}.so.12 + +sdir=$(cd "$(dirname -- "$0")" && pwd -P) +$sdir/test-basic.sh diff --git a/.cibw/test-Linux-fedora.sh b/.cibw/test-Linux-fedora.sh new file mode 100755 index 0000000..0a0f612 --- /dev/null +++ b/.cibw/test-Linux-fedora.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -euo pipefail + +packages=( + python3.6 + python3.7 + python3.8 + python3.9 + python3.10 + python3.11 + python3.12 + pypy3.9 + pypy3.10 + mpich + openmpi +) +sudo=$(command -v sudo || true) +opts=--setopt=install_weak_deps=False +$sudo dnf install -y $opts ${packages[@]} +set +u +source /etc/profile.d/modules.sh +set -u + +sdir=$(cd "$(dirname -- "$0")" && pwd -P) +$sdir/test-basic.sh diff --git a/.cibw/test-Linux-ubuntu.sh b/.cibw/test-Linux-ubuntu.sh new file mode 100755 index 0000000..7287c4a --- /dev/null +++ b/.cibw/test-Linux-ubuntu.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -euo pipefail + +packages=( + python3.10-venv + python3.11-venv + pypy3 + libmpich12 + libopenmpi3 +) +sudo=$(command -v sudo || true) +$sudo apt update -y +$sudo apt install -y ${packages[@]} +$sudo ln -sr /usr/lib/$(arch)-linux-gnu/libmpi{ch,}.so.12 + +sdir=$(cd "$(dirname -- "$0")" && pwd -P) +$sdir/test-basic.sh diff --git a/.cibw/test-Windows.sh b/.cibw/test-Windows.sh new file mode 100755 index 0000000..134ff5f --- /dev/null +++ b/.cibw/test-Windows.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -euo pipefail + +sdir=$(cd "$(dirname -- "$0")" && pwd -P) +$sdir/test-basic.sh diff --git a/.cibw/test-basic.sh b/.cibw/test-basic.sh new file mode 100755 index 0000000..68359e7 --- /dev/null +++ b/.cibw/test-basic.sh @@ -0,0 +1,104 @@ +#!/bin/bash +set -euo pipefail + +wheelhouse="${1:-dist}" + +PYTHON=( + "${python36-python3.6}" + "${python37-python3.7}" + "${python38-python3.8}" + "${python39-python3.9}" + "${python310-python3.10}" + "${python311-python3.11}" + "${python312-python3.12}" + "${pypy37-pypy3.7}" + "${pypy38-pypy3.8}" + "${pypy39-pypy3.9}" + "${pypy310-pypy3.10}" +) + +if [[ $(uname) =~ NT ]]; then + MPI=(impi msmpi) + bin="Scripts" + exe=".exe" +else + MPI=(mpich openmpi) + bin="bin" + exe="" +fi + +venvroot=$(mktemp -d) +trap "rm -rf $venvroot" EXIT +export PIP_QUIET=1 + +function setup-python { + test -z $(command -v "$python") && return 1 + venvdir=$(mktemp -d -p "$venvroot" XXX) + "$python" -m venv "$venvdir" + python="$venvdir/$bin/python$exe" + "$python" --version + "$python" -m pip install pip --upgrade +} + +function setup-mpi4py { + "$python" -m pip install mpi4py --no-index --find-links="$wheelhouse" + test $? -ne 0 && return 1 + "$python" -m mpi4py --version +} + +function setup-mpi { + local mpi=$1 + if command -v brew > /dev/null; then + brew unlink mpich openmpi > /dev/null + brew link $mpi > /dev/null + elif command -v module > /dev/null; then + module unload mpi + module load mpi/$mpi-$(arch) + else + export MPI4PY_MPIABI=$mpi + fi +} + +function teardown-mpi { + local mpi=$1 + if command -v brew > /dev/null; then + brew unlink $mpi > /dev/null + elif command -v module > /dev/null; then + module unload mpi/$mpi-$(arch) + fi + unset MPI4PY_MPIABI + unset MPI4PY_LIBMPI +} + +function mpi4py-test-basic { + "$python" -m mpi4py --mpi-std-version + "$python" -m mpi4py --mpi-lib-version | head -n 1 +} + +for python in ${PYTHON[@]}; do + test -z $(command -v "$python") && continue + pyversion=$("$python" -c "import sys; print(sys.version.split()[0])") + pyimpname=$("$python" -c "import sys; print(sys.implementation.name)") + echo "::group::Python $pyversion [$pyimpname]" + setup-python || continue + setup-mpi4py || continue + for mpi in ${MPI[@]}; do + echo "* Use MPI=$mpi" + setup-mpi $mpi + echo "- Test MPIABI discovery" + mpi4py-test-basic + if [ $mpi == $mpi ]; then + export MPI4PY_MPIABI=$mpi + echo "- Test MPIABI=$MPI4PY_MPIABI" + mpi4py-test-basic + fi + if [ $mpi == mpich -o $mpi == openmpi ]; then + export MPI4PY_MPIABI=mpi31-$mpi + echo "- Test MPIABI=$MPI4PY_MPIABI" + mpi4py-test-basic + fi + teardown-mpi $mpi + echo "" + done + echo "::endgroup::" +done diff --git a/.cibw/test-macOS.sh b/.cibw/test-macOS.sh new file mode 100755 index 0000000..8f982bd --- /dev/null +++ b/.cibw/test-macOS.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -euo pipefail + +packages_py=( + python@3.8 + python@3.9 + python@3.10 + python@3.11 + python@3.12 + pypy3.9 + pypy3.10 +) +packages_mpi=( + mpich + openmpi +) +brew install ${packages_py[@]} +for mpi in ${packages_mpi[@]}; do + brew unlink $mpi || true +done +for mpi in ${packages_mpi[@]}; do + brew install $mpi + brew unlink $mpi +done + +sdir=$(cd "$(dirname -- "$0")" && pwd -P) +$sdir/test-basic.sh diff --git a/.github/workflows/cd-wheel.yml b/.github/workflows/cd-wheel.yml index 8bfbe0f..00e771c 100644 --- a/.github/workflows/cd-wheel.yml +++ b/.github/workflows/cd-wheel.yml @@ -252,149 +252,311 @@ jobs: name: wheel-${{ runner.os }} path: dist/*.whl - test-setup: + test-Linux: + if: ${{ contains(needs.setup.outputs.os-arch-list, '"Linux-x86_64"') }} needs: [setup, merge] - runs-on: 'ubuntu-latest' - outputs: - matrix-test-cf: ${{ steps.setup.outputs.matrix-test-cf }} - matrix-test-gh: ${{ steps.setup.outputs.matrix-test-gh }} + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + runner: + - ubuntu-latest + steps: - uses: actions/checkout@v4 - - if: ${{ contains(needs.setup.outputs.os-arch-list, '"Linux-x86_64"') }} - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v3 with: - name: build-Linux-x86_64 - path: wheelhouse - - if: ${{ contains(needs.setup.outputs.os-arch-list, '"macOS-x86_64"') }} - uses: actions/download-artifact@v3 + name: wheel-${{ runner.os }} + path: dist + + - uses: docker://debian:latest with: - name: build-macOS-x86_64 - path: wheelhouse - - if: ${{ contains(needs.setup.outputs.os-arch-list, '"Windows-AMD64"') }} - uses: actions/download-artifact@v3 + entrypoint: /bin/bash + args: .cibw/test-Linux-debian.sh + + - uses: docker://ubuntu:latest with: - name: build-Windows-AMD64 - path: wheelhouse - - id: setup - run: python -u .cibw/setup-test.py wheelhouse >> "$GITHUB_OUTPUT" - - test-cf: - if: ${{ needs.test-setup.outputs.matrix-test-cf != '[]' }} - needs: test-setup - runs-on: ${{ (matrix.os == 'Linux' && 'ubuntu-latest' ) || - (matrix.os == 'macOS' && 'macos-latest' ) || - (matrix.os == 'Windows' && 'windows-latest') }} + entrypoint: /bin/bash + args: .cibw/test-Linux-ubuntu.sh + + - uses: docker://fedora:latest + with: + entrypoint: /bin/bash + args: .cibw/test-Linux-fedora.sh + + test-macOS: + if: contains(needs.setup.outputs.os-arch-list, '"macOS-x86_64"') + needs: [setup, merge] + runs-on: ${{ matrix.runner }} strategy: fail-fast: false matrix: - include: ${{ fromJSON(needs.test-setup.outputs.matrix-test-cf) }} - + runner: + - macos-11 + - macos-12 + - macos-13 defaults: run: - shell: bash -el {0} + shell: bash steps: - - uses: actions/checkout@v4 - - - uses: mamba-org/setup-micromamba@v1 - with: - init-shell: bash - post-cleanup: none - environment-name: test - create-args: >- - ${{ matrix.mpi }}=${{ matrix.mpi-version }} - python=${{ matrix.py }} - pip - condarc: | - show_channel_urls: true - channel_priority: >- - ${{ matrix.mpi == 'impi_rt' && 'flexible' || 'strict' }} - channels: - - conda-forge - - ${{ matrix.mpi == 'impi_rt' && 'intel' || 'nodefaults' }} - - nodefaults - - - run: | - # Tweak MPI runtime - case $(uname)-${{ matrix.mpi }} in - Linux-*) - ;; - Darwin-*) - ;; - *NT*-impi_rt) - I_MPI_ROOT=$(cygpath -w "$CONDA_PREFIX/Library") - echo "I_MPI_ROOT=$I_MPI_ROOT" >> $GITHUB_ENV - echo "$I_MPI_ROOT\\bin" >> $GITHUB_PATH - echo "$I_MPI_ROOT\\bin\\libfabric" >> $GITHUB_PATH - ;; - *NT*-msmpi) - MSMPI_ROOT=$(cygpath -w "$CONDA_PREFIX/Library") - echo "MSMPI_BIN=$MSMPI_ROOT\\bin" >> $GITHUB_ENV - echo "MSMPI_INC=$MSMPI_ROOT\\include" >> $GITHUB_ENV - echo "MSMPI_LIB64=$MSMPI_ROOT\\lib" >> $GITHUB_ENV - echo "$MSMPI_BIN" >> $GITHUB_PATH - ;; - esac - - uses: actions/download-artifact@v3 with: name: wheel-${{ runner.os }} path: dist - - run: python -m pip install mpi4py --no-index --find-links=dist - - - uses: ./.github/actions/mpi4py-test-basic - timeout-minutes: 2 - with: - shell: bash -el {0} - - - if: ${{ matrix.mpi == 'mpich' || matrix.mpi == 'openmpi' }} - uses: ./.github/actions/mpi4py-test-basic - timeout-minutes: 2 - env: - MPI4PY_MPIABI: mpi31-${{ matrix.mpi }} - with: - shell: bash -el {0} + - run: .cibw/test-${{ runner.os }}.sh - test-gh: - if: ${{ needs.test-setup.outputs.matrix-test-gh != '[]' }} - needs: test-setup + test-Windows: + if: contains(needs.setup.outputs.os-arch-list, '"Windows-AMD64"') + needs: [setup, merge] runs-on: ${{ matrix.runner }} strategy: fail-fast: false matrix: - include: ${{ fromJSON(needs.test-setup.outputs.matrix-test-gh) }} + runner: + - windows-2019 + - windows-2022 + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v4 + - uses: actions/download-artifact@v3 + with: + name: wheel-${{ runner.os }} + path: dist + + - run: .cibw/test-${{ runner.os }}.sh + if: ${{ runner.os != 'Windows' }} - - uses: mpi4py/setup-mpi@v1 + - uses: actions/setup-python@v4 with: - mpi: ${{ matrix.mpi }} + python-version: '3.8' + update-environment: false + id: cp38 - - if: ${{ matrix.mpi == 'mpich' && runner.os == 'Linux' }} - run: cd /usr/lib/$(gcc -print-multiarch) && sudo ln -s libmpi{ch,}.so.12 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + update-environment: false + id: cp39 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v4 with: - python-version: ${{ matrix.py }} + python-version: '3.10' + update-environment: false + id: cp310 - - run: python -m pip install --upgrade pip + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + update-environment: false + id: cp311 - - uses: actions/download-artifact@v3 + - uses: actions/setup-python@v4 with: - name: wheel-${{ runner.os }} - path: dist + python-version: '3.12' + update-environment: false + id: cp312 + + - uses: actions/setup-python@v4 + with: + python-version: 'pypy-3.8' + update-environment: false + id: pp38 - - run: python -m pip install mpi4py --no-index --find-links=dist + - uses: actions/setup-python@v4 + with: + python-version: 'pypy-3.9' + update-environment: false + id: pp39 - - uses: ./.github/actions/mpi4py-test-basic - timeout-minutes: 2 + - uses: actions/setup-python@v4 + with: + python-version: 'pypy-3.10' + update-environment: false + id: pp310 - - if: ${{ matrix.mpi == 'mpich' || matrix.mpi == 'openmpi' }} - uses: ./.github/actions/mpi4py-test-basic - timeout-minutes: 2 - env: - MPI4PY_MPIABI: mpi31-${{ matrix.mpi }} + - run: | + # setup Python versions + setenv() { + local name="$1" path="${2:-}" + if [[ "$(uname)" =~ NT ]] && [[ -n "$path" ]]; then + path=$(cygpath -u "$path") + fi + echo "$name=$path" >> $GITHUB_ENV; + }; + setenv python36 "" + setenv python37 "" + setenv python38 "${{ steps.cp38.outputs.python-path }}" + setenv python39 "${{ steps.cp39.outputs.python-path }}" + setenv python310 "${{ steps.cp310.outputs.python-path }}" + setenv python311 "${{ steps.cp311.outputs.python-path }}" + setenv python312 "${{ steps.cp312.outputs.python-path }}" + setenv pypy36 "" + setenv pypy37 "" + setenv pypy38 "${{ steps.pp38.outputs.python-path }}" + setenv pypy39 "${{ steps.pp39.outputs.python-path }}" + setenv pypy310 "${{ steps.pp310.outputs.python-path }}" + + - if: ${{ runner.os == 'Windows' }} + uses: mpi4py/setup-mpi@v1 + with: + mpi: intelmpi + + - if: ${{ runner.os == 'Windows' }} + uses: mpi4py/setup-mpi@v1 + with: + mpi: msmpi + + - run: .cibw/test-${{ runner.os }}.sh + +# test-setup: +# needs: [setup, merge] +# runs-on: 'ubuntu-latest' +# outputs: +# matrix-test-cf: ${{ steps.setup.outputs.matrix-test-cf }} +# matrix-test-gh: ${{ steps.setup.outputs.matrix-test-gh }} +# steps: +# - uses: actions/checkout@v4 +# - if: ${{ contains(needs.setup.outputs.os-arch-list, '"Linux-x86_64"') }} +# uses: actions/download-artifact@v3 +# with: +# name: build-Linux-x86_64 +# path: wheelhouse +# - if: ${{ contains(needs.setup.outputs.os-arch-list, '"macOS-x86_64"') }} +# uses: actions/download-artifact@v3 +# with: +# name: build-macOS-x86_64 +# path: wheelhouse +# - if: ${{ contains(needs.setup.outputs.os-arch-list, '"Windows-AMD64"') }} +# uses: actions/download-artifact@v3 +# with: +# name: build-Windows-AMD64 +# path: wheelhouse +# - id: setup +# run: python -u .cibw/setup-test.py wheelhouse >> "$GITHUB_OUTPUT" +# +# test-cf: +# if: ${{ needs.test-setup.outputs.matrix-test-cf != '[]' }} +# needs: test-setup +# runs-on: ${{ (matrix.os == 'Linux' && 'ubuntu-latest' ) || +# (matrix.os == 'macOS' && 'macos-latest' ) || +# (matrix.os == 'Windows' && 'windows-latest') }} +# strategy: +# fail-fast: false +# matrix: +# include: ${{ fromJSON(needs.test-setup.outputs.matrix-test-cf) }} +# +# defaults: +# run: +# shell: bash -el {0} +# +# steps: +# +# - uses: actions/checkout@v4 +# +# - uses: mamba-org/setup-micromamba@v1 +# with: +# init-shell: bash +# post-cleanup: none +# environment-name: test +# create-args: >- +# ${{ matrix.mpi }}=${{ matrix.mpi-version }} +# python=${{ matrix.py }} +# pip +# condarc: | +# show_channel_urls: true +# channel_priority: >- +# ${{ matrix.mpi == 'impi_rt' && 'flexible' || 'strict' }} +# channels: +# - conda-forge +# - ${{ matrix.mpi == 'impi_rt' && 'intel' || 'nodefaults' }} +# - nodefaults +# +# - run: | +# # Tweak MPI runtime +# case $(uname)-${{ matrix.mpi }} in +# Linux-*) +# ;; +# Darwin-*) +# ;; +# *NT*-impi_rt) +# I_MPI_ROOT=$(cygpath -w "$CONDA_PREFIX/Library") +# echo "I_MPI_ROOT=$I_MPI_ROOT" >> $GITHUB_ENV +# echo "$I_MPI_ROOT\\bin" >> $GITHUB_PATH +# echo "$I_MPI_ROOT\\bin\\libfabric" >> $GITHUB_PATH +# ;; +# *NT*-msmpi) +# MSMPI_ROOT=$(cygpath -w "$CONDA_PREFIX/Library") +# echo "MSMPI_BIN=$MSMPI_ROOT\\bin" >> $GITHUB_ENV +# echo "MSMPI_INC=$MSMPI_ROOT\\include" >> $GITHUB_ENV +# echo "MSMPI_LIB64=$MSMPI_ROOT\\lib" >> $GITHUB_ENV +# echo "$MSMPI_BIN" >> $GITHUB_PATH +# ;; +# esac +# +# - uses: actions/download-artifact@v3 +# with: +# name: wheel-${{ runner.os }} +# path: dist +# +# - run: python -m pip install mpi4py --no-index --find-links=dist +# +# - uses: ./.github/actions/mpi4py-test-basic +# timeout-minutes: 2 +# with: +# shell: bash -el {0} +# +# - if: ${{ matrix.mpi == 'mpich' || matrix.mpi == 'openmpi' }} +# uses: ./.github/actions/mpi4py-test-basic +# timeout-minutes: 2 +# env: +# MPI4PY_MPIABI: mpi31-${{ matrix.mpi }} +# with: +# shell: bash -el {0} +# +# test-gh: +# if: ${{ needs.test-setup.outputs.matrix-test-gh != '[]' }} +# needs: test-setup +# runs-on: ${{ matrix.runner }} +# strategy: +# fail-fast: false +# matrix: +# include: ${{ fromJSON(needs.test-setup.outputs.matrix-test-gh) }} +# +# steps: +# +# - uses: actions/checkout@v4 +# +# - uses: mpi4py/setup-mpi@v1 +# with: +# mpi: ${{ matrix.mpi }} +# +# - if: ${{ matrix.mpi == 'mpich' && runner.os == 'Linux' }} +# run: cd /usr/lib/$(gcc -print-multiarch) && sudo ln -s libmpi{ch,}.so.12 +# +# - uses: actions/setup-python@v4 +# with: +# python-version: ${{ matrix.py }} +# +# - run: python -m pip install --upgrade pip +# +# - uses: actions/download-artifact@v3 +# with: +# name: wheel-${{ runner.os }} +# path: dist +# +# - run: python -m pip install mpi4py --no-index --find-links=dist +# +# - uses: ./.github/actions/mpi4py-test-basic +# timeout-minutes: 2 +# +# - if: ${{ matrix.mpi == 'mpich' || matrix.mpi == 'openmpi' }} +# uses: ./.github/actions/mpi4py-test-basic +# timeout-minutes: 2 +# env: +# MPI4PY_MPIABI: mpi31-${{ matrix.mpi }}