diff --git a/newsfragments/1587.deprecated.rst b/newsfragments/1587.deprecated.rst new file mode 100644 index 0000000000..03c0677c80 --- /dev/null +++ b/newsfragments/1587.deprecated.rst @@ -0,0 +1,4 @@ +The ``tiebreaker`` argument to `trio.testing.wait_all_tasks_blocked` +has been deprecated. This is a highly obscure feature that was +probably never used by anyone except `trio.testing.MockClock`, and +`~trio.testing.MockClock` doesn't need it anymore. diff --git a/trio/_core/_generated_run.py b/trio/_core/_generated_run.py index edf46fd741..49e2d6acd9 100644 --- a/trio/_core/_generated_run.py +++ b/trio/_core/_generated_run.py @@ -161,7 +161,7 @@ def current_trio_token(): raise RuntimeError("must be called from async context") -async def wait_all_tasks_blocked(cushion=0.0, tiebreaker=0): +async def wait_all_tasks_blocked(cushion=0.0, tiebreaker='deprecated'): """Block until there are no runnable tasks. This is useful in testing code when you want to give other tasks a @@ -179,9 +179,7 @@ async def wait_all_tasks_blocked(cushion=0.0, tiebreaker=0): then the one with the shortest ``cushion`` is the one woken (and this task becoming unblocked resets the timers for the remaining tasks). If there are multiple tasks that have exactly the same - ``cushion``, then the one with the lowest ``tiebreaker`` value is - woken first. And if there are multiple tasks with the same ``cushion`` - and the same ``tiebreaker``, then all are woken. + ``cushion``, then all are woken. You should also consider :class:`trio.testing.Sequencer`, which provides a more explicit way to control execution ordering within a diff --git a/trio/_core/_run.py b/trio/_core/_run.py index 8b112051e5..8e8b1e90b4 100644 --- a/trio/_core/_run.py +++ b/trio/_core/_run.py @@ -41,7 +41,7 @@ ) from ._thread_cache import start_thread_soon from .. import _core -from .._deprecate import deprecated +from .._deprecate import deprecated, warn_deprecated from .._util import Final, NoPublicConstructor, coroutine_or_error _NO_SEND = object() @@ -1563,7 +1563,7 @@ def _deliver_ki_cb(self): waiting_for_idle = attr.ib(factory=SortedDict) @_public - async def wait_all_tasks_blocked(self, cushion=0.0, tiebreaker=0): + async def wait_all_tasks_blocked(self, cushion=0.0, tiebreaker="deprecated"): """Block until there are no runnable tasks. This is useful in testing code when you want to give other tasks a @@ -1581,9 +1581,7 @@ async def wait_all_tasks_blocked(self, cushion=0.0, tiebreaker=0): then the one with the shortest ``cushion`` is the one woken (and this task becoming unblocked resets the timers for the remaining tasks). If there are multiple tasks that have exactly the same - ``cushion``, then the one with the lowest ``tiebreaker`` value is - woken first. And if there are multiple tasks with the same ``cushion`` - and the same ``tiebreaker``, then all are woken. + ``cushion``, then all are woken. You should also consider :class:`trio.testing.Sequencer`, which provides a more explicit way to control execution ordering within a @@ -1623,6 +1621,16 @@ async def test_lock_fairness(): print("FAIL") """ + if tiebreaker == "deprecated": + tiebreaker = 0 + else: + warn_deprecated( + "the 'tiebreaker' argument to wait_all_tasks_blocked", + "v0.16.0", + issue=1558, + instead=None, + ) + task = current_task() key = (cushion, tiebreaker, id(task)) self.waiting_for_idle[key] = task diff --git a/trio/_core/tests/test_mock_clock.py b/trio/_core/tests/test_mock_clock.py index aef4cef498..bea9509686 100644 --- a/trio/_core/tests/test_mock_clock.py +++ b/trio/_core/tests/test_mock_clock.py @@ -84,15 +84,6 @@ async def test_mock_clock_autojump(mock_clock): await wait_all_tasks_blocked(0.01) assert t == _core.current_time() - # This should wake up at the same time as the autojump_threshold, and - # confuse things. There is no deadline, so it shouldn't actually jump - # the clock. But does it handle the situation gracefully? - await wait_all_tasks_blocked(cushion=0.02, tiebreaker=float("inf")) - # And again with threshold=0, because that has some special - # busy-wait-avoidance logic: - mock_clock.autojump_threshold = 0 - await wait_all_tasks_blocked(tiebreaker=float("inf")) - # set up a situation where the autojump task is blocked for a long long # time, to make sure that cancel-and-adjust-threshold logic is working mock_clock.autojump_threshold = 10000 @@ -132,8 +123,7 @@ def test_mock_clock_autojump_preset(): async def test_mock_clock_autojump_0_and_wait_all_tasks_blocked_0(mock_clock): # Checks that autojump_threshold=0 doesn't interfere with - # calling wait_all_tasks_blocked with the default cushion=0 and arbitrary - # tiebreakers. + # calling wait_all_tasks_blocked with the default cushion=0. mock_clock.autojump_threshold = 0 @@ -144,9 +134,8 @@ async def sleeper(): record.append("yawn") async def waiter(): - for i in range(10): - await wait_all_tasks_blocked(tiebreaker=i) - record.append(i) + await wait_all_tasks_blocked() + record.append("waiter woke") await sleep(1000) record.append("waiter done") @@ -154,7 +143,7 @@ async def waiter(): nursery.start_soon(sleeper) nursery.start_soon(waiter) - assert record == list(range(10)) + ["yawn", "waiter done"] + assert record == ["waiter woke", "yawn", "waiter done"] @slow diff --git a/trio/tests/test_testing.py b/trio/tests/test_testing.py index 304f18cb88..706d0a5a13 100644 --- a/trio/tests/test_testing.py +++ b/trio/tests/test_testing.py @@ -103,7 +103,8 @@ async def wait_big_cushion(): ] -async def test_wait_all_tasks_blocked_with_tiebreaker(): +# This test can be deleted after tiebreaker= is removed +async def test_wait_all_tasks_blocked_with_tiebreaker(recwarn): record = [] async def do_wait(cushion, tiebreaker):