Repository navigation
Publish sdist and wheels #377
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |