首页
/ uv 与 marimo 深度集成:用 uv 管理 Notebook 依赖、隔离环境与脚本化执行

uv 与 marimo 深度集成:用 uv 管理 Notebook 依赖、隔离环境与脚本化执行

2026-09-06 17:52:55作者:虞亚竹Luna

marimo 是一个将交互式计算与传统软件的可复现性相结合的开源 Python notebook,它以纯 Python 脚本形式存储,因此可以像普通代码一样用 Git 版本化、以脚本形式运行、并以应用形式分享。本文基于 uv 官方集成指南,系统讲解在四种典型场景下(独立工具、内联脚本元数据、项目内、非项目环境)如何结合 uv 使用 marimo,并结合 uv 源码说明内联脚本元数据(PEP 723)的解析原理与 uv run 的执行逻辑,使读者既能直接复制命令,也能理解底层机制。

为什么 marimo 与 uv 天然契合

marimo 与传统 Jupyter 类 notebook 的关键区别在于:它的 notebook 就是普通的 .py 文件。这意味着:

  • notebook 可以被 Git 跟踪和 diff;
  • notebook 可以作为脚本直接执行(headless 运行);
  • notebook 文件本身可以携带 PEP 723 内联脚本元数据,声明自己的 Python 版本与依赖——而这正是 uv 脚本管理的核心格式。

uv 对这一形态提供了完整支持:uvx 临时运行工具、uv add --script 维护脚本依赖、uv run 按声明自动构建环境并执行。下面的各节命令均可直接复制使用(来源:docs/guides/integration/marimo.md)。

场景一:将 marimo 作为独立工具使用

对于临时、即时的 notebook 访问,可以用 uvx 在隔离环境中随时启动 marimo 服务:

$ uvx marimo edit

指定编辑某个特定 notebook 文件:

$ uvx marimo edit my_notebook.py

uvxuv tool run 的便捷别名:每次调用时 uv 会把 marimo 包安装到一个临时的、隔离的虚拟环境中并执行其提供的 marimo 可执行文件(见 docs/guides/tools.md)。其要点:

  • 无需预先安装 marimo,也不污染全局 Python 环境;
  • 环境是一次性的,适合 ad-hoc 使用;
  • 如果当前目录是一个 uv 项目且你希望工具使用项目环境,官方建议改用 uv run 而非 uvx

场景二:使用内联脚本元数据(PEP 723)管理 notebook 依赖

由于 marimo notebook 就是 Python 脚本,它们可以用 uv 支持的内联脚本元数据把依赖声明在文件头部,实现“自包含”的 notebook。

添加依赖

以给 notebook 增加 numpy 为例:

$ uv add --script my_notebook.py numpy

