@@ -21,26 +21,23 @@ create an installable :doc:`distribution of your package
21
21
<../packs/distribution>`. It searches the :file: `tox.ini ` file for a list of
22
22
environments and then performs the following steps for each:
23
23
24
- #. creates a :term: `virtual environment <Virtual environment> `,
25
- #. installs some dependencies with :term: `pip `,
26
- #. build your package,
27
- #. install your package with pip,
28
- #. run further tests.
24
+ #. creates a :term: `virtual environment <Virtual environment> `
25
+ #. installs some dependencies with :term: `pip `
26
+ #. build your package
27
+ #. install your package with pip
28
+ #. run further tests
29
29
30
30
After all environments have been tested, tox outputs a summary of the results.
31
31
32
- .. note ::
33
- Although tox is used by many projects, there are alternatives that fulfil
34
- similar functions. Two alternatives to tox are `nox
35
- <https://nox.thea.codes/en/stable/> `_ and `invoke
36
- <https://www.pyinvoke.org> `_.
32
+ To accelerate this process with :term: `uv `, we don’t use tox directly, but
33
+ `tox-uv <https://github.com/tox-dev/tox-uv >`_.
37
34
38
35
Setting up tox
39
36
--------------
40
37
41
38
Until now, we had the items code in a :file: `src/ ` directory and the tests in
42
- :file: `tests/api/ ` and :file: `tests/cli/ `. Now we will add a :file: `tox.ini ` file
43
- so that the structure looks like this:
39
+ :file: `tests/api/ ` and :file: `tests/cli/ `. Now we will add a :file: `tox.ini `
40
+ file so that the structure looks like this:
44
41
45
42
.. code-block :: console
46
43
:emphasize-lines: 16
@@ -83,77 +80,77 @@ adding more Python versions shortly, but using one version helps to understand
83
80
the flow of tox.
84
81
85
82
Also note the line ``isolated_build = True ``: This is required for all packages
86
- configured with :file: `pyproject.toml `. However, for all projects configured with
87
- :file: `setup.py ` that use the :term: `setuptools ` library, this line can be
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
88
85
omitted.
89
86
90
- In the ``[testenv] `` section, ``pytest `` and ``faker `` are listed as dependencies
91
- under ``deps ``. So tox knows that we need these two tools for testing. If you
92
- wish, you can also specify which version should be used, for example
93
- ``pytest>=6.0 ``. Finally, commands instruct tox to execute ``pytest `` in every
94
- environment.
87
+ In the ``[testenv] `` section, ``pytest `` and ``faker `` are listed as
88
+ dependencies under ``deps ``. So tox knows that we need these two tools for
89
+ testing. If you wish, you can also specify which version should be used, for
90
+ example ``pytest>=6.0 ``. Finally, commands instruct tox to execute ``pytest `` in
91
+ every environment.
95
92
96
93
Executing tox
97
94
-------------
98
95
99
- Before you can run tox, you must ensure that you have installed it :
96
+ Before you can run tox, you must ensure that you have installed tox-uv :
100
97
101
98
.. tab :: Linux/macOS
102
99
103
100
.. code-block :: console
104
101
105
- $ python3 -m venv .venv
106
- $ . .venv/bin/activate
107
- $ python -m pip install tox
102
+ $ uv sync --extra dev
108
103
109
104
.. tab :: Windows
110
105
111
106
.. code-block :: ps1con
112
107
113
- C:> python -m venv .venv
114
- C:> .venv\Scripts\activate.bat
115
- C:> python -m pip install tox
108
+ C:> uv sync --extra dev
116
109
117
110
To run tox, simply start tox:
118
111
119
112
.. code-block :: pytest
120
113
121
- $ python -m tox
122
- 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
123
- py313: commands[0]> coverage run -m pytest
114
+ $ 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
116
+ py313: commands[0]> python --version --version
124
117
============================= test session starts ==============================
125
- platform darwin -- Python 3.13.0, pytest-8.3.3 , pluggy-1.5 .0
118
+ platform darwin -- Python 3.13.0, pytest-8.4.1 , pluggy-1.6 .0
126
119
cachedir: .tox/py313/.pytest_cache
127
120
rootdir: /Users/veit/cusy/prj/items
128
121
configfile: pyproject.toml
129
122
testpaths: tests
130
- plugins: cov-5.0.0, anyio-4.6.0, Faker-30.3.0
131
- collected 49 items
132
-
133
- tests/api/test_add.py .... [ 8%]
134
- tests/api/test_config.py . [ 10%]
135
- tests/api/test_count.py ... [ 16%]
136
- tests/api/test_delete.py ... [ 22%]
137
- tests/api/test_finish.py .... [ 30%]
138
- tests/api/test_list.py ......... [ 48%]
139
- tests/api/test_start.py .... [ 57%]
140
- tests/api/test_update.py .... [ 65%]
141
- tests/api/test_version.py . [ 67%]
142
- tests/cli/test_add.py .. [ 71%]
143
- tests/cli/test_config.py .. [ 75%]
144
- tests/cli/test_count.py . [ 77%]
145
- tests/cli/test_delete.py . [ 79%]
146
- tests/cli/test_errors.py .... [ 87%]
147
- tests/cli/test_finish.py . [ 89%]
148
- tests/cli/test_list.py .. [ 93%]
149
- tests/cli/test_start.py . [ 95%]
150
- tests/cli/test_update.py . [ 97%]
123
+ plugins: anyio-4.9.0, Faker-37.4.0, cov-6.2.1
124
+ collected 83 items
125
+
126
+ tests/api/test_add.py ...... [ 7%]
127
+ tests/api/test_config.py . [ 8%]
128
+ tests/api/test_count.py ... [ 12%]
129
+ tests/api/test_delete.py ... [ 15%]
130
+ tests/api/test_delete_all.py .. [ 18%]
131
+ tests/api/test_exceptions.py .. [ 20%]
132
+ tests/api/test_finish.py .... [ 25%]
133
+ tests/api/test_item.py ... [ 28%]
134
+ tests/api/test_item_id.py . [ 30%]
135
+ tests/api/test_list.py ......... [ 40%]
136
+ tests/api/test_list_edge_cases.py ........ [ 50%]
137
+ tests/api/test_start.py .... [ 55%]
138
+ tests/api/test_update.py ..... [ 61%]
139
+ tests/api/test_version.py . [ 62%]
140
+ tests/cli/test_add.py .. [ 65%]
141
+ tests/cli/test_config.py .. [ 67%]
142
+ tests/cli/test_count.py . [ 68%]
143
+ tests/cli/test_delete.py . [ 69%]
144
+ tests/cli/test_errors.py ....... [ 78%]
145
+ tests/cli/test_finish.py . [ 79%]
146
+ tests/cli/test_help.py ......... [ 90%]
147
+ tests/cli/test_list.py ..... [ 96%]
148
+ tests/cli/test_start.py . [ 97%]
149
+ tests/cli/test_update.py . [ 98%]
151
150
tests/cli/test_version.py . [100%]
152
151
153
- ============================== 49 passed in 0.16s ==============================
154
- .pkg: _exit> python /Users/veit/cusy/prj/items/.venv/lib/python3.13/site-packages/pyproject_api/_backend.py True hatchling.build
155
- py313: OK ✔ in 1.48 seconds
156
- congratulations :) (1.48 seconds)
152
+ ============================== 83 passed in 0.27s ==============================
153
+ py313: OK ✔ in 1.17 seconds
157
154
158
155
Testing multiple Python versions
159
156
--------------------------------
@@ -179,7 +176,7 @@ although I will only highlight the differences in the following illustration:
179
176
.. code-block :: pytest
180
177
:emphasize-lines: 3-4, 8-12, 16-20, 24-28, 32-
181
178
182
- $ python -m tox
179
+ $ uv run tox
183
180
...
184
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
185
182
py39: commands[0]> coverage run -m pytest
@@ -223,7 +220,7 @@ other. It is also possible to run them in parallel with the ``-p`` option:
223
220
224
221
.. code-block :: pytest
225
222
226
- $ python -m tox -p
223
+ $ uv run tox -p
227
224
py310: SKIP ⚠ in 0.09 seconds
228
225
py312: OK ✔ in 2.08 seconds
229
226
py313: OK ✔ in 2.18 seconds
@@ -273,8 +270,8 @@ extend commands to ``pytest --cov=items``:
273
270
coverage report
274
271
275
272
When using Coverage with ``tox ``, it can sometimes be useful to add a section in
276
- the :file: `:file:` pyproject.toml`` file to tell Coverage which source code paths
277
- should be considered identical:
273
+ the :file: `pyproject.toml ` file to tell Coverage which source code paths should
274
+ be considered identical:
278
275
279
276
.. code-block :: ini
280
277
@@ -289,7 +286,7 @@ example.
289
286
.. code-block :: console
290
287
:emphasize-lines: 1
291
288
292
- $ python -m tox
289
+ $ uv run tox
293
290
...
294
291
coverage-report: commands[0]> coverage combine
295
292
Combined data file .coverage.fay.local.19539.XpQXpsGx
@@ -366,7 +363,7 @@ keyword option. We also use ``--no-cov`` to disable coverage:
366
363
.. code-block :: pytest
367
364
:emphasize-lines: 1, 3
368
365
369
- $ tox -e py313 -- -k test_version --no-cov
366
+ $ uv run tox -e py313 -- -k test_version --no-cov
370
367
...
371
368
py313: commands[0]> coverage run -m pytest -k test_version --no-cov
372
369
============================= test session starts ==============================
@@ -411,30 +408,38 @@ of environments are available for GitHub actions:
411
408
412
409
jobs :
413
410
coverage :
414
- name : Ensure 99 % test coverage
411
+ name : Ensure 100 % test coverage
415
412
runs-on : ubuntu-latest
416
413
needs : tests
417
414
if : always()
415
+
418
416
steps :
419
417
- uses : actions/checkout@v4
418
+ with :
419
+ persist-credentials : false
420
420
- uses : actions/setup-python@v5
421
421
with :
422
- cache : pip
423
- python-version : 3.13
422
+ python-version-file : .python-version
423
+ - uses : hynek/setup-cached-uv@v2
424
+
424
425
- name : Download coverage data
425
426
uses : actions/download-artifact@v4
426
427
with :
427
428
pattern : coverage-data-*
428
429
merge-multiple : true
429
- - name : Combine coverage and fail if it’s <99%.
430
+
431
+ - name : Combine coverage and fail if it’s <100%.
430
432
run : |
431
- python -m pip install --upgrade coverage[toml]
432
- python -m coverage combine
433
- python -m coverage html --skip-covered --skip-empty
433
+ uv tool install coverage
434
+
435
+ coverage combine
436
+ coverage html --skip-covered --skip-empty
437
+
434
438
# Report and write to summary.
435
- python -m coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
436
- # Report again and fail if under 99%.
437
- python -m coverage report --fail-under=99
439
+ coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
440
+
441
+ # Report again and fail if under 100%.
442
+ coverage report --fail-under=100
438
443
439
444
``name ``
440
445
can be any name. It is displayed in the GitHub Actions user interface.
@@ -445,43 +450,16 @@ of environments are available for GitHub actions:
445
450
is a GitHub actions tool that checks out our repository so that the rest
446
451
of the workflow can access it.
447
452
``uses: actions/setup-python@v5 ``
448
- is a GitHub actions tool that configures Python and installs it in a build
449
- environment.
453
+ is a GitHub actions tool that configures Python and installs it in a
454
+ build environment.
450
455
``with: python-version: ${{ matrix.python }} ``
451
- says that an environment should be created for each of the Python versions
452
- listed in ``matrix.python ``.
453
- ``run: python -m pip install tox tox-gh-actions ``
454
- installs tox and simplifies the execution of tox in GitHub actions with
455
- `tox-gh-actions <https://pypi.org/project/tox-gh-actions/ >`_ by providing
456
- the environment that tox itself uses as the environment for the tests.
457
- However, we still need to adjust our :file: `tox.ini ` file for this, for
458
- example:
459
-
460
- .. code-block :: ini
461
-
462
- [gh-actions]
463
- python =
464
- 3.9: py39
465
- 3.10: py310
466
- 3.11: py311
467
- 3.12: py312
468
- 3.13: py313
469
-
470
- This assigns GitHub actions to tox environments.
471
-
472
- .. note ::
473
- * You do not need to specify all variants of your environment. This
474
- distinguishes ``tox-gh-actions `` from ``tox -e py ``.
475
- * Make sure that the versions in the ``[gh-actions] `` section match the
476
- available Python versions and, if applicable, those in the
477
- :ref: `GitHub actions for Git pre-commit hooks
478
- <gh-action-pre-commit-example>`.
479
- * Since all tests for a specific Python version are executed one after
480
- the other in a container, the advantages of parallel execution are
481
- lost.
482
-
483
- ``run: python -m tox ``
484
- executes tox.
456
+ says that an environment should be created for each of the Python
457
+ versions listed in ``matrix.python ``.
458
+ ``uses: hynek/setup-cached-uv@v2 ``
459
+ uses :term: `uv ` in GitHub Actions.
460
+
461
+ .. seealso ::
462
+ * `setup-cached-uv <https://github.com/hynek/setup-cached-uv >`_
485
463
486
464
#. You can then click on :guilabel: `Start commit `. As we want to make further
487
465
changes before the tests are executed automatically, we select
@@ -494,18 +472,18 @@ of environments are available for GitHub actions:
494
472
The actions syntax is well documented. A good starting point in the GitHub
495
473
Actions documentation is the `Building and Testing Python
496
474
<https://docs.github.com/en/actions/use-cases-and-examples/building-and-testing/building-and-testing-python> `__
497
- page. The documentation also shows you how to run pytest directly without tox and
498
- how to extend the matrix to multiple operating systems. As soon as you have set
499
- up your :file: `*.yml ` file and uploaded it to your GitHub repository, it will be
500
- executed automatically. You can then see the runs in the :menuselection: ` Actions `
501
- tab:
475
+ page. The documentation also shows you how to run pytest directly without tox
476
+ and how to extend the matrix to multiple operating systems. As soon as you have
477
+ set up your :file: `*.yml ` file and uploaded it to your GitHub repository, it
478
+ will be executed automatically. You can then see the runs in the
479
+ :menuselection: ` Actions ` tab:
502
480
503
481
.. figure :: github-actions.png
504
482
:alt: Screenshot of the GitHub actions overview
505
483
506
- The different Python environments are listed on the left-hand side. If you select
507
- one, the results for this environment are displayed, as shown in the following
508
- screenshot:
484
+ The different Python environments are listed on the left-hand side. If you
485
+ select one, the results for this environment are displayed, as shown in the
486
+ following screenshot:
509
487
510
488
.. figure :: github-actions-run.png
511
489
:alt: Screenshot of a GitHub actions run for an environment
@@ -538,8 +516,8 @@ Extend tox
538
516
----------
539
517
540
518
tox uses `pluggy <https://pluggy.readthedocs.io/en/stable/ >`_ to customise the
541
- default behaviour. Pluggy finds a plugin by searching for an entry point with the
542
- name ``tox ``, for example in a :file: `pyproject.toml ` file:
519
+ default behaviour. Pluggy finds a plugin by searching for an entry point with
520
+ the name ``tox ``, for example in a :file: `pyproject.toml ` file:
543
521
544
522
.. code-block :: toml
545
523
0 commit comments