Skip to content

Commit a28d344

Browse files
committed
Capture stdout/stderr in server test and align completion timing
Update the language server test cell code to use stdout/stderr. Inserts a short 20ms delay before setting the completion event to ensure we capture the stdout/stderr, which are buffered and flushed every 10ms. Ideally, we could flush prior to the "idle" cell-op for each cell run, but that requires more complicated upstream change so this works for now. We will do the same thing in the extension front end.
1 parent 8d72a6c commit a28d344

File tree

2 files changed

+72
-7
lines changed

2 files changed

+72
-7
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,5 @@ ignore = [
5454
"SLF001",
5555
"PLC",
5656
"PLR",
57+
"FIX",
5758
]

tests/test_server.py

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,13 @@ def __():
298298
@pytest.mark.asyncio
299299
async def test_simple_marimo_run(client: LanguageClient) -> None:
300300
"""Test that we can collect marimo operations until cell reaches idle state."""
301+
code = """\
302+
import sys
303+
304+
print("hello, world")
305+
print("error message", file=sys.stderr)
306+
x = 42\
307+
"""
301308

302309
client.notebook_document_did_open(
303310
lsp.DidOpenNotebookDocumentParams(
@@ -317,7 +324,7 @@ async def test_simple_marimo_run(client: LanguageClient) -> None:
317324
uri="file:///exec_test.py#cell1",
318325
language_id="python",
319326
version=1,
320-
text="x = 42",
327+
text=code,
321328
)
322329
],
323330
),
@@ -327,11 +334,14 @@ async def test_simple_marimo_run(client: LanguageClient) -> None:
327334
completion_event = asyncio.Event()
328335

329336
@client.feature("marimo/operation")
330-
def on_marimo_operation(params: Any) -> None: # noqa: ANN401
337+
async def on_marimo_operation(params: Any) -> None: # noqa: ANN401
331338
# pygls dynamically makes an `Object` named tuple which makes snapshotting hard
332339
# we just convert to a regular dict here for snapshotting
333340
messages.append(to_dict(params))
334341
if params.op == "completed-run":
342+
# FIXME: stdin/stdout are flushed every 10ms, so wait 20ms to ensure
343+
# all related events. The frontend uses the same workaround.
344+
await asyncio.sleep(0.02)
335345
completion_event.set()
336346

337347
await client.workspace_execute_command_async(
@@ -341,7 +351,7 @@ def on_marimo_operation(params: Any) -> None: # noqa: ANN401
341351
{
342352
"notebook_uri": "file:///exec_test.py",
343353
"cell_ids": ["cell1"],
344-
"codes": ["x = 42"],
354+
"codes": [code],
345355
}
346356
],
347357
)
@@ -355,7 +365,15 @@ def on_marimo_operation(params: Any) -> None: # noqa: ANN401
355365
"op": "update-cell-codes",
356366
"data": {
357367
"cell_ids": ["cell1"],
358-
"codes": ["x = 42"],
368+
"codes": [
369+
"""\
370+
import sys
371+
372+
print("hello, world")
373+
print("error message", file=sys.stderr)
374+
x = 42\
375+
"""
376+
],
359377
"code_is_stale": False,
360378
},
361379
},
@@ -369,7 +387,8 @@ def on_marimo_operation(params: Any) -> None: # noqa: ANN401
369387
"op": "variables",
370388
"data": {
371389
"variables": [
372-
{"name": "x", "declared_by": ["cell1"], "used_by": []}
390+
{"name": "sys", "declared_by": ["cell1"], "used_by": []},
391+
{"name": "x", "declared_by": ["cell1"], "used_by": []},
373392
]
374393
},
375394
},
@@ -410,7 +429,10 @@ def on_marimo_operation(params: Any) -> None: # noqa: ANN401
410429
"notebookUri": "file:///exec_test.py",
411430
"op": "variable-values",
412431
"data": {
413-
"variables": [{"name": "x", "value": "42", "datatype": "int"}]
432+
"variables": [
433+
{"name": "sys", "value": "sys", "datatype": "module"},
434+
{"name": "x", "value": "42", "datatype": "int"},
435+
]
414436
},
415437
},
416438
{
@@ -446,6 +468,48 @@ def on_marimo_operation(params: Any) -> None: # noqa: ANN401
446468
"timestamp": IsFloat(),
447469
},
448470
},
449-
{"notebookUri": "file:///exec_test.py", "op": "completed-run", "data": {}},
471+
{
472+
"notebookUri": "file:///exec_test.py",
473+
"op": "completed-run",
474+
"data": {},
475+
},
476+
{
477+
"notebookUri": "file:///exec_test.py",
478+
"op": "cell-op",
479+
"data": {
480+
"cell_id": "cell1",
481+
"output": None,
482+
"console": {
483+
"channel": "stdout",
484+
"mimetype": "text/plain",
485+
"data": "hello, world\n",
486+
"timestamp": IsFloat(),
487+
},
488+
"status": None,
489+
"stale_inputs": None,
490+
"run_id": None,
491+
"serialization": None,
492+
"timestamp": IsFloat(),
493+
},
494+
},
495+
{
496+
"notebookUri": "file:///exec_test.py",
497+
"op": "cell-op",
498+
"data": {
499+
"cell_id": "cell1",
500+
"output": None,
501+
"console": {
502+
"channel": "stderr",
503+
"mimetype": "text/plain",
504+
"data": "error message\n",
505+
"timestamp": IsFloat(),
506+
},
507+
"status": None,
508+
"stale_inputs": None,
509+
"run_id": None,
510+
"serialization": None,
511+
"timestamp": IsFloat(),
512+
},
513+
},
450514
]
451515
)

0 commit comments

Comments
 (0)