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.LINUX_ARM64_RUNNER: Final = 'ubuntu-26.04-arm'¶

GitHub-hosted image of the ARM Linux slot.

repomatic.matrix.axes.LINUX_X64_RUNNER: Final = 'ubuntu-26.04'¶

GitHub-hosted image of the x86 Linux slot.

repomatic.matrix.axes.MACOS_ARM64_RUNNER: Final = 'macos-26'¶

GitHub-hosted image of the Apple-silicon macOS slot.

repomatic.matrix.axes.MACOS_X64_RUNNER: Final = 'macos-26-intel'¶

GitHub-hosted image of the Intel macOS slot.

repomatic.matrix.axes.WINDOWS_ARM64_RUNNER: Final = 'windows-11-arm'¶

GitHub-hosted image of the ARM Windows slot.

repomatic.matrix.axes.WINDOWS_X64_RUNNER: Final = 'windows-2025'¶

GitHub-hosted image of the x86 Windows slot.

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.

Each label is spelled once, in the slot constants above, which the test axes and the Nuitka build fleet (NUITKA_BUILD_TARGETS) both read. sync-runner-images moves a retiring label by rewriting its one literal, so both follow.

Note

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

An image counts as stable here once it has been validated against this suite, not once a vendor relabels it. GitHub’s preview label gates whether an image can sit behind the -latest aliases, and this project never uses those aliases: a floating alias re-points with no commit to review, and check_runner_images() rejects one outright. The Ubuntu 26.04 pair was adopted that way while still in preview, before GitHub declared it generally available on 2026-09-17. 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.

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.KNOWN_RUNNERS: Final[frozenset[str]] = frozenset({'macos-26', 'macos-26-intel', 'ubuntu-26.04', 'ubuntu-26.04-arm', 'windows-11-arm', 'windows-2025'})¶

Every runner image this project has deliberately chosen.

The closest thing to a curated list of images a project should be running on, and the one place carrying measured guidance on their relative speed and cost. A job naming something outside it has been picked without that guidance.

The test axes are the whole list: every job runs on an image the suite is also validated against, so “where is the suite exercised” and “what may a job run on” are one question. That is deliberate, since each extra image is one more to track, pin and migrate. A job needing something else is a decision to make explicitly, by widening the axes rather than by naming an image here.

repomatic.matrix.axes.TEST_PYTHON_FULL = ('3.11', '3.15', '3.16')¶

Python versions tested across every runner in the full matrix.

Spans the supported range: the floor (3.11), the latest stable release (3.15), and the in-development version (3.16, flagged continue-on-error via UNSTABLE_PYTHON_VERSIONS). Intermediate releases (3.12 to 3.14) 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.11', '3.15')¶

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.16'})¶

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.16-dev rather than a bare py3.16 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.16t reads 3.16t-dev.

The spelling is borrowed, not invented. pyenv ships version definitions named 3.16-dev and 3.16t-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.16 parses as a version request (“No interpreter found for Python 3.16”), while uv python find 3.16-dev falls through to the executable-name branch (“No interpreter found for executable name 3.16-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.15t': '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).

class repomatic.matrix.axes.MatrixName(*values)[source]¶

Bases: StrEnum

The two test matrices every project gets, and the axes each one starts from.

FULL = 'full'¶

The matrix of pushes to the default branch and of scheduled runs.

PR = 'pr'¶

The reduced matrix of pull requests, for fast feedback.

property runners: tuple[str, ...]¶

The runner images this matrix seeds its os axis with, in order.

property python_versions: tuple[str, ...]¶

The Python versions this matrix seeds its python-version axis with.

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().