Skip to content
90 changes: 76 additions & 14 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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: |
Expand Down
8 changes: 6 additions & 2 deletions download_all_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -46,14 +49,15 @@ 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:
# This stops download progress logs from clogging the output in non-interactive environments
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)