diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5fe8823..6e6f893 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,24 +1,92 @@ name: ANTsPyNet Unit Tests on: + pull_request: + types: [opened, synchronize] + branches: [master] workflow_call: workflow_dispatch: + env: - USE_SOURCE_BUILD: false # Set to 'false' to use PyPI version of ANTsPy + USE_ANTSPY_SOURCE_BUILD: false jobs: + + ########################################### + # Job 1 — Build ANTsXNet Data Cache + # + # This job downloads all ANTsXNet data and pretrained models and uploads as an artifact + # The data is too big for Github's cache and runner disk space to handle + # + # But we still avoid independent downloads from figshare for each build matrix job + # + ########################################### + prepare-data: + name: Prepare ANTsXNet data and models + runs-on: ubuntu-22.04 + + outputs: + cache-key: ${{ steps.compute-key.outputs.cache-key }} + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Compute cache key + id: compute-key + run: | + KEY="antsxnet-${{ hashFiles( + 'antspynet/utilities/get_antsxnet_data.py', + 'antspynet/utilities/get_pretrained_network.py' + ) }}" + echo "cache-key=$KEY" >> "$GITHUB_OUTPUT" + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install ANTsPy for data download + run: | + echo "Installing ANTsPy from PyPI for cache preparation" + pip install antspyx + + - name: Download ANTsXNet data and models + run: | + pip install -e . + python download_all_data.py --strict --cache-dir ${{ runner.temp }}/ANTsXNet + + - name: Upload data to artifact + uses: actions/upload-artifact@v4 + with: + name: ANTSXNet-data-${{ steps.compute-key.outputs.cache-key }} + path: ${{ runner.temp }}/ANTsXNet + retention-days: 7 + + + ########################################### + # Job 2 — Test Matrix + ########################################### test: name: Test on Python ${{ matrix.python-version }} runs-on: ubuntu-22.04 + needs: prepare-data strategy: + fail-fast: false matrix: - python-version: [3.11] + python-version: ["3.11", "3.13"] steps: - - name: Checkout ANTsPyNet + - name: Checkout repository uses: actions/checkout@v3 + - name: Download ANTsXNet data and models artifact + uses: actions/download-artifact@v4 + with: + name: ANTSXNet-data-${{ needs.prepare-data.outputs.cache-key }} + path: ~/.keras/ANTsXNet + - name: Set up Python uses: actions/setup-python@v5 with: @@ -29,27 +97,21 @@ jobs: sudo apt-get update sudo apt-get install -y cmake build-essential git - - name: Install ANTsPy (source or PyPI) + - name: Install ANTsPy run: | - if [ "$USE_SOURCE_BUILD" = "true" ]; then - echo "🔧 Installing ANTsPy from GitHub source..." + if [ "$USE_ANTSPY_SOURCE_BUILD" = "true" ]; then + echo "Installing ANTsPy from source..." git clone https://github.com/ANTsX/ANTsPy.git - pip install scikit-build-core pybind11 nanobind # 🔑 install build backend dependencies + pip install scikit-build-core pybind11 nanobind pip install ./ANTsPy --no-build-isolation --no-deps else - echo "📦 Installing ANTsPy from PyPI..." + echo "Installing ANTsPy from PyPI..." pip install antspyx fi - name: Install ANTsPyNet and dependencies run: | pip install -e . - sed -i '/antspyx==/d' requirements.txt - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - - name: Pre-download ANTsXNet models and data - run: | - python download_all_data.py --strict - name: Run tests (individually via pytest) run: | diff --git a/download_all_data.py b/download_all_data.py index f4abddf..e85fada 100644 --- a/download_all_data.py +++ b/download_all_data.py @@ -3,8 +3,11 @@ import sys import tensorflow as tf -def download_all_data(strict=False): +def download_all_data(strict=False, cache_dir=None): print("Downloading data files from get_antsxnet_data...") + if cache_dir is not None: + antspynet.set_antsxnet_cache_directory(cache_dir) + print(f"Using custom cache directory: {cache_dir}") try: data_keys = antspynet.get_antsxnet_data("show") for key in data_keys: @@ -46,6 +49,7 @@ def download_all_data(strict=False): parser = argparse.ArgumentParser() parser.add_argument("--strict", action="store_true", help="Exit on first failed download.") parser.add_argument("--verbose", action="store_true", help="Enable verbose output showing download progress.") + parser.add_argument("--cache-dir", type=str, help="Custom cache directory for downloads.", default=None) args = parser.parse_args() if not args.verbose: @@ -53,7 +57,7 @@ def download_all_data(strict=False): tf.keras.utils.disable_interactive_logging() try: - download_all_data(strict=args.strict) + download_all_data(strict=args.strict, cache_dir=args.cache_dir) except Exception as e: print(f"\nAborted due to error: {e}") sys.exit(1)