Skip to content

Commit 7504e2d

Browse files
committed
📝 Simplify tox’s version range syntax
1 parent e25d599 commit 7504e2d

File tree

1 file changed

+129
-87
lines changed

1 file changed

+129
-87
lines changed

docs/test/tox.rst

Lines changed: 129 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -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
7978
adding more Python versions shortly, but using one version helps to understand
8079
the 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-
8781
In the ``[testenv]`` section, ``pytest`` and ``faker`` are listed as
8882
dependencies under ``deps``. So tox knows that we need these two tools for
8983
testing. 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
--------------------------------
@@ -159,58 +160,98 @@ To do this, we extend ``envlist`` in the :file:`tox.ini` file to add further
159160
Python versions:
160161

161162
.. code-block:: ini
162-
:emphasize-lines: 2, 4
163163
164164
[tox]
165-
envlist = py3{9,10,11,12,13,13t,14,14t}
166-
isolated_build = True
165+
envlist =
166+
py3{10-14}
167+
py3{13-14}t
167168
skip_missing_interpreters = True
168169
169-
We will now test Python versions from 3.8 to 3.11. In addition, we have also
170+
We will now test Python versions from 3.10 to 3.14. In addition, we have also
170171
added the setting ``skip_missing_interpreters = True`` so that tox does not fail
171172
if one of the listed Python versions is missing on your system. If the value is
172173
set to ``True``, tox will run the tests with every available Python version, but
173174
will skip versions it doesn’t find without failing. The output is very similar,
174175
although I will only highlight the differences in the following illustration:
175176

176177
.. 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)
178+
:emphasize-lines: 3-6, 10-14, 18-22, 26-30, 34-38, 42-46, 50-54, 59-
179+
180+
$ uv run tox
181+
...
182+
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
183+
py310: commands[0]> python --version --version
184+
Python 3.10.17 (main, Apr 9 2025, 03:47:39) [Clang 20.1.0 ]
185+
py310: commands[1]> coverage run -m pytest
186+
============================= test session starts ==============================
187+
...
188+
============================== 83 passed in 0.35s ==============================
189+
py310: OK ✔ in 1.3 seconds
190+
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
191+
py311: commands[0]> python --version --version
192+
Python 3.11.11 (main, Feb 5 2025, 18:58:27) [Clang 19.1.6 ]
193+
py311: commands[1]> coverage run -m pytest
194+
============================= test session starts ==============================
195+
...
196+
============================== 83 passed in 0.36s ==============================
197+
py311: OK ✔ in 1.16 seconds
198+
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
199+
py312: commands[0]> python --version --version
200+
Python 3.12.12 (main, Oct 14 2025, 21:38:21) [Clang 20.1.4 ]
201+
py312: commands[1]> coverage run -m pytest
202+
============================= test session starts ==============================
203+
...
204+
============================== 83 passed in 0.55s ==============================
205+
py312: OK ✔ in 1.79 seconds
206+
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
207+
py313: commands[0]> python --version --version
208+
Python 3.13.0 (main, Oct 7 2024, 23:47:22) [Clang 18.1.8 ]
209+
py313: commands[1]> coverage run -m pytest
210+
============================= test session starts ==============================
211+
...
212+
============================== 83 passed in 0.35s ==============================
213+
py313: OK ✔ in 1.07 seconds
214+
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
215+
py314: commands[0]> python --version --version
216+
Python 3.14.0 (main, Oct 14 2025, 21:10:22) [Clang 20.1.4 ]
217+
py314: commands[1]> coverage run -m pytest
218+
============================= test session starts ==============================
219+
...
220+
============================== 83 passed in 0.36s ==============================
221+
py314: OK ✔ in 1.28 seconds
222+
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
223+
py313t: commands[0]> python --version --version
224+
Python 3.13.0 experimental free-threading build (main, Oct 16 2024, 08:24:33) [Clang 18.1.8 ]
225+
py313t: commands[1]> coverage run -m pytest
226+
============================= test session starts ==============================
227+
...
228+
============================== 83 passed in 0.49s ==============================
229+
py313t: OK ✔ in 1.51 seconds
230+
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
231+
py314t: commands[0]> python --version --version
232+
Python 3.14.0b4 free-threading build (main, Jul 8 2025, 21:06:49) [Clang 20.1.4 ]
233+
py314t: commands[1]> coverage run -m pytest
234+
============================= test session starts ==============================
235+
...
236+
============================== 83 passed in 0.39s ==============================
237+
.pkg: _exit> python /Users/veit/cusy/prj/items/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True hatchling.build
238+
py310: OK (1.30=setup[0.54]+cmd[0.01,0.75] seconds)
239+
py311: OK (1.16=setup[0.38]+cmd[0.01,0.76] seconds)
240+
py312: OK (1.79=setup[0.42]+cmd[0.01,1.36] seconds)
241+
py313: OK (1.07=setup[0.34]+cmd[0.01,0.71] seconds)
242+
py314: OK (1.28=setup[0.42]+cmd[0.01,0.85] seconds)
243+
py313t: OK (1.51=setup[0.44]+cmd[0.01,1.05] seconds)
244+
py314t: OK (1.34=setup[0.44]+cmd[0.01,0.89] seconds)
245+
congratulations :) (9.48 seconds)
246+
247+
.. versionchanged:: tox≥4.25.0
248+
Before tox 4.25.0 dated 27 March 2025, the versions had to be specified one
249+
by one:
250+
251+
.. code-block:: ini
252+
253+
[tox]
254+
envlist = py3{10,11,12,13,14,13t,14t}
214255
215256
Running Tox environments in parallel
216257
------------------------------------
@@ -221,17 +262,20 @@ other. It is also possible to run them in parallel with the ``-p`` option:
221262
.. code-block:: pytest
222263
223264
$ 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)
265+
py311: OK ✔ in 1.7 seconds
266+
py310: OK ✔ in 1.8 seconds
267+
py313: OK ✔ in 1.8 seconds
268+
py314t: OK ✔ in 1.89 seconds
269+
py314: OK ✔ in 1.91 seconds
270+
py313t: OK ✔ in 2.24 seconds
271+
py310: OK (1.80=setup[0.62]+cmd[0.02,1.16] seconds)
272+
py311: OK (1.70=setup[0.54]+cmd[0.02,1.15] seconds)
273+
py312: OK (2.28=setup[0.58]+cmd[0.01,1.69] seconds)
274+
py313: OK (1.80=setup[0.60]+cmd[0.02,1.18] seconds)
275+
py314: OK (1.91=setup[0.62]+cmd[0.02,1.28] seconds)
276+
py313t: OK (2.24=setup[0.72]+cmd[0.02,1.51] seconds)
277+
py314t: OK (1.89=setup[0.61]+cmd[0.02,1.26] seconds)
278+
congratulations :) (2.33 seconds)
235279
236280
.. note::
237281
The output is not abbreviated; this is the full output you will see if
@@ -247,11 +291,12 @@ the ``pytest-cov`` plugin is installed in the tox test environments. Including
247291
extend commands to ``pytest --cov=items``:
248292

