ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Jupytext MyST Markdown 格式实战:用 md:myst 把 Notebook 变成保留单元格元数据的 Markdown 文档

Jupytext MyST Markdown 格式实战:用 md:myst 把 Notebook 变成保留单元格元数据的 Markdown 文档 开发工具【免费下载链接】jupytextJupyter Notebooks as Markdown Documents, Julia, Python or R scripts项目地址https://gitcode.com/gh_mirrors/ju/jupytext点击查看免费下载Jupytext 允许把 Jupyter Notebook 以多种纯文本格式保存其中 MyST Markdownmd:myst是专为文档生态设计的表示方式它用 YAML front matter 承载 notebook 级元数据、用{code-cell}指令承载代码单元格、用围栏内的 YAML 块原样保留单元格级元数据同时让 Markdown 文本天然地成为可渲染文档。本文以仓库中的实际转换产物 Notebook with function and cell metadata 164.md 为骨架逐段拆解 MyST 文本表示的结构与语义并结合 src/jupytext/myst.py 的源码实现讲清转换器如何写入/解析 front matter、指令围栏与单元格元数据以及如何用 CLI、Python API 和 Jupyter 配对格式落地使用。一、MyST Markdown 在 Jupytext 中的定位MySTMarkedly Structured Text是一套面向文档出版的 Markdown 超集其 notebook 化的文本表示约定由{code-cell}等指令构成。在 Jupytext 中MyST 是md格式的一个具名变体格式名为myst对应 CLI 目标md:myst在 src/jupytext/myst.py 中定义指令常量CODE_DIRECTIVE {code-cell}、RAW_DIRECTIVE {raw-cell}可用扩展名.md、.myst、.mystnb、.mnb见myst_extensions()当no_mdTrue时仅认可后三者避免与普通 Markdown 混淆解析依赖markdown-it-py含front_matter_plugin、myst_block_plugin、myst_role_plugin未安装时调用转换会抛出ImportError(The MyST Markdown format requires python 3.6 and markdown-it-py~1.0)。matches_mystnb()用于从扩展名和内容判断一个文件是否应被识别为 MyST扩展名命中.myst/.mystnb/.mnb直接判定对.md文件则检查是否以---front matter 开头、front matter 中是否有jupytext.text_representation.format_name: myst或正文中是否出现{code-cell}/{raw-cell}指令围栏。这套判定逻辑在 tests/functional/simple_notebooks/test_ipynb_to_myst.py 中有大量用例覆盖。二、转换产物逐段解剖一个带非平凡单元格元数据的示例仓库中 Notebook with function and cell metadata 164.ipynb 是一个 nbformat 4.2 的 Python 笔记本包含 4 个代码单元格和 2 个 Markdown 单元格。其中定义函数f的代码单元格与其后调用f(5)的单元格带有非平凡元数据metadata: { attributes: { classes: [], id: , n: 10 } }该笔记本经ipynb - md:myst转换后得到的镜像文件即为 ipynb_to_myst 目录下的 164 号产物全文如下--- kernelspec: display_name: Python 3 language: python name: python3 --- {code-cell} ipython3 1 1 A markdown cell And below, the cell for function f has non trivial cell metadata. And the next cell as well. {code-cell} ipython3 --- attributes: classes: [] id: n: 10 --- def f(x): return x {code-cell} ipython3 --- attributes: classes: [] id: n: 10 --- f(5) More text {code-cell} ipython3 2 2 这个 40 行的文本文件包含了 MyST 文本表示的全部核心要素下面逐层解读。1. YAML front matternotebook 级元数据文件开头以---包裹的 YAML 块是文档级notebook 级元数据此处仅保留了kernelspec。对比原始 ipynb 可以看到原笔记本还带有language_info、celltoolbar: Edit Metadata、toc: {...}等元数据但它们并未出现在文本产物中——这正是 Jupytext 默认元数据过滤策略的体现默认情况下仅保留kernelspec与jupytext命名空间内的信息其余如language_info、toc被过滤掉以免文本文件被与渲染无关的噪声信息污染。该 front matter 由notebook_to_myst()中的dump_yaml_blocks(nb_metadata, compactFalse)生成compactFalse强制使用---围栏包裹即使字典是扁平的。2.{code-cell} ipython3代码单元格指令与词法器每个代码单元格都渲染为 Markdown 围栏代码块语言标签形如{code-cell} ipython3{code-cell}是 MyST 的代码单元格指令名紧随其后的ipython3是词法器lexer名供语法高亮器使用。它来自 notebook 元数据language_info.pygments_lexer本例原始 ipynb 中该值为ipython3若该字段缺失则回退到notebook_to_myst的default_lexer参数。源码notebook_to_myst()src/jupytext/myst.py在写出代码单元格时还调用three_backticks_or_more()定义于 src/jupytext/cell_to_text.py它会扫描单元格源码中连续反引号的行自动加长围栏分隔符确保单元格源码里出现甚至更长反引号串时外层围栏依然能正确闭合。3. 游离文本Markdown 单元格指令围栏之间的普通文本就是 Markdown 单元格。本例中“A markdown cell / And below, the cell for function f...”和“More text”两段文本分别对应原始 ipynb 中的两个 Markdown 单元格。myst_to_notebook()读取时会把每个指令之间的空白清理后的文本收集为 Markdown 单元格_flush_markdown内部调用strip_blank_lines去掉首部空行。需要说明的是如果 Markdown 单元格本身带有元数据文本表示中会在单元格文本前插入 {json...}分隔行见notebook_to_myst中f\n {json.dumps(metadata)}\n的分支逻辑后跟一段 JSON 字典本示例的 Markdown 单元格元数据为空因此未出现该标记。4. 指令内的 YAML 块单元格级元数据这是本例最值得关注的部分。两个带元数据的代码单元格在指令首行与源码之间插入了一个被---包围的 YAML 块--- attributes: classes: [] id: n: 10 ---原始 ipynb 中attributes的classes是空数组、id是空字符串、n是字符串10——文本表示中classes: []、id: 、n: 10与之一一对应数值与类型都得到了保真。这证明 MyST 文本表示可以完整承载非平凡嵌套结构的单元格元数据适合配合 Jupyter 的“Edit Metadata”工具链使用原 ipynb 的celltoolbar: Edit Metadata正是这类工作流的典型配置。三、源码视角单元格元数据是如何写进去的notebook_to_myst()写出代码/原始单元格时的逻辑为src/jupytext/myst.py以three_backticks_or_more确定围栏分隔符拼上{code-cell}/{raw-cell}指令与 lexer若cell.metadata非空调用dump_yaml_blocks(metadata)写入元数据块写入单元格源码以同样的分隔符闭合。关键函数dump_yaml_blocks()src/jupytext/myst.py决定 YAML 块的两种风格紧凑冒号风格当 YAML 每一行的首个非空字符都是字母即无嵌套结构、无非字典元素时用:key: value形式逐行书写例如:tags: [hide-output, show-input]---围栏风格当存在嵌套字典如本例的attributes时改用---包裹。本例中classes: []与id: 等行以空格缩进开头不满足“全部以字母开头”的紧凑条件因此落入围栏风格。同时CompactDumper对列表采用 flow 风格classes: []而非多行列表对字典采用 block 风格并保持键序sort_keysFalse这解释了产物的精确排版。allow_unicodeTrue则保证带重音字符的元数据可正常写出对应测试 test_myst_header.py 中的 unicode 用例。四、反向读取从 MyST 文本回到 Notebookmyst_to_notebook()src/jupytext/myst.py负责把文本解析回 notebook 对象其流程为用 markdown-it 解析器get_parser()启用 table、front matter、myst block、myst role 插件并禁用 inline 解析以提升效率得到 token 流首个front_mattertoken 用yaml.safe_load解析为 notebook 元数据遍历 token遇到fence且信息以{code-cell}开头先冲刷此前的文本为 Markdown 单元格再解析指令内容生成代码单元格{raw-cell}同理生成原始单元格myst_block_break即则用于携带其后 Markdown 单元格的元数据。指令内元数据的解析由parse_directive_options()src/jupytext/myst.py完成它同时支持---围栏包裹的 YAML 块本例所用风格:key: value冒号行风格。若 YAML 语法非法会抛出MystMetadataParsingError并携带单元格序号与行号信息。对应的错误路径在 test_ipynb_to_myst.py 中有专门用例非法 notebook 元数据{{a、非法代码单元格元数据、非法 Markdown 元数据 {{a以及非字典元数据 [1, 2]都会被逐一拒绝。反向转换时若文档没有language_info而指令中出现了统一的 lexer解析器会把该 lexer 写入jupyter.jupytext.default_lexer若文档存在多个不同语言lexer的代码单元格会发出All code cells in a MyST notebook must have the same language的警告。五、元数据过滤配置控制哪些信息进入文本MyST 文本表示中哪些元数据该保留由 Jupytext 的过滤配置控制定义于 src/jupytext/config.pynotebook_metadata_filternotebook 级元数据过滤器示例值all、-all、kernelspec,jupytext默认只保留kernelspec与jupytext命名空间这正是本例 front matter 中language_info、toc被剔除的原因root_level_metadata_filter控制哪些 notebook 元数据被“提升”到文本文件顶层front matter默认实现见 src/jupytext/header.pycell_metadata_filter单元格级元数据过滤器示例值all、hide_input,hide_output配合-all可显式丢弃全部单元格元数据如spin等格式在 src/jupytext/combine.py 中的处理default_cell_metadata_filter/default_notebook_metadata_filter已废弃的旧选项名设置时会告警并自动转发到新选项。这些过滤器同样作用于单元格元数据的写入BaseCellExporter在 src/jupytext/cell_to_text.py 中对cell.metadata先做filter_metadata再写出因此被过滤掉的元数据不会进入文本文件。六、落地使用三种调用方式MyST 格式与 Jupytext 的其他格式一样可通过三条路径使用均有测试佐证见 tests/functional/round_trip/test_mirror.py 与 test_ipynb_to_myst.py1. CLI 转换jupytext --to md:myst notebook.ipynb # ipynb - MyST Markdown jupytext --to ipynb:myst notebook.md # MyST Markdown - ipynb未安装markdown-it-py时CLI 会给出可读的ImportError对应测试test_meaningfull_error_write_myst_missing。2. Python APIimport jupytext nb jupytext.read(notebook.ipynb) text jupytext.writes(nb, fmtmd:myst) # 序列化为 MyST 文本 nb2 jupytext.reads(text, fmtmd:myst) # 反序列化回 notebook3. Jupyter 配对格式在 Jupyter 配置文件如jupyter_notebook_config.py中声明配对格式c.ContentsManager.formats ipynb,md:myst保存.ipynb时会同步生成/更新同名的.md文本镜像。测试 test_ipynb_to_myst.py 的test_myst_representation_same_cli_or_contents_manager验证了 CLI、Python API 与 ContentsManager 三种路径产出的文本完全一致。七、镜像与回归保障为什么可以放心使用仓库把每个 ipynb 的 MyST 产物固化在 tests/data/notebooks/outputs/ipynb_to_myst/ 目录下作为“镜像文件”mirror并在 test_mirror.py 中通过assert_conversion_same_as_mirror(ipynb_file, md:myst, ipynb_to_myst)断言每次改动后ipynb 转换出的文本必须与镜像文件逐字一致同时test_myst_to_ipynb断言镜像文本转回 ipynb 后与原笔记本在经元数据过滤后的结构上等价。这套双向回归机制保证了转换输出的稳定性——本示例 164 号产物就是这套镜像体系中的一个样本。八、使用注意事项小结输出outputs不入文本MyST 文本表示只承载源码与元数据execution_count、输出结果不会写入.md如需保留输出应保持.ipynb与.md配对Jupyter 中同时维护两个文件。lexer 一致性MyST 文档内所有代码单元格应使用同一语言混用不同 lexer 会触发警告。元数据保真边界单元格元数据默认全部保留除非配置cell_metadata_filter过滤但 notebook 级元数据默认只保留kernelspec与jupytext命名空间需要保留language_info、toc等时请显式配置notebook_metadata_filter。依赖要求MyST 读写依赖markdown-it-py~1.0缺失时 CLI、API 与 ContentsManager 均会给出明确报错。综上md:myst格式在 Jupytext 中承担着“既适合人类阅读与文档发布、又能无损保留单元格元数据”的角色。通过本文的逐段拆解与源码印证你可以放心地用它把带有非平凡单元格元数据的 Notebook 固化为 Markdown 文档并在 CLI、Python API 与 Jupyter 三种场景下自由往返。赞分享开发工具【免费下载链接】jupytextJupyter Notebooks as Markdown Documents, Julia, Python or R scripts项目地址https://gitcode.com/gh_mirrors/ju/jupytext点击查看免费下载相关推荐Jupytext MyST Markdown 格式实战LaTeX 数学公式、 单元格分隔与 cell_marker 元数据的保留机制Jupytext MyST Markdown 格式实战LaTeX 数学公式、 单元格分隔与 cell_marker 元数据的保留机制 本篇技术指南以开发工具Jupytext MyST Markdown 格式详解从 .ipynb 到 Myst 文档的双向转换与单元格元数据编码Jupytext MyST Markdown 格式详解从 .ipynb 到 Myst 文档的双向转换与单元格元数据编码 本文以 Jupytext 仓库中的真实开发工具TiKV 监控面板的代码化生成TiKV Details Dashboard 的工作原理与维护指南TiKV 监控面板的代码化生成TiKV Details Dashboard 的工作原理与维护指南 TiKV 将核心监控面板 TiKV Details 以开发工具上一篇TestDisk PhotoRec终极免费数据恢复完全指南轻松找回丢失的分区和文件下一篇Sunshine游戏串流主机跨平台低延迟游戏体验的终极解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表