blob: 4fd473911fb0b61bc8b1a1974e60b68bdc5ee3fd [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: Build Python Wheels
concurrency:
group: python-wheel-${{ github.ref }}
cancel-in-progress: false
on:
# Trigger the workflow on push or pull request,
# but only for the main branch
push:
branches:
- "main"
paths:
- 'cpp/**'
- 'python/**'
- '.github/workflows/python-wheel-workflow.yml'
pull_request:
branches:
- "main"
paths:
- 'cpp/**'
- 'python/**'
- '.github/workflows/python-wheel-workflow.yml'
workflow_dispatch:
inputs:
publish_pypi:
description: "Publish to PyPI (manual runs only)"
required: true
default: false
type: boolean
jobs:
build_sdist:
name: Build source distribution
runs-on: ubuntu-24.04
steps:
# fetch-depth 0 is required: since version
# is derived from git history
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Build sdist
run: |
# Bundle C++ sources into python/ so the sdist contains them.
rm -rf python/_bundled_cpp
cp -a cpp python/_bundled_cpp
cd python
python -m build --sdist
- name: Store artifacts
uses: actions/upload-artifact@v4
with:
name: sdist
path: python/dist/*
build_wheels:
name: Build wheels on ${{ matrix.runner }}
runs-on: ${{ matrix.runner }}
needs: build_sdist
strategy:
matrix:
include:
# Job 1: Native x86_64 build
- platform: x86_64
runner: ubuntu-24.04 # This is the standard x86_64 runner
os: linux
manylinux: _2_28
# Job 2: Native aarch64 build
- platform: aarch64
runner: ubuntu-24.04-arm # This is a native ARM64 runner
os: linux
manylinux: _2_28
# Job 3: macOS arm64 build
# Pinned, not macos-latest: the runner OS sets the effective macOS
# deployment target (see CIBW_ENVIRONMENT_MACOS), so a mutable label
# could silently change the minimum macOS of the produced wheels.
- platform: arm64
runner: macos-15
os: macos
env:
# Must match the pyarrow pinned in python/pyproject.toml (pyarrow == 24.0.0).
# Single source of truth for the Arrow version: it is used by the macOS
# steps (build from source) and by the Linux dnf pins below.
ARROW_VERSION: "24.0.0"
CIBW_PLATFORM: ${{ matrix.os }}
# Keep in sync with requires-python (>= 3.10) and the classifiers in
# python/pyproject.toml. pyarrow ~= 24.0 (the runtime Arrow provider) has
# wheels for cp310-cp314 on every platform we build.
CIBW_BUILD: "cp310-* cp311-* cp312-* cp313-* cp314-*"
CIBW_SKIP: "*-musllinux_*"
# Use uv on macOS to avoid transient GitHub rate limits when cibuildwheel
CIBW_BUILD_FRONTEND: ${{ matrix.os == 'macos' && 'build[uv]' || 'build' }}
# Pin arch to the matrix platform
CIBW_ARCHS: ${{ matrix.platform }}
CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.os == 'linux' && format('manylinux{0}', matrix.manylinux) || '' }}
CIBW_MANYLINUX_AARCH64_IMAGE: ${{ matrix.os == 'linux' && format('manylinux{0}', matrix.manylinux) || '' }}
CIBW_ENVIRONMENT_MACOS: ${{ matrix.os == 'macos' && 'MACOSX_DEPLOYMENT_TARGET=$(sw_vers -productVersion) CMAKE_OSX_DEPLOYMENT_TARGET=$(sw_vers -productVersion) CFLAGS=-mmacosx-version-min=$(sw_vers -productVersion) CXXFLAGS=-mmacosx-version-min=$(sw_vers -productVersion) LDFLAGS=-mmacosx-version-min=$(sw_vers -productVersion)' || '' }}
CIBW_BEFORE_BUILD_LINUX: |
set -eux
if [ -f /etc/system-release-cpe ]; then
ALMA_MAJOR="$(cut -d: -f5 /etc/system-release-cpe | cut -d. -f1)"
else
. /etc/os-release
ALMA_MAJOR="${VERSION_ID%%.*}"
fi
dnf install -y 'dnf-command(config-manager)' || dnf install -y dnf-plugins-core || true
# Follow official Apache Arrow install instructions for AlmaLinux/RHEL-family
dnf install -y epel-release || dnf install -y oracle-epel-release-el$(cut -d: -f5 /etc/system-release-cpe | cut -d. -f1) || dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-$(cut -d: -f5 /etc/system-release-cpe | cut -d. -f1).noarch.rpm
dnf install -y https://packages.apache.org/artifactory/arrow/almalinux/$(cut -d: -f5 /etc/system-release-cpe | cut -d. -f1)/apache-arrow-release-latest.rpm
dnf config-manager --set-enabled epel || :
dnf config-manager --set-enabled powertools || :
dnf config-manager --set-enabled crb || :
dnf config-manager --set-enabled ol$(cut -d: -f5 /etc/system-release-cpe | cut -d. -f1)_codeready_builder || :
dnf config-manager --set-enabled codeready-builder-for-rhel-$(cut -d: -f5 /etc/system-release-cpe | cut -d. -f1)-rhui-rpms || :
subscription-manager repos --enable codeready-builder-for-rhel-$(cut -d: -f5 /etc/system-release-cpe | cut -d. -f1)-$(arch)-rpms || :
# Pin the exact Arrow version: the wheel must be built against the same
# 24.0.0 that pyarrow == 24.0.0 ships (and that ARROW_VERSION above
# pins for macOS), because Arrow is resolved at runtime from the
# sibling pyarrow package instead of being bundled (see
# CIBW_REPAIR_WHEEL_COMMAND_* below). Installing the unpinned "latest"
# (e.g. 25.x) would produce libs whose SONAME does not exist in
# pyarrow, breaking every wheel.
dnf install -y arrow-devel-24.0.0 # For C++
dnf install -y arrow-glib-devel-24.0.0 # For GLib (C)
dnf install -y arrow-dataset-devel-24.0.0 # For Apache Arrow Dataset C++
dnf install -y arrow-dataset-glib-devel-24.0.0 # For Apache Arrow Dataset GLib (C)
dnf install -y arrow-acero-devel-24.0.0 # For Apache Arrow Acero C++
dnf install -y arrow-flight-devel-24.0.0 # For Apache Arrow Flight C++
dnf install -y arrow-flight-glib-devel-24.0.0 # For Apache Arrow Flight GLib (C)
dnf install -y arrow-flight-sql-devel-24.0.0 # For Apache Arrow Flight SQL C++
dnf install -y arrow-flight-sql-glib-devel-24.0.0 # For Apache Arrow Flight SQL GLib (C)
dnf install -y parquet-devel-24.0.0 # For Apache Parquet C++
dnf install -y parquet-glib-devel-24.0.0 # For Apache Parquet GLib (C)
# Do NOT bundle Arrow/Parquet/Dataset/Acero/Compute into the wheel: the
# python/CMakeLists.txt RPATH ($ORIGIN/../pyarrow on Linux,
# @loader_path/../pyarrow on macOS) resolves them at runtime from the
# sibling pyarrow package (pyarrow ~= 24.0). auditwheel/delocate keep the
# preserved RPATH entry and only bundle whatever else is left (e.g. re2,
# zstd from the manylinux container).
CIBW_REPAIR_WHEEL_COMMAND_LINUX: |
auditwheel repair --exclude libarrow.so.* --exclude libarrow_compute.so.* --exclude libarrow_dataset.so.* --exclude libarrow_acero.so.* --exclude libparquet.so.* -w {dest_dir} {wheel}
CIBW_REPAIR_WHEEL_COMMAND_MACOS: |
delocate-wheel --exclude libarrow --exclude libarrow_compute --exclude libarrow_dataset --exclude libarrow_acero --exclude libparquet -w {dest_dir} -v {wheel}
steps:
- name: Checkout (needed for some tooling)
uses: actions/checkout@v7
with:
# fetch-depth 0 is required: the sdist is extracted inside this
# checkout and setuptools-scm (search_parent_directories) picks up the
# parent .git. Without tags the wheel version collapses to "0.1.dev1"
# instead of reproducing the version baked into the sdist's PKG-INFO.
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.10"
- name: Install Arrow (macOS)
if: matrix.os == 'macos'
shell: bash
run: |
set -euxo pipefail
brew bundle --file=cpp/Brewfile
# Homebrew's apache-arrow is built without ORC support, so it is
# removed here and Arrow is built from source in the next step (with
# ARROW_ORC), exactly like the python.yml CI workflow does.
brew uninstall apache-arrow || true
echo "CMAKE_PREFIX_PATH=$GITHUB_WORKSPACE/arrow-dist" >> "$GITHUB_ENV"
- name: Cache Arrow build (macOS)
if: matrix.os == 'macos'
id: arrow-cache
uses: actions/cache@v6
with:
path: ${{ github.workspace }}/arrow-dist
# The hash of this workflow is part of the key so that changing the
# Arrow CMake flags below invalidates the cached build.
key: arrow-${{ runner.os }}-${{ runner.arch }}-${{ env.ARROW_VERSION }}-${{ hashFiles('.github/workflows/python-wheel-workflow.yml') }}
- name: Build Arrow from source (macOS, with ORC)
if: matrix.os == 'macos' && steps.arrow-cache.outputs.cache-hit != 'true'
run: |
set -euxo pipefail
curl -fLsS -o "apache-arrow-${ARROW_VERSION}.tar.gz" \
"https://archive.apache.org/dist/arrow/arrow-${ARROW_VERSION}/apache-arrow-${ARROW_VERSION}.tar.gz"
tar xzf "apache-arrow-${ARROW_VERSION}.tar.gz"
cmake -S "apache-arrow-${ARROW_VERSION}/cpp" -B arrow-build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="${CMAKE_PREFIX_PATH}" \
-DCMAKE_INSTALL_LIBDIR=lib \
-DARROW_BUILD_SHARED=ON \
-DARROW_BUILD_STATIC=OFF \
-DARROW_DEPENDENCY_SOURCE=BUNDLED \
-DARROW_PARQUET=ON \
-DARROW_DATASET=ON \
-DARROW_ACERO=ON \
-DARROW_ORC=ON \
-DARROW_CSV=ON \
-DARROW_JSON=ON \
-DARROW_COMPUTE=ON \
-DARROW_FILESYSTEM=ON \
-DARROW_WITH_SNAPPY=ON \
-DARROW_WITH_ZSTD=ON \
-DARROW_WITH_LZ4=ON \
-DARROW_WITH_BZ2=ON \
-DARROW_WITH_BROTLI=ON \
-DARROW_WITH_ZLIB=ON \
-DARROW_WITH_UTF8PROC=ON \
-DARROW_WITH_RE2=ON \
-DARROW_S3=OFF \
-DARROW_GCS=OFF \
-DARROW_AZURE=OFF \
-DARROW_FLIGHT=OFF \
-DARROW_JEMALLOC=OFF \
-DARROW_MIMALLOC=OFF \
-DARROW_BUILD_TESTS=OFF \
-DARROW_BUILD_BENCHMARKS=OFF \
-DARROW_BUILD_EXAMPLES=OFF \
-DARROW_BUILD_INTEGRATION=OFF \
-DARROW_BUILD_UTILITIES=OFF \
-DARROW_PYTHON=OFF
cmake --build arrow-build --target install -j "$(sysctl -n hw.ncpu)"
- name: Download sdist artifact
uses: actions/download-artifact@v4
with:
name: sdist
path: sdist
- name: Extract sdist
shell: bash
run: |
set -euxo pipefail
ls -lah sdist
SDIST_FILE=""
for f in sdist/*.tar.gz sdist/*.zip; do
if [ -f "$f" ]; then
SDIST_FILE="$f"
break
fi
done
if [ -z "$SDIST_FILE" ]; then
echo "No sdist file found in sdist/" >&2
exit 1
fi
mkdir -p sdist_pkg
case "$SDIST_FILE" in
*.tar.gz) tar -xzf "$SDIST_FILE" -C sdist_pkg ;;
*.zip) unzip -q "$SDIST_FILE" -d sdist_pkg ;;
esac
PKGDIR="$(find sdist_pkg -mindepth 1 -maxdepth 1 -type d | head -n 1)"
if [ -z "$PKGDIR" ]; then
echo "Failed to locate extracted sdist directory" >&2
exit 1
fi
echo "PKGDIR=$PKGDIR" >> "$GITHUB_ENV"
- name: Build wheels
shell: bash
run: |
set -euxo pipefail
python -m pip install --upgrade pip
if [ "${{ matrix.os }}" = "macos" ]; then
python -m pip install packaging "cibuildwheel[uv]>=2.22"
else
python -m pip install packaging "cibuildwheel>=2.22"
fi
mkdir -p python/dist
python -m cibuildwheel --output-dir python/dist "$PKGDIR"
- name: Store artifacts
uses: actions/upload-artifact@v4
with:
name: wheels-${{ matrix.os }}-${{ matrix.platform }}
path: python/dist/*
- name: Smoke test wheel
shell: bash
run: |
set -euxo pipefail
python -m pip uninstall -y graphar || true
python -m pip install --find-links python/dist graphar
python -c "import graphar; import graphar._core; print('GraphAr imported successfully')"
graphar --help >/dev/null
upload_test_pypi:
name: Publish to TestPyPI (auto)
needs: [build_wheels, build_sdist]
runs-on: ubuntu-24.04
if: github.event_name == 'push'
permissions:
contents: read
id-token: write
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: dist
- name: Move artifacts to correct location
run: |
mkdir -p python/dist
find dist -name "*" -type f -exec mv {} python/dist/ \;
- name: Publish to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
packages-dir: python/dist/
upload_pypi:
name: Publish (manual)
needs: [build_wheels, build_sdist]
runs-on: ubuntu-24.04
if: github.event_name == 'workflow_dispatch' && inputs.publish_pypi
permissions:
contents: read
id-token: write
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: dist
- name: Move artifacts to correct location
run: |
mkdir -p python/dist
find dist -name "*" -type f -exec mv {} python/dist/ \;
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/2473ec6c6aa87f38946284d51289219fd0b87264
with:
packages-dir: python/dist/