Skip to content

Support dynamic Python build matrices - #3541

Merged
luhenry merged 5 commits into
mainfrom
tgamblin/dynamic-python-matrix
Nov 4, 2026
Merged

luhenry merged 5 commits into
mainfrom
tgamblin/dynamic-python-matrix

Conversation

@threexc

@threexc threexc commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

Instead of hard-coding our target versions, change our code in ci_scripts/, .github/workflows, skills/, and docs/development.md to support dynamically deriving a target Python build matrix for each package, which can be rolled out gradually as updates are performed (instead of having to bulk rewrite and trigger all existing workflows). Now, when a workflow sets the python-matrix parameter to true, use ci_scripts/pending_versions.py to derive the list based on what the release targets upstream. Also allow us to extend/exclude the lists on a per-package basis by setting the python-extend and python-exclude inputs.

Modify build-falcon.yml as a test change. The skills files indicate that the rollout should be gradual, so our existing automation can convert workflows over time as new releases are built.

@threexc
threexc requested review from justeph and luhenry October 20, 2026 16:16
@threexc threexc changed the title Support dynamic Python versions Support dynamic Python build matrices Oct 20, 2026
@threexc
threexc force-pushed the tgamblin/dynamic-python-matrix branch from 1ca9f20 to f7c4321 Compare October 21, 2026 13:10
@luhenry

luhenry commented Oct 22, 2026

Copy link
Copy Markdown
Member

Can't we get the list of python configuration we should build in check_versions.py and store that information in the docs/packages/<pkg>.yml per-version, like:

- version: 1.2.3
  python-versions: [3.10, 3.11, 3.14, 3.14t] // the versions that upstream builds for that package

Then in .github/workflows/_setup.yml we still only have docs/packages/<pkg>.yml to check. I like the idea of python-exclude to make sure we can still only have a subset for things that don't work. I don't get the need for python-extend: though as there shouldn't be anything we build that upstream doesn't build already.

@justeph

justeph commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

Can't we get the list of python configuration we should build in check_versions.py and store that information in the docs/packages/<pkg>.yml per-version, like:

- version: 1.2.3
  python-versions: [3.10, 3.11, 3.14, 3.14t] // the versions that upstream builds for that package

Then in .github/workflows/_setup.yml we still only have docs/packages/<pkg>.yml to check. I like the idea of python-exclude to make sure we can still only have a subset for things that don't work. I don't get the need for python-extend: though as there shouldn't be anything we build that upstream doesn't build already.

I really like the idea of having that info in docs/packages/<pkg>.yml.

Comment thread .github/workflows/_setup.yml Outdated
python-matrix:
description: Also compute the matrix output, querying PyPI for the interpreters upstream builds each version for.
required: false
default: false

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why false by default?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The idea was to set it to false by default as part of a gradual rollout to our workflows - the skills/ directory gives the LLM instructions for converting workflows to use a dynamic matrix as it updates them to build new versions. That way existing workflows keep working as expected until there's a reason to trigger them again.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For the transition, can't we simply generate it all the time and simply ignore the output in the workflows that haven't migrated yet?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@luhenry I've reworked it so that a matrix is always generated, but it's ignored if python-versions is missing because we're manually specifying a version list.

Comment thread .github/workflows/_setup.yml Resolved
Comment thread .github/workflows/_setup.yml Resolved
@threexc

threexc commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

Can't we get the list of python configuration we should build in check_versions.py and store that information in the docs/packages/<pkg>.yml per-version, like:

- version: 1.2.3
  python-versions: [3.10, 3.11, 3.14, 3.14t] // the versions that upstream builds for that package

I like that idea. I'll work on a change to do that instead.

Then in .github/workflows/_setup.yml we still only have docs/packages/<pkg>.yml to check. I like the idea of python-exclude to make sure we can still only have a subset for things that don't work. I don't get the need for python-extend: though as there shouldn't be anything we build that upstream doesn't build already.

python-extend was meant as an opposite to python-exclude, e.g. for if we wanted to build free-threaded wheels for a project which doesn't, or something like that. It's unnecessary future-proofing at this point though, so I'll remove it.

@threexc
threexc force-pushed the tgamblin/dynamic-python-matrix branch from f7c4321 to 4e76952 Compare October 22, 2026 16:44
@threexc
threexc marked this pull request as ready for review October 22, 2026 16:44
@threexc

threexc commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

Updated to address most feedback. Still left the questions about default versions to exclude and default python-matrix state.

@luhenry

luhenry commented Oct 26, 2026

Copy link
Copy Markdown
Member

@threexc LGTM. Only question is around how do we migrate the build-<pkg>.yml files to this new way of working.

