From 3b8157883cd13bd1a91d27a3e7edbd9456ac373a Mon Sep 17 00:00:00 2001 From: "Maarten A. Breddels" Date: Mon, 27 Jan 2025 12:46:45 +0100 Subject: [PATCH] test: compatibility with reacton 2.0 See https://github.com/widgetti/reacton/pull/42 Solara is already compatible with it, but the tests were not. We might want to test this in CI, before releasing Solara 2.0 --- solara/tasks.py | 6 ++++++ tests/unit/task_test.py | 23 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/solara/tasks.py b/solara/tasks.py index 6f3165743..8960b03cb 100644 --- a/solara/tasks.py +++ b/solara/tasks.py @@ -104,6 +104,9 @@ def __init__(self, key: str): self._progress = ref(self._result.fields.progress) self._exception = ref(self._result.fields.exception) self._state_ = ref(self._result.fields._state) + # used for tests only + self._start_event = threading.Event() + self._start_event.set() @property def result(self) -> TaskResult[R]: @@ -253,6 +256,8 @@ def is_current(self): return (self.current_task == asyncio.current_task()) and not running_task.cancelled() async def _async_run(self, call_event_loop: asyncio.AbstractEventLoop, future: asyncio.Future, args, kwargs) -> None: + self._start_event.wait() + task_for_this_call = asyncio.current_task() assert task_for_this_call is not None @@ -351,6 +356,7 @@ def is_current(self): def _run(self, _last_finished_event, previous_thread: Optional[threading.Thread], cancel_event, args, kwargs) -> None: # use_thread has this as default, which can make code run 10x slower + self._start_event.wait() intrusive_cancel = False wait_on_previous = False self._local.cancel_event = cancel_event diff --git a/tests/unit/task_test.py b/tests/unit/task_test.py index b48f7e966..198e4cb19 100644 --- a/tests/unit/task_test.py +++ b/tests/unit/task_test.py @@ -86,7 +86,11 @@ def collect(): box, rc = solara.render(SquareButton(3, on_render=collect), handle_error=False) button = rc.find(v.Btn, children=["Run"]).widget + # a combination of .clear/.set is needed to force the rendering of all the states + # otherwise some states are not rendered + square._start_event.clear() # type: ignore button.click() + square._start_event.set() # type: ignore assert square._last_finished_event # type: ignore square._last_finished_event.wait() # type: ignore assert results == [ @@ -98,7 +102,9 @@ def collect(): results.clear() rc.render(SquareButton(2, on_render=collect)) button = rc.find(v.Btn, children=["Run"]).widget + square._start_event.clear() button.click() + square._start_event.set() square._last_finished_event.wait() # type: ignore assert results == [ # extra finished due to the rc.render call @@ -152,7 +158,9 @@ def collect(): box, rc = solara.render(SquareButtonAsync(3, on_render=collect), handle_error=False) button = rc.find(v.Btn, children=["Run"]).widget + square_async._start_event.clear() # type: ignore button.click() + square_async._start_event.set() # type: ignore assert square_async.current_future # type: ignore await square_async.current_future # type: ignore assert results == [ @@ -164,7 +172,9 @@ def collect(): results.clear() rc.render(SquareButtonAsync(2, on_render=collect)) button = rc.find(v.Btn, children=["Run"]).widget + square_async._start_event.clear() # type: ignore button.click() + square_async._start_event.set() # type: ignore await square_async.current_future # type: ignore assert results == [ # extra finished due to the rc.render call @@ -195,8 +205,9 @@ def Test(): box, rc = solara.render(Test(), handle_error=False) button = rc.find(v.Btn, children=["Run"])[0].widget + square._start_event.clear() # type: ignore button.click() - assert square._last_finished_event # type: ignore + square._start_event.set() # type: ignore square._last_finished_event.wait() # type: ignore assert ( results2 @@ -214,7 +225,9 @@ def Test(): results2.clear() results3.clear() button = rc.find(v.Btn, children=["Run"])[1].widget + square._start_event.clear() # type: ignore button.click() + square._start_event.set() # type: ignore assert square._last_finished_event # type: ignore square._last_finished_event.wait() # type: ignore assert ( @@ -244,7 +257,9 @@ def collect(): button = rc.find(v.Btn, children=["Run"]).widget cancel_square = True try: + square._start_event.clear() # type: ignore button.click() + square._start_event.set() # type: ignore assert square._last_finished_event # type: ignore square._last_finished_event.wait() # type: ignore assert results == [ @@ -284,7 +299,9 @@ def collect(): button = rc.find(v.Btn, children=["Run"]).widget cancel_square_async = True try: + square_async._start_event.clear() # type: ignore button.click() + square_async._start_event.set() # type: ignore assert square_async.current_future # type: ignore try: await square_async.current_future # type: ignore @@ -337,7 +354,9 @@ def collect2(): button2 = rc2.find(v.Btn, children=["Run"]).widget with context1: + something._start_event.clear() # type: ignore button1.click() + something._start_event.set() # type: ignore finished_event1 = something._last_finished_event # type: ignore assert finished_event1 @@ -356,7 +375,9 @@ def collect2(): assert results2 == [(TaskState.NOTCALLED, None)] with context2: + something._start_event.clear() # type: ignore button2.click() + something._start_event.set() # type: ignore finished_event2 = something._last_finished_event # type: ignore assert finished_event2 finished_event2.wait()