Add a Scheduling Protocol
- Clearly delineate the required interface of schedulers - Useful for typing
This commit is contained in:
@@ -15,6 +15,7 @@ from xdist.scheduler import LoadFileScheduling
|
|||||||
from xdist.scheduler import LoadGroupScheduling
|
from xdist.scheduler import LoadGroupScheduling
|
||||||
from xdist.scheduler import LoadScheduling
|
from xdist.scheduler import LoadScheduling
|
||||||
from xdist.scheduler import LoadScopeScheduling
|
from xdist.scheduler import LoadScopeScheduling
|
||||||
|
from xdist.scheduler import Scheduling
|
||||||
from xdist.scheduler import WorkStealingScheduling
|
from xdist.scheduler import WorkStealingScheduling
|
||||||
from xdist.workermanage import NodeManager
|
from xdist.workermanage import NodeManager
|
||||||
|
|
||||||
@@ -97,17 +98,21 @@ class DSession:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@pytest.hookimpl(trylast=True)
|
@pytest.hookimpl(trylast=True)
|
||||||
def pytest_xdist_make_scheduler(self, config, log):
|
def pytest_xdist_make_scheduler(self, config, log) -> Scheduling | None:
|
||||||
dist = config.getvalue("dist")
|
dist = config.getvalue("dist")
|
||||||
schedulers = {
|
if dist == "each":
|
||||||
"each": EachScheduling,
|
return EachScheduling(config, log)
|
||||||
"load": LoadScheduling,
|
if dist == "load":
|
||||||
"loadscope": LoadScopeScheduling,
|
return LoadScheduling(config, log)
|
||||||
"loadfile": LoadFileScheduling,
|
if dist == "loadscope":
|
||||||
"loadgroup": LoadGroupScheduling,
|
return LoadScopeScheduling(config, log)
|
||||||
"worksteal": WorkStealingScheduling,
|
if dist == "loadfile":
|
||||||
}
|
return LoadFileScheduling(config, log)
|
||||||
return schedulers[dist](config, log)
|
if dist == "loadgroup":
|
||||||
|
return LoadGroupScheduling(config, log)
|
||||||
|
if dist == "worksteal":
|
||||||
|
return WorkStealingScheduling(config, log)
|
||||||
|
return None
|
||||||
|
|
||||||
@pytest.hookimpl
|
@pytest.hookimpl
|
||||||
def pytest_runtestloop(self):
|
def pytest_runtestloop(self):
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ from xdist.scheduler.load import LoadScheduling as LoadScheduling
|
|||||||
from xdist.scheduler.loadfile import LoadFileScheduling as LoadFileScheduling
|
from xdist.scheduler.loadfile import LoadFileScheduling as LoadFileScheduling
|
||||||
from xdist.scheduler.loadgroup import LoadGroupScheduling as LoadGroupScheduling
|
from xdist.scheduler.loadgroup import LoadGroupScheduling as LoadGroupScheduling
|
||||||
from xdist.scheduler.loadscope import LoadScopeScheduling as LoadScopeScheduling
|
from xdist.scheduler.loadscope import LoadScopeScheduling as LoadScopeScheduling
|
||||||
|
from xdist.scheduler.protocol import Scheduling as Scheduling
|
||||||
from xdist.scheduler.worksteal import WorkStealingScheduling as WorkStealingScheduling
|
from xdist.scheduler.worksteal import WorkStealingScheduling as WorkStealingScheduling
|
||||||
|
|||||||
@@ -103,6 +103,9 @@ class EachScheduling:
|
|||||||
def mark_test_pending(self, item):
|
def mark_test_pending(self, item):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def remove_pending_tests_from_node(self, node, indices):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
def remove_node(self, node):
|
def remove_node(self, node):
|
||||||
# KeyError if we didn't get an add_node() yet
|
# KeyError if we didn't get an add_node() yet
|
||||||
pending = self.node2pending.pop(node)
|
pending = self.node2pending.pop(node)
|
||||||
|
|||||||
@@ -160,6 +160,9 @@ class LoadScheduling:
|
|||||||
for node in self.node2pending:
|
for node in self.node2pending:
|
||||||
self.check_schedule(node)
|
self.check_schedule(node)
|
||||||
|
|
||||||
|
def remove_pending_tests_from_node(self, node, indices):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
def check_schedule(self, node, duration=0):
|
def check_schedule(self, node, duration=0):
|
||||||
"""Maybe schedule new items on the node.
|
"""Maybe schedule new items on the node.
|
||||||
|
|
||||||
|
|||||||
@@ -244,6 +244,9 @@ class LoadScopeScheduling:
|
|||||||
def mark_test_pending(self, item):
|
def mark_test_pending(self, item):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def remove_pending_tests_from_node(self, node, indices):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
def _assign_work_unit(self, node):
|
def _assign_work_unit(self, node):
|
||||||
"""Assign a work unit to a node."""
|
"""Assign a work unit to a node."""
|
||||||
assert self.workqueue
|
assert self.workqueue
|
||||||
|
|||||||
47
src/xdist/scheduler/protocol.py
Normal file
47
src/xdist/scheduler/protocol.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Protocol
|
||||||
|
from typing import Sequence
|
||||||
|
|
||||||
|
from xdist.workermanage import WorkerController
|
||||||
|
|
||||||
|
|
||||||
|
class Scheduling(Protocol):
|
||||||
|
@property
|
||||||
|
def nodes(self) -> list[WorkerController]: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def collection_is_completed(self) -> bool: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tests_finished(self) -> bool: ...
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_pending(self) -> bool: ...
|
||||||
|
|
||||||
|
def add_node(self, node: WorkerController) -> None: ...
|
||||||
|
|
||||||
|
def add_node_collection(
|
||||||
|
self,
|
||||||
|
node: WorkerController,
|
||||||
|
collection: Sequence[str],
|
||||||
|
) -> None: ...
|
||||||
|
|
||||||
|
def mark_test_complete(
|
||||||
|
self,
|
||||||
|
node: WorkerController,
|
||||||
|
item_index: int,
|
||||||
|
duration: float = 0,
|
||||||
|
) -> None: ...
|
||||||
|
|
||||||
|
def mark_test_pending(self, item: str) -> None: ...
|
||||||
|
|
||||||
|
def remove_pending_tests_from_node(
|
||||||
|
self,
|
||||||
|
node: WorkerController,
|
||||||
|
indices: Sequence[int],
|
||||||
|
) -> None: ...
|
||||||
|
|
||||||
|
def remove_node(self, node: WorkerController) -> str | None: ...
|
||||||
|
|
||||||
|
def schedule(self) -> None: ...
|
||||||
Reference in New Issue
Block a user