Skip to content

Commit

Permalink
refactor: do not run all runners in ipywidgets_runner fixture
Browse files Browse the repository at this point in the history
Each time the ipywidgets_runner fixture was used, all fixtures
are used. This means the ipywidgets_runner_solara runner was
also used, causing the solara_test fixture to always run
and also close the app each time, which close all the contexts.

This is bad for performance of the tests, but it is possibly also
the cause for some flakeyness in our tests.
  • Loading branch information
maartenbreddels committed Sep 29, 2023
1 parent 6abc803 commit 5227429
Showing 1 changed file with 41 additions and 61 deletions.
102 changes: 41 additions & 61 deletions solara/test/pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,11 @@ def page_session(context_session: "playwright.sync_api.BrowserContext"):

@pytest.fixture()
def solara_app(solara_server):
used_app = None

@contextlib.contextmanager
def run(app: Union[solara.server.app.AppScript, str]):
nonlocal used_app
if "__default__" in solara.server.app.apps:
solara.server.app.apps["__default__"].close()
if isinstance(app, str):
Expand All @@ -146,9 +149,9 @@ def run(app: Union[solara.server.app.AppScript, str]):
if app.name in reload.reloader.watched_modules:
reload.reloader.watched_modules.remove(app.name)

app.close()

return run
yield run
if used_app:
used_app.close()


run_event = threading.Event()
Expand All @@ -165,37 +168,23 @@ def SyncWrapper():
return w.VBox(children=[w.HTML(value="Test in solara"), w.VBox()])


@pytest.fixture()
def solara_test(solara_server, solara_app, page_session: "playwright.sync_api.Page"):
checks = 0


@contextlib.contextmanager
def _solara_test(solara_server, solara_app, page_session: "playwright.sync_api.Page"):
global checks
checks += 1
global run_calls
with solara_app("solara.test.pytest_plugin:SyncWrapper"):
# a currently open page will try to connect to solara, creating a
# new context, so we navigate away first, then close all contexts
page_session.goto("about:blank")
for key in list(solara.server.app.contexts):
try:
solara.server.app.contexts[key].close()
except: # noqa
pass
assert len(solara.server.app.contexts) == 0
page_session.goto(solara_server.base_url)
try:
run_event.wait()
# for some reason, we still get 2 context sometimes, it could be the reconnection
# code of the websocket of the previous page still running. We wait a bit
# till we end up with only one context
n = 0
# we wait till the all contexts are closed
while len(solara.server.app.contexts) != 1:
page_session.wait_for_timeout(100)
n += 1
if n > 50:
raise RuntimeError("Timeout waiting for a single context, contexts found: %r", list(solara.server.app.contexts))

assert run_calls == 1
keys = list(solara.server.app.contexts)
assert len(keys) == 1, "expected only one context, got %s" % keys
context = solara.server.app.contexts[keys[0]]
context = solara.server.app.contexts[keys[-1]]
with context:
test_output_warmup = widgets.Output()
test_output = widgets.Output()
Expand All @@ -218,6 +207,12 @@ def solara_test(solara_server, solara_app, page_session: "playwright.sync_api.Pa
run_event.clear()


@pytest.fixture()
def solara_test(solara_server, solara_app, page_session: "playwright.sync_api.Page"):
with _solara_test(solara_server, solara_app, page_session):
yield


class ServerVoila(ServerBase):
popen = None

Expand Down Expand Up @@ -455,7 +450,8 @@ def run(f: Callable):
return run


def create_runner_solara(solara_test, solara_server, page_session: "playwright.sync_api.Page"):
@contextlib.contextmanager
def create_runner_solara(solara_server, solara_app, page_session: "playwright.sync_api.Page"):
count = 0

def run(f: Callable):
Expand All @@ -474,51 +470,35 @@ def run(f: Callable):
sys.path.remove(cwd)
count += 1

return run


@pytest.fixture(scope="session")
def ipywidgets_runner_voila(voila_server, notebook_path, page_session: "playwright.sync_api.Page"):
if "voila" not in runners:
return None
return create_runner_voila(voila_server, notebook_path, page_session)


@pytest.fixture(scope="session")
def ipywidgets_runner_jupyter_lab(jupyter_server, notebook_path, page_session: "playwright.sync_api.Page"):
if "jupyter_lab" not in runners:
return None
return create_runner_jupyter_lab(jupyter_server, notebook_path, page_session)


@pytest.fixture(scope="session")
def ipywidgets_runner_jupyter_notebook(jupyter_server, notebook_path, page_session: "playwright.sync_api.Page"):
if "jupyter_notebook" not in runners:
return None
return create_runner_jupyter_notebook(jupyter_server, notebook_path, page_session)


@pytest.fixture()
def ipywidgets_runner_solara(solara_test, solara_server, page_session: "playwright.sync_api.Page"):
if "solara" not in runners:
return None
return create_runner_solara(solara_test, solara_server, page_session)
with _solara_test(solara_server, solara_app, page_session):
yield run


runners = os.environ.get("SOLARA_TEST_RUNNERS", "solara,voila,jupyter_lab,jupyter_notebook").split(",")


@pytest.fixture(params=runners)
def ipywidgets_runner(
ipywidgets_runner_jupyter_notebook,
ipywidgets_runner_jupyter_lab,
ipywidgets_runner_voila,
ipywidgets_runner_solara,
solara_server,
solara_app,
voila_server,
jupyter_server,
notebook_path,
page_session: "playwright.sync_api.Page",
request,
):
runner = request.param
name = f"ipywidgets_runner_{runner}"
return locals()[name]
if runner == "solara":
with create_runner_solara(solara_server, solara_app, page_session) as runner:
yield runner
elif runner == "voila":
yield create_runner_voila(voila_server, notebook_path, page_session)
elif runner == "jupyter_lab":
yield create_runner_jupyter_lab(jupyter_server, notebook_path, page_session)
elif runner == "jupyter_notebook":
yield create_runner_jupyter_notebook(jupyter_server, notebook_path, page_session)
else:
raise RuntimeError(f"Unknown runner {runner}")


@pytest.fixture(scope="session")
Expand Down

0 comments on commit 5227429

Please sign in to comment.