Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

uv_matrix-0.0.1.tar.gz (15.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

uv_matrix-0.0.1-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

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

Hashes for uv_matrix-0.0.1.tar.gz
Algorithm Hash digest
SHA256 d560d30c1c3a00b8c31dc71e8e8e9113df9619d71cbf356a5648e695d6cd3cb8
MD5 eefb50d4ee1f8e5d1ce00c11686ff017
BLAKE2b-256 c7ce6f8abcc2dcb2f35bb71a87efc90a7c47a96b4fe61c8b135978c54a3f3203

See more details on using hashes here.

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

Hashes for uv_matrix-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e198cd2801e84cec4c1cabc223707ee44815c531080eafa776909bd33bf7a47d
MD5 822f62a6793ab1f0e5242908d9ee35ac
BLAKE2b-256 6256018beeaf52060172c7be1d81a7cac9cf254bc4b64fdb0e2f761bfa1fb53b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page