Compare commits

..

24 Commits

Author SHA1 Message Date
Shane Smiskol
2b4372bd62 gotcha
Some checks failed
test / package (push) Failing after 2m31s
test / test (ubuntu-latest, 3.10, py310-psutil) (push) Has been skipped
test / test (ubuntu-latest, 3.10, py310-pytestlatest) (push) Has been skipped
test / test (ubuntu-latest, 3.10, py310-setproctitle) (push) Has been skipped
test / test (ubuntu-latest, 3.11, py311-pytestlatest) (push) Has been skipped
test / test (ubuntu-latest, 3.11, py311-pytestmain) (push) Has been skipped
test / test (ubuntu-latest, 3.12, py312-pytestlatest) (push) Has been skipped
test / test (ubuntu-latest, 3.13, py313-pytestlatest) (push) Has been skipped
test / test (ubuntu-latest, 3.9, py39-pytestlatest) (push) Has been skipped
test / test (ubuntu-latest, 3.9, py39-pytestmin) (push) Has been skipped
test / test (windows-latest, 3.10, py310-psutil) (push) Has been skipped
test / test (windows-latest, 3.10, py310-pytestlatest) (push) Has been skipped
test / test (windows-latest, 3.10, py310-setproctitle) (push) Has been skipped
test / test (windows-latest, 3.11, py311-pytestlatest) (push) Has been skipped
test / test (windows-latest, 3.11, py311-pytestmain) (push) Has been skipped
test / test (windows-latest, 3.12, py312-pytestlatest) (push) Has been skipped
test / test (windows-latest, 3.13, py313-pytestlatest) (push) Has been skipped
test / test (windows-latest, 3.9, py39-pytestlatest) (push) Has been skipped
test / test (windows-latest, 3.9, py39-pytestmin) (push) Has been skipped
2025-07-25 19:39:12 -07:00
Shane Smiskol
1bb1a0f62a one line 2025-07-25 19:38:49 -07:00
Shane Smiskol
f8ea4a23b7 fix again 2025-07-25 19:37:34 -07:00
pre-commit-ci[bot]
68bf76dce4 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-07-26 02:35:24 +00:00
Shane Smiskol
28c0a72e3a fix test 2025-07-25 19:35:11 -07:00
pre-commit-ci[bot]
9d7dcae9d2 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-07-26 02:14:35 +00:00
Shane Smiskol
a3374b8d5c clean up 2025-07-25 19:14:22 -07:00
Shane Smiskol
5824f221ca clean up 2025-07-25 19:14:10 -07:00
pre-commit-ci[bot]
6ca0790e02 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-07-26 02:12:40 +00:00
Shane Smiskol
b59e010821 parallel 2025-07-25 18:50:32 -07:00
pre-commit-ci[bot]
239def9be9 Merge pull request #1227 from pytest-dev/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2025-07-14 19:34:51 -03:00
pre-commit-ci[bot]
ec87d0a139 [pre-commit.ci] pre-commit autoupdate (#1226)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.12.1 → v0.12.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.1...v0.12.2)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-07-08 08:43:31 +02:00
Bruno Oliveira
fe10f1c411 Merge pull request #1224 from pytest-dev/release-3.8.0
Release 3.8.0
2025-07-01 10:31:26 -03:00
pre-commit-ci[bot]
3572d0b13c [pre-commit.ci] pre-commit autoupdate (#1223)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.12.0 → v0.12.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.0...v0.12.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-06-30 18:33:44 -03:00
Bruno Oliveira
1e3e4dc165 Release 3.8.0 2025-06-30 11:05:48 -03:00
Shane Smiskol
600aad575a Ensure all xdist group names are strings (#1216) 2025-06-30 11:01:27 -03:00
darwintree
9d7ba5b5fb Add --no-loadscope-reorder and --loadscope-reorder options (#1217)
Based on #1098.

Closes #1098

---------

Co-authored-by: Toan Vuong <toan.vuong@hyperscience.com>
2025-06-30 10:59:40 -03:00
Bruno Oliveira
532f07fb18 Merge pull request #1210 from pytest-dev/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2025-06-24 08:24:11 -03:00
Bruno Oliveira
0883ad085e Fix Path usage in test_rsync_roots_no_roots 2025-06-24 08:21:48 -03:00
pre-commit-ci[bot]
58a51bc140 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.11.11 → v0.12.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.11.11...v0.12.0)
- [github.com/pre-commit/mirrors-mypy: v1.15.0 → v1.16.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.15.0...v1.16.1)
2025-06-23 20:16:47 +00:00
Bruno Oliveira
59a2ad0150 Merge pull request #1220 from pytest-dev/dependabot/github_actions/github-actions-33a29a28f8
build(deps): bump hynek/build-and-inspect-python-package from 2.12 to 2.13 in the github-actions group
2025-06-16 17:43:36 -03:00
dependabot[bot]
d42b9c7204 build(deps): bump hynek/build-and-inspect-python-package
Bumps the github-actions group with 1 update: [hynek/build-and-inspect-python-package](https://github.com/hynek/build-and-inspect-python-package).


Updates `hynek/build-and-inspect-python-package` from 2.12 to 2.13
- [Release notes](https://github.com/hynek/build-and-inspect-python-package/releases)
- [Changelog](https://github.com/hynek/build-and-inspect-python-package/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hynek/build-and-inspect-python-package/compare/v2.12...v2.13)

---
updated-dependencies:
- dependency-name: hynek/build-and-inspect-python-package
  dependency-version: '2.13'
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-16 19:13:50 +00:00
Bruno Oliveira
ebfcb99072 Merge pull request #1206 from pytest-dev/release-3.7.0
Release 3.7.0
2025-05-26 18:24:03 -03:00
pre-commit-ci[bot]
23b7fd6054 [pre-commit.ci] pre-commit autoupdate (#1207)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.11.10 → v0.11.11](https://github.com/astral-sh/ruff-pre-commit/compare/v0.11.10...v0.11.11)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-05-26 22:52:00 +02:00
10 changed files with 95 additions and 18 deletions

View File

@@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v4
- name: Build and Check Package
uses: hynek/build-and-inspect-python-package@v2.12
uses: hynek/build-and-inspect-python-package@v2.13
deploy:
needs: package

View File

@@ -22,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Build and Check Package
uses: hynek/build-and-inspect-python-package@v2.12
uses: hynek/build-and-inspect-python-package@v2.13
test:

View File

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.11.10"
rev: "v0.12.3"
hooks:
- id: ruff
args: ["--fix"]
@@ -23,7 +23,7 @@ repos:
language: python
additional_dependencies: [pygments, restructuredtext_lint]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.15.0
rev: v1.16.1
hooks:
- id: mypy
files: ^(src/|testing/)

View File

@@ -1,3 +1,15 @@
pytest-xdist 3.8.0 (2025-06-30)
===============================
Features
--------
- `#1083 <https://github.com/pytest-dev/pytest-xdist/issues/1083>`_: 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.
pytest-xdist 3.7.0 (2025-05-26)
===============================

View File

@@ -127,6 +127,32 @@ def pytest_addoption(parser: pytest.Parser) -> None:
"(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(
"--tx",
dest="tx",

View File

@@ -248,7 +248,7 @@ class WorkerInteractor:
if len(mark.args) > 0
else mark.kwargs.get("name", "default")
)
gnames.add(name)
gnames.add(str(name))
if not gnames:
continue
item._nodeid = f"{item.nodeid}@{'_'.join(sorted(gnames))}"

View File

@@ -371,11 +371,15 @@ class LoadScopeScheduling:
work_unit = unsorted_workqueue.setdefault(scope, {})
work_unit[nodeid] = False
if self.config.option.loadscopereorder:
# Insert tests scopes into work queue ordered by number of tests.
for scope, nodeids in sorted(
unsorted_workqueue.items(), key=lambda item: -len(item[1])
):
self.workqueue[scope] = nodeids
else:
for scope, nodeids in unsorted_workqueue.items():
self.workqueue[scope] = nodeids
# Avoid having more workers than work
extra_nodes = len(self.nodes) - len(self.workqueue)

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
from collections.abc import Sequence
from concurrent.futures import ThreadPoolExecutor
import enum
import fnmatch
import os
@@ -94,15 +95,23 @@ class NodeManager:
) -> list[WorkerController]:
self.config.hook.pytest_xdist_setupnodes(config=self.config, specs=self.specs)
self.trace("setting up nodes")
return [self.setup_node(spec, putevent) for spec in self.specs]
with ThreadPoolExecutor(max_workers=len(self.specs)) as executor:
futs = [
executor.submit(self.setup_node, spec, putevent, idx)
for idx, spec in enumerate(self.specs)
]
return [f.result() for f in futs]
def setup_node(
self,
spec: execnet.XSpec,
putevent: Callable[[tuple[str, dict[str, Any]]], None],
idx: int | None = None,
) -> WorkerController:
if getattr(spec, "execmodel", None) != "main_thread_only":
spec = execnet.XSpec(f"execmodel=main_thread_only//{spec}")
if idx is not None:
spec = execnet.XSpec(f"{spec}//id=gw{idx}")
gw = self.group.makegateway(spec)
self.config.hook.pytest_xdist_newgateway(gateway=gw)
self.rsync_roots(gw)

View File

@@ -1254,6 +1254,24 @@ class TestLoadScope:
"test_b.py::test", result.outlines
) == {"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:
"""Fix test suite never finishing in case all workers start with a single test (#277)."""
test_file1 = """

View File

@@ -82,11 +82,19 @@ class TestNodeManagerPopen:
call = hookrecorder.popcall("pytest_xdist_setupnodes")
assert len(call.specs) == 2
call = hookrecorder.popcall("pytest_xdist_newgateway")
assert call.gateway.spec == execnet.XSpec("execmodel=main_thread_only//popen")
assert call.gateway.id == "gw0"
call = hookrecorder.popcall("pytest_xdist_newgateway")
assert call.gateway.id == "gw1"
# check expected gateways
gw_calls = [
hookrecorder.popcall("pytest_xdist_newgateway"),
hookrecorder.popcall("pytest_xdist_newgateway"),
]
assert {c.gateway.id for c in gw_calls} == {"gw0", "gw1"}
for c in gw_calls:
expected_spec = execnet.XSpec(
f"execmodel=main_thread_only//popen//id={c.gateway.id}"
)
assert c.gateway.spec == expected_spec
assert len(hm.group) == 2
hm.teardown_nodes()
assert not len(hm.group)
@@ -206,8 +214,8 @@ class TestNodeManager:
p = Path(p)
print("remote curdir", p)
assert p == dest.joinpath(config.rootpath.name)
assert p.joinpath("dir1").check()
assert p.joinpath("dir1", "file1").check()
assert p.joinpath("dir1").is_dir()
assert p.joinpath("dir1", "file1").is_file()
def test_popen_rsync_subdir(
self,