GitLab CI/CD Python Tox Multi-Version Pipeline Prompt
Test a Python package across interpreter versions in GitLab CI with tox — parallel matrix, pip/tox caching, coverage merge, and clean version-to-job mapping.
- Target user
- Python and DevOps engineers running multi-version test matrices in GitLab CI
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT, Cursor
The prompt
You are a senior Python release engineer who runs multi-interpreter test matrices in GitLab CI using tox. You know how to map tox environments to CI jobs cleanly, cache pip without corrupting per-version virtualenvs, run versions in parallel, and merge coverage into one report — and the traps in each.
I will provide:
- The package (`pyproject.toml`/`setup.cfg`, `tox.ini` if any)
- Supported Python versions (e.g., 3.9–3.13) and any pre-release targets
- Current CI (YAML) or none
- Extra factors (lint, type-check, docs, min vs. latest deps)
- The goal (build the matrix / speed it up / add coverage merge)
Your job:
1. **Map tox envs to CI jobs, one version per job**:
- Prefer `parallel:matrix:` with a `PYTHON_VERSION` axis, each job on the matching `python:X.Y` image running `tox -e py{XY}`.
- Or use tox's own factors and a single `TOXENV` per job. Never loop all versions in one job.
2. **Cache correctly**:
- Cache the **pip download cache** (`~/.cache/pip`) keyed on the lockfile — safe across versions.
- If caching `.tox/`, key it on `PYTHON_VERSION` + `tox.ini` hash so envs never cross interpreters.
3. **Handle pre-release/optional versions** with `allow_failure: true` scoped ONLY to non-supported versions; supported versions must gate.
4. **Add non-test factors** (lint, mypy, build) as their own jobs so a lint failure doesn't masquerade as a test failure.
5. **Merge coverage**: each job emits `.coverage.$PYTHON_VERSION`; a final job runs `coverage combine` + `coverage xml` and publishes the Cobertura report + `coverage:` regex for the MR badge.
6. **Speed**: use `needs` so coverage-merge starts as soon as the test jobs finish; pin tox and use `--installpkg` where a prebuilt wheel avoids recompiling per version.
7. **Fail fast where useful** but keep the full matrix visible so you see if a failure is one version or all.
Deliverables:
- A `tox.ini` (or confirmation the existing one is CI-ready)
- A `.gitlab-ci.yml` with a clean per-version matrix, correct caching, and coverage merge
- The `coverage:` regex + Cobertura wiring for the MR
- Which versions gate vs. allow-failure, and why
Mark DESTRUCTIVE or RISKY: cross-version `.tox/` cache reuse, allow_failure on supported versions, and coverage combine across incompatible sources.
---
Package config: [pyproject/setup.cfg + tox.ini]
Supported versions: [e.g. 3.9-3.13 + pre-release?]
Current CI (YAML): [PASTE or none]
Extra factors: [lint / mypy / docs / min-deps]
Goal: [build matrix / speed / coverage merge]
Run this prompt with AI
Test it, get an AI-improved version, or compare models — live in the Prompt Workspace. No copy-paste.
Why this prompt works
The common tox-in-CI mistake is a single job that loops every interpreter — slow, and it hides which version broke. Splitting to one job per version makes failures legible and reruns cheap, but then the cache becomes a footgun: a shared .tox/ corrupts across ABIs. This prompt fixes both, and adds the coverage-merge step teams usually skip.
How to use it
- One CI job per Python version via
parallel:matrix. - Cache pip downloads; never share built
.tox/across versions. - allow_failure only on pre-release interpreters.
- Combine per-version coverage into one Cobertura report.
Useful commands
# Run a single env locally, matching one CI job
tox -e py312
# List configured environments
tox -l
# Merge coverage from multiple version runs
coverage combine .coverage.* # each job wrote .coverage.<ver>
coverage report && coverage xml # -> coverage.xml (Cobertura)
GitLab CI patterns
Per-version matrix with safe pip cache
stages: [test, coverage]
.tox-test:
stage: test
image: python:${PYTHON_VERSION}
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.pip-cache"
cache:
key:
files: [poetry.lock] # or requirements*.txt / pyproject.toml
paths:
- .pip-cache # pip DOWNLOAD cache — safe across versions
before_script:
- pip install tox
script:
- tox -e "py${PYTHON_VERSION//./}" # 3.12 -> py312
- mv .coverage ".coverage.${PYTHON_VERSION}"
artifacts:
paths: [".coverage.${PYTHON_VERSION}"]
test:
extends: .tox-test
parallel:
matrix:
- PYTHON_VERSION: ["3.9", "3.10", "3.11", "3.12"]
test-prerelease:
extends: .tox-test
allow_failure: true # ONLY for unsupported/pre-release
parallel:
matrix:
- PYTHON_VERSION: ["3.13-rc"]
Non-test factors as separate jobs
lint:
stage: test
image: python:3.12
script:
- pip install tox
- tox -e lint
typecheck:
stage: test
image: python:3.12
script:
- pip install tox
- tox -e mypy
Coverage merge + MR badge
coverage:
stage: coverage
image: python:3.12
needs:
- job: test
artifacts: true
script:
- pip install coverage
- coverage combine .coverage.*
- coverage report
- coverage xml
coverage: '/^TOTAL.+?(\d+\%)$/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
Minimal tox.ini
[tox]
envlist = py39,py310,py311,py312
isolated_build = true
[testenv]
deps = -r requirements-dev.txt
commands = coverage run -m pytest {posargs}
[testenv:lint]
deps = ruff
commands = ruff check .
[testenv:mypy]
deps = mypy
commands = mypy src
Common findings this catches
- A single job looping all interpreters, hiding which version failed.
- Shared
.tox/cache restored into the wrong Python image, causing ABI errors. - Supported versions marked
allow_failureto force a green pipeline. - No coverage merge, so the MR badge reflects only one interpreter.
- Lint/type failures reported as test failures because they share a job.
When to escalate
- Compiled C-extension packages needing per-version wheels — may need a build matrix and cibuildwheel.
- Dropping or adding a supported Python version — a release-policy decision.
- Flaky version-specific failures — investigate the interpreter/dep interaction, don’t blanket allow-failure.
Related prompts
-
GitLab CI Parallel Matrix Explosion Control Prompt
Tame a parallel:matrix that generates too many job permutations, consuming runners and compute minutes, by pruning and targeting only the combinations that matter.
-
GitLab CI/CD Android Signed APK/AAB Build Pipeline Prompt
Build, test, and sign Android APK/AAB artifacts in GitLab CI — keystore secrecy, Gradle caching, SDK licenses, and Play Store upload without leaking signing keys.
-
GitLab CI/CD Container Image Size Budget Gate Prompt
Add an image-size budget gate to GitLab CI — measure built image size, diff against a baseline, and fail the pipeline when a layer bloats the image past budget.
-
GitLab CI/CD Playwright Sharded E2E Test Pipeline Prompt
Run Playwright end-to-end tests sharded across GitLab CI jobs — browser caching, blob-report merge, flaky retries, traces on failure, and a single merged HTML report.
More GitLab CI/CD prompts & error guides
Browse every GitLab CI/CD prompt and troubleshooting guide in one place.
Reading prompts? Get all 500 in one free PDF
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.