Add --no-loadscope-reorder and --loadscope-reorder options (#1217)
Based on #1098. Closes #1098 --------- Co-authored-by: Toan Vuong <toan.vuong@hyperscience.com>
This commit is contained in:
5
changelog/1083.improvement.rst
Normal file
5
changelog/1083.improvement.rst
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Add ``--no-loadscope-reorder`` and ``--loadscope-reorder`` option to control whether to automatically reorder tests in loadscope for tests where relative ordering matters. This only applies when using ``loadscope``.
|
||||||
|
|
||||||
|
For example, [test_file_1, test_file_2, ..., test_file_n] are given as input test files, if ``--no-loadscope-reorder`` is used, for either worker, the ``test_file_a`` will be executed before ``test_file_b`` only if ``a < b``.
|
||||||
|
|
||||||
|
The default behavior is to reorder the tests to maximize the number of tests that can be executed in parallel.
|
||||||
@@ -127,6 +127,32 @@ def pytest_addoption(parser: pytest.Parser) -> None:
|
|||||||
"(default) no: Run tests inprocess, don't distribute."
|
"(default) no: Run tests inprocess, don't distribute."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
group.addoption(
|
||||||
|
"--loadscope-reorder",
|
||||||
|
dest="loadscopereorder",
|
||||||
|
action="store_true",
|
||||||
|
default=True,
|
||||||
|
help=(
|
||||||
|
"Pytest-xdist will default reorder tests by number of tests per scope "
|
||||||
|
"when used in conjunction with loadscope.\n"
|
||||||
|
"This option will enable loadscope reorder which will improve the "
|
||||||
|
"parallelism of the test suite.\n"
|
||||||
|
"However, the partial order of tests might not be retained.\n"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
group.addoption(
|
||||||
|
"--no-loadscope-reorder",
|
||||||
|
dest="loadscopereorder",
|
||||||
|
action="store_false",
|
||||||
|
help=(
|
||||||
|
"Pytest-xdist will default reorder tests by number of tests per scope "
|
||||||
|
"when used in conjunction with loadscope.\n"
|
||||||
|
"This option will disable loadscope reorder, "
|
||||||
|
"and the partial order of tests can be retained.\n"
|
||||||
|
"This is useful when pytest-xdist is used together with "
|
||||||
|
"other plugins that specify tests in a specific order."
|
||||||
|
),
|
||||||
|
)
|
||||||
group.addoption(
|
group.addoption(
|
||||||
"--tx",
|
"--tx",
|
||||||
dest="tx",
|
dest="tx",
|
||||||
|
|||||||
@@ -371,11 +371,15 @@ class LoadScopeScheduling:
|
|||||||
work_unit = unsorted_workqueue.setdefault(scope, {})
|
work_unit = unsorted_workqueue.setdefault(scope, {})
|
||||||
work_unit[nodeid] = False
|
work_unit[nodeid] = False
|
||||||
|
|
||||||
# Insert tests scopes into work queue ordered by number of tests.
|
if self.config.option.loadscopereorder:
|
||||||
for scope, nodeids in sorted(
|
# Insert tests scopes into work queue ordered by number of tests.
|
||||||
unsorted_workqueue.items(), key=lambda item: -len(item[1])
|
for scope, nodeids in sorted(
|
||||||
):
|
unsorted_workqueue.items(), key=lambda item: -len(item[1])
|
||||||
self.workqueue[scope] = nodeids
|
):
|
||||||
|
self.workqueue[scope] = nodeids
|
||||||
|
else:
|
||||||
|
for scope, nodeids in unsorted_workqueue.items():
|
||||||
|
self.workqueue[scope] = nodeids
|
||||||
|
|
||||||
# Avoid having more workers than work
|
# Avoid having more workers than work
|
||||||
extra_nodes = len(self.nodes) - len(self.workqueue)
|
extra_nodes = len(self.nodes) - len(self.workqueue)
|
||||||
|
|||||||
@@ -1254,6 +1254,24 @@ class TestLoadScope:
|
|||||||
"test_b.py::test", result.outlines
|
"test_b.py::test", result.outlines
|
||||||
) == {"gw0": 20}
|
) == {"gw0": 20}
|
||||||
|
|
||||||
|
def test_workqueue_ordered_by_input(self, pytester: pytest.Pytester) -> None:
|
||||||
|
test_file = """
|
||||||
|
import pytest
|
||||||
|
@pytest.mark.parametrize('i', range({}))
|
||||||
|
def test(i):
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
pytester.makepyfile(test_a=test_file.format(10), test_b=test_file.format(20))
|
||||||
|
result = pytester.runpytest(
|
||||||
|
"-n2", "--dist=loadscope", "--no-loadscope-reorder", "-v"
|
||||||
|
)
|
||||||
|
assert get_workers_and_test_count_by_prefix(
|
||||||
|
"test_a.py::test", result.outlines
|
||||||
|
) == {"gw0": 10}
|
||||||
|
assert get_workers_and_test_count_by_prefix(
|
||||||
|
"test_b.py::test", result.outlines
|
||||||
|
) == {"gw1": 20}
|
||||||
|
|
||||||
def test_module_single_start(self, pytester: pytest.Pytester) -> None:
|
def test_module_single_start(self, pytester: pytest.Pytester) -> None:
|
||||||
"""Fix test suite never finishing in case all workers start with a single test (#277)."""
|
"""Fix test suite never finishing in case all workers start with a single test (#277)."""
|
||||||
test_file1 = """
|
test_file1 = """
|
||||||
|
|||||||
Reference in New Issue
Block a user