@@ -66,7 +66,6 @@ This is a typical layout for many projects. Let’s take a look at a simple
6666
6767 [tox]
6868 envlist = py313
69- isolated_build = True
7069
7170 [testenv]
7271 deps =
@@ -79,11 +78,6 @@ shortcut that tells tox to run our tests with Python version 3.13. We will be
7978adding more Python versions shortly, but using one version helps to understand
8079the flow of tox.
8180
82- Also note the line ``isolated_build = True ``: This is required for all packages
83- configured with :file: `pyproject.toml `. However, for all projects configured
84- with :file: `setup.py ` that use the :term: `setuptools ` library, this line can be
85- omitted.
86-
8781In the ``[testenv] `` section, ``pytest `` and ``faker `` are listed as
8882dependencies under ``deps ``. So tox knows that we need these two tools for
8983testing. If you wish, you can also specify which version should be used, for
@@ -112,15 +106,20 @@ To run tox, simply start tox:
112106.. code-block :: pytest
113107
114108 $ uv run tox
115- py313: install_package> .venv/bin/uv pip install --reinstall --no-deps items@/Users/veit/cusy/prj/items/.tox/.tmp/package/57/items-0.1.0.tar.gz
109+ .pkg: _optional_hooks> python /Users/veit/cusy/prj/items/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True hatchling.build
110+ .pkg: get_requires_for_build_sdist> python /Users/veit/cusy/prj/items/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True hatchling.build
111+ .pkg: build_sdist> python /Users/veit/cusy/prj/items/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True hatchling.build
112+ py313: install_package> .venv/bin/uv pip install --reinstall --no-deps items@/Users/veit/cusy/prj/items/.tox/.tmp/package/18/items-0.1.0.tar.gz
116113 py313: commands[0]> python --version --version
114+ Python 3.13.0 (main, Oct 7 2024, 23:47:22) [Clang 18.1.8 ]
115+ py313: commands[1]> coverage run -m pytest
117116 ============================= test session starts ==============================
118- platform darwin -- Python 3.13.0, pytest-8.4.1 , pluggy-1.6.0
117+ platform darwin -- Python 3.13.0, pytest-9.0.2 , pluggy-1.6.0
119118 cachedir: .tox/py313/.pytest_cache
120119 rootdir: /Users/veit/cusy/prj/items
121120 configfile: pyproject.toml
122121 testpaths: tests
123- plugins: anyio-4.9.0, Faker-37.4 .0, cov-6.2.1
122+ plugins: Faker-40.1 .0, cov-7.0.0
124123 collected 83 items
125124
126125 tests/api/test_add.py ...... [ 7%]
@@ -149,8 +148,10 @@ To run tox, simply start tox:
149148 tests/cli/test_update.py . [ 98%]
150149 tests/cli/test_version.py . [100%]
151150
152- ============================== 83 passed in 0.27s ==============================
153- py313: OK ✔ in 1.17 seconds
151+ ============================== 83 passed in 0.35s ==============================
152+ .pkg: _exit> python /Users/veit/cusy/prj/items/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True hatchling.build
153+ py313: OK (1.19=setup[0.45]+cmd[0.01,0.72] seconds)
154+ congratulations :) (1.23 seconds)
154155
155156 Testing multiple Python versions
156157--------------------------------
@@ -162,55 +163,96 @@ Python versions:
162163 :emphasize-lines: 2, 4
163164
164165 [tox]
165- envlist = py3{9,10,11,12,13,13t,14,14t}
166- isolated_build = True
166+ envlist =
167+ py3{10-14}
168+ py3{13-14}t
167169 skip_missing_interpreters = True
168170
169- We will now test Python versions from 3.8 to 3.11 . In addition, we have also
171+ We will now test Python versions from 3.10 to 3.14 . In addition, we have also
170172added the setting ``skip_missing_interpreters = True `` so that tox does not fail
171173if one of the listed Python versions is missing on your system. If the value is
172174set to ``True ``, tox will run the tests with every available Python version, but
173175will skip versions it doesn’t find without failing. The output is very similar,
174176although I will only highlight the differences in the following illustration:
175177
176178.. code-block :: pytest
177- :emphasize-lines: 3-4, 8-12, 16-20, 24-28, 32-
178-
179- $ uv run tox
180- ...
181- py39: install_package> python -I -m pip install --force-reinstall --no-deps /Users/veit/cusy/prj/items/.tox/.tmp/package/17/items-0.1.0.tar.gz
182- py39: commands[0]> coverage run -m pytest
183- ============================= test session starts ==============================
184- ...
185- ============================== 49 passed in 0.16s ==============================
186- py39: OK ✔ in 2.17 seconds
187- py310: skipped because could not find python interpreter with spec(s): py310
188- py310: SKIP ⚠ in 0.01 seconds
189- py311: install_package> python -I -m pip install --force-reinstall --no-deps /Users/veit/cusy/prj/items/.tox/.tmp/package/18/items-0.1.0.tar.gz
190- py311: commands[0]> coverage run -m pytest
191- ============================= test session starts ==============================
192- ...
193- ============================== 49 passed in 0.15s ==============================
194- py311: OK ✔ in 1.41 seconds
195- py312: install_package> python -I -m pip install --force-reinstall --no-deps /Users/veit/cusy/prj/items/.tox/.tmp/package/19/items-0.1.0.tar.gz
196- py312: commands[0]> coverage run -m pytest
197- ============================= test session starts ==============================
198- ...
199- ============================== 49 passed in 0.15s ==============================
200- py312: OK ✔ in 1.43 seconds
201- py313: install_package> python -I -m pip install --force-reinstall --no-deps /Users/veit/cusy/prj/items/.tox/.tmp/package/20/items-0.1.0.tar.gz
202- py313: commands[0]> coverage run -m pytest
203- ============================= test session starts ==============================
204- ...
205- ============================== 49 passed in 0.16s ==============================
206- .pkg: _exit> python /Users/veit/cusy/prj/items/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True hatchling.build
207- py313: OK ✔ in 1.48 seconds
208- py39: OK (2.17=setup[1.54]+cmd[0.63] seconds)
209- py310: SKIP (0.01 seconds)
210- py311: OK (1.41=setup[0.81]+cmd[0.60] seconds)
211- py312: OK (1.43=setup[0.82]+cmd[0.61] seconds)
212- py313: OK (1.48=setup[0.82]+cmd[0.66] seconds)
213- congratulations :) (10.46 seconds)
179+ :emphasize-lines: 3-6, 10-14, 18-22, 26-30, 34-38, 42-46, 50-54, 59-
180+
181+ $ uv run tox
182+ ...
183+ py310: install_package> .venv/bin/uv pip install --reinstall --no-deps items@/Users/veit/cusy/prj/items/.tox/.tmp/package/19/items-0.1.0.tar.gz
184+ py310: commands[0]> python --version --version
185+ Python 3.10.17 (main, Apr 9 2025, 03:47:39) [Clang 20.1.0 ]
186+ py310: commands[1]> coverage run -m pytest
187+ ============================= test session starts ==============================
188+ ...
189+ ============================== 83 passed in 0.35s ==============================
190+ py310: OK ✔ in 1.3 seconds
191+ py311: install_package> .venv/bin/uv pip install --reinstall --no-deps items@/Users/veit/cusy/prj/items/.tox/.tmp/package/20/items-0.1.0.tar.gz
192+ py311: commands[0]> python --version --version
193+ Python 3.11.11 (main, Feb 5 2025, 18:58:27) [Clang 19.1.6 ]
194+ py311: commands[1]> coverage run -m pytest
195+ ============================= test session starts ==============================
196+ ...
197+ ============================== 83 passed in 0.36s ==============================
198+ py311: OK ✔ in 1.16 seconds
199+ py312: install_package> .venv/bin/uv pip install --reinstall --no-deps items@/Users/veit/cusy/prj/items/.tox/.tmp/package/21/items-0.1.0.tar.gz
200+ py312: commands[0]> python --version --version
201+ Python 3.12.12 (main, Oct 14 2025, 21:38:21) [Clang 20.1.4 ]
202+ py312: commands[1]> coverage run -m pytest
203+ ============================= test session starts ==============================
204+ ...
205+ ============================== 83 passed in 0.55s ==============================
206+ py312: OK ✔ in 1.79 seconds
207+ py313: install_package> .venv/bin/uv pip install --reinstall --no-deps items@/Users/veit/cusy/prj/items/.tox/.tmp/package/22/items-0.1.0.tar.gz
208+ py313: commands[0]> python --version --version
209+ Python 3.13.0 (main, Oct 7 2024, 23:47:22) [Clang 18.1.8 ]
210+ py313: commands[1]> coverage run -m pytest
211+ ============================= test session starts ==============================
212+ ...
213+ ============================== 83 passed in 0.35s ==============================
214+ py313: OK ✔ in 1.07 seconds
215+ py314: install_package> .venv/bin/uv pip install --reinstall --no-deps items@/Users/veit/cusy/prj/items/.tox/.tmp/package/23/items-0.1.0.tar.gz
216+ py314: commands[0]> python --version --version
217+ Python 3.14.0 (main, Oct 14 2025, 21:10:22) [Clang 20.1.4 ]
218+ py314: commands[1]> coverage run -m pytest
219+ ============================= test session starts ==============================
220+ ...
221+ ============================== 83 passed in 0.36s ==============================
222+ py314: OK ✔ in 1.28 seconds
223+ py313t: install_package> .venv/bin/uv pip install --reinstall --no-deps items@/Users/veit/cusy/prj/items/.tox/.tmp/package/24/items-0.1.0.tar.gz
224+ py313t: commands[0]> python --version --version
225+ Python 3.13.0 experimental free-threading build (main, Oct 16 2024, 08:24:33) [Clang 18.1.8 ]
226+ py313t: commands[1]> coverage run -m pytest
227+ ============================= test session starts ==============================
228+ ...
229+ ============================== 83 passed in 0.49s ==============================
230+ py313t: OK ✔ in 1.51 seconds
231+ py314t: install_package> .venv/bin/uv pip install --reinstall --no-deps items@/Users/veit/cusy/prj/items/.tox/.tmp/package/25/items-0.1.0.tar.gz
232+ py314t: commands[0]> python --version --version
233+ Python 3.14.0b4 free-threading build (main, Jul 8 2025, 21:06:49) [Clang 20.1.4 ]
234+ py314t: commands[1]> coverage run -m pytest
235+ ============================= test session starts ==============================
236+ ...
237+ ============================== 83 passed in 0.39s ==============================
238+ .pkg: _exit> python /Users/veit/cusy/prj/items/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True hatchling.build
239+ py310: OK (1.30=setup[0.54]+cmd[0.01,0.75] seconds)
240+ py311: OK (1.16=setup[0.38]+cmd[0.01,0.76] seconds)
241+ py312: OK (1.79=setup[0.42]+cmd[0.01,1.36] seconds)
242+ py313: OK (1.07=setup[0.34]+cmd[0.01,0.71] seconds)
243+ py314: OK (1.28=setup[0.42]+cmd[0.01,0.85] seconds)
244+ py313t: OK (1.51=setup[0.44]+cmd[0.01,1.05] seconds)
245+ py314t: OK (1.34=setup[0.44]+cmd[0.01,0.89] seconds)
246+ congratulations :) (9.48 seconds)
247+
248+ .. versionchanged :: tox≥4.25.0
249+ Before tox 4.25.0 dated 27 March 2025, the versions had to be specified one
250+ by one:
251+
252+ .. code-block :: ini
253+
254+ [tox]
255+ envlist = py3{10,11,12,13,14,13t,14t}
214256
215257 Running Tox environments in parallel
216258------------------------------------
@@ -221,17 +263,20 @@ other. It is also possible to run them in parallel with the ``-p`` option:
221263.. code-block :: pytest
222264
223265 $ uv run tox -p
224- py310: SKIP ⚠ in 0.09 seconds
225- py312: OK ✔ in 2.08 seconds
226- py313: OK ✔ in 2.18 seconds
227- py311: OK ✔ in 2.23 seconds
228- py39: OK ✔ in 2.91 seconds
229- py39: OK (2.91=setup[2.17]+cmd[0.74] seconds)
230- py310: SKIP (0.09 seconds)
231- py311: OK (2.23=setup[1.27]+cmd[0.96] seconds)
232- py312: OK (2.08=setup[1.22]+cmd[0.86] seconds)
233- py313: OK (2.18=setup[1.23]+cmd[0.95] seconds)
234- congratulations :) (3.05 seconds)
266+ py311: OK ✔ in 1.7 seconds
267+ py310: OK ✔ in 1.8 seconds
268+ py313: OK ✔ in 1.8 seconds
269+ py314t: OK ✔ in 1.89 seconds
270+ py314: OK ✔ in 1.91 seconds
271+ py313t: OK ✔ in 2.24 seconds
272+ py310: OK (1.80=setup[0.62]+cmd[0.02,1.16] seconds)
273+ py311: OK (1.70=setup[0.54]+cmd[0.02,1.15] seconds)
274+ py312: OK (2.28=setup[0.58]+cmd[0.01,1.69] seconds)
275+ py313: OK (1.80=setup[0.60]+cmd[0.02,1.18] seconds)
276+ py314: OK (1.91=setup[0.62]+cmd[0.02,1.28] seconds)
277+ py313t: OK (2.24=setup[0.72]+cmd[0.02,1.51] seconds)
278+ py314t: OK (1.89=setup[0.61]+cmd[0.02,1.26] seconds)
279+ congratulations :) (2.33 seconds)
235280
236281 .. note ::
237282 The output is not abbreviated; this is the full output you will see if
@@ -247,11 +292,12 @@ the ``pytest-cov`` plugin is installed in the tox test environments. Including
247292extend commands to ``pytest --cov=items ``:
248293
249294.. code-block ::
250- :emphasize-lines: 12 -
295+ :emphasize-lines: 11 -
251296
252297 [tox]
253- envlist = py3{9,10,11,12,13,13t,14,14t}
254- isolated_build = True
298+ envlist =
299+ py3{10-14}
300+ py3{13-14}t
255301 skip_missing_interpreters = True
256302
257303 [testenv]
@@ -273,7 +319,7 @@ When using Coverage with ``tox``, it can sometimes be useful to add a section in
273319the :file: `pyproject.toml ` file to tell Coverage which source code paths should
274320be considered identical:
275321
276- .. code-block :: ini
322+ .. code-block :: toml
277323
278324 [tool.coverage.paths]
279325 source = ["src", ".tox/py*/**/site-packages"]
@@ -288,23 +334,20 @@ example.
288334
289335 $ uv run tox
290336 ...
291- coverage-report: commands[0]> coverage combine
292- Combined data file .coverage.fay.local.19539.XpQXpsGx
293- coverage-report: commands[1]> coverage report
294- Name Stmts Miss Branch BrPart Cover Missing
295- --------------------------------------------------------------
296- src/items/api.py 68 1 12 1 98% 88
297- --------------------------------------------------------------
298- TOTAL 428 1 32 1 99%
299-
300- 26 files skipped due to complete coverage.
301- py39: OK (2.12=setup[1.49]+cmd[0.63] seconds)
302- py310: SKIP (0.01 seconds)
303- py311: OK (1.41=setup[0.80]+cmd[0.62] seconds)
304- py312: OK (1.43=setup[0.81]+cmd[0.62] seconds)
305- py313: OK (1.46=setup[0.83]+cmd[0.62] seconds)
306- coverage-report: OK (0.16=setup[0.00]+cmd[0.07,0.09] seconds)
307- congratulations :) (10.26 seconds)
337+ Name Stmts Miss Branch BrPart Cover Missing
338+ ---------------------------------------------------
339+ TOTAL 540 0 32 0 100%
340+
341+ 33 files skipped due to complete coverage.
342+ py310: OK (1.10=setup[0.44]+cmd[0.01,0.64] seconds)
343+ py311: OK (0.98=setup[0.31]+cmd[0.01,0.66] seconds)
344+ py312: OK (1.59=setup[0.34]+cmd[0.01,1.24] seconds)
345+ py313: OK (1.06=setup[0.34]+cmd[0.01,0.71] seconds)
346+ py314: OK (1.10=setup[0.35]+cmd[0.01,0.74] seconds)
347+ py313t: OK (1.36=setup[0.40]+cmd[0.01,0.95] seconds)
348+ py314t: OK (1.31=setup[0.44]+cmd[0.01,0.86] seconds)
349+ coverage-report: OK (1.55=setup[0.37]+cmd[1.08,0.10] seconds)
350+ congratulations :) (10.09 seconds)
308351
309352 Set minimum coverage
310353--------------------
@@ -336,15 +379,15 @@ We can also call individual tests with tox by making another change so that
336379:term: `parameters <Parameter> ` can be passed to pytest:
337380
338381.. code-block :: ini
339- :emphasize-lines: 17
382+ :emphasize-lines: 16
340383
341384 [tox]
342385 envlist =
343386 pre-commit
344387 docs
345- py3{9,10,11,12,13,13t,14,14t}
388+ py3{10-14}
389+ py3{13-14}t
346390 coverage-report
347- isolated_build = True
348391 skip_missing_interpreters = True
349392
350393 [testenv]
0 commit comments