diff --git a/.github/workflows/cibuildwheel-impl/action.yml b/.github/workflows/cibuildwheel-impl/action.yml index 9e8d7825f4f98..e0e01aad81b52 100644 --- a/.github/workflows/cibuildwheel-impl/action.yml +++ b/.github/workflows/cibuildwheel-impl/action.yml @@ -8,10 +8,22 @@ inputs: runs: using: "composite" steps: + - name: Install system dependencies + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y \ + binutils cmake dpkg-dev g++ gcc libssl-dev git libx11-dev \ + libxext-dev libxft-dev libxpm-dev python3 libtbb-dev libvdt-dev libgif-dev + - name: Build wheel uses: pypa/cibuildwheel@v3.0.1 env: + PIP_NO_CACHE_DIR: "1" CIBW_BUILD: ${{ inputs.build-tag }} + CIBW_TEST_REQUIRES: "-r test_tutorials/requirements.txt" + CIBW_TEST_SOURCES: "test_tutorials" + CIBW_TEST_COMMAND: "pytest -v" - name: Upload wheel uses: actions/upload-artifact@v4 diff --git a/.github/workflows/python_wheel_build.yml b/.github/workflows/python_wheel_build.yml index 9a2a34f54d7b5..c8c703bc3d2e5 100644 --- a/.github/workflows/python_wheel_build.yml +++ b/.github/workflows/python_wheel_build.yml @@ -11,7 +11,7 @@ on: schedule: - cron: '01 1 * * *' pull_request: - types: [labeled] + types: [opened, synchronize, reopened, labeled] jobs: build-wheels: @@ -21,6 +21,7 @@ jobs: contains(github.event.pull_request.labels.*.name, 'build-python-wheels') runs-on: ubuntu-latest strategy: + fail-fast: false matrix: target: [cp38-manylinux_x86_64, cp39-manylinux_x86_64, cp310-manylinux_x86_64, cp311-manylinux_x86_64, cp312-manylinux_x86_64, cp313-manylinux_x86_64] name: ${{ matrix.target }} diff --git a/test_tutorials/requirements.txt b/test_tutorials/requirements.txt new file mode 100644 index 0000000000000..b38c47fcad9ad --- /dev/null +++ b/test_tutorials/requirements.txt @@ -0,0 +1,47 @@ +# ROOT requirements for third-party Python packages + +# PyROOT: Interoperability with numpy arrays +numpy +pandas + +# TMVA: SOFIE +# dm-sonnet # used for GNNs +# graph_nets +# onnx + +# TMVA: PyMVA interfaces +# scikit-learn +# tensorflow ; python_version < "3.13" # TensorFlow doesn't support Python 3.13 yet +# torch +# xgboost + +# PyROOT: ROOT.Numba.Declare decorator +numba>=0.48 +cffi>=1.9.1 + +# Notebooks: ROOT C++ kernel +# IPython +# jupyter +# metakernel>=0.20.0 +# notebook>=4.4.1 + +# Distributed RDataFrame +pyspark>=2.4 # Spark backend +dask>=2022.08.1 # Dask backend +distributed>=2022.08.1 # Dask backend + +# JsMVA: Jupyter notebook magic for TMVA +# ipywidgets + +# Unified Histogram Interface (UHI) +uhi +matplotlib +mplhep + +# For testing +# nbconvert>=7.4.0 +pytest +# setuptools + +# Look for CPU-only versions of PyTorch to avoid pulling CUDA in the CI docker images. +# -f https://download.pytorch.org/whl/cpu/torch_stable.html diff --git a/test_tutorials/test_tutorials.py b/test_tutorials/test_tutorials.py new file mode 100644 index 0000000000000..1952e4e3e23bb --- /dev/null +++ b/test_tutorials/test_tutorials.py @@ -0,0 +1,34 @@ +import subprocess +import sys +import pathlib +import ROOT +import os +import pytest + +ROOT.gROOT.SetBatch(True) + +tutorial_dir = pathlib.Path(str(ROOT.gROOT.GetTutorialDir())) +tutorials = list(tutorial_dir.rglob("*.py")) + + +def test_tutorials_are_detected(): + assert len(tutorials) > 0 + +@pytest.mark.parametrize("tutorial", tutorials, ids=lambda p: p.name) +def test_tutorial(tutorial): + env = dict(**os.environ) + # force matplotlib to use a non-GUI backend + env["MPLBACKEND"] = "Agg" + try: + subprocess.run( + [sys.executable, str(tutorial)], + check=True, + env=env, + capture_output=True, + text=True + ) + except subprocess.CalledProcessError as e: + # read stderr to see if EOFError occurred + if "EOFError" in e.stderr: + pytest.skip("Skipping tutorial that requires user input") + raise \ No newline at end of file