使用 nbconvert 执行 Notebook

执行前提:执行 Notebook 会运行其中的代码。请先确认文件及依赖可信,并在合适的隔离环境和资源限制下运行。示例中的 notebook_filename、run_path 与 notebook_filename_out 需要替换或定义为实际输入、工作目录和输出路径;保存操作可能覆盖同名输出文件。

Jupyter Notebook 经常以清空输出单元格的状态保存。nbconvert 提供了一种方便的方法:执行 .ipynb Notebook 文件的输入单元格,再将输入与输出单元格一起保存为 .ipynb 文件。

本节演示如何执行 .ipynb 文档,并以 Notebook 格式保存结果。如果需要导出为 reStructuredText、Markdown 等其他格式,并选择是否执行,请参阅 将 nbconvert 用作库。执行 Notebook 很有用,例如一次运行 Python 库中的全部 Notebook,或者自动完成涉及多个 Notebook 的项目的数据分析。

从命令行执行 Notebook

执行 Notebook 的相同功能同时提供命令行接口和 Python API。例如,可以使用以下命令执行一个 Notebook:

jupyter nbconvert --to notebook --execute mynotebook.ipynb

通过 Python API 执行 Notebook

本节介绍 Python API。

完整示例

先从一个完整的快速示例开始,细节将在后面说明。

导入:首先导入 nbconvert 和 ExecutePreprocessor 类:

import nbformat
from nbconvert.preprocessors import ExecutePreprocessor

加载:假设 notebook_filename 保存了 Notebook 路径,可以这样加载:

with open(notebook_filename) as f:
    nb = nbformat.read(f, as_version=4)

配置:接着配置 Notebook 的执行方式:

ep = ExecutePreprocessor(timeout=600, kernel_name='python3')

这里指定了两个可选参数 timeout 和 kernel_name,分别定义单元格执行超时时间和执行内核。

执行(预处理):真正运行 Notebook 时,调用 preprocess() 方法:

ep.preprocess(nb, {'metadata': {'path': 'notebooks/'}})

理想情况下,执行过程中不会出现错误;错误处理见最后一节。注意,path 指定 Notebook 执行时所在的文件夹。

保存:最后保存执行后的 Notebook:

with open('executed_notebook.ipynb', 'w', encoding='utf-8') as f:
    nbformat.write(nb, f)

至此,执行后的 Notebook 会保存到当前文件夹中的 executed_notebook.ipynb 文件。

执行参数:traitlets

传给 ExecutePreprocessor 的参数是一类称为 traitlets 的配置选项。traitlets 有许多便利之处:例如约束输入类型,并能作为类属性访问或修改。每个 traitlet 还会自动暴露为命令行选项。例如,从命令行传入超时时间:

jupyter nbconvert --ExecutePreprocessor.timeout=600 --to notebook --execute mynotebook.ipynb

下面详细介绍刚才使用的两个 traitlet。

timeout 定义每个 Notebook 单元格允许运行的最长时间,单位为秒。超过此时间就会抛出异常。原文所述默认值为 30 秒;遇到运行时间较长的单元格时,可以设置更大的值。也可以将 timeout 设为 None 或 -1,取消执行时间限制。

版本校注:教程正文的“30 秒”与同版本 7.17.1 配置参考不一致;配置参考列出的 ExecutePreprocessor.timeout 默认值为 None,即不设该超时,且 timeout_func 可覆盖它。实际任务应像前面的示例一样显式设置合适的超时,不应依赖这里的历史默认值描述。

kernel_name 用于指定执行时使用的内核名称。默认情况下,内核名称来自 Notebook 元数据;设置该 traitlet 可以用用户指定的内核覆盖元数据中的值。常见场景是兼容 Python 2/3 的库带有用于文档或测试的 Notebook。这些 Notebook 的元数据会注明 python2 或 python3,取决于上次保存时使用的内核。实际上,它们可能同时适用于 Python 2 和 Python 3,而测试时需要能以编程方式在两个版本中执行。此时,kernel_name 可简化流程并保持一致:先以 python2 为内核运行一次,再以 python3 运行一次。

处理错误与异常

前面展示了在没有执行错误时保存已执行的 Notebook。如果出现错误,该怎么办?

执行到首个错误

默认情况下,执行过程中出现错误会停止执行并抛出 CellExecutionError。导致错误的源单元格,以及原始错误名称和消息也会一并打印出来。出现错误后,仍然可以按前面的方法保存 Notebook:

with open('executed_notebook.ipynb', mode='w', encoding='utf-8') as f:
    nbformat.write(nb, f)

保存的 Notebook 包含直到失败单元格为止的输出,也包含完整的堆栈跟踪和错误信息,可用于调试。

处理错误

以下模式适合在处理错误的同时执行 Notebook:

from nbconvert.preprocessors import CellExecutionError

try:
    out = ep.preprocess(nb, {'metadata': {'path': run_path}})
except CellExecutionError:
    out = None
    msg = 'Error executing the notebook "%s".\n\n' % notebook_filename
    msg += 'See notebook "%s" for the traceback.' % notebook_filename_out
    print(msg)
    raise
finally:
    with open(notebook_filename_out, mode='w', encoding='utf-8') as f:
        nbformat.write(nb, f)

无论是否发生执行错误,都会保存执行后的 Notebook。不过,如果发生错误,还会打印一条额外消息并再次抛出 CellExecutionError。该消息引导用户查看保存的 Notebook,以进一步检查问题。

执行到底并保存所有错误

有时需要执行会抛出异常的 Notebook,例如展示一种错误情形。此时可以使用默认值为 False 的 allow_errors traitlet,让程序不在首个错误处停止。设置 allow_errors=True 后,Notebook 会执行到最后,不论期间是否发生错误。输出 Notebook 会保存所有抛出异常的单元格的堆栈跟踪和错误消息。

范围说明:allow_errors=True 处理的是单元格执行错误,并不代表内核启动失败、执行超时或输出文件写入失败等情况都能被忽略。错误处理示例中的 finally 会尝试保存,但文件系统错误仍可能使保存失败。

Widget 状态

如果 Notebook 包含 Jupyter Widgets,可以将全部 Widget 的状态存储在 Notebook 元数据中。这使得 nbviewer 或转换后的 HTML 可以呈现可交互的 Widget。

使用 store_widget_state 参数,可以让 nbconvert 不存储这些状态:

jupyter nbconvert --ExecutePreprocessor.store_widget_state=False --to notebook --execute mynotebook.ipynb

执行过程中不会在浏览器中进行 Widget 渲染,因此只会计算 Widget 的默认状态或由用户代码修改的状态。%%javascript 单元格将在 Notebook 渲染时执行,从而让复杂交互在 UI 中查看时按预期工作。

如果执行后无法查看 Widget 结果,可能需要在菜单中选择 File → Trust Notebook(文件 → 信任 Notebook)。

只有在确认 Notebook 及输出内容可信后,才应执行“信任 Notebook”。信任操作不是对未知文件的安全检查,也不能代替审阅。

来源与许可

原文:nbconvert 7.17.1 官方文档。文档页脚为 © Copyright 2015–2026, Jupyter Development Team。软件许可另保留 ©2001–2015 IPython Development Team 与 ©2015– Jupyter Development Team。本版完整翻译原文,保留历史版本说明并增加明确的默认值和执行范围校注。

官方原文 · 许可证与版权声明

原文参考链接

许可证原文

BSD 3-Clause License

- Copyright (c) 2001-2015, IPython Development Team
- Copyright (c) 2015-, Jupyter Development Team

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容