repomatic.matrix_axes module

Test matrix constants for CI workflows.

Defines the GitHub-hosted runner images and Python versions used to build test matrices. Separating these from repomatic.metadata.core makes the CI matrix configuration self-contained and easier to update when runner images or Python releases change.

repomatic.matrix_axes.TEST_RUNNERS_FULL = ('ubuntu-26.04-arm', 'ubuntu-26.04', 'macos-26', 'macos-26-intel', 'windows-11-arm', 'windows-2025')

GitHub-hosted runners for the full test matrix.

Two variants per platform (one per architecture). See available images.

Note

Preview images are adopted on measurement, not on GitHub’s label

GitHub still marks the Ubuntu 26.04 pair preview, which gates their eligibility to sit behind the -latest aliases. This project never uses those aliases (a floating alias re-points with no commit to review, which check_runner_images() rejects outright), so that distinction does not reach it. An image is treated as stable here once it has been validated against this suite, not once a vendor relabels it. Measured over consecutive runs before the swap, ubuntu-26.04-arm beat ubuntu-24.04-arm by 16% on Python 3.10 and 28% on 3.14, tied on 3.15, and failed nothing.

The residual risk is capacity rather than correctness: GitHub warns a preview image’s capacity “will be balanced only throughout the next weeks”, so queue time may be worse than the runtimes above suggest. Release binaries are built on GA images for that reason, see NUITKA_BUILD_TARGETS.

Note

Architecture speed is not uniform across platforms

When reducing to one runner per OS, choose by measured speed, not architecture (see Test matrix). Tendencies from repomatic’s own full test suite: ARM Linux runs two to three times as fast as the lean x86 ubuntu-slim that preceded ubuntu-26.04 on this axis; Apple-silicon macos-26 beats macos-26-intel by ~2x; the two Windows images tie on compute (windows-2025 is the PR pick). Per-job wall-clock folds in setup and upload, so isolate the test steps before blaming the image. These figures drift as images are re-provisioned, so re-confirm against your own job timings.

repomatic.matrix_axes.TEST_RUNNERS_PR = ('ubuntu-26.04-arm', 'macos-26', 'windows-2025')

Reduced runner set for pull request test matrices.

One runner per platform: ARM Linux (ubuntu-26.04-arm) and Apple-silicon macOS (macos-26) are the fastest of their platform on the test workload, plus x86 Windows (windows-2025, where the two Windows images tie on compute). x86 Linux stays covered by the full matrix (TEST_RUNNERS_FULL).

Note

Why ARM Linux for the PR slot

The suite runs pytest --numprocesses=auto, so it scales with cores and favors ARM, by two to three times over the x86 image, for quicker PR feedback. See Test matrix for the measurements.

repomatic.matrix_axes.TEST_PYTHON_FULL = ('3.10', '3.14', '3.15')

Python versions tested across every runner in the full matrix.

Spans the supported range: the floor (3.10), the latest stable release (3.14), and the in-development version (3.15, flagged continue-on-error via UNSTABLE_PYTHON_VERSIONS). Intermediate releases (3.11, 3.12, 3.13) are skipped to reduce CI load. Released build flavors (free-threaded) are not full-spread; they get a single-runner smoke test instead, see SINGLE_RUNNER_PYTHON_VERSIONS.

repomatic.matrix_axes.TEST_PYTHON_PR = ('3.10', '3.14')

Reduced Python version set for pull request test matrices.

Just the floor and the latest stable release, for fast PR feedback. The in-development version and released build flavors (free-threaded) are left to the full matrix.

repomatic.matrix_axes.UNSTABLE_PYTHON_VERSIONS: Final[frozenset[str]] = frozenset({'3.15'})

Python versions still in development.

Jobs using these versions run with continue-on-error in CI. Contrast with SINGLE_RUNNER_PYTHON_VERSIONS, which are released and run stable.

repomatic.matrix_axes.PRERELEASE_LABEL_SUFFIX: Final[str] = '-dev'

Suffix marking an unreleased Python in a CI job name.

Appended to each UNSTABLE_PYTHON_VERSIONS member to form the python-label matrix key, so a continue-on-error cell states why it may fail: ⁉️ ubuntu-26.04 / py3.15-dev rather than a bare py3.15 indistinguishable from a released one. Being a plain suffix append, it composes with the free-threaded flavor the way both tools below spell it: 3.15t reads 3.15t-dev.

The spelling is borrowed, not invented. pyenv ships version definitions named 3.15-dev and 3.15t-dev that build from the CPython branch tip, and actions/setup-python documents an x.y-dev syntax resolving to “the latest patch version of Python, alpha, beta and rc (release candidate) releases included”. Anyone reading a GitHub Actions job name has met it in one of the two.

Warning

A label, never a uv request

uv does not implement the syntax. uv python find 3.15 parses as a version request (“No interpreter found for Python 3.15”), while uv python find 3.15-dev falls through to the executable-name branch (“No interpreter found for executable name 3.15-dev”). The workflow hands python-version straight to uv venv --python, so the axis value stays the bare version and this suffix reaches the job name: alone. Writing it into a [tool.repomatic.test-matrix] directive matches no cell.

repomatic.matrix_axes.SINGLE_RUNNER_PYTHON_VERSIONS: Final[dict[str, str]] = {'3.14t': 'ubuntu-26.04-arm'}

Released Python build flavors smoke-tested on a single runner, mapped to it.

A free-threaded build (the t suffix, made officially supported in 3.14 by PEP 779) runs the same released interpreter as its base version, just without the GIL. The base version already gets the full cross-platform spread (TEST_PYTHON_FULL), so the library logic is covered everywhere; the flavor only needs one runner to catch a free-threading-specific break. These run stable (expected to pass), unlike the unreleased UNSTABLE_PYTHON_VERSIONS. The runner is ubuntu-26.04-arm, the default single-runner pick: the fastest measured on compute-bound parallel work and the cheapest tier, and free-threading targets server workloads where Linux/ARM is the norm (see Test matrix).

repomatic.matrix_axes.python_version_sort_key(version)[source]

Sort key ordering python-version axis values by release.

Compares on the numeric release components, then places a build flavor (the free-threaded t suffix of SINGLE_RUNNER_PYTHON_VERSIONS) directly after its base version rather than after every later release: 3.14 sorts before 3.14t, which sorts before 3.15. Non-numeric components are dropped, so an axis value like pypy3.10 falls back to the digits it carries.

Parameters:

version (str) – A python-version axis value, like 3.14 or 3.14t.

Return type:

tuple[tuple[int, ...], int]

Returns:

A key tuple suitable for sorted().