Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 100 additions & 8 deletions .github/workflows/build-wheels-defined.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ on:
type: boolean
required: false
default: true
os_linux_armv7_legacy:
description: Build on linux armv7 legacy (bullseye, glibc 2.31)
type: boolean
required: false
default: false

env:
GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
Expand Down Expand Up @@ -86,7 +91,7 @@ jobs:
- name: Upload artifacts of downloaded_wheels directory
uses: actions/upload-artifact@v4
with:
name: wheels-download-directory-ubuntu-${{ matrix.python-version }}
name: wheels-download-directory-linux-x86_64-${{ matrix.python-version }}
path: ./downloaded_wheels


Expand Down Expand Up @@ -116,14 +121,17 @@ jobs:
- name: Install build dependencies
run: python -m pip install -r build_requirements.txt

- name: Install additional OS dependencies - Windows
run: powershell -ExecutionPolicy Bypass -File os_dependencies/windows.ps1

- name: Build wheels
run: |
python build_wheels_from_file.py --requirements ${{ inputs.packages }}

- name: Upload artifacts of downloaded_wheels directory
uses: actions/upload-artifact@v4
with:
name: wheels-download-directory-windows-${{ matrix.python-version }}
name: wheels-download-directory-windows-x86_64-${{ matrix.python-version }}
path: ./downloaded_wheels


Expand Down Expand Up @@ -165,7 +173,7 @@ jobs:
- name: Upload artifacts of downloaded_wheels directory
uses: actions/upload-artifact@v4
with:
name: wheels-download-directory-macos-x86-${{ matrix.python-version }}
name: wheels-download-directory-macos-x86_64-${{ matrix.python-version }}
path: ./downloaded_wheels


Expand Down Expand Up @@ -262,7 +270,7 @@ jobs:
- name: Upload artifacts of downloaded_wheels directory
uses: actions/upload-artifact@v4
with:
name: wheels-download-directory-linux-arm7-${{ matrix.python-version }}
name: wheels-download-directory-linux-armv7-${{ matrix.python-version }}
path: ./downloaded_wheels


Expand All @@ -289,7 +297,7 @@ jobs:
run: python -m pip install -r build_requirements.txt

- name: Install additional OS dependencies - Linux ARM
run: os_dependencies/linux_arm.sh
run: sudo bash os_dependencies/linux_arm.sh

- name: Build wheels
run: |
Expand All @@ -301,17 +309,101 @@ jobs:
name: wheels-download-directory-linux-arm64-${{ matrix.python-version }}
path: ./downloaded_wheels