249293
.. code-block::
250-
:emphasize-lines: 12-
294+
:emphasize-lines: 11-
251295
252296
[tox]
253-
envlist = py3{9,10,11,12,13,13t,14,14t}
254-
isolated_build = True
297+
envlist =
298+
py3{10-14}
299+
py3{13-14}t
255300
skip_missing_interpreters = True
256301
257302
[testenv]
@@ -273,7 +318,7 @@ When using Coverage with ``tox``, it can sometimes be useful to add a section in
273318
the :file:`pyproject.toml` file to tell Coverage which source code paths should
274319
be considered identical:
275320

276-
.. code-block:: ini
321+
.. code-block:: toml
277322
278323
[tool.coverage.paths]
279324
source = ["src", ".tox/py*/**/site-packages"]
@@ -288,23 +333,20 @@ example.
288333
289334
$ uv run tox
290335
...
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)
336+
Name Stmts Miss Branch BrPart Cover Missing
337+
---------------------------------------------------
338+
TOTAL 540 0 32 0 100%
339+
340+
33 files skipped due to complete coverage.
341+
py310: OK (1.10=setup[0.44]+cmd[0.01,0.64] seconds)
342+
py311: OK (0.98=setup[0.31]+cmd[0.01,0.66] seconds)
343+
py312: OK (1.59=setup[0.34]+cmd[0.01,1.24] seconds)
344+
py313: OK (1.06=setup[0.34]+cmd[0.01,0.71] seconds)
345+
py314: OK (1.10=setup[0.35]+cmd[0.01,0.74] seconds)
346+
py313t: OK (1.36=setup[0.40]+cmd[0.01,0.95] seconds)
347+
py314t: OK (1.31=setup[0.44]+cmd[0.01,0.86] seconds)
348+
coverage-report: OK (1.55=setup[0.37]+cmd[1.08,0.10] seconds)
349+
congratulations :) (10.09 seconds)
308350
309351
Set minimum coverage
310352
--------------------
@@ -336,15 +378,15 @@ We can also call individual tests with tox by making another change so that
336378
:term:`parameters <Parameter>` can be passed to pytest:
337379

338380
.. code-block:: ini
339-
:emphasize-lines: 17
381+
:emphasize-lines: 15-
340382
341383
[tox]
342384
envlist =
343385
pre-commit
344386
docs
345-
py3{9,10,11,12,13,13t,14,14t}
387+
py3{10-14}
388+
py3{13-14}t
346389
coverage-report
347-
isolated_build = True
348390
skip_missing_interpreters = True
349391
350392
[testenv]

0 commit comments

Comments
 (0)