Skip to content

Commit c82840f

Browse files
ciaconetpre-commit-ci[bot]dependabot[bot]nicoddemus
authored
Merge pytest-xdist latest changes + correct lint errors in nTop fork (#6)
* [pre-commit.ci] pre-commit autoupdate (pytest-dev#1120) updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.1 → v0.6.2](astral-sh/ruff-pre-commit@v0.6.1...v0.6.2) - [github.com/pre-commit/mirrors-mypy: v1.11.1 → v1.11.2](pre-commit/mirrors-mypy@v1.11.1...v1.11.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * build(deps): bump pypa/gh-action-pypi-publish (pytest-dev#1123) Bumps the github-actions group with 1 update: [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish). Updates `pypa/gh-action-pypi-publish` from 1.9.0 to 1.10.0 - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](pypa/gh-action-pypi-publish@v1.9.0...v1.10.0) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * [pre-commit.ci] pre-commit autoupdate (pytest-dev#1124) updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.2 → v0.6.3](astral-sh/ruff-pre-commit@v0.6.2...v0.6.3) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * Publish package with attestations (pytest-dev#1125) Follow up to pytest-dev#1123. * build(deps): bump the github-actions group with 2 updates (pytest-dev#1127) Bumps the github-actions group with 2 updates: [hynek/build-and-inspect-python-package](https://github.com/hynek/build-and-inspect-python-package) and [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish). Updates `hynek/build-and-inspect-python-package` from 2.8 to 2.9 - [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](hynek/build-and-inspect-python-package@v2.8...v2.9) Updates `pypa/gh-action-pypi-publish` from 1.10.0 to 1.10.1 - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](pypa/gh-action-pypi-publish@v1.10.0...v1.10.1) --- updated-dependencies: - dependency-name: hynek/build-and-inspect-python-package dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * [pre-commit.ci] pre-commit autoupdate (pytest-dev#1128) updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.3 → v0.6.4](astral-sh/ruff-pre-commit@v0.6.3...v0.6.4) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * [pre-commit.ci] pre-commit autoupdate (pytest-dev#1129) updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.4 → v0.6.5](astral-sh/ruff-pre-commit@v0.6.4...v0.6.5) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * all ruff checks should pass * mypy fixes * undo protocol/other scheduler changes, add asserts for mypy check * undo newline add/remove changes in diff for other schedulers * remove unused function from dsession.py --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Bruno Oliveira <[email protected]>
1 parent f73e306 commit c82840f

File tree

8 files changed

+60
-41
lines changed

8 files changed

+60
-41
lines changed

.github/workflows/deploy.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- uses: actions/checkout@v4
2020

2121
- name: Build and Check Package
22-
uses: hynek/build-and-inspect-python-package@v2.8
22+
uses: hynek/build-and-inspect-python-package@v2.9
2323

2424
deploy:
2525
needs: package
@@ -39,7 +39,9 @@ jobs:
3939
path: dist
4040

4141
- name: Publish package to PyPI
42-
uses: pypa/[email protected]
42+
uses: pypa/[email protected]
43+
with:
44+
attestations: true
4345

4446
- name: Push tag
4547
run: |

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
steps:
2323
- uses: actions/checkout@v4
2424
- name: Build and Check Package
25-
uses: hynek/build-and-inspect-python-package@v2.8
25+
uses: hynek/build-and-inspect-python-package@v2.9
2626

2727
test:
2828

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
3-
rev: "v0.6.1"
3+
rev: "v0.6.5"
44
hooks:
55
- id: ruff
66
args: ["--fix"]
@@ -23,7 +23,7 @@ repos:
2323
language: python
2424
additional_dependencies: [pygments, restructuredtext_lint]
2525
- repo: https://github.com/pre-commit/mirrors-mypy
26-
rev: v1.11.1
26+
rev: v1.11.2
2727
hooks:
2828
- id: mypy
2929
files: ^(src/|testing/)

src/xdist/dsession.py

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,25 @@
55
from queue import Empty
66
from queue import Queue
77
import sys
8+
import traceback
89
from typing import Any
10+
from typing import Callable
911
from typing import Sequence
1012
import warnings
11-
import traceback
1213

1314
import execnet
1415
import pytest
1516

1617
from xdist.remote import Producer
1718
from xdist.remote import WorkerInfo
19+
from xdist.scheduler import CustomGroup
1820
from xdist.scheduler import EachScheduling
1921
from xdist.scheduler import LoadFileScheduling
2022
from xdist.scheduler import LoadGroupScheduling
2123
from xdist.scheduler import LoadScheduling
2224
from xdist.scheduler import LoadScopeScheduling
2325
from xdist.scheduler import Scheduling
2426
from xdist.scheduler import WorkStealingScheduling
25-
from xdist.scheduler import CustomGroup
2627
from xdist.workermanage import NodeManager
2728
from xdist.workermanage import WorkerController
2829

@@ -60,14 +61,14 @@ def __init__(self, config: pytest.Config) -> None:
6061
self._failed_collection_errors: dict[object, bool] = {}
6162
self._active_nodes: set[WorkerController] = set()
6263
self._failed_nodes_count = 0
63-
self.saved_put = None
64+
self.saved_put: Callable[[tuple[str, dict[str, Any]]], None]
6465
self.remake_nodes = False
6566
self.ready_to_run_tests = False
6667
self._max_worker_restart = get_default_max_worker_restart(self.config)
6768
# summary message to print at the end of the session
6869
self._summary_report: str | None = None
6970
self.terminal = config.pluginmanager.getplugin("terminalreporter")
70-
self.worker_status: dict[WorkerController, str] = {}
71+
self.worker_status: dict[str, str] = {}
7172
if self.terminal:
7273
self.trdist = TerminalDistReporter(config)
7374
config.pluginmanager.register(self.trdist, "terminaldistreporter")
@@ -180,68 +181,75 @@ def loop_once(self) -> None:
180181
self.triggershutdown()
181182

182183

183-
def is_node_finishing(self, node: WorkerController):
184+
def is_node_finishing(self, node: WorkerController) -> bool:
184185
"""Check if a test worker is considered to be finishing.
185186
186187
Evaluate whether it's on its last test, or if no tests are pending.
187188
"""
189+
assert self.sched is not None
190+
assert type(self.sched) is CustomGroup
188191
pending = self.sched.node2pending.get(node)
189192
return pending is not None and len(pending) < 2
190193

191194

192-
def is_node_clear(self, node: WorkerController):
193-
"""Check if a test worker has no pending tests."""
194-
pending = self.sched.node2pending.get(node)
195-
return pending is None or len(pending) == 0
196-
197-
198-
def are_all_nodes_finishing(self):
195+
def are_all_nodes_finishing(self) -> bool:
199196
"""Check if all workers are finishing (See 'is_node_finishing' above)."""
197+
assert self.sched is not None
200198
return all(self.is_node_finishing(node) for node in self.sched.nodes)
201199

202200

203-
def are_all_nodes_done(self):
201+
def are_all_nodes_done(self) -> bool:
204202
"""Check if all nodes have reported to finish."""
205203
return all(s == "finished" for s in self.worker_status.values())
206204

207205

208-
def are_all_active_nodes_collected(self):
206+
def are_all_active_nodes_collected(self) -> bool:
209207
"""Check if all nodes have reported collection to be complete."""
210208
if not all(n.gateway.id in self.worker_status for n in self._active_nodes):
211209
return False
212210
return all(self.worker_status[n.gateway.id] == "collected" for n in self._active_nodes)
213211

214212

215-
def reset_nodes_if_needed(self):
213+
def reset_nodes_if_needed(self) -> None:
214+
assert self.sched is not None
215+
assert type(self.sched) is CustomGroup
216216
if self.are_all_nodes_finishing() and self.ready_to_run_tests and not self.sched.do_resched:
217217
self.reset_nodes()
218218

219219

220-
def reset_nodes(self):
220+
def reset_nodes(self) -> None:
221221
"""Issue shutdown notices to workers for rescheduling purposes."""
222+
assert self.sched is not None
223+
assert type(self.sched) is CustomGroup
222224
if len(self.sched.pending) != 0:
223225
self.remake_nodes = True
224226
for node in self.sched.nodes:
225227
if self.is_node_finishing(node):
226228
node.shutdown()
227229

228230

229-
def reschedule(self):
231+
def reschedule(self) -> None:
230232
"""Reschedule tests."""
233+
assert self.sched is not None
234+
assert type(self.sched) is CustomGroup
231235
self.sched.do_resched = False
232236
self.sched.check_schedule(self.sched.nodes[0], 1.0, True)
233237

234238

235-
def prepare_for_reschedule(self):
239+
def prepare_for_reschedule(self) -> None:
236240
"""Update test workers and their status tracking so rescheduling is ready."""
241+
assert type(self.sched) is CustomGroup
242+
assert self.sched is not None
237243
self.remake_nodes = False
238244
num_workers = self.sched.dist_groups[self.sched.pending_groups[0]]['group_workers']
239245
self.trdist._status = {}
246+
assert self.nodemanager is not None
240247
new_nodes = self.nodemanager.setup_nodes(self.saved_put, num_workers)
241248
self.worker_status = {}
242249
self._active_nodes = set()
243250
self._active_nodes.update(new_nodes)
244251
self.sched.node2pending = {}
252+
assert type(self.sched) is CustomGroup
245253
self.sched.do_resched = True
246254

247255
#
@@ -287,7 +295,9 @@ def worker_workerfinished(self, node: WorkerController) -> None:
287295
try:
288296
self.prepare_for_reschedule()
289297
except Exception as e:
290-
self.shouldstop = f"Exception caught during preparation for rescheduling. Giving up.\n{''.join(traceback.format_exception(e))}"
298+
msg = ("Exception caught during preparation for rescheduling. Giving up."
299+
f"\n{''.join(traceback.format_exception(e))}")
300+
self.shouldstop = msg
291301
return
292302
self.config.hook.pytest_testnodedown(node=node, error=None)
293303
if node.workeroutput["exitstatus"] == 2: # keyboard-interrupt
@@ -308,10 +318,11 @@ def worker_workerfinished(self, node: WorkerController) -> None:
308318
assert not crashitem, (crashitem, node)
309319
self._active_nodes.remove(node)
310320

311-
def update_worker_status(self, node, status):
321+
def update_worker_status(self, node: WorkerController, status: str) -> None:
312322
"""Track the worker status.
313323
314-
Can be used at callbacks like 'worker_workerfinished' so we remember wchic event was reported last by each worker.
324+
Can be used at callbacks like 'worker_workerfinished' so we remember wchic event
325+
was reported last by each worker.
315326
"""
316327
self.worker_status[node.workerinfo["id"]] = status
317328

src/xdist/scheduler/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
from xdist.scheduler.customgroup import CustomGroup as CustomGroup
12
from xdist.scheduler.each import EachScheduling as EachScheduling
23
from xdist.scheduler.load import LoadScheduling as LoadScheduling
3-
from xdist.scheduler.customgroup import CustomGroup as CustomGroup
44
from xdist.scheduler.loadfile import LoadFileScheduling as LoadFileScheduling
55
from xdist.scheduler.loadgroup import LoadGroupScheduling as LoadGroupScheduling
66
from xdist.scheduler.loadscope import LoadScopeScheduling as LoadScopeScheduling

src/xdist/scheduler/customgroup.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

33
from itertools import cycle
4-
from typing import Sequence, Any
4+
from typing import Any
5+
from typing import Sequence
56

67
import pytest
78

@@ -10,6 +11,7 @@
1011
from xdist.workermanage import parse_spec_config
1112
from xdist.workermanage import WorkerController
1213

14+
1315
class CustomGroup:
1416
"""Implement grouped load scheduling across a variable number of nodes.
1517
@@ -203,7 +205,7 @@ def remove_pending_tests_from_node(
203205
) -> None:
204206
raise NotImplementedError()
205207

206-
def check_schedule(self, node: WorkerController, duration: float = 0, from_dsession=False) -> None:
208+
def check_schedule(self, node: WorkerController, duration: float = 0, from_dsession: bool = False) -> None:
207209
"""Maybe schedule new items on the node.
208210
209211
If there are any globally pending nodes left then this will
@@ -226,7 +228,7 @@ def check_schedule(self, node: WorkerController, duration: float = 0, from_dsess
226228
dist_group_key = self.pending_groups.pop(0)
227229
dist_group = self.dist_groups[dist_group_key]
228230
nodes = cycle(self.nodes[0:dist_group['group_workers']])
229-
schedule_log = {n.gateway.id:[] for n in self.nodes[0:dist_group['group_workers']]}
231+
schedule_log: dict[str, Any] = {n.gateway.id:[] for n in self.nodes[0:dist_group['group_workers']]}
230232
for _ in range(len(dist_group['test_indices'])):
231233
n = next(nodes)
232234
#needs cleaner way to be identified
@@ -235,13 +237,16 @@ def check_schedule(self, node: WorkerController, duration: float = 0, from_dsess
235237

236238
self._send_tests_group(n, 1, dist_group_key)
237239
del self.dist_groups[dist_group_key]
238-
message = f"\n[-] [csg] check_schedule: processed scheduling for {dist_group_key}: {' '.join([f'{nid} ({len(nt)})' for nid,nt in schedule_log.items()])}"
240+
message = (f"\n[-] [csg] check_schedule: processed scheduling for {dist_group_key}:"
241+
f" {' '.join([f'{nid} ({len(nt)})' for nid,nt in schedule_log.items()])}")
239242
self.report_line(message)
240243

241244
else:
242-
pending = self.node2pending.get(node)
245+
pending = self.node2pending.get(node, [])
243246
if len(pending) < 2:
244-
self.report_line(f"[-] [csg] Shutting down {node.workerinput['workerid']} because only one case is pending")
247+
self.report_line(
248+
f"[-] [csg] Shutting down {node.workerinput['workerid']} because only one case is pending"
249+
)
245250
node.shutdown()
246251

247252
self.log("num items waiting for node:", len(self.pending))
@@ -301,7 +306,7 @@ def schedule(self) -> None:
301306
if not self.collection:
302307
return
303308

304-
dist_groups = {}
309+
dist_groups: dict[str, dict[Any, Any]] = {}
305310

306311
if self.is_first_time:
307312
for i, test in enumerate(self.collection):
@@ -338,15 +343,16 @@ def schedule(self) -> None:
338343
dist_group_key = self.pending_groups.pop(0)
339344
dist_group = self.dist_groups[dist_group_key]
340345
nodes = cycle(self.nodes[0:dist_group['group_workers']])
341-
schedule_log = {n.gateway.id: [] for n in self.nodes[0:dist_group['group_workers']]}
346+
schedule_log: dict[str, Any] = {n.gateway.id: [] for n in self.nodes[0:dist_group['group_workers']]}
342347
for _ in range(len(dist_group['test_indices'])):
343348
n = next(nodes)
344349
# needs cleaner way to be identified
345350
tests_per_node = self.dist_groups[dist_group_key]['pending_indices'][:1]
346351
schedule_log[n.gateway.id].extend(tests_per_node)
347352
self._send_tests_group(n, 1, dist_group_key)
348353
del self.dist_groups[dist_group_key]
349-
message = f"\n[-] [csg] schedule: processed scheduling for {dist_group_key}: {' '.join([f'{nid} ({len(nt)})' for nid, nt in schedule_log.items()])}"
354+
message = ("\n[-] [csg] schedule: processed scheduling for "
355+
f"{dist_group_key}: {' '.join([f'{nid} ({len(nt)})' for nid, nt in schedule_log.items()])}")
350356
self.report_line(message)
351357

352358
def _send_tests(self, node: WorkerController, num: int) -> None:
@@ -356,7 +362,7 @@ def _send_tests(self, node: WorkerController, num: int) -> None:
356362
self.node2pending[node].extend(tests_per_node)
357363
node.send_runtest_some(tests_per_node)
358364

359-
def _send_tests_group(self, node: WorkerController, num: int, dist_group_key) -> None:
365+
def _send_tests_group(self, node: WorkerController, num: int, dist_group_key: str) -> None:
360366
tests_per_node = self.dist_groups[dist_group_key]['pending_indices'][:num]
361367
if tests_per_node:
362368
del self.dist_groups[dist_group_key]['pending_indices'][:num]
@@ -396,4 +402,4 @@ def _check_nodes_have_same_collection(self) -> bool:
396402

397403
def report_line(self, line: str) -> None:
398404
if self.terminal and self.config.option.verbose >= 0:
399-
self.terminal.write_line(line)
405+
self.terminal.write_line(line)

src/xdist/workermanage.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from typing import Literal
1212
from typing import Sequence
1313
from typing import Union
14-
from typing import Optional
1514
import uuid
1615
import warnings
1716

@@ -83,7 +82,7 @@ def rsync_roots(self, gateway: execnet.Gateway) -> None:
8382
def setup_nodes(
8483
self,
8584
putevent: Callable[[tuple[str, dict[str, Any]]], None],
86-
max_nodes: Optional[int] = None
85+
max_nodes: int | None = None
8786
) -> list[WorkerController]:
8887
self.config.hook.pytest_xdist_setupnodes(config=self.config, specs=self.specs)
8988
self.trace("setting up nodes")

xdist-testing-ntop/test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import pytest
21
import time
32

3+
import pytest
4+
45

56
@pytest.mark.xdist_custom(name="low_4")
67
def test_1():

0 commit comments

Comments
 (0)