mrkeyoor.com_
Tue 22 Sept 00:45 UTC
PyPITestingupdated 21 Sept 2026

tox review

tox creates named Python environments, installs the project and test dependencies into them, and runs configured commands. One file can cover interpreter versions, dependency factors, package builds, pytest, type checking, linting, documentation, and CI labels. TOML is now the preferred configuration; INI still loads but is deprecated and frozen. Version 4.60.0 added {home} and {tox_root_name} substitutions plus earlier provisioning, while current 4.60.1 replaces raw tracebacks with handled errors for malformed configs, invalid skip regexes, unreadable files, and empty TOML commands.

Verdict

Our tox 4.60.0 install took 0.5 seconds, used 10 MB across 13 packages, imported in 0.66 seconds, and had no known audit findings; PyPI now serves the unmeasured 4.60.1 patch. Use tox for a real package matrix, and keep one-environment applications on a direct test command unless isolation proves useful.

We installed it

Lab card: what happened when we installed toxScreenshot of tox documentation
Install✓ · 0.5s13 packages on disk · 10 MB
Importimport tox in 0.66s · pure Python · py.typed · requires Python >=3.10
Known vulns0(pip-audit)

Answers from our run

Does tox install cleanly?

Yes. In a fresh container with an empty cache, pip install tox finished in 0.5s, leaving 13 packages and 10 MB on disk. pip-audit reported no known vulnerabilities.

What does tox need to run?

Python >=3.10, and nothing compiled: it is pure Python. In our run import tox succeeded in 0.66s, and the package ships py.typed for type checkers.

tox or nox: which should you use?

nox: Use it when Python functions express sessions and matrix logic more clearly than declarative TOML. Our tox 4.60.0 install took 0.5 seconds, used 10 MB across 13 packages, imported in 0.66 seconds, and had no known audit findings; PyPI now serves the unmeasured 4.60.1 patch.

When should you not use tox?

The service deploys one locked Python environment and has no compatibility matrix; a direct pytest command has less orchestration state

API stability4/5The tox 4 command model, environment inheritance, packaging modes, substitutions, lifecycle, and plugin hooks are established, with patch releases mainly adding settings or better diagnostics. The jump from tox 3 required real migration, and INI is now deprecated in favor of typed TOML. Existing tox.ini files still execute, but a team expecting new settings should plan a format move rather than assuming INI will grow with later 4.x releases.
Docs5/5tox.wiki returns HTTP 200 and supplies a TOML-first tutorial, complete command and setting references, an execution model, package-flow diagrams, environment-variable precedence, factor matrices, parallel rules, provisioning, migration guidance, plugins, and release notes. The site states that INI is deprecated and explains when environments are reused or recreated. Those details answer the cache and ordering questions that usually cause CI-only surprises.
Maintenance5/5PyPI published 4.60.1 on August 25, 2026, and GitHub shows the matching push that day. The unarchived repository has 3,924 stars and only 1 open issue or pull request. The patch handles malformed and unreadable configuration, invalid skip regexes, empty TOML commands, set_env semicolons, and Windows CI termination. Such an active release line is healthy, though CI should pin it so a formatter or parser change does not arrive mid-run.
Ecosystem5/5The supplied weekly count is 6,899,939 downloads. tox works alongside pytest, virtualenv, build backends, and CI platforms without requiring one runner, and its pluggy extension system supports alternate installers and provisioners. Auto-provisioning can fetch required plugins for a project. That flexibility creates another reproducibility surface, so plugin ranges and the tox version belong in reviewed configuration rather than floating independently.

Use it if

  • A Python distribution must be built and tested under several interpreter or dependency versions
  • Local developers and CI should choose the same test, lint, type-check, and documentation environments by name
  • Packaging mistakes need to surface by installing an sdist or wheel before tests import the project
  • A matrix needs factor-specific dependencies, labels, bounded parallel execution, or ordered coverage aggregation
Skip it if

Setup reality

We installed tox 4.60.0 in a fresh Python 3.12 Bookworm sandbox in 0.5 seconds. The install left 13 packages occupying 10 MB. The measured release declares 16 direct dependencies, requires Python 3.10 or newer, and is pure Python. It ships py.typed and uses the MIT License. import tox completed in 0.66 seconds, and pip-audit reported zero known vulnerabilities. PyPI now serves 4.60.1; we did not rerun the lab install for that patch.

Place tox.toml, a [tool.tox] section, or the deprecated tox.ini at the repository root. Every requested interpreter must already be discoverable. Tox keeps environments, logs, and package builds under .tox. Test environments build an sdist by default. Set package = "wheel" to test a wheel, use sdist-wheel to make that wheel from the sdist, or skip package installation for a lint-only job. Version 4.60.1 improves configuration failures but does not remove the need to migrate INI.

The first run of each matrix creates virtual environments and installs their dependencies, so the 0.66-second import says nothing about full project runtime. Later commands reuse cached environments. Added requirements are installed, while removals can trigger recreation; tox run -r forces a clean environment when state is doubtful. Host variables are filtered. Name required entries in pass_env, set controlled values in set_env, and allow external programs narrowly through allowlist_externals instead of broad secret or command wildcards.

