agentsclimarketplace

Marimo notebook tests

Skill 0x0f0f0f/research-engineering-skills/skills/marimo-notebook-tests

Set up a Python project so files are simultaneously marimo interactive notebooks and pytest test modules — assertions are the source of truth, cells render the results. Use when the user wants notebooks that double as tests, asks to wire up marimo with pytest, or wants executable documentation/tutorials that stay green in CI.From its SKILL.md

Install
npx -y skills add 0x0f0f0f/research-engineering-skills --skill marimo-notebook-tests

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.1 KB, as published. Nobody here has run it

marimo-notebook-tests

Set up a Python project so that notebooks/*.py are simultaneously marimo interactive notebooks and pytest test modules.

Assumes marimo is installed as a dev dependency alongside pytest.

Follow marimo's notebook authoring guidelines

This skill owns the notebook-as-test wiring — the test_* / @app.cell split below. It does not redefine how marimo cells are written. That is owned by marimo's official marimo-notebook skill. Load that skill by name and always follow it when writing the cell bodies — it installs alongside this one (bundled in the research-engineering-skills plugin; fetched as a sibling skill by npx skills). Canonical upstream: marimo-team/skills. Do not run npx skills add marimo-team/skills to reinstall it — it already ships alongside this skill.

Apply its rules verbatim. The load-bearing ones, repeated here so they are never skipped:

  • PEP 723 script metadata at the top of every notebook file (# /// script … # dependencies = ["marimo", …] … # ///).
  • Variables between cells define the reactivity — let marimo order cells from their parameters; don't wrap cell bodies in needless if/try.
  • Never mutate an object across cells — create a new object instead, so the dependency graph stays correct.
  • Always create UI elements; only vary the data source by mode via mo.app_meta().mode == "script" (synthetic/default data in script mode, widget values interactively). Don't conditionally hide widgets.
  • Render equations with mo.md(r"""$...$""") so the notebook mirrors the paper's notation.
  • Don't over-prefix variables with underscores — reserve _ for a cell-local throwaway or two, not as a habit.
  • Run marimo check <notebook.py> before committing to catch the common mistakes automatically.

When marimo's guidance and the wiring below ever disagree, marimo wins on cell style; this skill only dictates the test_* / cell split and the execution modes.

The pattern

Every notebook file has three layers:

import marimo
app = marimo.App(width="medium")


# 1. test_* functions at module level — importable, pytest-visible.
#    Convention: return results so cells can reuse them for display
#    without running the logic twice.
def test_something():
    from mylib import thing
    result = thing()
    assert result == expected
    return result


# 2. @app.cell functions — marimo reactive UI.
#    mo is imported once in the first cell and flows as a dependency.
@app.cell
def _():
    import marimo as mo
    return (mo,)

@app.cell
def _(mo):
    result = test_something()   # assertion always runs inside the cell
    return (mo.md(f"✓ result: {result}"),)


# 3. entry point — launches the notebook UI when run directly
if __name__ == "__main__":
    app.run()

Execution modes

commandbehaviour
pytest notebooks/finds test_* functions at module level, runs assertions
marimo run notebooks/foo.pyinteractive notebook; cells call test_* then render prose
python notebooks/foo.pylaunches the notebook UI
from notebooks.foo import test_xplain import, marimo never invoked

pyproject.toml

[project.optional-dependencies]
test = ["pytest>=7", "marimo>=0.9"]   # marimo is a dev dep; add your package(s) under test

[tool.pytest.ini_options]
testpaths = ["tests"]          # default: fast unit tests only
# to include notebook integration tests: pytest tests/ notebooks/

Key invariants

  • test_* functions never import marimo — pure logic, no UI coupling.
  • import marimo as mo lives in the first cell only; all subsequent cells receive mo as a parameter via marimo's dependency injection.
  • @app.cell returns a Cell object, not the original function, so pytest will not accidentally treat cell functions as tests.
  • Multiple cells named _ are fine: marimo registers each before the name is rebound; pytest ignores underscore-prefixed names.
  • Cells call test_* first, then display — the assertion is the single source of truth, the cell just renders the result.

Where to put them

  • tests/tutorials/ — preferred when the notebooks are tutorial-style tests for a library. Sits inside the existing test tree alongside unit tests; since pytest recurses into tests/, no extra testpaths config is needed.
  • notebooks/ — alternative if docs-primary identity is preferred.

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.