fix(notebooks): drop cascade errors from snapshot parsing
All checks were successful
CI / lint (push) Successful in 31s
CI / notebooks-smoke (push) Successful in 1m28s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / mc (push) Has been skipped
Deploy / report (push) Successful in 13s
CI / test (push) Successful in 13m32s
All checks were successful
CI / lint (push) Successful in 31s
CI / notebooks-smoke (push) Successful in 1m28s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / mc (push) Has been skipped
Deploy / report (push) Successful in 13s
CI / test (push) Successful in 13m32s
marimo marks every descendant of a failed or stopped cell with its own
error output ('An ancestor raised an exception', 'ancestor-stopped').
The root cause is always present as a non-ancestor error in the same
snapshot, so cascades only inflate the report — and each one filed its
own deduplicated issue (6 of the 12 nb issues from the first nightly
run were cascade noise). Also makes intentional mo.stop() flow control
count as a pass instead of a failure.
This commit is contained in:
@@ -82,6 +82,14 @@ def parse_snapshot(path: Path) -> list[dict]:
|
||||
for out in cell.get("outputs", []):
|
||||
if out.get("type") != "error":
|
||||
continue
|
||||
# Cascade noise: marimo marks every descendant of a failed or
|
||||
# stopped cell with its own error output. The root cause is
|
||||
# always present as a non-ancestor error in the same snapshot,
|
||||
# so these only inflate the report (and the issue tracker).
|
||||
if out.get("ename") == "ancestor-stopped" or out.get(
|
||||
"evalue", ""
|
||||
).startswith("An ancestor raised an exception"):
|
||||
continue
|
||||
detail = ""
|
||||
for con in cell.get("console", []):
|
||||
if con.get("name") == "stderr":
|
||||
|
||||
@@ -86,6 +86,45 @@ def test_parse_snapshot_extracts_errors_with_console_detail(tmp_path):
|
||||
assert "intentional failure" in e["detail"]
|
||||
|
||||
|
||||
def test_parse_snapshot_drops_cascade_errors(tmp_path):
|
||||
"""Descendants of a failed/stopped cell get their own error outputs;
|
||||
only the root-cause error should survive parsing."""
|
||||
snap = {
|
||||
"version": "1",
|
||||
"metadata": {"marimo_version": "0.23.13"},
|
||||
"cells": [
|
||||
SNAPSHOT_ERR["cells"][1],
|
||||
{
|
||||
"id": "ecfG",
|
||||
"outputs": [
|
||||
{
|
||||
"type": "error",
|
||||
"ename": "exception",
|
||||
"evalue": "An ancestor raised an exception (ValueError): ",
|
||||
"traceback": None,
|
||||
}
|
||||
],
|
||||
"console": [],
|
||||
},
|
||||
{
|
||||
"id": "xXTn",
|
||||
"outputs": [
|
||||
{
|
||||
"type": "error",
|
||||
"ename": "ancestor-stopped",
|
||||
"evalue": "This cell wasn't run because an ancestor "
|
||||
"was stopped with `mo.stop`: ",
|
||||
"traceback": None,
|
||||
}
|
||||
],
|
||||
"console": [],
|
||||
},
|
||||
],
|
||||
}
|
||||
errors = nbi.parse_snapshot(_write(tmp_path, "cascade.py.json", snap))
|
||||
assert [e["cell"] for e in errors] == ["MJUe"]
|
||||
|
||||
|
||||
def test_parse_snapshot_missing_file_reports_export_error(tmp_path):
|
||||
errors = nbi.parse_snapshot(tmp_path / "never-written.py.json")
|
||||
assert len(errors) == 1
|
||||
|
||||
Reference in New Issue
Block a user