@threexc
threexc force-pushed the tgamblin/dynamic-python-matrix branch from 4e76952 to 3add317 Compare October 26, 2026 15:58
@threexc

threexc commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

@threexc LGTM. Only question is around how do we migrate the build-<pkg>.yml files to this new way of working.

There's a section added in skills/python-project-porting/references/workflow-anatomy.md to teach the LLM what to do as it upgrades packages:

+**Converting old workflows is gradual.** Most `build-<pkg>.yml` still hard-code `python:
+[...]` next to `version:`. When a workflow is touched to build a new release, switch it:
+make sure the new version's entry has `python-versions`, add `python-matrix: true` to the
+`setup` call, and replace the `version:` + `python:` vectors
+of the build job(s) with `include: ${{ fromJSON(needs.setup.outputs.matrix) }}` (see
+`build-falcon.yml`). The matrix may grow (cp310/cp311, cp315/cp315t): exclude what fails for
+riscv64-specific reasons rather than reverting to a hard-coded list. Workflows whose extra
+axes (`libc`, `build`) don't fit a `{version, python}` include can stay hard-coded.
+
+A JSON `include:` can't carry per-entry keys (`test_skip`, `pytest_k`, …) or be trimmed by
+`exclude:`, so compute per-interpreter values in expressions instead, e.g.
+`CIBW_TEST_SKIP: ${{ endsWith(matrix.python, 't') && '*' || '' }}`.

Do you think more is needed? I wanted to avoid an immediate rewrite to all of the existing workflows.

@threexc

threexc commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Rebased the PR and fixed conflicts.

@threexc
threexc force-pushed the tgamblin/dynamic-python-matrix branch 4 times, most recently from a88cfb7 to d66bc45 Compare November 3, 2026 19:25
@threexc

threexc commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator Author

GitHub says this was updated ~3h ago, but I see nothing new... rebasing anyway.

python-wheels currently has a narrow, manually-set list of Python
versions to build for, but this is often at odds with upstream projects.
Instead, have check_versions.py record the Python versions upstream
builds each release for (from its wheels on PyPI) as python-versions in
the package's docs/packages/ file when declaring new versions, and add a
--python-versions option to fill them in for entries added by hand.
pending_versions.py then builds the workflow matrix from that data, with
no network access. Versions without python-versions are left out of the
matrix with a warning rather than failing, so workflows that don't use
the matrix yet keep working.

Keep the interpreters riscv64 can build in one place, RISCV64_PYTHONS in
pending_versions.py, which check_versions.py's deprecation check now
uses too. Update it when bumping cibuildwheel. Let riscv64_resolve.py
accept any interpreter tag, not only the old default four.

We may still want to exclude certain versions for a given package (for
example, to omit an older wheel that won't build on riscv64), so allow
passing flags to the script to indicate these versions.

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
Have _setup.yml always output a 'matrix' of {version, python} pairs,
built by pending_versions.py from each version's python-versions in
docs/packages/<pkg>.yaml. Workflows that still hard-code their
interpreters ignore it, so they can be converted gradually. Versions
missing python-versions are left out of the matrix and reported as
warning annotations rather than failing the setup job.

Add a 'python-exclude' input to drop interpreters for every version of
a package. It defaults to "cp39 cp310 cp311", following NumPy, which
only supports Python 3.12 and newer and which much of the registry
depends on.

Convert build-falcon.yml as a sample case, and run nightly.yml's PR
checks when pending_versions.py changes, since check_versions.py now
imports it.

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
…trix logic

Provide better instructions based on the changes in ci_scripts/ and
.github/workflows, to support dynamic Python matrix generation and
situational excludes. Make sure that any automated rework to existing
workflows is gradual, i.e. it occurs when a workflow is modified during
meaningful work, instead of bulk editing all workflows now.

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
@threexc
threexc force-pushed the tgamblin/dynamic-python-matrix branch from d66bc45 to 34bd739 Compare November 4, 2026 14:01
@luhenry

luhenry commented Nov 4, 2026

Copy link
Copy Markdown
Member

Gave a try to build-falcon.yml here. Matrix output is:

Matrix: [{"version":"4.4.0","python":"cp312"},{"version":"4.4.0","python":"cp313"},{"version":"4.4.0","python":"cp314"},{"version":"4.4.0","python":"cp314t"},{"version":"4.4.0","python":"cp315"},{"version":"4.4.0","python":"cp315t"}]

@luhenry
luhenry merged commit ca0a5c8 into main Nov 4, 2026
11 of 17 checks passed
@luhenry
luhenry deleted the tgamblin/dynamic-python-matrix branch November 4, 2026 16:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants