Concepts¶
Overview¶
tox is an environment orchestrator. Use it to define how to set up and execute various tools on your projects. The tool can set up environments for and invoke:
For a step-by-step introduction, see the Getting Started tutorial. For practical recipes, see How-to Guides.
System overview¶
Below is a graphical representation of the tox lifecycle:
flowchart TD
start(( )) --> config[Load configuration]
config --> envloop
subgraph envloop [for each selected environment]
direction TB
create[Create environment]
create --> deps[Install dependencies]
deps --> pkg{package project?}
pkg -- yes --> build[Build and install package]
pkg -- no --> extra
build --> extra[Run extra_setup_commands]
extra --> cmds
cmds[Run commands]
end
cmds --> report[Report results]
report --> done(( ))
classDef configStyle fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e3a5f
classDef envStyle fill:#dcfce7,stroke:#22c55e,stroke-width:2px,color:#14532d
classDef pkgStyle fill:#ffedd5,stroke:#f97316,stroke-width:2px,color:#7c2d12
classDef setupStyle fill:#fde68a,stroke:#fbbf24,stroke-width:2px,color:#78350f
classDef cmdStyle fill:#ede9fe,stroke:#8b5cf6,stroke-width:2px,color:#3b0764
classDef reportStyle fill:#ccfbf1,stroke:#14b8a6,stroke-width:2px,color:#134e4a
classDef decisionStyle fill:#fef9c3,stroke:#eab308,stroke-width:2px,color:#713f12
class config configStyle
class create,deps envStyle
class build pkgStyle
class extra setupStyle
class cmds cmdStyle
class report reportStyle
class pkg decisionStyle
The primary tox states are:
Configuration: load tox configuration files (such as
tox.toml,tox.ini,pyproject.tomlandtoxfile.py) and merge it with options from the command line plus the operating system environment variables. Configuration is loaded lazily – individual environment settings are only read when that environment is used.Environment: for each selected tox environment (e.g.
3.13,lint) do:Creation: create a fresh environment; by default virtualenv is used, but configurable via runner. For
virtualenvtox will use the virtualenv discovery logic where the python specification is defined by the tox environments base_python (if not set will default to the environments name). This is created at first run only to be reused at subsequent runs. If certain aspects of the project change (python version, dependencies removed, etc.), a re-creation of the environment is automatically triggered. To force the recreation tox can be invoked with the recreate flag (-r).Install dependencies (optional): install the environment dependencies specified inside the
depsconfiguration section, and then the earlier packaged source distribution. By defaultpipis used to install packages, however one can customize this viainstall_command.Packaging (optional): create a distribution of the current project (see Packaging below).
Extra setup commands (optional): run the extra_setup_commands specified. These execute after all installations complete but before test commands, and run during the
--notestphase.Commands: run the specified commands in the specified order. Whenever the exit code of any of them is not zero, stop and mark the environment failed. When you start a command with a dash character, the exit code will be ignored.
Report print out a report of outcomes for each tox environment:
____________________ summary ____________________ 3.13: commands succeeded ERROR: 3.12: commands failed
Only if all environments ran successfully tox will return exit code
0(success). In this case you’ll also see the messagecongratulations :).
Environment variable handling¶
tox takes care of environment variable isolation. By default, it removes system environment variables not specified via
pass_env and alters the PATH variable so that commands resolve within the current active tox environment.
External commands need to be explicitly allowed via allowlist_externals.
Evaluation order: tox composes the environment for command execution in this order:
pass_env – glob patterns are matched against the host
os.environ. Matching variables are passed through.disallow_pass_env – exclusion patterns are applied to remove specific variables after
pass_envexpansion.PATH – tox prepends the virtual environment’s binary directory to
PATH, so commands resolve inside the virtualenv first.set_env – values defined here are applied last and can override anything from the previous steps, including
PATH.Injected variables – tox adds
TOX_ENV_NAME,TOX_WORK_DIR,TOX_ENV_DIR,VIRTUAL_ENV,PIP_USER=0, andPYTHONIOENCODING=utf-8. These cannot be overridden.
PATH behavior: because tox prepends the virtualenv bin/ directory to PATH at step 3, commands like
python and pip resolve to the virtualenv versions. If you override PATH in set_env, be aware that this
replaces the composed PATH entirely – you should include {env_bin_dir} in your custom value to preserve
virtualenv resolution:
[env_run_base]
set_env.PATH = "{env_bin_dir}{:}/usr/local/bin{:}{env:PATH}"
[testenv]
set_env =
PATH = {env_bin_dir}{:}/usr/local/bin{:}{env:PATH}
Conditional environment variables: in INI, set_env supports PEP 508-style markers separated by ; to
conditionally set variables based on platform:
[testenv]
set_env =
COVERAGE_FILE = {work_dir}/.coverage.{env_name}
LDFLAGS = -L/usr/local/lib ; sys_platform == "darwin"
Dependency change detection¶
tox discovers package dependency changes (via PEP 621 or PEP 517
prepare_metadata_for_build_wheel/build_wheel metadata). When new dependencies are added they are installed on
the next run. When a dependency is removed the entire environment is automatically recreated. This also works for
requirements files within deps. In most cases you should never need to use the --recreate flag – tox
detects changes and applies them automatically.
Main features¶
automation of tedious Python related test activities
test your Python package against many interpreter and dependency configurations
automatic customizable (re)creation of virtualenv test environments
installs your project into each virtual environment
test-tool agnostic: runs pytest, unittest, or any other test runner
plugin system to modify tox execution with simple hooks
uses pip and virtualenv by default; plugins can replace either
cross-Python compatible: tox requires CPython 3.10 and higher, but it can create environments for older versions. Special configuration might be required: Test end-of-life Python versions.
cross-platform: Windows, macOS and Unix style environments
full interoperability with devpi: is integrated with and is used for testing in the devpi system, a versatile PyPI index server and release managing tool
concise reporting about tool invocations and configuration errors
supports using different / multiple PyPI index servers
Packaging¶
tox builds projects in a PEP 518 compatible virtual environment and communicates with the build backend according to
the interface defined in PEP 517 and PEP 660. To define package build dependencies and specify the build backend
to use, create a pyproject.toml at the root of the project. For example to use hatch:
[build-system]
build-backend = "hatchling.build"
requires = ["hatchling>=0.22", "hatch-vcs>=0.2"]
Package modes¶
The package configuration controls how the project is packaged:
flowchart TD
pkg{package setting}
pkg -- sdist --> sdist[sdist — default]
pkg -- wheel --> wheel[wheel — faster install]
pkg -- editable --> editable[editable — PEP 660]
pkg -- editable-legacy --> legacy[editable-legacy — pip -e]
pkg -- skip --> skip[skip — no packaging]
pkg -- external --> external[external — provided]
sdist --> env_pkg[build env: .pkg]
wheel --> env_wheel[build env: .pkg-cpython313]
editable --> env_wheel
legacy --> env_pkg
skip --> no_env[no build env]
external --> no_env
classDef decisionStyle fill:#fef9c3,stroke:#eab308,stroke-width:2px,color:#713f12
classDef pkgStyle fill:#ffedd5,stroke:#f97316,stroke-width:2px,color:#7c2d12
classDef envStyle fill:#dcfce7,stroke:#22c55e,stroke-width:2px,color:#14532d
classDef skipStyle fill:#f3f4f6,stroke:#9ca3af,stroke-width:2px,color:#374151
class pkg decisionStyle
class sdist,wheel,editable,legacy,external pkgStyle
class env_pkg,env_wheel envStyle
class skip,no_env skipStyle
sdist(default): builds a source distributionwheel: builds a wheel (much faster to install)editable: builds an editable wheel as defined by PEP 660editable-legacy: invokes pip with-e(fallback when the backend doesn’t support PEP 660)skip: skips packaging entirely (useful for tools like linters that don’t need the project installed)external: uses an externally provided package
Build environments¶
tox uses a virtual environment for building, whose name depends on the artifact type:
For source distributions: the package_env (default
.pkg)For wheels: the wheel_build_env (default
.pkg-<impl><version>, e.g..pkg-cpython313)
For pure Python projects (no C extensions), set wheel_build_env to the same value as package_env. This way the wheel is built once and reused for all tox environments:
[env_run_base]
package = "wheel"
wheel_build_env = ".pkg"
[testenv]
package = wheel
wheel_build_env = .pkg
Packaging environment configuration¶
Packaging environments do not inherit settings from env_run_base (TOML) or [testenv] (INI). Instead, they
inherit from the env_pkg_base table (TOML) or [pkgenv] section (INI). This prevents test settings from
conflicting with packaging settings.
[env_pkg_base]
pass_env = ["PKG_CONFIG", "PKG_CONFIG_PATH"]
[pkgenv]
pass_env =
PKG_CONFIG
PKG_CONFIG_PATH
To configure a specific packaging environment, use the standard environment syntax (e.g. [testenv:.pkg] in INI or
env.".pkg" in TOML).
Auto-provisioning¶
When the installed tox version does not satisfy either the requires or the min_version, tox automatically creates a virtual environment under provision_tox_env name that satisfies those constraints and delegates all calls to this meta environment.
flowchart TD
invoke[tox invoked] --> check{requires and min_version satisfied?}
check -- yes --> run[run normally]
check -- no --> create[create .tox/.tox virtualenv]
create --> install[install tox + required plugins]
install --> delegate[re-invoke tox inside .tox/.tox]
delegate --> run
classDef decisionStyle fill:#fef9c3,stroke:#eab308,stroke-width:2px,color:#713f12
classDef envStyle fill:#dcfce7,stroke:#22c55e,stroke-width:2px,color:#14532d
classDef cmdStyle fill:#ede9fe,stroke:#8b5cf6,stroke-width:2px,color:#3b0764
class check decisionStyle
class create,install envStyle
class invoke,run,delegate cmdStyle
For example given:
requires = ["tox>=4", "tox-uv>=1"]
[tox]
requires =
tox>=4
tox-uv>=1
tox will automatically ensure that both the minimum version and requires constraints are satisfied, by creating a
virtual environment under .tox, and then installing into it tox>=4 and tox-uv>=1. Afterwards all tox
invocations are forwarded to the tox installed inside .tox/.tox (referred to as the provisioned tox).
This allows tox to automatically set up itself with all its plugins for the current project. If the host tox satisfies the constraints no provisioning is done (to avoid setup cost and indirection).
Note
The provisioning environment (.tox by default) does not inherit settings from env_run_base (TOML) or
[testenv] (INI). It must be explicitly configured if you need to customize it (e.g. env.".tox" in TOML or
[testenv:.tox] in INI).
Parallel mode¶
tox allows running environments in parallel mode via the parallel sub-command:
After the packaging phase completes tox runs environments in parallel processes (multi-thread based).
The
--parallelflag takes an argument specifying the degree of parallelization, defaulting toauto:allto run all invoked environments in parallel,autoto limit it to CPU count,or pass an integer to set that limit.
Parallel mode displays a progress spinner while running environments in parallel, and reports outcome as soon as environments complete. To run without the spinner, use
--parallel-no-spinner.Parallel mode by default shows output only of failed environments and ones marked as parallel_show_output
= true.Environments can declare dependencies on other environments via depends. tox re-orders the environment list to satisfy these dependencies (also for sequential runs). In parallel mode, tox only schedules an environment once all of its dependencies have finished (independent of their outcome).
dependssupports glob patterns (*,?,[seq]) usingfnmatch, so instead of listing each environment explicitly you can writedepends = 3.*to match all environments starting with3..Warning
dependsdoes not pull in dependencies into the run target. For example, if you select3.13,3.12,coveragevia-etox will only run those three (even ifcoveragemay specify asdependsother targets too – such as3.13, 3.12, 3.11).--parallel-live/-oshows live output of stdout and stderr, and turns off the spinner.Parallel evaluation disables standard input. Use non-parallel invocation if you need standard input.
Example final output:
$ tox -e 3.13,3.12,coverage -p all
✔ OK 3.12 in 9.533 seconds
✔ OK 3.13 in 9.96 seconds
✔ OK coverage in 2.0 seconds
___________________________ summary ______________________________________________________
3.13: commands succeeded
3.12: commands succeeded
coverage: commands succeeded
congratulations :)
Example progress bar, showing a rotating spinner, the number of environments running and their list (limited up to 120 characters):
⠹ [2] 3.13 | 3.12
Fail-fast mode¶
When running multiple environments, tox normally runs all of them even if an early environment fails. The
--fail-fast flag stops execution after the first environment failure, saving time in CI pipelines and development
workflows.
tox run -e 3.13,3.12,3.11 --fail-fast
You can also enable it per-environment via the fail_fast configuration:
[env.critical]
fail_fast = true
commands = [["pytest", "tests/critical"]]
[testenv:critical]
fail_fast = true
commands = pytest tests/critical
The fail-fast behavior:
Works in both sequential and parallel execution modes.
In parallel mode, environments already running when a failure occurs will continue to completion. Only environments not yet queued will be skipped.
Respects ignore_outcome – environments with
ignore_outcome = truewill not trigger fail-fast even if they fail.Respects environment dependencies defined via depends – dependent environments will not run if a dependency fails with fail-fast enabled.
Environments not yet started are skipped with exit code -2 and marked as
SKIPin the output.The overall tox exit code will be the exit code of the first failed environment.
Configuration inheritance¶
Every tox environment has its own configuration section. If a value is not defined in the environment-specific section,
it falls back to the base section (base configuration). For tox.toml this is the env_run_base table, for
tox.ini this is [testenv]. If the base section also lacks the value, the configuration default is used.
[env_run_base]
commands = [["pytest", "tests"]]
[env.test]
description = "run the test suite with pytest"
[testenv]
commands = pytest tests
[testenv:test]
description = run the test suite with pytest
Here test inherits commands from the base because it is not specified in [env.test].
Known limitations¶
Interactive terminal programs¶
Programs that require advanced terminal control — such as IPython, debuggers with rich UIs, or any tool built on prompt_toolkit — may not work correctly under tox.
tox captures subprocess output by routing stdout and stderr through pseudo-terminal (PTY) pairs. This is
necessary for logging, result reporting, and colorized output. However, the subprocess’s stdin remains connected to
the real terminal. This means stdin and stdout are on different terminal devices.
Libraries like prompt_toolkit assume all streams share the same terminal. They set raw mode on stdin (to read
individual keystrokes) while writing VT100 escape sequences to stdout (for cursor positioning, screen clearing,
etc.). When stdout goes through tox’s capture buffer instead of directly to the terminal, escape sequences are
delayed and the synchronous terminal control these libraries depend on breaks.
Workarounds:
For IPython, pass
--simple-promptto disableprompt_toolkit’s advanced terminal features.For other tools, look for a “dumb terminal” or “no-color” mode that avoids VT100 escape sequences.