New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a Scheduling Protocol #1061
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
from xdist.scheduler import LoadGroupScheduling | ||
from xdist.scheduler import LoadScheduling | ||
from xdist.scheduler import LoadScopeScheduling | ||
from xdist.scheduler import Scheduling | ||
from xdist.scheduler import WorkStealingScheduling | ||
from xdist.workermanage import NodeManager | ||
|
||
|
@@ -97,17 +98,21 @@ def pytest_collection(self): | |
return 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") | ||
schedulers = { | ||
"each": EachScheduling, | ||
"load": LoadScheduling, | ||
"loadscope": LoadScopeScheduling, | ||
"loadfile": LoadFileScheduling, | ||
"loadgroup": LoadGroupScheduling, | ||
"worksteal": WorkStealingScheduling, | ||
} | ||
return schedulers[dist](config, log) | ||
if dist == "each": | ||
return EachScheduling(config, log) | ||
if dist == "load": | ||
return LoadScheduling(config, log) | ||
if dist == "loadscope": | ||
return LoadScopeScheduling(config, log) | ||
if dist == "loadfile": | ||
return LoadFileScheduling(config, log) | ||
if dist == "loadgroup": | ||
return LoadGroupScheduling(config, log) | ||
if dist == "worksteal": | ||
return WorkStealingScheduling(config, log) | ||
return None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a semantic change here -- if |
||
|
||
@pytest.hookimpl | ||
def pytest_runtestloop(self): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,6 +103,9 @@ def mark_test_complete(self, node, item_index, duration=0): | |
def mark_test_pending(self, item): | ||
raise NotImplementedError() | ||
|
||
def remove_pending_tests_from_node(self, node, indices): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some schedulers were missing this method that is used by |
||
raise NotImplementedError() | ||
|
||
def remove_node(self, node): | ||
# KeyError if we didn't get an add_node() yet | ||
pending = self.node2pending.pop(node) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Protocol | ||
from typing import Sequence | ||
|
||
from xdist.workermanage import WorkerController | ||
|
||
|
||
class Scheduling(Protocol): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor, up to you: I think a more appropriate name would be Up to you really. 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I don't know why the existing schedulers are called |
||
@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: ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not using the dict because I don't want to include the
__init__
in the protocol (if that's even possible...)