linux-armv7-legacy:
needs: get-supported-versions
name: linux aarch32 (armv7 legacy)
if: ${{ inputs.os_linux_armv7_legacy }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ${{ fromJson(needs.get-supported-versions.outputs.supported_python) }}
exclude:
# Python 3.14 doesn't have bullseye images for ARM
- python-version: '3.14'
steps:
- name: Set up QEMU for ARMv7
uses: docker/setup-qemu-action@v3
with:
platforms: linux/arm/v7

- name: Checkout repository
uses: actions/checkout@v4

- name: Build wheels - ARMv7 Legacy (in Docker)
# Build on Bullseye (glibc 2.31) for compatibility with older systems
run: |
docker run --rm --platform linux/arm/v7 \
-v $(pwd):/work \
-w /work \
-e GH_TOKEN="${GH_TOKEN}" \
-e PIP_NO_CACHE_DIR=1 \
python:${{ matrix.python-version }}-bullseye \
bash -c "
set -e
python --version
# Install pip packages without cache to reduce memory usage
python -m pip install --no-cache-dir --upgrade pip
python -m pip install --no-cache-dir -r build_requirements.txt
bash os_dependencies/linux_arm.sh
# Source Rust environment after installation
. \$HOME/.cargo/env
python build_wheels_from_file.py --requirements '${{ inputs.packages }}'
"

- name: Upload artifacts of downloaded_wheels directory
uses: actions/upload-artifact@v4
with:
name: wheels-download-directory-linux-armv7legacy-${{ matrix.python-version }}
path: ./downloaded_wheels

# Repair wheels for dynamically linked libraries on all platforms
# https://github.com/espressif/idf-python-wheels/blob/main/README.md#universal-wheel-tag---linking-of-dynamic-libraries
repair-wheels:
if: ${{ always() }}
needs: [get-supported-versions, ubuntu-latest, windows-latest, macos-latest, macos-m1, linux-armv7, linux-arm64]
needs: [get-supported-versions, ubuntu-latest, windows-latest, macos-latest, macos-m1, linux-armv7, linux-arm64, linux-armv7-legacy]
name: Repair wheels
uses: ./.github/workflows/wheels-repair.yml

upload-python-wheels:
if: ${{ always() }}
needs: [repair-wheels]
needs: [get-supported-versions, repair-wheels]
name: Upload Python wheels
uses: espressif/idf-python-wheels/.github/workflows/upload-python-wheels.yml@main
uses: ./.github/workflows/upload-python-wheels.yml
with:
supported_python_versions: ${{ needs.get-supported-versions.outputs.supported_python }}
secrets: inherit

verify-s3-wheels:
if: ${{ always() }}
needs: [get-supported-versions, upload-python-wheels]
name: Verify S3 wheels against exclude list
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Get latest Python version
id: python-version
run: |
VERSIONS='${{ needs.get-supported-versions.outputs.supported_python }}'
LATEST=$(echo "$VERSIONS" | jq -r '.[0]')
echo "version=$LATEST" >> $GITHUB_OUTPUT

- name: Setup Python ${{ steps.python-version.outputs.version }}
uses: actions/setup-python@v5
with:
python-version: ${{ steps.python-version.outputs.version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r build_requirements.txt

- name: Verify S3 wheels
run: python verify_s3_wheels.py ${{ secrets.DL_BUCKET }} ${{ needs.get-supported-versions.outputs.oldest_supported_python }}
40 changes: 36 additions & 4 deletions .github/workflows/build-wheels-platforms.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ jobs:

- name: Install additional OS dependencies - Linux ARM64
if: matrix.os == 'Linux ARM64'
run: os_dependencies/linux_arm.sh
run: sudo bash os_dependencies/linux_arm.sh

- name: Install additional OS dependencies - Windows
if: matrix.os == 'Windows'
Expand All @@ -127,7 +127,6 @@ jobs:
-e MIN_IDF_MINOR_VERSION=${{ needs.get-supported-versions.outputs.min_idf_minor_version }} \
-e GH_TOKEN="${GH_TOKEN}" \
-e PIP_NO_CACHE_DIR=1 \
-e LDFLAGS="-Wl,-z,max-page-size=0x1000" \
python:${{ matrix.python-version }}-bookworm \
bash -c "
set -e
Expand All @@ -153,7 +152,6 @@ jobs:
-e MIN_IDF_MINOR_VERSION=${{ needs.get-supported-versions.outputs.min_idf_minor_version }} \
-e GH_TOKEN="${GH_TOKEN}" \
-e PIP_NO_CACHE_DIR=1 \
-e LDFLAGS="-Wl,-z,max-page-size=0x1000" \
python:${{ matrix.python-version }}-bullseye \
bash -c "
set -e
Expand Down Expand Up @@ -214,7 +212,41 @@ jobs:
uses: ./.github/workflows/wheels-repair.yml

upload-python-wheels:
needs: [repair-wheels]
needs: [get-supported-versions, repair-wheels]
name: Upload Python wheels
uses: ./.github/workflows/upload-python-wheels.yml
with:
supported_python_versions: ${{ needs.get-supported-versions.outputs.supported_python }}
secrets: inherit

verify-s3-wheels:
needs: [get-supported-versions, upload-python-wheels]
name: Verify S3 wheels against exclude list
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Get latest Python version
id: python-version
run: |
VERSIONS='${{ needs.get-supported-versions.outputs.supported_python }}'
LATEST=$(echo "$VERSIONS" | jq -r '.[0]')
echo "version=$LATEST" >> $GITHUB_OUTPUT

- name: Setup Python ${{ steps.python-version.outputs.version }}
uses: actions/setup-python@v5
with:
python-version: ${{ steps.python-version.outputs.version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r build_requirements.txt

- name: Verify S3 wheels
run: python verify_s3_wheels.py ${{ secrets.DL_BUCKET }} ${{ needs.get-supported-versions.outputs.oldest_supported_python }}
8 changes: 5 additions & 3 deletions .github/workflows/build-wheels-python-dependent.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,11 @@ jobs:

- name: Install additional OS dependencies - Linux ARM64
if: matrix.os == 'Linux ARM64'
run: os_dependencies/linux_arm.sh
run: sudo bash os_dependencies/linux_arm.sh

- name: Install additional OS dependencies - Windows
if: matrix.os == 'Windows'
run: powershell -ExecutionPolicy Bypass -File os_dependencies/windows.ps1

- name: Download artifacts
uses: actions/download-artifact@v4
Expand All @@ -134,7 +138,6 @@ jobs:
-e PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 \
-e GH_TOKEN="${GH_TOKEN}" \
-e PIP_NO_CACHE_DIR=1 \
-e LDFLAGS="-Wl,-z,max-page-size=0x1000" \
python:${{ matrix.python-version }}-bookworm \
bash -c "
set -e
Expand All @@ -158,7 +161,6 @@ jobs:
-e PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 \
-e GH_TOKEN="${GH_TOKEN}" \
-e PIP_NO_CACHE_DIR=1 \
-e LDFLAGS="-Wl,-z,max-page-size=0x1000" \
python:${{ matrix.python-version }}-bullseye \
bash -c "
set -e
Expand Down
121 changes: 121 additions & 0 deletions .github/workflows/test-wheels-install.yml
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was pointed out by AI. Please check its validity....

**Platform-specific exclusions can be re-introduced by artifact merge**

  test-wheels-install.yml runs a matrix (per OS and Python). Each job:
  • Downloads all repaired wheels (wheels-repaired-all),
  • Runs test_wheels_install.py, which uses current runner platform and deletes only wheels excluded for that platform,
  • Uploads ./downloaded_wheels/*.whl as wheels-tested-${{ matrix.arch }}-${{ matrix.python-version }}.

  The upload job then downloads with pattern: wheels-tested-* and merge-multiple: true. So it gets the union of all per-job artifacts. A wheel that is excluded only on one platform (e.g. Windows) is deleted in that platform’s job but
  still present in other jobs’ artifacts (e.g. Linux). After merge, that wheel is back in the set that gets uploaded. So platform-specific exclusions are not fully enforced before upload; they are only caught later by verify_s3_wheels,
   and by then the wheel is already on S3.
  Recommendation: Either:
  • Add the same exclude check in upload_wheels.py as above (evaluate each wheel’s target platform from its filename and skip if it matches any exclude rule), so the merge no longer allows excluded wheels to slip through, or
  • Or change the flow so a single job (or a dedicated “filter” step) runs the exclude logic for every wheel’s target platform (e.g. using the same logic as verify_s3_wheels) and produces one filtered artifact for upload.

  The first option (filter in upload_wheels.py) is simpler and gives one clear enforcement point.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a wrong suggestion. The logic described is basically true, but it is a valid and desired behavior.
I will try to clarify the behaviour:

  • Downloads all repaired wheels (wheels-repaired-all)
  • Runs test_wheels_install.py, which uses the current runner platform - this is crucial because we need to actually test the "bank" of all the repaired wheels if we are able to use pip resolver to pick the wheel for the platform
  • On that runner removes all packages which have some exclusion rule - applied exclude_list
  • Uploads ./downloaded_wheels/*.whl as wheels-tested-${{ matrix.arch }}-${{ matrix.python-version }}

What is not true is that:

deleted in that platform’s job, but still present in other jobs’ artifacts

When the exclusion rule is stricter (e.g., the whole package -> the package is deleted on all platforms, and there is no way to get back into the tested-wheels artifacts)

When the final merge of tested wheels is done, this is basically what happens on the S3: all packages get merged together in the correct PyPI endpoint. This is mainly done to save some upload complexity because of a few identical packages produced, for example, from the legacy ARMv7 and ARMv7 runners

I hope this has explained it better, and the reason why this suggestion will not be taken into account.

Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: Test wheels installation

# Test that all built wheels are valid and platform-compatible
# This workflow runs after repair-wheels and before upload to catch any issues
# Uses test_wheels_install.py for consistent testing across all platforms

on:
workflow_call:
inputs:
supported_python_versions:
description: 'JSON array of supported Python versions'
required: true
type: string

jobs:
test-install:
name: Test ${{ matrix.os }} - Python ${{ matrix.python-version }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
os:
- Windows
- Linux x86_64
- macOS Intel
- macOS ARM
- Linux ARM64
- Linux ARMv7
- Linux ARMv7 Legacy
include:
- os: Windows
runner: windows-latest
arch: windows-x86_64
- os: Linux x86_64
runner: ubuntu-latest
arch: linux-x86_64
- os: macOS Intel
runner: macos-15-intel
arch: macos-x86_64
- os: macOS ARM
runner: macos-latest
arch: macos-arm64
- os: Linux ARM64
runner: ubuntu-24.04-arm
arch: linux-arm64
- os: Linux ARMv7
runner: ubuntu-latest
arch: linux-armv7
- os: Linux ARMv7 Legacy
runner: ubuntu-latest
arch: linux-armv7legacy
python-version: ${{ fromJson(inputs.supported_python_versions) }}
exclude:
# Python 3.14 doesn't have bullseye images for ARM
- python-version: '3.14'
os: Linux ARMv7 Legacy

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up QEMU for ARMv7
if: matrix.os == 'Linux ARMv7' || matrix.os == 'Linux ARMv7 Legacy'
uses: docker/setup-qemu-action@v3
with:
platforms: linux/arm/v7

- name: Download all repaired wheels
uses: actions/download-artifact@v4
with:
name: wheels-repaired-all
path: ./downloaded_wheels

- name: Setup Python
if: matrix.os != 'Linux ARMv7' && matrix.os != 'Linux ARMv7 Legacy'
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Test wheel installation
if: matrix.os != 'Linux ARMv7' && matrix.os != 'Linux ARMv7 Legacy'
run: |
python --version
python -m pip install --upgrade pip
pip install -r build_requirements.txt
python test_wheels_install.py

- name: Test wheel installation - ARMv7 (in Docker)
if: matrix.os == 'Linux ARMv7'
run: |
docker run --rm --platform linux/arm/v7 \
-v $(pwd):/work \
-w /work \
python:${{ matrix.python-version }}-bookworm \
bash -c "
python --version
python -m pip install --upgrade pip
pip install -r build_requirements.txt
python test_wheels_install.py
"

- name: Test wheel installation - ARMv7 Legacy (in Docker)
if: matrix.os == 'Linux ARMv7 Legacy'
run: |
docker run --rm --platform linux/arm/v7 \
-v $(pwd):/work \
-w /work \
python:${{ matrix.python-version }}-bullseye \
bash -c "
python --version
python -m pip install --upgrade pip
pip install -r build_requirements.txt
python test_wheels_install.py
"

- name: Upload tested wheels
uses: actions/upload-artifact@v4
with:
name: wheels-tested-${{ matrix.arch }}-${{ matrix.python-version }}
path: ./downloaded_wheels/*.whl
if-no-files-found: warn
Loading
Loading