Skip to content

Commit 8cd1022

Browse files
authored
Add sphinx docs folder and changelog URLs to metadata (#751)
1 parent 1a5ad8a commit 8cd1022

14 files changed

+615
-521
lines changed

README.rst

Lines changed: 4 additions & 521 deletions
Large diffs are not rendered by default.

docs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
_build/

docs/boxed.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
.. _boxed:
3+
4+
Running tests in a boxed subprocess (moved to pytest-forked)
5+
============================================================
6+
7+
This functionality has been moved to the
8+
`pytest-forked <https://github.com/pytest-dev/pytest-forked>`_ plugin, but the ``--boxed`` option
9+
is still kept for backward compatibility.

docs/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=========
2+
Changelog
3+
=========
4+
5+
.. include:: ../CHANGELOG.rst

docs/conf.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Configuration file for the Sphinx documentation builder.
2+
#
3+
# This file only contains a selection of the most common options. For a full
4+
# list see the documentation:
5+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
6+
7+
# -- Path setup --------------------------------------------------------------
8+
9+
# If extensions (or modules to document with autodoc) are in another directory,
10+
# add these directories to sys.path here. If the directory is relative to the
11+
# documentation root, use os.path.abspath to make it absolute, like shown here.
12+
#
13+
# import os
14+
# import sys
15+
# sys.path.insert(0, os.path.abspath('.'))
16+
17+
18+
# -- Project information -----------------------------------------------------
19+
20+
project = "pytest-xdist"
21+
copyright = "2022, holger krekel and contributors"
22+
author = "holger krekel and contributors"
23+
24+
master_doc = "index"
25+
26+
# -- General configuration ---------------------------------------------------
27+
28+
# Add any Sphinx extension module names here, as strings. They can be
29+
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
30+
# ones.
31+
extensions = [
32+
"sphinx_rtd_theme",
33+
]
34+
35+
# Add any paths that contain templates here, relative to this directory.
36+
templates_path = ["_templates"]
37+
38+
# List of patterns, relative to source directory, that match files and
39+
# directories to ignore when looking for source files.
40+
# This pattern also affects html_static_path and html_extra_path.
41+
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
42+
43+
44+
# -- Options for HTML output -------------------------------------------------
45+
46+
# The theme to use for HTML and HTML Help pages. See the documentation for
47+
# a list of builtin themes.
48+
#
49+
html_theme = "sphinx_rtd_theme"
50+
51+
# Add any paths that contain custom static files (such as style sheets) here,
52+
# relative to this directory. They are copied after the builtin static files,
53+
# so a file named "default.css" will overwrite the builtin "default.css".
54+
# html_static_path = ['_static']

docs/crash.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
When tests crash
2+
================
3+
4+
If a test crashes a worker, pytest-xdist will automatically restart that worker
5+
and report the test’s failure. You can use the ``--max-worker-restart`` option
6+
to limit the number of worker restarts that are allowed, or disable restarting
7+
altogether using ``--max-worker-restart 0``.

docs/distribution.rst

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
.. _parallelization:
2+
3+
Running tests across multiple CPUs
4+
==================================
5+
6+
To send tests to multiple CPUs, use the ``-n`` (or ``--numprocesses``) option::
7+
8+
pytest -n 8
9+
10+
Pass ``-n auto`` to use as many processes as your computer has CPU cores. This
11+
can lead to considerable speed ups, especially if your test suite takes a
12+
noticeable amount of time.
13+
14+
* ``--maxprocesses=maxprocesses``: limit the maximum number of workers to
15+
process the tests.
16+
17+
* ``--max-worker-restart``: maximum number of workers that can be restarted
18+
when crashed (set to zero to disable this feature).
19+
20+
The test distribution algorithm is configured with the ``--dist`` command-line option:
21+
22+
.. _distribution modes:
23+
24+
* ``--dist load`` **(default)**: Sends pending tests to any worker that is
25+
available, without any guaranteed order.
26+
27+
* ``--dist loadscope``: Tests are grouped by **module** for *test functions*
28+
and by **class** for *test methods*. Groups are distributed to available
29+
workers as whole units. This guarantees that all tests in a group run in the
30+
same process. This can be useful if you have expensive module-level or
31+
class-level fixtures. Grouping by class takes priority over grouping by
32+
module.
33+
34+
* ``--dist loadfile``: Tests are grouped by their containing file. Groups are
35+
distributed to available workers as whole units. This guarantees that all
36+
tests in a file run in the same worker.
37+
38+
* ``--dist loadgroup``: Tests are grouped by the ``xdist_group`` mark. Groups are
39+
distributed to available workers as whole units. This guarantees that all
40+
tests with same ``xdist_group`` name run in the same worker.
41+
42+
.. code-block:: python
43+
44+
@pytest.mark.xdist_group(name="group1")
45+
def test1():
46+
pass
47+
48+
class TestA:
49+
@pytest.mark.xdist_group("group1")
50+
def test2():
51+
pass
52+
53+
This will make sure ``test1`` and ``TestA::test2`` will run in the same worker.
54+
Tests without the ``xdist_group`` mark are distributed normally as in the ``--dist=load`` mode.
55+
56+
* ``--dist no``: The normal pytest execution mode, runs one test at a time (no distribution at all).

docs/how-it-works.rst

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
How it works?
2+
=============
3+
4+
``xdist`` works by spawning one or more **workers**, which are
5+
controlled by the **controller**. Each **worker** is responsible for
6+
performing a full test collection and afterwards running tests as
7+
dictated by the **controller**.
8+
9+
The execution flow is:
10+
11+
1. **controller** spawns one or more **workers** at the beginning of the
12+
test session. The communication between **controller** and **worker**
13+
nodes makes use of `execnet <https://codespeak.net/execnet/>`__ and
14+
its
15+
`gateways <https://codespeak.net/execnet/basics.html#gateways-bootstrapping-python-interpreters>`__.
16+
The actual interpreters executing the code for the **workers** might
17+
be remote or local.
18+
19+
2. Each **worker** itself is a mini pytest runner. **workers** at this
20+
point perform a full test collection, sending back the collected
21+
test-ids back to the **controller** which does not perform any
22+
collection itself.
23+
24+
3. The **controller** receives the result of the collection from all
25+
nodes. At this point the **controller** performs some sanity check to
26+
ensure that all **workers** collected the same tests (including
27+
order), bailing out otherwise. If all is well, it converts the list
28+
of test-ids into a list of simple indexes, where each index
29+
corresponds to the position of that test in the original collection
30+
list. This works because all nodes have the same collection list, and
31+
saves bandwidth because the **controller** can now tell one of the
32+
workers to just *execute test index 3* index of passing the full test
33+
id.
34+
35+
4. If **dist-mode** is **each**: the **controller** just sends the full
36+
list of test indexes to each node at this moment.
37+
38+
5. If **dist-mode** is **load**: the **controller** takes around 25% of
39+
the tests and sends them one by one to each **worker** in a round
40+
robin fashion. The rest of the tests will be distributed later as
41+
**workers** finish tests (see below).
42+
43+
6. Note that ``pytest_xdist_make_scheduler`` hook can be used to
44+
implement custom tests distribution logic.
45+
46+
7. **workers** re-implement ``pytest_runtestloop``: pytest’s default
47+
implementation basically loops over all collected items in the
48+
``session`` object and executes the ``pytest_runtest_protocol`` for
49+
each test item, but in xdist **workers** sit idly waiting for
50+
**controller** to send tests for execution. As tests are received by
51+
**workers**, ``pytest_runtest_protocol`` is executed for each test.
52+
Here it worth noting an implementation detail: **workers** always
53+
must keep at least one test item on their queue due to how the
54+
``pytest_runtest_protocol(item, nextitem)`` hook is defined: in order
55+
to pass the ``nextitem`` to the hook, the worker must wait for more
56+
instructions from controller before executing that remaining test. If
57+
it receives more tests, then it can safely call
58+
``pytest_runtest_protocol`` because it knows what the ``nextitem``
59+
parameter will be. If it receives a “shutdown” signal, then it can
60+
execute the hook passing ``nextitem`` as ``None``.
61+
62+
8. As tests are started and completed at the **workers**, the results
63+
are sent back to the **controller**, which then just forwards the
64+
results to the appropriate pytest hooks: ``pytest_runtest_logstart``
65+
and ``pytest_runtest_logreport``. This way other plugins (for example
66+
``junitxml``) can work normally. The **controller** (when in
67+
dist-mode **load**) decides to send more tests to a node when a test
68+
completes, using some heuristics such as test durations and how many
69+
tests each **worker** still has to run.
70+
71+
9. When the **controller** has no more pending tests it will send a
72+
“shutdown” signal to all **workers**, which will then run their
73+
remaining tests to completion and shut down. At this point the
74+
**controller** will sit waiting for **workers** to shut down, still
75+
processing events such as ``pytest_runtest_logreport``.
76+
77+
FAQ
78+
---
79+
80+
**Question**: Why does each worker do its own collection, as opposed to having the
81+
controller collect once and distribute from that collection to the
82+
workers?
83+
84+
If collection was performed by controller then it would have to
85+
serialize collected items to send them through the wire, as workers live
86+
in another process. The problem is that test items are not easily
87+
(impossible?) to serialize, as they contain references to the test
88+
functions, fixture managers, config objects, etc. Even if one manages to
89+
serialize it, it seems it would be very hard to get it right and easy to
90+
break by any small change in pytest.

0 commit comments

Comments
 (0)