Skip to content

Commit 4038aef

Browse files
committed
fix --forever interaction with pytest-xdist
1 parent c99a50d commit 4038aef

4 files changed

Lines changed: 49 additions & 9 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ those fixtures are shared between threads.
8484
the user explicitly ends the process with Ctrl-C. This is especially
8585
helpful when trying to reproduce thread safety bugs that might only
8686
occur rarely. Note that pytest's progress indicator will keep showing
87-
100% forever after the first pass of the test suite.
87+
100% forever after the first pass of the test suite. `forever` is not
88+
compatible with `-n` from [pytest-xdist](https://github.com/pytest-dev/pytest-xdist).
8889
- `--ignore-gil-enabled` to ignore the RuntimeWarning generated
8990
when the GIL is enabled at runtime on the free-threaded build
9091
and run the tests despite the fact that the GIL is enabled.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ psutil = [
5454
test = [
5555
"coverage[toml]>=7.5",
5656
"pytest-order",
57+
"pytest-xdist",
5758
"hypothesis>=6.135.33",
5859
"check-manifest",
5960
]

src/pytest_run_parallel/plugin.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ def pytest_runtestloop(self, session: pytest.Session):
190190
Based on the default implementation in pytest, but also adds support
191191
for running the tests in an endless loop.
192192
"""
193+
if not self.forever:
194+
# let the default pytest_runtestloop run if we don't need any
195+
# customization for --forever.
196+
return None
193197

194198
if (
195199
session.testsfailed
@@ -205,12 +209,10 @@ def pytest_runtestloop(self, session: pytest.Session):
205209
number_of_items = len(session.items)
206210
iter_number = 0
207211
idx = 0
208-
next_idx = idx + 1
209-
if self.forever:
210-
next_idx = next_idx % number_of_items
212+
next_idx = (idx + 1) % number_of_items
211213

212214
while idx < number_of_items:
213-
if idx == 0 and self.forever:
215+
if idx == 0:
214216
print("\n\n", end="")
215217
print("==========================================================")
216218
print("You ran the test suite with 'forever' mode enabled.")
@@ -228,9 +230,7 @@ def pytest_runtestloop(self, session: pytest.Session):
228230
raise session.Interrupted(session.shouldstop)
229231

230232
idx = next_idx
231-
next_idx = idx + 1
232-
if self.forever:
233-
next_idx = next_idx % number_of_items
233+
next_idx = (idx + 1) % number_of_items
234234

235235
return True
236236

@@ -407,6 +407,14 @@ def thread_comp(num_parallel_threads):
407407

408408

409409
def pytest_configure(config):
410+
if (
411+
config.option.forever
412+
and (n := getattr(config.option, "numprocesses", None)) is not None
413+
):
414+
raise pytest.UsageError(
415+
f"--forever from pytest-run-parallel is incompatible with `-n {n}` from pytest-xdist."
416+
)
417+
410418
config.addinivalue_line(
411419
"markers",
412420
"parallel_threads(n): run the given test function in parallel "
@@ -491,7 +499,8 @@ def pytest_addoption(parser):
491499
default=False,
492500
help="Run the test loop forever (starting from the top when all the tests have been run), "
493501
"until one crashes or the user explicitly stops the process with Ctrl-C. This is especially "
494-
"helpful for hitting thread safety bugs that only occur rarely.",
502+
"helpful for hitting thread safety bugs that only occur rarely. --forever is not compatible "
503+
"with -n from pytest-xdist.",
495504
)
496505
parser.addini(
497506
"thread_unsafe_fixtures",

tests/test_run_parallel.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,3 +698,32 @@ def test_warning_gil_enabled_ignore_option():
698698
""")
699699
result = pytester.runpytest("-v", "--ignore-gil-enabled", "-W", "default")
700700
assert result.ret == 0
701+
702+
703+
def test_runs_with_xdist(pytester):
704+
pytester.makepyfile("""
705+
def test_parallel1(num_parallel_threads):
706+
assert num_parallel_threads == 10
707+
708+
def test_parallel2(num_parallel_threads):
709+
assert num_parallel_threads == 10
710+
""")
711+
result = pytester.runpytest("--parallel-threads=10", "-n", "2", "-v")
712+
result.stdout.fnmatch_lines(["*test_parallel1*"])
713+
result.stdout.fnmatch_lines(["*test_parallel2*"])
714+
result.stdout.fnmatch_lines(["*All tests were run in parallel!*"])
715+
assert result.ret == 0
716+
717+
718+
def test_forever_with_xdist_errors(pytester):
719+
pytester.makepyfile("""
720+
def test_example():
721+
assert True
722+
""")
723+
result = pytester.runpytest("--forever", "-n", "2")
724+
assert result.ret != 0
725+
result.stderr.fnmatch_lines(
726+
[
727+
"*--forever from pytest-run-parallel is incompatible with `-n 2` from pytest-xdist*"
728+
]
729+
)

0 commit comments

Comments
 (0)