Parallel work starts after packaging. Standard input is disabled, successful output is buffered unless live mode is requested, and depends only orders environments already selected for that invocation. It does not select dependencies automatically. Pin min_version or requires when configuration or plugins need a particular tox build. If the host command cannot satisfy those constraints, tox provisions another copy under .tox/.tox before the requested environments run, adding one more installation and cache to diagnose.

Patterns

Test one wheel on Python 3.12 and 3.13 create-toml-config

env_list = ['3.12', '3.13']

[env_run_base]
package = 'wheel'
deps = ['pytest>=8']
commands = [
  ['pytest', { replace = 'posargs', default = ['tests'], extend = true }],
]

Both interpreters must already be discoverable; tox does not download the missing Python version.

Configure tox inside pyproject.toml configure-in-pyproject

[tool.tox]
env_list = ['3.12', '3.13']

[tool.tox.env_run_base]
package = 'wheel'
deps = ['pytest>=8']
commands = [
  ['pytest', { replace = 'posargs', default = ['tests'], extend = true }],
]

The [tool.tox] prefix belongs only in pyproject.toml; standalone tox.toml places these keys at the root.

Cross Python and Django factors generate-dependency-matrix

env_list = [
  { product = [
    ['3.12', '3.13'],
    ['django52', 'django60'],
  ] },
]

[env_run_base]
deps = [
  'pytest',
  { replace = 'if', condition = 'factor.django52', then = ['Django>=5.2,<6'], extend = true },
  { replace = 'if', condition = 'factor.django60', then = ['Django>=6,<6.1'], extend = true },
]
commands = [['pytest', 'tests']]

This product creates 4 environments, and each conditional dependency extends pytest only for its matching factor.

Send pytest flags through tox run-one-environment

tox run -e 3.12 -- -k test_login -x

Arguments after the bare separator fill posargs; earlier flags are parsed by tox itself.

Inspect expanded environment settings inspect-resolved-config

tox list
tox config -e 3.12

tox config resolves inheritance and substitutions, which exposes values placed in the wrong section.

Bound a parallel matrix run-matrix-in-parallel

tox parallel --parallel 4
tox parallel --parallel-live --parallel 2

Parallel mode disables stdin; --parallel-live streams output instead of buffering successful environments.

Pass only reviewed host variables control-environment-variables

[env_run_base]
pass_env = ['CI', 'HTTP_PROXY']
disallow_pass_env = ['*_TOKEN']
set_env.PYTHONWARNINGS = 'error'
set_env.DATABASE_URL = 'sqlite:///{env_tmp_dir}/test.db'

set_env can override passed values, and broad pass_env patterns risk copying credentials into every test environment.

Run Ruff without packaging the project add-lint-environment

env_list = ['3.12', 'lint']

[env.lint]
skip_install = true
deps = ['ruff']
commands = [
  ['ruff', 'check', '.'],
  ['ruff', 'format', '--check', '.'],
]

skip_install changes this job to package mode skip, avoiding a source build and project installation.

Reuse one pure-Python wheel build reuse-wheel-build

[env_run_base]
package = 'wheel'
wheel_build_env = '.pkg'
deps = ['pytest']
commands = [['pytest', 'tests']]

A shared wheel build fits pure Python; native extensions may require a different artifact for each interpreter.

Select static checks by label group-environments-by-label

env_list = ['3.12', 'ruff', 'mypy']
labels = { tests = ['3.12'], static = ['ruff', 'mypy'] }

[env.ruff]
skip_install = true
deps = ['ruff']
commands = [['ruff', 'check', '.']]

[env.mypy]
deps = ['mypy']
commands = [['mypy', 'src']]

# Run with: tox run -m static

tox run -m static chooses the two named environments without duplicating them in the CI command.

Order coverage after selected tests order-coverage-aggregation

env_list = ['3.12', '3.13', 'coverage']

[env.coverage]
depends = ['3.*']
skip_install = true
deps = ['coverage']
commands = [['coverage', 'combine'], ['coverage', 'report']]

depends controls ordering only among environments included in the run; selecting coverage alone does not add Python 3.12 or 3.13.

Provision a pinned tox toolchain pin-tox-and-plugin

min_version = '4.60'
requires = ['tox>=4.60,<5', 'tox-uv>=1,<2']

env_list = ['3.12']

Unsatisfied constraints create .tox/.tox, install the requested tox and plugin versions there, and delegate the run.

Alternatives

PackageRegistryPick it when
noxPyPIUse it when Python functions express sessions and matrix logic more clearly than declarative TOML
hatchPyPIUse it when environments should share one tool with project building, versioning, and publishing
uvPyPIUse it when interpreter installation, locking, and fast commands matter more than a tox-style matrix

More testing guides

pytest · chai · vitest · jsdom · playwright · coverage · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.