#10870·marimo

WASM: version specifiers in a notebook's PEP 723 dependencies are dropped before install

Author: ljchangCreated Sep 16, 2026Updated Sep 16, 2026

Describe the bug

In a WASM notebook, a pinned dependency is installed unpinned.

PyodideSession.find_packages reads the notebook's PEP 723 block and then strips each requirement before handing it to micropip:

# marimo/_pyodide/pyodide_session.py
if len(script_deps) > 0:
    return [strip_requirement_name(dep) for dep in script_deps]
>>> deps = ["pandas==2.1.0", "nltools==0.6.0.dev2"]
>>> [strip_requirement_name(d) for d in deps]
['pandas', 'nltools']

So micropip.install never sees the constraint the notebook declared.

Why this is more than a loss of precision

Installers skip pre-releases unless a specifier asks for one. A pin is therefore the only thing that can select a pre-release — so stripping it doesn't make the resolution fuzzier, it sends it to a different release, and specifically to the newest stable one.

That is exactly the case that broke for us. The notebook pinned nltools==0.6.0.dev2, which installs and runs in Pyodide. Unpinned, nltools resolves to the latest stable, 0.5.1, which requires numpy<1.24:

await micropip.install("nltools==0.6.0.dev2")  # ok
await micropip.install("nltools")              # Can't find a pure Python 3 wheel for 'numpy<1.24'

The reader gets Some packages failed to install → Failed to install nltools, and the notebook cannot boot.

Reproduce

A notebook whose block pins a package whose newest stable release is unusable in Pyodide, while a pre-release works:

# /// script
# dependencies = ["nltools==0.6.0.dev2"]
# ///
import marimo
app = marimo.App()

@app.cell
def _():
    from nltools.data import BrainData
    return

Open it in WASM. The install fails; the browser console shows the numpy<1.24 resolution error from the 0.5.1 metadata.

Expected

micropip receives nltools==0.6.0.dev2 — the requirement the notebook declared.

Notes

The stripped list is used in three places in loadNotebookDeps (frontend/src/core/wasm/worker/bootstrap.ts). Two are "already installed?" lookups keyed by name; only the third, micropip.install, wants the requirement. So the name can be derived where a name is needed, leaving the requirement intact for the install — the existing skip behaviour is unchanged and only what gets installed differs.

Happy to send a PR along these lines.

Environment

marimo 0.24.2, Pyodide v314.0.0, Chrome. Found while giving chapters an in-browser editor in marimo-book.