A tiny matrix runner for Python projects using Astral uv.
Project description
uv-matrix
A tiny matrix runner for Python projects using Astral uv.
Status: early development.
uv-matrix expands declarative matrices from pyproject.toml into jobs, runs them with uv run, and reports failures.
📖 Documentation: https://uv-matrix.readthedocs.io/
uv-matrix does not manage Python interpreters, virtual environments, or dependencies itself. All interpreter discovery and download, virtual environment creation, and dependency resolution come from uv. uv-matrix only decides which commands to run, with which matrix values, and in what order.
Why uv-matrix?
Many Python projects need to run the same checks across several Python versions, dependency versions, or task variants.
uv-matrix is pyproject.toml-centered: matrices and reusable tasks live alongside the rest of your project configuration:
[tool.uv-matrix.matrix.test]
python-version = ["3.12", "3.13"]
tasks = ["run-test"]
[tool.uv-matrix.tasks.run-test]
run = "pytest"
It is intentionally smaller than tox. tox manages test environments; uv-matrix delegates environment management to uv and focuses only on scheduling matrix jobs.
How is this different from tox?
tox is powerful and mature, but matrix-style configuration can become hard to read when combinations are encoded into environment names and factors.
uv-matrix keeps the matrix explicit: Python versions, dependency variants, and task variants are written as plain axes in pyproject.toml.
Installation
uv-matrix needs Python 3.10+ and a working uv install.
uv add --dev uv-matrix
uv run uv-matrix --help
Or run it directly:
uvx uv-matrix --help
Configuration
Configuration lives under [tool.uv-matrix] in pyproject.toml.
[project]
name = "matrix-test"
version = "0.1.0"
requires-python = ">=3.12"
# Optional dependencies (extras) selectable per job via a task's `extras`.
[project.optional-dependencies]
django = [
"django>=6.0.6",
]
flask = [
"flask>=3.1.3",
]
# Dependency groups selectable per job via a task's `groups`.
[dependency-groups]
dev = [
"ruff>=0.15.20",
]
doc = [
"sphinx>=9.1.0",
]
[tool.uv-matrix]
continue-on-error = false # stop the run on the first failing job (the default)
max-jobs = 4 # run up to 4 jobs at once (1 = sequential)
# A matrix named "test": every key except `tasks` is an axis, and the axes are
# combined as a cartesian product (here 2 x 3 = 6 cells).
[tool.uv-matrix.matrix.test]
python-version = ["3.12", "3.13"] # reserved axis: inherited as `uv run --python`
webui = ["", "django", "flask"] # arbitrary axis: read in templates as matrix['webui']
tasks = ["test"] # run these tasks for every cell
# A second, independent matrix. With no extra axes it runs each task once.
[tool.uv-matrix.matrix.checks]
python-version = ["3.13"]
tasks = ["lint", "doc"]
# Task definitions are reusable across matrices. `run` is the command to execute.
[tool.uv-matrix.tasks.test]
run = "pytest {{ posargs }}" # {{ posargs }} expands to args passed after `--`
extras = ["{{ matrix['webui'] }}"] # adds `--extra <webui>`; the empty "" cell renders blank and is dropped
when = "matrix['webui'] != 'django' or platform != 'win32'" # run unless it's the django cell on Windows; a false `when` skips the job
[tool.uv-matrix.tasks.lint]
run = "ruff check ."
[tool.uv-matrix.tasks.doc]
groups = ["doc"] # adds `--group doc` to the uv run command
run = "make html"
cwd = "docs" # run the command from this directory
A matrix defines the values to test. A task defines the command to run.
Task fields support Jinja2 templates such as {{ matrix['webui'] }} and {{ posargs }}; see the template reference for available variables and rendering rules.
when is evaluated with Python's eval against uv-matrix-provided context, so treat configuration as trusted project code; see the conditions reference for available variables and examples.
These templates and when expressions are evaluated only when you invoke run (the point at which jobs are actually built and executed). Commands that merely enumerate jobs, such as list, expand the matrix without rendering templates or evaluating when, so nothing from your config is executed.
The example above expands to:
test:test python-version=3.12 webui=""
test:test python-version=3.12 webui="django"
test:test python-version=3.12 webui="flask"
test:test python-version=3.13 webui=""
test:test python-version=3.13 webui="django"
test:test python-version=3.13 webui="flask"
checks:lint python-version=3.13
checks:doc python-version=3.13
Inside a matrix, every key except tasks defines an axis. The special python-version axis is inherited by tasks that do not set their own Python version.
Commands are executed through uv run. Each job runs in its own isolated environment rather than the project's .venv. For example, the test task above runs roughly like this on Linux:
uv run --python 3.12 sh -c "pytest"
Usage
uv-matrix run # run every job from every matrix
uv-matrix run --matrix test # run one matrix
uv-matrix run --filter webui=django # select jobs
uv-matrix run --task lint # run one task wherever it appears
uv-matrix run --max-jobs 4 # run up to 4 jobs at once
uv-matrix run --dry-run # print commands without running them
uv-matrix run --task test -- -k slow # pass extra args as {{ posargs }}
uv-matrix list # list selectable jobs
By default, uv-matrix finds pyproject.toml by walking up from the current directory, then runs from the project root. Override this with --config PATH or --project DIR.
License
MIT License. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file uv_matrix-0.0.1.tar.gz.
File metadata
- Download URL: uv_matrix-0.0.1.tar.gz
- Upload date:
- Size: 15.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d560d30c1c3a00b8c31dc71e8e8e9113df9619d71cbf356a5648e695d6cd3cb8
|
|
| MD5 |
eefb50d4ee1f8e5d1ce00c11686ff017
|
|
| BLAKE2b-256 |
c7ce6f8abcc2dcb2f35bb71a87efc90a7c47a96b4fe61c8b135978c54a3f3203
|
File details
Details for the file uv_matrix-0.0.1-py3-none-any.whl.
File metadata
- Download URL: uv_matrix-0.0.1-py3-none-any.whl
- Upload date:
- Size: 18.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e198cd2801e84cec4c1cabc223707ee44815c531080eafa776909bd33bf7a47d
|
|
| MD5 |
822f62a6793ab1f0e5242908d9ee35ac
|
|
| BLAKE2b-256 |
6256018beeaf52060172c7be1d81a7cac9cf254bc4b64fdb0e2f761bfa1fb53b
|