Skip to content

Commit 3c6bbad

Browse files
committed
📝 Switch to tox-uv
1 parent ce62711 commit 3c6bbad

File tree

1 file changed

+95
-117
lines changed

1 file changed

+95
-117
lines changed

docs/test/tox.rst

Lines changed: 95 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,23 @@ create an installable :doc:`distribution of your package
2121
<../packs/distribution>`. It searches the :file:`tox.ini` file for a list of
2222
environments and then performs the following steps for each:
2323

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
2929

3030
After all environments have been tested, tox outputs a summary of the results.
3131

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>`_.
3734

3835
Setting up tox
3936
--------------
4037

4138
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:
4441

4542
.. code-block:: console
4643
:emphasize-lines: 16
@@ -83,77 +80,77 @@ adding more Python versions shortly, but using one version helps to understand
8380
the flow of tox.
8481

8582
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
8885
omitted.
8986

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.
9592

9693
Executing tox
9794
-------------
9895

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:
10097

10198
.. tab:: Linux/macOS
10299

103100
.. code-block:: console
104101
105-
$ python3 -m venv .venv
106-
$ . .venv/bin/activate
107-
$ python -m pip install tox
102+
$ uv sync --extra dev
108103
109104
.. tab:: Windows
110105

111106
.. code-block:: ps1con
112107
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
116109
117110
To run tox, simply start tox:
118111

119112
.. code-block:: pytest
120113
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
124117
============================= 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
126119
cachedir: .tox/py313/.pytest_cache
127120
rootdir: /Users/veit/cusy/prj/items
128121
configfile: pyproject.toml
129122
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%]
151150
tests/cli/test_version.py . [100%]
152151
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
157154
158155
Testing multiple Python versions
159156
--------------------------------
@@ -179,7 +176,7 @@ although I will only highlight the differences in the following illustration:
179176
.. code-block:: pytest
180177
:emphasize-lines: 3-4, 8-12, 16-20, 24-28, 32-
181178
182-
$ python -m tox
179+
$ uv run tox
183180
...
184181
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
185182
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:
223220

224221
.. code-block:: pytest
225222
226-
$ python -m tox -p
223+
$ uv run tox -p
227224
py310: SKIP ⚠ in 0.09 seconds
228225
py312: OK ✔ in 2.08 seconds
229226
py313: OK ✔ in 2.18 seconds
@@ -273,8 +270,8 @@ extend commands to ``pytest --cov=items``:
273270
coverage report
274271
275272
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:
278275

279276
.. code-block:: ini
280277
@@ -289,7 +286,7 @@ example.
289286
.. code-block:: console
290287
:emphasize-lines: 1
291288
292-
$ python -m tox
289+
$ uv run tox
293290
...
294291
coverage-report: commands[0]> coverage combine
295292
Combined data file .coverage.fay.local.19539.XpQXpsGx
@@ -366,7 +363,7 @@ keyword option. We also use ``--no-cov`` to disable coverage:
366363
.. code-block:: pytest
367364
:emphasize-lines: 1, 3
368365
369-
$ tox -e py313 -- -k test_version --no-cov
366+
$ uv run tox -e py313 -- -k test_version --no-cov
370367
...
371368
py313: commands[0]> coverage run -m pytest -k test_version --no-cov
372369
============================= test session starts ==============================
@@ -411,30 +408,38 @@ of environments are available for GitHub actions:
411408
412409
jobs:
413410
coverage:
414-
name: Ensure 99% test coverage
411+
name: Ensure 100% test coverage
415412
runs-on: ubuntu-latest
416413
needs: tests
417414
if: always()
415+
418416
steps:
419417
- uses: actions/checkout@v4
418+
with:
419+
persist-credentials: false
420420
- uses: actions/setup-python@v5
421421
with:
422-
cache: pip
423-
python-version: 3.13
422+
python-version-file: .python-version
423+
- uses: hynek/setup-cached-uv@v2
424+
424425
- name: Download coverage data
425426
uses: actions/download-artifact@v4
426427
with:
427428
pattern: coverage-data-*
428429
merge-multiple: true
429-
- name: Combine coverage and fail if it’s <99%.
430+
431+
- name: Combine coverage and fail if it’s <100%.
430432
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+
434438
# 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
438443
439444
``name``
440445
can be any name. It is displayed in the GitHub Actions user interface.
@@ -445,43 +450,16 @@ of environments are available for GitHub actions:
445450
is a GitHub actions tool that checks out our repository so that the rest
446451
of the workflow can access it.
447452
``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.
450455
``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>`_
485463

486464
#. You can then click on :guilabel:`Start commit`. As we want to make further
487465
changes before the tests are executed automatically, we select
@@ -494,18 +472,18 @@ of environments are available for GitHub actions:
494472
The actions syntax is well documented. A good starting point in the GitHub
495473
Actions documentation is the `Building and Testing Python
496474
<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:
502480

503481
.. figure:: github-actions.png
504482
:alt: Screenshot of the GitHub actions overview
505483

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:
509487

510488
.. figure:: github-actions-run.png
511489
:alt: Screenshot of a GitHub actions run for an environment
@@ -538,8 +516,8 @@ Extend tox
538516
----------
539517

540518
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:
543521

544522
.. code-block:: toml
545523

0 commit comments

Comments
 (0)