Modernising Build Process #1052
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: tests | |
| on: | |
| # quick tests for pull requests and the releasing branches | |
| push: | |
| branches: | |
| - dev | |
| - main | |
| - releasing/* | |
| paths-ignore: # skip if only docs are modified | |
| - '**.md' | |
| - '**.rst' | |
| - 'docs/**' | |
| pull_request: | |
| branches: | |
| - dev | |
| - main | |
| - releasing/* | |
| paths-ignore: # skip if only docs are modified | |
| - '**.md' | |
| - '**.rst' | |
| - 'docs/**' | |
| concurrency: | |
| # automatically cancel the previously triggered workflows when there's a newer version | |
| group: cicd-tests-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| # Supported versions of Python and PyTorch are listed here for use below and as documentation | |
| env: | |
| # supported versions of Python | |
| PYTHON_VER1: '3.10' | |
| PYTHON_VER2: '3.11' | |
| PYTHON_VER3: '3.12' | |
| PYTHON_VER4: '3.13' | |
| # PYTHON_VER5: '3.14' # TODO: not compatible with Torchscript, re-enable once Torchscript removed from MONAI | |
| # supported versions of PyTorch | |
| PYTORCH_VER1: '2.8.0' | |
| PYTORCH_VER2: '2.9.1' | |
| PYTORCH_VER3: '2.10.0' | |
| PYTORCH_VER4: '2.11.0' | |
| TORCHVISION_VER1: '0.23.0' # used for testing with lowest PyTorch version (PYTORCH_VER1), update as needed | |
| # versions of PyTorch/Torchvision to use for full-dep Windows tests, needed to get around a gloo bug | |
| WIN_FULLDEP_VER: '2.11.0' | |
| WIN_FULLDEP_VISION_VER: '0.26.0' | |
| PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION: python # https://github.com/Project-MONAI/MONAI/issues/4354 | |
| # These jobs run the CICD tests, type checking, and testing packaging. These use the minimum supported versions of | |
| # Python and PyTorch in many places using the above environment variables but also hard coded where necessary. | |
| # When support is dropped for a version it is important to update these as appropriate. | |
| jobs: | |
| static-checks: # Perform static type and other checks using runtests.sh | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| opt: ["codeformat", "pyrefly"] | |
| steps: | |
| - name: Clean unused tools | |
| run: | | |
| find /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \; | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /usr/local/lib/android | |
| sudo rm -rf /opt/ghc /usr/local/.ghcup | |
| sudo docker system prune -f | |
| - uses: actions/checkout@v7 | |
| - name: Set up Python ${{ env.PYTHON_VER1 }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ env.PYTHON_VER1 }} | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip wheel | |
| python -m pip install .[all,testing] | |
| - name: Lint and type check | |
| run: | | |
| # clean up temporary files | |
| $(pwd)/runtests.sh --build --clean | |
| $(pwd)/runtests.sh --build --${{ matrix.opt }} | |
| min-dep: # Test with minumum dependencies installed for different OS, Python, and PyTorch combinations | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # Base test cases are to test on all three OSes with the lowest versions of Python and PyTorch, other cases are | |
| # added below as special cases to cover other Python and PyTorch versions under Ubuntu | |
| os: [windows-latest, macOS-latest, ubuntu-latest] | |
| python-version: ['3.10'] | |
| pytorch-version: ['2.8.0'] | |
| include: | |
| # Test Python versions under Ubuntu with lowest PyTorch version supported | |
| - os: ubuntu-latest | |
| pytorch-version: '2.8.0' | |
| python-version: '3.11' | |
| - os: ubuntu-latest | |
| pytorch-version: '2.8.0' | |
| python-version: '3.12' | |
| - os: ubuntu-latest | |
| pytorch-version: '2.8.0' | |
| python-version: '3.13' | |
| # - os: ubuntu-latest | |
| # pytorch-version: '2.9.1' | |
| # python-version: '3.14' | |
| # Test PyTorch versions under Ubuntu with lowest Python version supported | |
| - os: ubuntu-latest | |
| python-version: '3.10' | |
| pytorch-version: '2.9.1' | |
| - os: ubuntu-latest | |
| python-version: '3.10' | |
| pytorch-version: '2.10.0' | |
| - os: ubuntu-latest | |
| python-version: '3.10' | |
| pytorch-version: '2.11.0' | |
| timeout-minutes: 40 | |
| steps: | |
| - if: runner.os == 'Linux' | |
| name: Clean unused tools | |
| run: | | |
| find /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \; | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /usr/local/lib/android | |
| sudo rm -rf /opt/ghc /usr/local/.ghcup | |
| sudo docker system prune -f | |
| - uses: actions/checkout@v7 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: 'pip' | |
| - name: Prepare pip wheel | |
| run: | | |
| which python | |
| python -m pip install --upgrade pip wheel tomli | |
| - name: Install the minimum dependencies | |
| run: | | |
| # min. requirements | |
| python -m pip install torch==${{ matrix.pytorch-version }} | |
| python monai/config/print_dependencies.py build-system | xargs pip install --no-build-isolation | |
| python -m pip install --no-build-isolation .[testing] | |
| python -m pip list | |
| shell: bash | |
| - if: matrix.os == 'linux-gpu-runner' | |
| name: Print GPU Info | |
| run: | | |
| nvidia-smi | |
| python -c 'import torch; print(torch.rand(2,2).to("cuda:0"))' | |
| shell: bash | |
| - name: Run quick tests | |
| run: | | |
| python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))' | |
| python -c "import monai; monai.config.print_config()" | |
| ./runtests.sh --min | |
| shell: bash | |
| env: | |
| QUICKTEST: True | |
| NGC_API_KEY: ${{ secrets.NGC_API_KEY }} | |
| NGC_ORG: ${{ secrets.NGC_ORG }} | |
| NGC_TEAM: ${{ secrets.NGC_TEAM }} | |
| full-dep: # Test with full dependencies installed for different OS runners | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [windows-latest, ubuntu-latest, macOS-latest] # macOS-latest is very slow (#8864), testing install only | |
| timeout-minutes: 120 | |
| env: | |
| QUICKTEST: True | |
| steps: | |
| - if: runner.os == 'Linux' | |
| name: Clean unused tools | |
| run: | | |
| find /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \; | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /usr/local/lib/android | |
| sudo rm -rf /opt/ghc /usr/local/.ghcup | |
| sudo docker system prune -f | |
| - if: runner.os == 'windows' | |
| name: Config pagefile (Windows only) | |
| uses: al-cheb/configure-pagefile-action@v1.5 | |
| with: | |
| minimum-size: 8GB | |
| maximum-size: 16GB | |
| disk-root: "D:" | |
| - uses: actions/checkout@v7 | |
| - name: Set up Python ${{ env.PYTHON_VER1 }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ env.PYTHON_VER1 }} | |
| cache: 'pip' | |
| - name: Prepare pip wheel | |
| run: | | |
| which python | |
| python -m pip install --upgrade pip wheel | |
| - if: runner.os == 'windows' | |
| name: Install torch cpu from pytorch.org (Windows only) | |
| run: | | |
| python -m pip install torch==${WIN_FULLDEP_VER} torchvision==${WIN_FULLDEP_VISION_VER}+cpu --index-url https://download.pytorch.org/whl/cpu | |
| shell: bash | |
| - if: runner.os != 'windows' | |
| name: Install torch gpu | |
| run: | | |
| # install the lowest version of PyTorch supported | |
| python -m pip install torch==${PYTORCH_VER1} torchvision==${TORCHVISION_VER1} | |
| shell: bash | |
| - if: runner.os == 'Linux' | |
| name: Install itk pre-release (Linux only) | |
| run: | | |
| python -m pip install --pre -U itk | |
| shell: bash | |
| - name: Install the complete dependencies | |
| run: | | |
| python -m pip install --user --upgrade pip wheel tomli | |
| python monai/config/print_dependencies.py build-system | xargs pip install --no-build-isolation | |
| python -m pip install --no-build-isolation .[all,testing] | |
| python -m pip list | |
| shell: bash | |
| - name: Run compiled (${{ runner.os }}) | |
| run: | | |
| python -m pip uninstall -y monai | |
| BUILD_MONAI=1 python -m pip install --no-build-isolation -e . # compile the cpp extensions in-place with -e | |
| # ensure extensions were compiled | |
| python -c 'import monai._C' > /dev/null | |
| shell: bash | |
| - if: runner.os != 'macOS' | |
| name: Run full tests | |
| run: | | |
| python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))' | |
| python -c "import monai; monai.config.print_config()" | |
| python -m unittest -v | |
| shell: bash | |
| - if: runner.os == 'macOS' | |
| name: Run min tests | |
| run: | | |
| python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))' | |
| python -c "import monai; monai.config.print_config()" | |
| # TODO: enable large range of macOS tests which don't take a very long time | |
| ./runtests.sh --min | |
| shell: bash | |
| hyena-dep: # Optional HyenaND dependency + the no-CUDA Hyena tests. | |
| # nvsubquadratic >= 0.1.1 supports Python >= 3.10 and keeps its CUDA-kernel sdist | |
| # (subquadratic-ops-torch-cu12) plus the megatron / dali / timm packages in opt-in | |
| # extras, so it installs on a CPU runner. We still pass ``--no-deps`` deliberately: | |
| # (1) the HyenaND operators import only torch + einops + omegaconf at runtime, so | |
| # skipping the (still batteries-included: datasets/lightning/wandb) core deps | |
| # keeps this job lean; and | |
| # (2) nvsubquadratic pins torch>=2.10,<2.11, which would otherwise upgrade/clash | |
| # with the torch this job (and MONAI's matrix) installs. | |
| # CUDA-required Hyena tests skip cleanly here; the GPU surface is covered by | |
| # ``.github/workflows/pythonapp-hyena-gpu.yml``. | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Clean unused tools | |
| run: | | |
| find /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \; | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /usr/local/lib/android | |
| sudo rm -rf /opt/ghc /usr/local/.ghcup | |
| sudo docker system prune -f | |
| - uses: actions/checkout@v6 | |
| - name: Set up Python ${{ env.PYTHON_VER1 }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ env.PYTHON_VER1 }} | |
| cache: 'pip' | |
| - name: Install dependencies + nvsubquadratic (no-deps) | |
| run: | | |
| python -m pip install --upgrade pip wheel tomli pytest | |
| # need a specific version of torch for nvsubquadratic | |
| python monai/config/print_dependencies.py build-system | \ | |
| xargs -d '\n' pip install --no-build-isolation torch==2.10.0 torchvision==0.25.0 | |
| # # nvsubquadratic runtime imports need only torch + einops + omegaconf; install | |
| # # the package itself without its core dependency tree (see job comment above). | |
| python -m pip install --no-build-isolation omegaconf | |
| python -m pip install --no-build-isolation --no-deps 'nvsubquadratic>=0.1.1' | |
| python -m pip install --no-build-isolation .[hyena,testing] | |
| python -m pip list | |
| shell: bash | |
| - name: Run Hyena tests (CUDA-required cases skip cleanly) | |
| run: | | |
| python -c "from monai.networks.blocks.hyena import is_nvsubquadratic_available; \ | |
| assert is_nvsubquadratic_available(), 'nvsubquadratic must be importable'" | |
| python -m pytest -v \ | |
| tests/networks/blocks/test_hyena_block.py \ | |
| tests/networks/nets/test_hyena_nd_unetr.py \ | |
| tests/networks/nets/test_swin_unetr.py | |
| shell: bash | |
| packaging: # Test package generation | |
| runs-on: ubuntu-latest | |
| env: | |
| QUICKTEST: True | |
| INDEX_URL: "https://download.pytorch.org/whl/cpu" | |
| steps: | |
| - name: Clean unused tools | |
| run: | | |
| find /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \; | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /usr/local/lib/android | |
| sudo rm -rf /opt/ghc /usr/local/.ghcup | |
| sudo docker system prune -f | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Python ${{ env.PYTHON_VER1 }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ env.PYTHON_VER1 }} | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --user --upgrade pip setuptools wheel twine packaging tomli | |
| # install the latest pytorch for testing | |
| python monai/config/print_dependencies.py build-system all testing | \ | |
| xargs -d '\n' pip install --no-build-isolation torch==${PYTORCH_VER1} --extra-index-url $INDEX_URL | |
| - name: Check packages | |
| run: | | |
| python -m pip uninstall -y monai | |
| python -m pip list | grep -iv monai | |
| git fetch --depth=1 origin +refs/tags/*:refs/tags/* | |
| set -e | |
| # build tar.gz and wheel | |
| python setup.py check -m -s | |
| python setup.py sdist bdist_wheel | |
| python -m twine check dist/* | |
| - run: echo "pwd=$PWD" >> $GITHUB_OUTPUT | |
| id: root | |
| - run: echo "tmp_dir=$(mktemp -d)" >> $GITHUB_OUTPUT | |
| id: mktemp | |
| - name: Move packages | |
| run: | | |
| printf ${{ steps.root.outputs.pwd }} | |
| printf ${{ steps.mktemp.outputs.tmp_dir }} | |
| # move packages to a temp dir | |
| cp dist/monai* "${{ steps.mktemp.outputs.tmp_dir }}" | |
| rm -r build dist monai.egg-info | |
| cd "${{ steps.mktemp.outputs.tmp_dir }}" | |
| ls -al | |
| - name: Install wheel file | |
| working-directory: ${{ steps.mktemp.outputs.tmp_dir }} | |
| run: | | |
| # install from wheel | |
| python -m pip install --no-build-isolation monai*.whl --extra-index-url $INDEX_URL | |
| python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown" | |
| python -c 'import monai; print(monai.__file__)' | |
| python -m pip uninstall -y monai | |
| rm monai*.whl | |
| - name: Install source archive | |
| working-directory: ${{ steps.mktemp.outputs.tmp_dir }} | |
| run: | | |
| for name in *.tar.gz; do break; done | |
| echo $name | |
| python -m pip install --no-build-isolation ${name}[all] --extra-index-url $INDEX_URL | |
| python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown" | |
| python -c 'import monai; print(monai.__file__)' | |
| python -m pip uninstall -y monai | |
| - name: Install using uv | |
| working-directory: ${{ steps.root.outputs.pwd }} | |
| run: | | |
| pip install uv | |
| uv pip install --system --no-build-isolation .[all] --extra-index-url $INDEX_URL | |
| python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown" | |
| python -c 'import monai; print(monai.__file__)' |