Skip to content

Publish sdist and wheels #378

Publish sdist and wheels

Publish sdist and wheels #378

Workflow file for this run

name: Publish sdist and wheels
env:
# A tag or branch name or a commit hash for the numpy/numpy repo, for which
# to build wheels. This is normally set to `main` in the main branch of this
# repo, and to a tag name (e.g., `v2.3.2`) on a release branch.
SOURCE_REF_TO_BUILD: main
UV_VERSION: "0.13.6"
UV_HASH: "f29c3e94ffabd7e6f3ba521dba169a9b7ec12100bf3257087f0f24f6123f3645"
on:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# │ │ │ │ │
- cron: "42 2 * * SUN,WED"
pull_request:
branches:
- main
- maintenance/**
push:
branches:
- main # FOR TESTING ONLY
workflow_dispatch:
inputs:
environment:
description: Which PyPI environment to upload to, if any
required: true
type: choice
options: ["none", "testpypi", "pypi"]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
check_lock:
name: Check uv.lock file
runs-on: ubuntu-latest
if: (github.repository == 'numpy/numpy-release' || github.repository == '')
steps:
- name: Checkout numpy-release
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Checkout numpy
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: numpy/numpy
ref: ${{ env.SOURCE_REF_TO_BUILD }}
path: numpy-src
persist-credentials: false
- name: Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
version: ${{ env.UV_VERSION }}
# unlike build_wheels, this job is Linux-only, so we can pin the download too
checksum: ${{ env.UV_HASH }}
enable-cache: false
- name: Check lock file
run: |
# pyproject.toml holds the dependency groups the builds install, copied out
# of numpy's; regenerating it here is what catches numpy changing them.
# See CONTRIBUTING.md for how to regenerate these files. The cooldown the
# lock was generated with is recorded in it, and has to be repeated here.
python3 tools/sync_dependency_groups.py numpy-src | diff -u pyproject.toml -
uv lock --check --exclude-newer "7 days"
- name: Record the pins that will be used
run: |
# the packages that actually get installed, for review of a lock file bump
{
echo '## Build and test dependencies for this run'
echo '```'
uv export --frozen --no-hashes --no-emit-project --no-default-groups \
--group build --group openblas32 --group openblas64 --group test
echo '```'
} | tee -a "$GITHUB_STEP_SUMMARY"
build_wheels:
if: github.repository == 'numpy/numpy-release'
name: BLD > ${{ matrix.python }}-${{ matrix.buildplat[1] }}-${{ matrix.buildplat[2] }}
runs-on: ${{ matrix.buildplat[0] }}
needs: [check_lock]
strategy:
# Ensure that a wheel builder finishes even if another fails
fail-fast: false
matrix:
# Github Actions doesn't support pairing matrix values together, let's improvise
# https://github.com/github/feedback/discussions/7835#discussioncomment-1769026
buildplat:
- [ubuntu-24.04, manylinux_x86_64, ""]
- [ubuntu-24.04, musllinux_x86_64, ""]
- [ubuntu-24.04-arm, manylinux_aarch64, ""]
- [ubuntu-24.04-arm, musllinux_aarch64, ""]
- [macos-15-intel, macosx_x86_64, openblas]
# targeting macos >= 14. Could probably build on macos-14, but it would be a cross-compile
- [macos-15-intel, macosx_x86_64, accelerate]
- [macos-15, macosx_arm64, openblas]
- [macos-15, macosx_arm64, accelerate]
- [windows-2022, win_amd64, ""]
- [windows-11-arm, win_arm64, ""]
python: ["cp312", "cp313", "cp314", "cp314t", "cp315", "cp315t"]
exclude:
- buildplat: [ macos-15-intel, macosx_x86_64, openblas ]
python: "cp314t"
include:
- buildplat: [ ubuntu-22.04, pyodide_wasm32, "" ]
python: "cp314"
steps:
- name: Checkout numpy-release
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Checkout numpy
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: numpy/numpy
ref: ${{ env.SOURCE_REF_TO_BUILD }}
path: numpy-src
submodules: true
persist-credentials: false
# the version of python we'll run cibuildwheel with
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: 3.13
# Used in cibw_before_build to install pinned build dependencies
# Note that cibuildwheel provides it in the Linux images, so this install
# is only useful on macOS/windows
- name: Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
# can't use checksum here, because there are different packages
# for different OS
version: ${{ env.UV_VERSION }}
enable-cache: false
- name: win_arm64 - set environment variables
if: ${{ matrix.buildplat[1] == 'win_arm64' }}
run: |
echo "CC=clang-cl" >> $env:GITHUB_ENV
echo "CXX=clang-cl" >> $env:GITHUB_ENV
echo "FC=flang" >> $env:GITHUB_ENV
- name: Windows setup
if: runner.os == 'windows'
env:
GITHUB_WORKSPACE: ${{ github.workspace }}
run: |
rm -fo c:/Strawberry/c/lib/pkgconfig/*.pc
$CIBW = "$env:GITHUB_WORKSPACE/.openblas"
# pkgconfig needs a complete path, and not just "./openblas since the
# build is run in a tmp dir (?)
# It seems somewhere in the env passing, `\` is not
# passed through, so convert it to '/'
$CIBW = $CIBW.replace("\","/")
echo "CIBW_ENVIRONMENT_WINDOWS=PKG_CONFIG_PATH=$CIBW" >> $env:GITHUB_ENV
- name: Setup macOS
if: startsWith(matrix.buildplat[0], 'macos')
env:
BLAS_BACKEND: ${{ matrix.buildplat[2] }}
run: |
# Needed due to https://github.com/actions/runner-images/issues/3371
# Supported versions: https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md
echo "FC=gfortran-15" >> "$GITHUB_ENV"
echo "F77=gfortran-15" >> "$GITHUB_ENV"
echo "F90=gfortran-15" >> "$GITHUB_ENV"
if [[ "$BLAS_BACKEND" == 'accelerate' ]]; then
# Builds with Accelerate only target macOS>=14.0
echo "CIBW_ENVIRONMENT_MACOS=MACOSX_DEPLOYMENT_TARGET=14.0 INSTALL_OPENBLAS=false" >> "$GITHUB_ENV"
else
echo "CIBW_ENVIRONMENT_MACOS=PKG_CONFIG_PATH=$PWD/.openblas" >> "$GITHUB_ENV"
fi
- name: Pyodide setup
if: ${{ matrix.buildplat[1] == 'pyodide_wasm32' }}
run: |
echo "CIBW_PLATFORM=pyodide" >> "$GITHUB_ENV"
echo "CIBW_ENVIRONMENT_PYODIDE=INSTALL_OPENBLAS=false" >> "$GITHUB_ENV"
- name: Build wheels
uses: pypa/cibuildwheel@f9b966cfadf4109556cadc5bb39ddb72d0ce664e # v4.3.5
env:
CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }}
SRC: ${{ github.workspace }}/numpy-src
with:
package-dir: numpy-src
output-dir: dist
config-file: cibuildwheel.toml
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: ${{ matrix.python }}-${{ matrix.buildplat[1] }}-${{ matrix.buildplat[2] }}
path: ./dist/*.whl
# -------------------------------------------------------------------------------------
# Should we upload to nightly. We do this on a scheduled run, or a workflow dispatch with environment 'none'
nightly_upload:
runs-on: ubuntu-latest
if: github.repository == 'numpy/numpy-release' && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'none'))
needs: [build_wheels]
steps:
- name: Download wheels
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: dist
merge-multiple: true
- name: Upload nightly wheel
uses: scientific-python/upload-nightly-action@5a74a2a4ec19d7ab8b5317c1cdd356c150d92cd0 # 0.6.6
with:
anaconda_nightly_upload_token: ${{ secrets.NUMPY_NIGHTLY_UPLOAD_TOKEN }}
artifacts_path: dist/
# -------------------------------------------------------------------------------------
build_sdist:
name: Build sdist
runs-on: ubuntu-latest
if: github.repository == 'numpy/numpy-release'
needs: [ check_lock ]
steps:
- name: Checkout numpy-release
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Checkout numpy
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: numpy/numpy
ref: ${{ env.SOURCE_REF_TO_BUILD }}
path: numpy-src
submodules: true
persist-credentials: false
- name: Install uv
uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
version: ${{ env.UV_VERSION }}
# unlike build_wheels, this job is Linux-only, so we can pin the download too
checksum: ${{ env.UV_HASH }}
enable-cache: false
- name: Build sdist
run: |
# use uv and a lock file to pin down all dependencies for the sdist build.
# The lock file lives in this repo, so sync from here; the environment goes
# into the numpy checkout, where `uv build --no-build-isolation` looks for it.
# --frozen : uses specification in uv.lock as source of truth
# only-managed: force uv to use a managed python. No version is requested, so
# it's uv's default managed CPython - i.e. UV_VERSION decides which Python
# the sdist is built and tested with; cibuildwheel isn't used in this job.
export UV_PROJECT_ENVIRONMENT=$GITHUB_WORKSPACE/numpy-src/.venv
uv sync --python-preference only-managed --frozen --no-default-groups --group build
cd numpy-src
uv build --sdist --no-build-isolation -Csetup-args=-Dallow-noblas=true .
- name: Install the sdist
run: |
# the sdist build environment has done its job; removing it proves that the
# test environment doesn't quietly depend on it
rm -rf $GITHUB_WORKSPACE/numpy-src/.venv
cd numpy-src/dist
# build and install the sdist in a fresh venv, populated by the same
# `uv sync` from the same lock file as the build environment above
export UV_PROJECT_ENVIRONMENT=$GITHUB_WORKSPACE/numpy-src/dist/test
uv sync --project $GITHUB_WORKSPACE --python-preference only-managed --frozen --no-default-groups --group build --group test
source test/bin/activate
uv pip install --no-deps --no-build-isolation -v *.gz
- name: Test the sdist
run: |
# each step gets a fresh shell, so re-enter the venv built above
cd numpy-src/dist
source test/bin/activate
python -c "import numpy, sys; print(numpy.__version__); sys.exit(numpy.test() is False)"
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: sdist
path: numpy-src/dist/*.tar.gz
# -------------------------------------------------------------------------------------
testpypi-publish:
name: Publish release to TestPyPI
if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'testpypi'
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/p/numpy
permissions:
id-token: write # mandatory for trusted publishing
steps:
- name: Download sdist and wheels
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: dist
merge-multiple: true
- name: Remove wasm wheels
run: |
cd dist
ls -al
rm -r *wasm*
ls -al
- name: Publish
uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
with:
repository-url: https://test.pypi.org/legacy/
skip-existing: true
print-hash: true
attestations: true
# -------------------------------------------------------------------------------------
check_version:
name: Ensure commit is tag before upload to PyPi
if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'pypi'
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
steps:
- name: Checkout numpy
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: numpy/numpy
ref: ${{ env.SOURCE_REF_TO_BUILD }}
path: numpy-src
fetch-depth: 0
fetch-tags: true
submodules: false
persist-credentials: false
- name: Examine git commit
run: |
cd numpy-src
hash=$(git describe HEAD)
echo $hash
if [[ $hash == *"-"*"-"* ]]; then
echo "SOURCE_REF_TO_BUILD is not a tag"
exit 1
else
echo "SOURCE_REF_TO_BUILD is a tag"
fi;
pypi-publish:
name: Publish release to PyPI
if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'pypi'
needs: [check_version]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/numpy
permissions:
id-token: write # mandatory for trusted publishing
steps:
- name: Download sdist and wheels
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: dist
merge-multiple: true
- name: Remove wasm wheels
run: |
cd dist
ls -al
rm -r *wasm*
ls -al
- name: Publish
uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
with:
print-hash: true
attestations: true