From 49aa7d89c38f154cc1d8cca2a2b0f3994e051912 Mon Sep 17 00:00:00 2001 From: Giorgis Georgakoudis Date: Sun, 27 Sep 2026 04:11:48 -0700 Subject: [PATCH] Support numba up to 0.65.1 and Python 3.14t Numba 0.64 and 0.65 keep llvmlite on LLVM 20, so no pass or runtime changes are needed; this extends the supported range and enables the free-threaded build that Numba 0.65 introduces. Packaging: - Widen the numba requirement to >=0.62, <0.66 in pyproject.toml and the conda recipe - Build cp314t wheels by removing the cibuildwheel skip - Require numba >=0.65 for free-threaded conda builds via the is_freethreading selector (default false in conda_build_config.yaml) - Raise ImportError at import time on free-threaded Python with numba < 0.65 CI: - Test wheels against numba 0.64.0, 0.65.0 and 0.65.1, and add Python 3.14t (numba 0.65.x only) - Build and upload a 3.14t conda package, selecting the free-threaded variant with a variant file (freethreading.yaml) because `conda build --output` ignores --variants - Modal GPU tests: match the ABI tag when selecting wheels, so cp314 no longer also matches cp314t, and test with numba 0.65.1 Docs: - Update the compatibility matrix to 0.62.x - 0.65.x and note that Python 3.14t requires numba 0.65.x Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/build-upload-conda.yml | 13 ++++++++++--- .github/workflows/build-upload-wheels.yml | 15 +++++++++++++-- README.md | 4 +++- .../conda-recipes/pyomp/conda_build_config.yaml | 5 +++++ .../conda-recipes/pyomp/freethreading.yaml | 4 ++++ buildscripts/conda-recipes/pyomp/meta.yaml | 6 ++++-- buildscripts/modal/test_gpu.py | 5 +++-- docs/source/installation.rst | 4 +++- pyproject.toml | 5 ++--- src/numba/openmp/__init__.py | 12 ++++++++++++ 10 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 buildscripts/conda-recipes/pyomp/freethreading.yaml diff --git a/.github/workflows/build-upload-conda.yml b/.github/workflows/build-upload-conda.yml index 75a35cc9cadd..74bbc236c29f 100644 --- a/.github/workflows/build-upload-conda.yml +++ b/.github/workflows/build-upload-conda.yml @@ -24,7 +24,7 @@ jobs: matrix: # TODO: Add windows. os: [ubuntu-latest, macos-latest, ubuntu-24.04-arm] - python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"] steps: - name: Determine conda label run: | @@ -62,15 +62,22 @@ jobs: conda config --set anaconda_upload no conda build --version + # Select the python variant; 3.14t needs the free-threaded ABI. + if [[ "${{ matrix.python-version }}" == "3.14t" ]]; then + PY_ARGS=(--python "3.14.* *_cp314t" -m buildscripts/conda-recipes/pyomp/freethreading.yaml) + else + PY_ARGS=(--python ${{ matrix.python-version }}) + fi + # Build the package. conda build \ -c conda-forge \ - --python ${{ matrix.python-version }} \ + "${PY_ARGS[@]}" \ buildscripts/conda-recipes/pyomp # Get the output file path. OUTPUT=$(conda build -c conda-forge --output \ - --python ${{ matrix.python-version }} \ + "${PY_ARGS[@]}" \ buildscripts/conda-recipes/pyomp) # Upload the package. diff --git a/.github/workflows/build-upload-wheels.yml b/.github/workflows/build-upload-wheels.yml index 6a91fcd25b2e..0bec5453fcff 100644 --- a/.github/workflows/build-upload-wheels.yml +++ b/.github/workflows/build-upload-wheels.yml @@ -84,13 +84,24 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, ubuntu-24.04-arm] - python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] - numba-version: ['0.62.0', '0.62.1', '0.63.0', '0.63.1'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.14t'] + numba-version: ['0.62.0', '0.62.1', '0.63.0', '0.63.1', '0.64.0', '0.65.0', '0.65.1'] exclude: - python-version: '3.14' numba-version: '0.62.0' - python-version: '3.14' numba-version: '0.62.1' + # Numba supports free-threaded Python starting with 0.65. + - python-version: '3.14t' + numba-version: '0.62.0' + - python-version: '3.14t' + numba-version: '0.62.1' + - python-version: '3.14t' + numba-version: '0.63.0' + - python-version: '3.14t' + numba-version: '0.63.1' + - python-version: '3.14t' + numba-version: '0.64.0' steps: - name: Download built wheels diff --git a/README.md b/README.md index cc12e95f8157..cadef92ae7fe 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,12 @@ conda install -c python-for-hpc -c conda-forge pyomp | PyOMP | Numba | | ----- | --------------- | -| 0.5.x | 0.62.x - 0.63.x | +| 0.5.x | 0.62.x - 0.65.x | | 0.4.x | 0.61.x | | 0.3.x | 0.57.x - 0.60.x | +Python 3.14t (free-threaded) requires Numba 0.65.x. + Besides a standard installation, we also provide the following options to quickly try out PyOMP online or through a container. diff --git a/buildscripts/conda-recipes/pyomp/conda_build_config.yaml b/buildscripts/conda-recipes/pyomp/conda_build_config.yaml index 7db90af45097..ab3a7bdab64b 100644 --- a/buildscripts/conda-recipes/pyomp/conda_build_config.yaml +++ b/buildscripts/conda-recipes/pyomp/conda_build_config.yaml @@ -1,3 +1,8 @@ +# --- Free-threading --- +# Default for the is_freethreading selector in meta.yaml; override for 3.14t. +is_freethreading: + - false + # --- Compilers --- c_compiler_version: - 9 # [linux] diff --git a/buildscripts/conda-recipes/pyomp/freethreading.yaml b/buildscripts/conda-recipes/pyomp/freethreading.yaml new file mode 100644 index 000000000000..cc62364b2688 --- /dev/null +++ b/buildscripts/conda-recipes/pyomp/freethreading.yaml @@ -0,0 +1,4 @@ +# Variant for free-threaded Python (3.14t) builds, passed with -m. Use this +# instead of --variants, which `conda build --output` ignores. +is_freethreading: + - true diff --git a/buildscripts/conda-recipes/pyomp/meta.yaml b/buildscripts/conda-recipes/pyomp/meta.yaml index 0c689c90fea6..e7c7030a050e 100644 --- a/buildscripts/conda-recipes/pyomp/meta.yaml +++ b/buildscripts/conda-recipes/pyomp/meta.yaml @@ -45,7 +45,8 @@ requirements: - sysroot_linux-aarch64 # [aarch64] - setuptools - setuptools_scm - - numba >=0.62, <0.64 + - numba >=0.62, <0.66 + - numba >=0.65, <0.66 # [is_freethreading] - clang {{ LLVM_VERSION }} - clangxx {{ LLVM_VERSION }} - clang-tools {{ LLVM_VERSION }} @@ -59,7 +60,8 @@ requirements: run: - python - setuptools - - numba >=0.62, <0.64 + - numba >=0.62, <0.66 + - numba >=0.65, <0.66 # [is_freethreading] # require llvm-openmp for the openmp cpu runtime. - llvm-openmp 21.1.8.* # [osx] - llvm-openmp {{ LLVM_VERSION }} # [not osx] diff --git a/buildscripts/modal/test_gpu.py b/buildscripts/modal/test_gpu.py index b01a55e94d6a..59f4d919d9b7 100644 --- a/buildscripts/modal/test_gpu.py +++ b/buildscripts/modal/test_gpu.py @@ -8,7 +8,7 @@ PYTHON_VERSIONS = ("3.10", "3.11", "3.12", "3.13", "3.14") -NUMBA_VERSION = "0.63.1" +NUMBA_VERSION = "0.65.1" MINIFORGE_VERSION = "26.3.2-3" MINIFORGE_SHA256 = "848194851a98903134187fbb4ab50efe87b003e0c0f808f97644b7524a62bf2c" WHEEL_DIRECTORY = ( @@ -26,7 +26,8 @@ def find_linux_wheels() -> dict[str, Path]: wheels = {} for python_version in PYTHON_VERSIONS: abi = python_version.replace(".", "") - matches = sorted(WHEEL_DIRECTORY.glob(f"*cp{abi}-*x86_64.whl")) + # Match the ABI tag too, so cp314 does not also match cp314t wheels. + matches = sorted(WHEEL_DIRECTORY.glob(f"*-cp{abi}-cp{abi}-*x86_64.whl")) if len(matches) != 1: raise RuntimeError( f"Expected one cp{abi} Linux x86-64 wheel in {WHEEL_DIRECTORY}, " diff --git a/docs/source/installation.rst b/docs/source/installation.rst index c7fdfae5b35c..6e0eeba7db19 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -24,13 +24,15 @@ supported. +--------+---------------------+ | PyOMP | Numba | +========+=====================+ -| 0.5.x | 0.62.x - 0.63.x | +| 0.5.x | 0.62.x - 0.65.x | +--------+---------------------+ | 0.4.x | 0.61.x | +--------+---------------------+ | 0.3.x | 0.57.x - 0.60.x | +--------+---------------------+ +Python 3.14t (free-threaded) requires Numba 0.65.x. + Additional options ------------------ diff --git a/pyproject.toml b/pyproject.toml index 5069c16cff2a..b8aedd06d6ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ classifiers = [ "Intended Audience :: Developers", "Topic :: Software Development :: Compilers", ] -dependencies = ["numba>=0.62, <0.64", "lark", "cffi", "setuptools"] +dependencies = ["numba>=0.62, <0.66", "lark", "cffi", "setuptools"] maintainers = [ { name = "Giorgis Georgakoudis", email = "georgakoudis1@llnl.gov" }, ] @@ -42,8 +42,7 @@ archs = ["native"] environment-pass = ["LLVM_VERSION"] # We use miniconda3 to get the clang/llvm toolchain on Linux. before-build = ["rm -rf build dist src/*.egg-info"] -# Skip building 3.14t wheels as they are not supported by the current numba/llvmlite version. -skip = ["*-musllinux_*", "cp38-*", "cp314t-*"] +skip = ["*-musllinux_*", "cp38-*"] test-command = [ # Run host OpenMP tests. "RUN_TARGET=0 python -m numba.runtests -v -- numba.openmp.tests.test_openmp", diff --git a/src/numba/openmp/__init__.py b/src/numba/openmp/__init__.py index 0d3e7ddafada..3c6d4110e55e 100644 --- a/src/numba/openmp/__init__.py +++ b/src/numba/openmp/__init__.py @@ -1,5 +1,17 @@ import llvmlite.binding as ll import sys +import sysconfig + +import numba + +# Numba supports free-threaded Python starting with 0.65. +if sysconfig.get_config_var("Py_GIL_DISABLED") and tuple( + int(x) for x in numba.__version__.split(".")[:2] +) < (0, 65): + raise ImportError( + f"PyOMP on free-threaded Python requires numba>=0.65, found {numba.__version__}" + ) + from ._version import version as __version__ # noqa: F401 from .config import (