uv add --script 会在文件顶部写入/更新一个 script 元数据块(TOML 格式、每行以 # 前缀):

# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "numpy",
# ]
# ///

交互式编辑带元数据的 notebook

$ uvx marimo edit --sandbox my_notebook.py

加上 --sandbox 后,marimo 会自动借助 uv 启动一个包含该脚本声明依赖的隔离虚拟环境来运行 notebook。此时若通过 marimo 的 UI 安装新包,安装包会被自动写回 notebook 的脚本元数据中——依赖始终与文件本身保持同步,可随 Git 一起版本化。

以脚本方式直接运行

不打开交互式会话,直接把 notebook 当脚本执行:

$ uv run my_notebook.py

源码层面:uv 如何解析内联元数据

uv 对内联脚本元数据的解析集中在 crates/uv-scripts/src/lib.rs 中,可以印证上述行为:

  • 解析器以 # /// script 作为起始标记,定位后逐行剥离前导 #,得到纯 TOML 内容,并在最后一个恰好为 # /// 的行处闭合(ScriptTag::parse)。规范上要求:起始标记必须位于文件首行或紧跟换行符之后、标记块内每行都必须以 #(加空格)开头,否则会被判定为“未闭合块”而报错——源码中的 Pep723Error::UnclosedBlockUnclosedBlockTrailingContent 等错误类型(crates/uv-scripts/src/lib.rs)即对应这些校验,且单元测试覆盖了 shebang 共存、尾随内容、重复块等边界情况。
  • 解析出的元数据结构 Pep723Metadata 支持三个核心字段:dependencies(依赖列表)、requires-python(Python 版本要求)、以及 tool 表(crates/uv-scripts/src/lib.rs)。[tool.uv] 子表进一步支持 exclude-newer、自定义索引、sources 等配置,可用于提升脚本的复现性。
  • 元数据块必须提供 dependencies 字段(即使为空),这是 uv 写入时的默认格式(见 Pep723Script::create 生成的 dependencies = [])。
  • uv add --script 更新依赖时,最终通过 Pep723Script::write 将新的元数据块原位替换写回文件,保留脚本其余内容(prelude/postlude)不变。

uv run 对 PEP 723 脚本的特殊处理

uv run 在执行命令时会首先判断目标是否为 PEP 723 脚本。从 crates/uv/src/commands/project/run.rs 可以看到,它区分 Pep723Item::Script(磁盘上的文件)、Pep723Item::Stdin(标准输入)和 Pep723Item::Remote(远程 URL)三种来源,并按脚本内声明的 requires-python 选择或下载匹配的 Python 解释器。

一个重要的行为细节:只要使用内联脚本元数据,即使 uv run 在某个 uv 项目中执行,项目的依赖也会被忽略,因此无需额外加 --no-project 标志(这一点在 docs/guides/scripts.md 中被明确标注为重要行为)。

场景三:在 uv 项目中使用 marimo

当 marimo notebook 是某个 uv 项目的一部分时(假设 marimo 已是项目依赖),可以直接用项目环境启动:

$ uv run marimo edit my_notebook.py

这样 notebook 运行时可 import 项目自身的模块。给 notebook 引入额外包有两条路:

  1. uv add 把包加入项目依赖(写入 pyproject.toml 并更新 uv.lock);
  2. 使用 marimo 内置的包安装 UI——它会替你调用 uv add,因此同样会持久化到项目声明中。

如果 marimo 本身不是项目依赖,仍可运行 notebook:

$ uv run --with marimo marimo edit my_notebook.py

--with 会在项目环境之上临时叠加 marimo 包(临时依赖机制见 docs/guides/scripts.md)。此方式下 notebook 依然能 import 项目模块,但有一个关键限制:在这种临时方式下通过 marimo UI 安装的包不会被写入项目依赖,且可能在后续启动中丢失。如果需要持久化,应改用 uv add

场景四:在非项目环境中使用 marimo

对于没有 pyproject.toml 的普通虚拟环境,直接把 marimo 装进环境即可:

$ uv venv
$ uv pip install numpy
$ uv pip install marimo
$ uv run marimo edit

此时 notebook 内的 import numpy 可正常工作;通过 marimo UI 安装新包时,marimo 会代你调用 uv pip install 将包装入该环境。注意这与场景三(调用 uv add)不同:非项目环境下安装结果只反映在虚拟环境里,没有声明式文件记录,环境重建时依赖会丢失。

以脚本形式运行 notebook:跨场景统一入口

无论依赖如何管理——内联脚本元数据、项目依赖还是非项目环境——运行 notebook 的命令都是同一个:

$ uv run my_notebook.py

uv run 会自动完成环境准备(解析/同步依赖、选择或下载 Python 版本),然后以脚本方式执行 notebook,全程不打开浏览器交互式会话。这正是 marimo “notebook 即脚本” 设计在 CI、定时任务等无头场景下的价值所在。

四种场景速查

场景 启动命令 依赖持久化位置 marimo UI 安装的行为
独立工具(ad-hoc) uvx marimo edit 无(临时环境) 仅存在于临时环境
内联脚本元数据 uvx marimo edit --sandbox my_notebook.py notebook 文件头部的 # /// script 自动写回脚本元数据
uv 项目内 uv run marimo edit my_notebook.py pyproject.toml + uv.lock 代为调用 uv add
项目内但 marimo 非依赖 uv run --with marimo marimo edit my_notebook.py 项目依赖不变,marimo 为临时包 不写入项目,可能丢失
非项目环境 uv venvuv pip install marimo,再 uv run marimo edit 仅虚拟环境本身 代为调用 uv pip install
脚本化执行(通用) uv run my_notebook.py 视所属场景 不适用(无 UI)

延伸阅读

登录后查看全文
热门项目推荐
相关项目推荐