diff --git a/docs/changelog/2408.doc.rst b/docs/changelog/2408.doc.rst new file mode 100644 index 000000000..c97175aa8 --- /dev/null +++ b/docs/changelog/2408.doc.rst @@ -0,0 +1 @@ +Add new documentation for tox 4 - by :user:`gaborbernat`. diff --git a/docs/conf.py b/docs/conf.py index 3759508f7..5822ec85f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -66,7 +66,13 @@ nitpicky = True nitpick_ignore = [] linkcheck_workers = 10 -linkcheck_ignore = [re.escape(r"https://github.com/tox-dev/tox/issues/new?title=Trouble+with+development+environment")] +linkcheck_ignore = [ + re.escape(i) + for i in ( + r"https://github.com/tox-dev/tox/issues/new?title=Trouble+with+development+environment", + r"https://www.unix.org/version2/sample/abort.html", + ) +] extlinks_detect_hardcoded_links = True diff --git a/docs/config.rst b/docs/config.rst index 9e2945b12..804896c4d 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -1,3 +1,5 @@ +.. _configuration: + Configuration +++++++++++++ @@ -102,10 +104,10 @@ Core :default: :version_added: 3.2.0 - Specify a list of `PEP-508 `_ compliant dependencies that must be - satisfied in the Python environment hosting tox when running the tox command. If any of these dependencies are not - satisfied will automatically create a provisioned tox environment that does not have this issue, and run the tox - command within that environment. See :ref:`provision_tox_env` for more details. + Specify a list of :pep:`508` compliant dependencies that must be satisfied in the Python environment hosting tox when + running the tox command. If any of these dependencies are not satisfied will automatically create a provisioned tox + environment that does not have this issue, and run the tox command within that environment. See + :ref:`provision_tox_env` for more details. .. code-block:: ini @@ -313,9 +315,9 @@ Base options :default: Each line specifies a command name (in glob-style pattern format) which can be used in the commands section even if - it's located outside of the tox environment. For example: if you use the unix make command for running tests you can list - ``allowlist_externals=make`` or ``allowlist_externals=/usr/bin/make``. If you want to allow all external commands - you can use ``allowlist_externals=*`` which will match all commands (not recommended). + it's located outside of the tox environment. For example: if you use the unix *rm* command for running tests you can + list ``allowlist_externals=rm`` or ``allowlist_externals=/usr/bin/rm``. If you want to allow all external + commands you can use ``allowlist_externals=*`` which will match all commands (not recommended). .. conf:: :keys: labels @@ -527,8 +529,8 @@ Python options Leaving this unset will cause an error if the package under test has a different Python requires than tox itself and tox is installed into a Python that's not supported by the package. For example, if your package requires - Python 3.9 or later, and you install tox in Python 3.8, when you run a tox environment that has left this - unspecified tox will use Python 3.8 to build and install your package which will fail given it requires 3.9. + Python 3.10 or later, and you install tox in Python 3.9, when you run a tox environment that has left this + unspecified tox will use Python 3.9 to build and install your package which will fail given it requires 3.10. .. conf:: :keys: env_site_packages_dir, envsitepackagesdir @@ -554,9 +556,25 @@ Python run :keys: deps :default: - Name of the Python dependencies as specified by `PEP-440`_. Installed into the environment prior to project after - environment creation, but before package installation. All installer commands are executed using the :ref:`tox_root` - as the current working directory. + Name of the Python dependencies. Installed into the environment prior to project after environment creation, but + before package installation. All installer commands are executed using the :ref:`tox_root` as the current working + directory. Each value must be one of: + + - a Python dependency as specified by :pep:`440`, + - a `requirement file `_ when the value starts with + ``-r`` (followed by a file path), + - a `constraint file `_ when the value starts with + ``-c`` (followed by a file path). + + For example: + + .. code-block:: ini + + [testenv] + deps = + pytest>=7,<8 + -r requirements.txt + -c constraints.txt .. conf:: :keys: use_develop, usedevelop @@ -610,7 +628,7 @@ tox supports operating with externally built packages. External packages might b :default: :ref_suffix: external - Name of the Python dependencies as specified by `PEP-440`_. Installed into the environment prior running the build + Name of the Python dependencies as specified by :pep:`440`. Installed into the environment prior running the build commands. All installer commands are executed using the :ref:`tox_root` as the current working directory. .. conf:: @@ -731,6 +749,3 @@ Pip installer If ``true``, adds ``--pre`` to the ``opts`` passed to :ref:`install_command`. This will cause it to install the latest available pre-release of any dependencies without a specified version. If ``false``, pip will only install final releases of unpinned dependencies. - -.. _`PEP-508`: https://www.python.org/dev/peps/pep-0508/ -.. _`PEP-440`: https://www.python.org/dev/peps/pep-0440/ diff --git a/docs/faq.rst b/docs/faq.rst index ffb798c01..0d232f56f 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -3,6 +3,50 @@ FAQ Here you'll find answers to some frequently asked questions. +Using a custom PyPI server +-------------------------- + +By default tox uses pip to install Python dependencies. Therefore to change the index server you should configure pip +directly. pip accepts environment variables as configuration flags, therefore the easiest way to do this is to set the +``PIP_INDEX_URL`` environment variable: + +.. code-block:: ini + + set_env = + PIP_INDEX_URL = https://tox.wiki/pypi/simple + +It's considered a best practice to allow the user to change the index server rather than hard code it, allowing them +to use for example a local cache when they are offline. Therefore, a better form of this would be: + +.. code-block:: ini + + set_env = + PIP_INDEX_URL = {env:PIP_INDEX_URL:https://tox.wiki/pypi/simple} + +Here we use an environment substitution to set the index URL if not set by the user, but otherwise default to our target +URI. + +Using two PyPI servers +---------------------- + +When you want to use two PyPI index servers because not all dependencies are found in either of them use the +``PIP_EXTRA_INDEX_URL`` environment variable: + +.. code-block:: ini + + set_env = + PIP_INDEX_URL = {env:PIP_INDEX_URL:https://tox.wiki/pypi/simple-first} + PIP_EXTRA_INDEX_URL = {env:PIP_EXTRA_INDEX_URL:https://tox.wiki/pypi/simple-second} + +If the index server defined under ``PIP_INDEX_URL`` does not contain a package, pip will attempt to resolve it also from +the URI from ``PIP_EXTRA_INDEX_URL``. + +.. warning:: + + Using an extra PyPI index for installing private packages may cause security issues. For example, if ``package1`` is + registered with the default PyPI index, pip will install ``package1`` from the default PyPI index, not from the extra + one. + Using constraint files ---------------------- `Constraint files `_ are a type of artifact, supported by @@ -75,3 +119,126 @@ and the following ``tox.ini`` content: You can invoke ``tox`` in the directory where your ``tox.ini`` resides. ``tox`` creates two virtualenv environments with the ``python3.10`` and ``python3.9`` interpreters, respectively, and will then run the specified command according to platform you invoke ``tox`` at. + +Ignoring the exit code of a given command +----------------------------------------- + +When multiple commands are defined within the :ref:`commands` configuration field tox will run them sequentially until +one of them fails (by exiting with non zero exit code) or all of them are run. If you want to ignore the status code of +a given command add a ``-`` prefix to that line (similar syntax to how the GNU ``make`` handles this): + +.. code-block:: ini + + + [testenv] + commands = + - python -c 'import sys; sys.exit(1)' + python --version + +Customizing virtual environment creation +---------------------------------------- + +By default tox uses the :pypi:`virtualenv` to create Python virtual environments to run your tools in. To change how tox +creates virtual environments you can set environment variables to customize virtualenv. For example, to provision a given +pip version in the virtual environment you can set ``VIRTUALENV_PIP`` or to enable system site packages use the +``VIRTUALENV_SYSTEM_SITE_PACKAGES``: + + +.. code-block:: ini + + + [testenv] + setenv = + VIRTUALENV_PIP==22.1 + VIRTUALENV_SYSTEM_SITE_PACKAGES=true + +Consult the :pypi:`virtualenv` project for supported values (any CLI flag for virtualenv, in all upper case, prefixed +by the ``VIRTUALENV_`` key). + +Building documentation with Sphinx +---------------------------------- + +It's possible to orchestrate the projects documentation with tox. The advantage of this is that now generating the +documentation can be part of the CI, and whenever any validations/checks/operations fail while generating the +documentation you'll catch it within tox. + +We don't recommend using the Make and Batch file generated by Sphinx, as this makes your documentation generation +platform specific. A better solution is to use tox to setup a documentation build environment and invoke sphinx inside +it. This solution is cross platform. + +For example if the sphinx file structure is under the ``docs`` folder the following configuration will generate +the documentation under ``.tox/docs_out/index.html`` and print out a link to the generated documentation: + +.. code-block:: ini + + [testenv:docs] + description = build documentation + basepython = python3.10 + deps = + sphinx>=4 + commands = + sphinx-build -d "{envtmpdir}{/}doctree" docs "{toxworkdir}{/}docs_out" --color -b html + python -c 'print(r"documentation available under file://{toxworkdir}{/}docs_out{/}index.html")' + +Note here we also require Python 3.10, allowing us to use f-strings within the sphinx ``conf.py``. + +Building documentation with mkdocs +---------------------------------- + +It's possible to orchestrate the projects documentation with tox. The advantage of this is that now generating the +documentation can be part of the CI, and whenever any validations/checks/operations fail while generating the +documentation you'll catch it within tox. + +It's best to define one environment to write/generate the documentation, and another to deploy it. Use the config +substitution logic to avoid duplication: + +.. code-block:: ini + + [testenv:docs] + description = Run a development server for working on documentation + deps = + mkdocs>=1.3 + mkdocs-material + commands = + mkdocs build --clean + python -c 'print("###### Starting local server. Press Control+C to stop server ######")' + mkdocs serve -a localhost:8080 + + [testenv:docs-deploy] + description = built fresh docs and deploy them + deps = {[testenv:docs]deps} + commands = mkdocs gh-deploy --clean + +Understanding ``InvocationError`` exit codes +-------------------------------------------- + +When a command executed by tox fails, it always has a non-zero exit code and an ``InvocationError`` exception is +raised: + +.. code-block:: shell + + ERROR: InvocationError for command + '' (exited with code 1) + +Generally always check the documentation for the command executed to understand what the code means. For example for +:pypi:`pytest` you'd read `here `_. On unix +systems, there are some rather `common exit codes `_. This is why for +exit codes larger than 128, if a signal with number equal to `` - 128`` is found in the :py:mod:`signal` +module, an additional hint is given: + +.. code-block:: shell + + ERROR: InvocationError for command + '' (exited with code 139) + Note: this might indicate a fatal error signal (139 - 128 = 11: SIGSEGV) + + +The signal numbers (e.g. 11 for a segmentation fault) can be found in the "Standard signals" section of the +`signal man page `_. +Their meaning is described in `POSIX signals `_. Beware +that programs may issue custom exit codes with any value, so their documentation should be consulted. + + +Sometimes, no exit code is given at all. An example may be found in +:gh:`pytest-qt issue #170 `, where Qt was calling +`abort() `_ instead of ``exit()``. diff --git a/docs/installation.rst b/docs/installation.rst index c751a5d80..9a6aaade4 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -4,7 +4,7 @@ Installation via pipx -------- -:pypi:`tox` is a CLI tool that needs a Python interpreter (version 3.6 or higher) to run. We recommend :pypi:`pipx` to +:pypi:`tox` is a CLI tool that needs a Python interpreter (version 3.7 or higher) to run. We recommend :pypi:`pipx` to install tox into an isolated environment. This has the added benefit that later you'll be able to upgrade tox without affecting other parts of the system. @@ -30,27 +30,24 @@ state. Note, if you go down this path you need to ensure pip is new enough per t wheel ~~~~~ Installing tox via a wheel (default with pip) requires an installer that can understand the ``python-requires`` tag (see -`PEP-503 `_), with pip this is version ``9.0.0`` (released in November 2016). -Furthermore, in case you're not installing it via PyPI you need to use a mirror that correctly forwards the -``python-requires`` tag (notably the OpenStack mirrors don't do this, or older :gh_repo:`devpi/devpi` versions - -added with version ``4.7.0``). +:pep:`503`), with pip this is version ``9.0.0`` (released in November 2016). Furthermore, in case you're not installing +it via PyPI you need to use a mirror that correctly forwards the ``python-requires`` tag (notably the OpenStack mirrors +don't do this, or older :gh_repo:`devpi/devpi` versions - added with version ``4.7.0``). .. _sdist: sdist ~~~~~ -When installing via a source distribution you need an installer that handles the -`PEP-517 `_ specification. In case of ``pip`` this is version ``18.0.0`` or -later (released in July 2018). If you cannot upgrade your pip to support this you need to ensure that the build -requirements from :gh:`pyproject.toml ` are satisfied before triggering the -installation. +When installing via a source distribution you need an installer that handles the :pep:`517` specification. In case of +``pip`` this is version ``18.0.0`` or later (released in July 2018). If you cannot upgrade your pip to support this you +need to ensure that the build requirements from :gh:`pyproject.toml ` are +satisfied before triggering the installation. via ``setup.py`` ---------------- -We don't recommend and officially support this method. You should prefer using an installer that supports -`PEP-517 `_ interface, such as pip ``19.0.0`` or later. That being said you -might be able to still install a package via this method if you satisfy build dependencies before calling the -installation command (as described under :ref:`sdist`). +We don't recommend and officially support this method. You should prefer using an installer that supports :pep:`517` +interface, such as pip ``19.0.0`` or later. That being said you might be able to still install a package via this method +if you satisfy build dependencies before calling the installation command (as described under :ref:`sdist`). latest unreleased ----------------- diff --git a/docs/user_guide.rst b/docs/user_guide.rst index a62ea9259..45daf7ed3 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide.rst @@ -4,8 +4,24 @@ User Guide Basic example ------------- -Put basic information about your project and the test environments you want your project to run in into a ``tox.ini`` -file residing at the root of your project: +tox is an environment orchestrator. Use it to define how to setup and execute various tools on your projects. The +tool can be: + +- a test runner (such as :pypi:`pytest`), +- a linter (e.g., :pypi:`flake8`), +- a formatter (for example :pypi:`black` or :pypi:`isort`), +- a documentation generator (e.g., :pypi:`sphinx`), +- library builder and publisher (e.g., :pypi:`build` with :pypi:`twine`), +- or anything else you may need to execute. + +First, in a configuration file you need to define what tools you need to run and how to provision a test environment for +these. The canonical file for this is the ``tox.ini`` file, let's take a look at an example of this (this needs to live +at the root of your project): + +.. note:: + + You can also generate a ``tox.ini`` file automatically by running ``tox quickstart`` and then answering a few + questions. .. code-block:: ini @@ -13,44 +29,63 @@ file residing at the root of your project: envlist = format py310 - py39 - [testenv] - # install pytest in a virtual environment and invoke it on the test folder + [testenv:format] + description = install black in a virtual environment and invoke it on the current folder + deps = black==22.3.0 + skip_install = true + commands = black . + + [testenv:py310] + description = install pytest in a virtual environment and invoke it on the tests folder deps = - pytest>=6 + pytest>=7 pytest-sugar commands = pytest tests {posargs} - [testenv:format] - # install black in a virtual environment and invoke it on the current folder - deps = black - skip_install = true - commands = black . -You can also try generating a ``tox.ini`` file automatically by running ``tox quickstart`` and then answering a few -simple questions. The configuration above will run three separate tox environments ``format``, ``py310`` and ``py39`` -when you type in ``tox`` onto the command line within the projects folder (as defined by ``envlist``). The ``format`` -environment will create a Python virtual environment, install the ``black`` tool in it and the invoke it on the project -root folder. +The configuration is split into two type of configuration: core settings are hosted under the ``tox`` section and per run +environment settings hosted under ``testenv:``. Under the core section we define that this project has two +run environments named ``format`` and ``py310`` respectively (we use the ``envlist`` configuration key to do so). + +Then we define separately what should the formatting environment (``testenv:format`` section) and the test environment +(``testenv:py310`` section). For example to format the project we: + +- add a description (visible when you type ``tox list`` into the command line), +- we define that it requires the ``black`` PyPI dependency with version ``22.3.0``, +- the black tool does not need the project we are testing to be installed into the test environment so we disable this + default behaviour via the ``skip_install`` configuration, +- and we define that the tool should be invoked as we'd type ``black .`` into the command line. + +For testing the project we use the ``py310`` environment, for which we: + +- define a text description of the environment, +- specify that requires ``pytest`` ``7`` ot later together with the :pypi:`pytest-sugar` project, +- and that the tool should be invoked via the ``pytest tests`` CLI command. -The ``py310`` and ``py39`` do not have their own dedicated configuration section as ```format`` had (via -``[testenv:format]``) so they'll pull their configuration entirely from the ``[testenv]`` section. A Python virtual -environment is created, the dependencies from the ``deps`` config installed, the project package built and installed, -and then the ``pytest`` tool invoked. +``{posargs}`` is a place holder part for the CLI command that allows us to pass additional flags to the pytest +invocation, for example if we'd want to run ``pytest tests -v`` as a one off, instead of ``tox run -e py310`` we'd type +``tox run -e py310 -- -v``. The ``--`` delimits flags for the tox tool and what should be forwarded to the tool within. -The ``{posargs}`` argument is replaced with whatever you pass in after the ``--`` on the CI, so if you'd run -``tox -- -k test_something`` the command tox would run would be ``pytest tests -k test_something``. Note for this to -work you must have Python 3.10 and 3.9 installed on the machine as virtualenv can only create virtual environments if -the given python version is globally available on the machine. +tox, by default, always creates a fresh virtual environment for every run environment. The Python version to use for a +given environment can be controlled via the :ref:`base_python` configuration, however if not set will try to use the +environment name to determine something sensible: if the name is in the format of ``pyxy`` then tox will create an environment with CPython +with version ``x.y`` (for example ``py310`` means CPython ``3.10``). If the name does not match this pattern it will +use a virtual environment with the same Python version as the one tox is installed into (this is the case for +``format``). -When you run ``tox`` a second time you'll notice that it runs much faster because it keeps track of virtualenv -details and will not recreate or re-install dependencies. +tox environments are reused between runs, so while the first ``tox run -e py310`` will take a while as tox needs to +create a virtual environment and install ``pytest`` and ``pytest-sugar`` in it, subsequent runs only need to reinstall +your project, as long as the environments dependency list does not change. + +Almost every step and aspect of virtual environments and command execution can be customized. You'll find +an exhaustive list of configuration flags (together with what it does and detailed explanation of what values are +accepted) at our :ref:`configuration page `. System overview --------------- -Here you can see a graphical representation of its run states: +Below is a graphical representation of the tox states and transition pathways between them: .. image:: img/overview_light.svg :align: center @@ -61,14 +96,14 @@ Here you can see a graphical representation of its run states: :class: only-dark -tox roughly follows the following states: +The primary tox states are: -#. **configuration:** load tox configuration files (such as ``tox.ini``, ``pyproject.toml``, and ``toxfile.py``) and - merge it with options from the command line and the operating system environment variables +#. **Configuration:** load tox configuration files (such as ``tox.ini``, ``pyproject.toml`` and ``toxfile.py``) and + merge it with options from the command line plus the operating system environment variables. -#. **environment**: for each selected tox environment (e.g. ``py310``, ``py39``) do: +#. **Environment**: for each selected tox environment (e.g. ``py310``, ``format``) do: - #. **creation**: create a fresh environment; by default :pypi:`virtualenv` is used, but configurable via + #. **Creation**: create a fresh environment; by default :pypi:`virtualenv` is used, but configurable via :ref:`runner`. For `virtualenv` tox will use the `virtualenv discovery logic `_ where the python specification is defined by the tox environments :ref:`base_python` (if not set will default to the environments name). This is @@ -76,14 +111,14 @@ tox roughly follows the following states: version, dependencies removed, etc.), a re-creation of the environment is automatically triggered. To force the recreation tox can be invoked with the :ref:`recreate` flag (``-r``). - #. **install dependencies** (optional): install the environment dependencies specified inside the ``deps`` + #. **Install dependencies** (optional): install the environment dependencies specified inside the ``deps`` configuration section, and then the earlier packaged source distribution. By default ``pip`` is used to install packages, however one can customize this via ``install_command``. Note ``pip`` will not update project dependencies (specified either in the ``install_requires`` or the ``extras`` section of the ``setup.py``) if any version already exists in the virtual environment; therefore we recommend to recreate your environments whenever your project dependencies change. - #. **packaging** (optional): create a distribution of the current project + #. **Packaging** (optional): create a distribution of the current project. #. **Build**: If the tox environment has a package configured tox will build a package from the current source tree. If multiple tox environments are run and the package built are compatible in between them then it will be @@ -94,11 +129,11 @@ tox roughly follows the following states: #. **Install the package**. This operation will force reinstall the package without its dependencies. - #. **commands**: run the specified commands in the specified order. Whenever the exit code of any of them is not + #. **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: +#. **Report** print out a report of outcomes for each tox environment: .. code:: bash @@ -109,10 +144,10 @@ tox roughly follows the following states: Only if all environments ran successfully tox will return exit code ``0`` (success). In this case you'll also see the message ``congratulations :)``. -tox will take care of environment isolation for you: it will strip away all operating system environment variables not -specified via ``passenv``. Furthermore, it will also alter the ``PATH`` variable so that your commands resolve -within the current active tox environment. In general, all executables in the path are available in ``commands``, but -tox will error if it was not explicitly allowed via :ref:`allowlist_externals`. +tox will take care of environment variable isolation for you. That means it will remove system environment variables not specified via +``passenv``. Furthermore, it will also alter the ``PATH`` variable so that your commands resolve within the current +active tox environment. In general, all executables outside of the tox environment are available in ``commands``, but +external commands need to be explicitly allowed via the :ref:`allowlist_externals` configuration. Main features ------------- @@ -126,12 +161,207 @@ Main features * ``plugin system`` to modify tox execution with simple hooks. * uses :pypi:`pip` and :pypi:`virtualenv` by default. Support for plugins replacing it with their own. -* **cross-Python compatible**: CPython 3.6 and higher. +* **cross-Python compatible**: tox requires CPython 3.7 and higher, but it can create environments 2.7 or later * **cross-platform**: Windows, macOS and Unix style environments * **full interoperability with devpi**: is integrated with and is used for testing in the :pypi:`devpi` system, a versatile PyPI index server and release managing tool * **driven by a simple (but flexible to allow expressing more complicated variants) ini-style config file** * **documented** examples and configuration * **concise reporting** about tool invocations and configuration errors -* **professionally** supported * supports using different / multiple PyPI index servers + +Related projects +---------------- + +tox has influenced several other projects in the Python test automation space. If tox doesn't quite fit your needs or +you want to do more research, we recommend taking a look at these projects: + +- `nox `__ is a project similar in spirit to tox but different in approach. The primary key + difference is that it uses Python scripts instead of a configuration file. It might be useful if you find tox + configuration too limiting but aren't looking to move to something as general-purpose as ``Invoke`` or ``make``. + Please note that tox will support defining configuration in a Python file soon, too. +- `Invoke `__ is a general-purpose task execution library, similar to Make. Invoke is far + more general-purpose than tox but it does not contain the Python testing-specific features that tox specializes in. + + +Auto-provisioning +----------------- +In case the installed tox version does not satisfy either the :ref:`min_version` or the :ref:`requires`, tox will automatically +create a virtual environment under :ref:`provision_tox_env` name that satisfies those constraints and delegate all +calls to this meta environment. This should allow satisfying constraints on your tox environment automatically, +given you have at least version ``3.8.0`` of tox. + +For example given: + +.. code-block:: ini + + [tox] + min_version = 4 + requires = tox-docker>=1 + +if the user runs it with tox ``3.8`` or later the installed tox application will automatically ensure that both the minimum version and +requires constraints are satisfied, by creating a virtual environment under ``.tox`` folder, and then installing into it +``tox>=4`` and ``tox-docker>=1``. Afterwards all tox invocations are forwarded to the tox installed inside ``.tox\.tox`` +folder (referred to as meta-tox or auto-provisioned tox). + +This allows tox to automatically setup itself with all its plugins for the current project. If the host tox satisfies +the constraints expressed with the :ref:`requires` and :ref:`min_version` no such provisioning is done (to avoid +setup cost and indirection when it's not explicitly needed). + +Cheat sheet +------------ + +This section details information that you'll use most often in short form. + +CLI +~~~ +- Each tox subcommand has a 1 (or 2) letter shortcut form too, e.g. ``tox run`` can also be written as ``tox r`` or + ``tox config`` can be shortened to ``tox c``. +- To run all tox environments defined in the :ref:`env_list` run tox without any flags: ``tox``. +- To run a single tox environment use the ``-e`` flag for the ``run`` sub-command as in ``tox run -e py310``. +- To run two or more tox environment pass comma separated values, e.g. ``tox run -e format,py310``. The run command will + run the tox environments sequentially, one at a time, in the specified order. +- To run two or more tox environment in parallel use the ``parallel`` sub-command , e.g. ``tox parallel -e py39,py310``. + The ``--parallel`` flag for this sub-command controls the degree of parallelism. +- To view the configuration value for a given environment and a given configuration key use the config sub-command with + the ``-k`` flag to filter for targeted configuration values: ``tox config -e py310 -k pass_env``. +- tox tries to automatically detect changes to your project dependencies and force a recreation when needed. + Unfortunately the detection is not always accurate, and it also won't detect changes on the PyPI index server. You can + force a fresh start for the tox environments by passing the ``-r`` flag to your run command. Whenever you see + something that should work but fails with some esoteric error it's recommended to use this flag to make sure you don't + have a stale Python environment; e.g. ``tox run -e py310 -r`` would clean the run environment and recreate it from + scratch. + +Configuration +~~~~~~~~~~~~~ + +- Every tox environment has its own configuration section (e.g. in case of ``tox.ini`` configuration method the + ``py310`` tox environments configuration is read from the ``testenv:py310`` section). If the section is missing or does + not contain that configuration value, it will fall back to the section defined by the :ref:`base` configuration (for + ``tox.ini`` this is the ``testenv`` section). For example: + + .. code-block:: ini + + [testenv] + commands = pytest tests + + [testenv:test] + description = run the test suite with pytest + + Here the environment description for ``test`` is taken from ``testenv:test``. As ``commands`` is not specified, + the value defined under the ``testenv`` section will be used. If the base environment is also missing a + configuration value then the configuration default will be used (e.g. in case of the ``pass_env`` configuration here). + +- To change the current working directory for the commands run use :ref:`change_dir` (note this will make the change for + all install commands too - watch out if you have relative paths in your project dependencies). + +- Environment variables: + - To view environment variables set and passed down use ``tox c -e py310 -k set_env pass_env``. + - To pass through additional environment variables use :ref:`pass_env`. + - To set environment variables use :ref:`set_env`. +- Setup operation can be configured via the :ref:`commands_pre`, while teardown commands via the :ref:`commands_post`. +- Configurations may be set conditionally within the ``tox.ini`` file. If a line starts with an environment name + or names, separated by a comma, followed by ``:`` the configuration will only be used if the + environment name(s) matches the executed tox environment. For example: + + .. code-block:: ini + + [testenv] + deps = + pip + format: black + py310,py39: pytest + + Here pip will be always installed as the configuration value is not conditional. black is only used for the ``format`` + environment, while ``pytest`` is only installed for the ``py310`` and ``py39`` environments. + +.. _`parallel_mode`: + +Parallel mode +------------- +``tox`` allows running environments in parallel mode via the ``parallel`` sub-command: + +- After the packaging phase completes tox will run the tox environments in parallel processes (multi-thread based). +- the ``--parallel`` flag takes an argument specifying the degree of parallelization, defaulting to ``auto``: + + - ``all`` to run all invoked environments in parallel, + - ``auto`` to limit it to CPU count, + - or pass an integer to set that limit. +- Parallel mode displays a progress spinner while running tox environments in parallel, and reports outcome of these as + soon as they have been completed with a human readable duration timing attached. This spinner can be disabled via the + ``--parallel-no-spinner`` flag. +- Parallel mode by default shows output only of failed environments and ones marked as :ref:`parallel_show_output` + ``=True``. +- There's now a concept of dependency between environments (specified via :ref:`depends`), tox will re-order the + environment list to be run to satisfy these dependencies, also for sequential runs. Furthermore, in parallel mode, + tox will only schedule a tox environment to run once all of its dependencies have finished (independent of their outcome). + + .. warning:: + + ``depends`` does not pull in dependencies into the run target, for example if you select ``py310,py39,coverage`` + via the ``-e`` tox will only run those three (even if ``coverage`` may specify as ``depends`` other targets too - + such as ``py310, py39, py38, py37``). + +- ``--parallel-live``/``-o`` allows showing the live output of the standard output and error, also turns off reporting + as described above. +- Note: parallel evaluation disables standard input. Use non parallel invocation if you need standard input. + +Example final output: + +.. code-block:: bash + + $ tox -e py310,py39,coverage -p all + ✔ OK py39 in 9.533 seconds + ✔ OK py310 in 9.96 seconds + ✔ OK coverage in 2.0 seconds + ___________________________ summary ______________________________________________________ + py310: commands succeeded + py39: 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): + +.. code-block:: bash + + ⠹ [2] py310 | py39 + +Packaging +--------- + +tox always 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: + +.. code-block:: toml + + [build-system] + build-backend = "hatchling.build" + requires = ["hatchling>=0.22", "hatch-vcs>=0.2"] + +By default tox will create and install a source distribution. You can configure to build a wheel instead by setting +the :ref:`package` configuration to ``wheel``. Wheels are much faster to install than source distributions. + +To query the projects dependencies tox will use a virtual environment whose name is defined under the :ref:`package_env` +configuration (by default ``.pkg``). The virtual environment used for building the package depends on the artifact +built: + +- for source distribution the :ref:`package_env`, +- for wheels the name defined under :ref:`wheel_build_env` (this depends on the Python version defined by the target tox + environment under :ref:`base_python`, if the environment targets CPython 3.10 it will be ``.pkg-cpython310`` or + for PyPy 3.9 it will be ``.pkg-pypy39``). + +For pure Python projects (non C-Extension ones) it's recommended to set :ref:`wheel_build_env` to the same as the +:ref:`package_env`. This way you'll build the wheel once and install the same wheel for all tox environments. + +Advanced features +----------------- + +tox supports these features that 90 percent of the time you'll not need, but are very useful the other ten percent. + +Generative environments +~~~~~~~~~~~~~~~~~~~~~~~ + +Django.