Sphinx toctree 通配符实战:用 `:glob:` 与 `:reversed:` 自动生成目录树
发布时间:2026/10/7 9:22:21 锦皓数字建站

文档开发工具【免费下载链接】sphinxThe Sphinx documentation generator项目地址https://gitcode.com/gh_mirrors/sp/sphinx点击查看免费下载导读本文以 Sphinx 文档生成器本仓库即 Sphinx 官方源码库中toctree指令的:glob:与:reversed:选项为核心讲解如何用 shell 风格通配符自动匹配文档、按字母序展开目录树、以及逆序排列条目。全文从测试根目录 tests/roots/test-toctree-glob/index.rst 这一真实用例出发结合指令源码 sphinx/directives/other.py、匹配算法 sphinx/util/matching.py 与单元测试 tests/test_environment/test_environment_toctree.py读完你将掌握何时用 glob 免维护目录、通配符的精确匹配规则、:reversed:与:glob:的组合用法以及 glob 在增量构建下的重读机制。一、从测试根目录理解:glob:的完整行为1.1 一个精心设计的 glob 测试文档仓库中的 tests/roots/test-toctree-glob/index.rst 是一份专门验证 glob 语义的文档它同时声明了normal order与reversed order两个 toctreetest-toctree-glob normal order ------------ .. toctree:: :glob: foo bar/index bar/* baz qux/index hyperref https://sphinx-doc.org/?qsphinx reversed order -------------- .. toctree:: :glob: :reversed: foo bar/index bar/* baz qux/index这段内容虽然简短却覆盖了 glob 的全部关键语义普通条目foo、bar/index、baz、qux/index按字面精确匹配通配条目bar/*触发目录扫描外部链接hyperref https://sphinx-doc.org/?qsphinx不参与 glob 匹配仅作为额外条目插入同一条目列表在加:reversed:后整体逆序。1.2 配套目录结构glob 的匹配对象与该文档配套的目录 tests/roots/test-toctree-glob 是理解匹配范围的关键。除了index.rst与 conf.py仅设置exclude_patterns [_build]外还存在以下文档foo.rst、baz.rst、quux.rst顶层平铺文档标题分别为 Foo、Baz、Quuxbar/index.rstBar 标题内含第二个:glob:toctree模式为*与bar_4/indexbar/bar_1.rst、bar/bar_2.rst、bar/bar_3.rst、bar/bar_4/index.rstqux/index.rstQux 标题内含:hidden::glob:的*toctree与qux/qux_1.rst、qux/qux_2.rst。当index.rst中的bar/*被解析时Sphinx 会以当前文档所在目录为基准展开模式从而命中bar/bar_1、bar/bar_2、bar/bar_3并顺带把bar/index同时被bar/*匹配包含进列表——这正是普通条目bar/index与通配条目bar/*并列出现的原因前者确保 index 一定在最前普通条目优先插入后者负责追加其余兄弟文档。二、源码级拆解TocTree指令如何解析 glob2.1 选项注册glob与reversed是布尔旗标SphinxDirective 中定义的TocTree指令sphinx/directives/other.py 第 42 行起通过option_spec注册了所有 toctree 选项option_spec { maxdepth: int, name: directives.unchanged, class: directives.class_option, caption: directives.unchanged_required, glob: directives.flag, hidden: directives.flag, includehidden: directives.flag, numbered: int_or_nothing, titlesonly: directives.flag, reversed: directives.flag, }其中glob与reversed均以directives.flag注册表示它们是出现即启用的布尔旗标不需要参数值。在run()中subnode[glob] glob in self.options因此只要指令块内出现:glob:一行subnode[glob]即为True后续parse_content()便进入通配解析分支。2.2parse_content()逐条解析的完整流程核心逻辑位于 sphinx/directives/other.py 的parse_content()第 89182 行其流程如下准备候选文档集合all_docnames self.env.found_docs.copy() | generated_docnames并移除当前文档自身all_docnames.remove(current_docname)同时排除exclude_patterns匹配的文档逐条处理 content对每条 entry先判断是否为显式标题explicit_title_re或URL 链接url_re。只有当glob为真、条目含通配符glob_re.match(entry)、且既不是显式标题也不是 URL 时才走 glob 分支glob 分支用docname_join(current_docname, entry)把相对模式拼成完整 docname 模式再调用patfilter(all_docnames, pat_name)筛选匹配文档sorted()排序后逐个追加到entries与includefiles已被 glob 消耗的 docname 会从all_docnames中移除避免被后续条目重复包含普通条目分支解析显式标题与 URL剥离source_suffix后缀docname_join归一化路径后校验存在性重复条目会触发duplicate_entry警告sphinx/directives/other.py 第 165174 行逆序收尾若存在:reversed:选项则同时反转entries与includefiles第 180182 行。关键判断正则定义在文件顶部glob_re re.compile(r.*[*?\[].*)即只有包含*、?或[的条目才被视为 glob 模式纯文字条目走普通解析。URL 与显式标题Some Title document永远不会被当作通配模式展开。2.3_translate_pattern*不匹配斜杠**才匹配斜杠glob 的语义并非直接使用 Pythonfnmatch而是由 sphinx/util/matching.py 中改编自 fnmatch 的_translate_pattern()决定。该函数把 shell 通配符翻译成正则表达式并做了关键增强单星*不匹配斜杠/用于限定在单个目录层级内双星**匹配任意字符序列包括斜杠用于跨目录递归匹配?匹配任意单个非斜杠字符[...]与[!...]支持字符集匹配同样不跨斜杠。这正好对应官方文档 doc/usage/restructuredtext/directives.rst 第 1770 行起脚注的说明可以使用标准 shell 结构*、?、[...]、[!...]且这些都不会匹配斜杠**可以匹配包括斜杠在内的任意字符序列。patfilter()第 103 行则基于编译缓存_pat_cache对候选 docname 列表做正则过滤返回匹配子集。典型模式的匹配含义以测试根目录为例模式匹配范围不含斜杠是否匹配斜杠典型用途*当前目录下的任意文档不递归否平铺目录自动收录bar/*bar/下的任意文档否按子目录收录**任意层级的任意文档是递归整棵树foo*以foo开头的文档否前缀分组bar/bar_[13]bar/bar_1与bar/bar_3否精确字符集选择需要说明测试根目录中bar/*命中bar/index、bar/bar_1、bar/bar_2、bar/bar_3bar/bar_4/是更深层级不会被单星命中除非另行列出bar_4/indexqux/index.rst内:hidden::glob:的*则会命中qux/qux_1与qux/qux_2构成一个不可见但参与导航的隐藏子目录树。2.4 排序规则字母序 先到先得官方文档明确All entries are matched against the list of available documents, and matches are inserted into the list alphabeticallydoc/usage/restructuredtext/directives.rst 第 204205 行。源码中每个 glob 模式的结果都先sorted()再追加sphinx/directives/other.py 第 111116 行而多个模式的顺序遵循出现在 toctree 内容中的先后顺序。测试的预期结果正是这一规则的实证foo bar/index bar/bar_1 bar/bar_2 bar/bar_3 baz qux/index即字面条目foo在前bar/index在前随后bar/*展开出的三个文档按字母序排列最后是baz与qux/index。三、:reversed:逆序排列的实现与适用场景3.1 源码实现entries 与 includefiles 同步反转:reversed:的逻辑十分简单直接sphinx/directives/other.py 第 180182 行if reversed in self.options: toctree[entries] list(reversed(toctree[entries])) toctree[includefiles] list(reversed(toctree[includefiles]))注意两个列表必须同步反转entries是(title, ref)列表控制渲染顺序includefiles是文档名列表控制遍历顺序二者一旦错位目录渲染与实际读取顺序就会不一致。测试用例断言了反转后的完整结果tests/test_environment/test_environment_toctree.py 第 271290 行assert_node( extract_node(toctree, 0, 1, 1, 1, 0), addnodes.toctree, ... includefileslist(reversed(includefiles)), entries[ (None, qux/index), (None, baz), (None, bar/bar_3), (None, bar/bar_2), (None, bar/bar_1), (None, bar/index), (None, foo), ], )3.2 官方定位与:glob:组合的新文档置顶技巧官方文档对reversed的说明是Reverse the order of the entries in the list. This is particularly useful when using the:glob:option.doc/usage/restructuredtext/directives.rst 第 221224 行自 Sphinx 1.5 起加入。最常见的组合用法是把:glob:与:reversed:一起用于更新日志类章节通配符自动收录新增文档逆序让最新的文档排在最前从而做到新增文件零配置、最新内容默认置顶。一个可落地的示例更新日志 .. toctree:: :glob: :reversed: :maxdepth: 1 changelog/*结合glob_re含*、?、[才触发 glob可以得出一个容易忽略的要点reversed本身不改变匹配逻辑它作用于最终条目列表因此即便不使用 globreversed也能对普通字面条目生效但与 glob 组合时价值最大因为手写条目的顺序本来就可控而 glob 展开结果的顺序只能通过reversed这类选项调整。四、glob 与增量构建新增文件为何会自动触发重读glob 目录树的一个显著特点是声明式、免维护往被 glob 覆盖的目录里加一个新.rst文件无需改动任何 toctree目录会自动包含新文档。这一机制建立在环境Environment的glob_toctrees集合上在 sphinx/environment/adapters/toctree.py 第 3839 行只要一个 toctree 节点的glob为真其所属 docname 就会被登记进env.glob_toctrees增量构建时sphinx/builders/init.py 第 487491 行检查if added or removed: changed.update(self.env.glob_toctrees self.env.found_docs)——即只要有任何文件被新增或删除所有含 glob toctree 的文档都会被强制列入重读名单因为只有重读才能重新展开通配模式、刷新目录内容sphinx/environment/collectors/toctree.py 第 5657 行则在环境合并时把其他环境的glob_toctrees并入当前环境保证跨进程/并行构建时该集合不丢失。这一设计也带来一个隐性约束glob 模式的匹配基于构建时已知的文档集合env.found_docs由 sphinx/directives/other.py 第 97 行all_docnames self.env.found_docs.copy() | generated_docnames可见。因此未纳入found_docs的文档例如被exclude_patterns排除、或尚未被扫描器发现的文件不会出现在 glob 结果中。五、边界行为与警告处理glob 分支并非对任何模式都静默成功其边界行为值得注意sphinx/directives/other.py 第 117123 行if not doc_names: logger.warning( __(toctree glob pattern %r didnt match any documents), entry, locationtoctree, subtypeempty_glob, )空模式警告当bar/*这类模式在扫描范围内一个文档都没匹配到时Sphinx 会发出empty_glob子类型的警告提示开发者模式可能写错或目录为空去重机制已被某个 glob 模式包含的 docname 会从all_docnames移除因此不同模式或普通条目 glob重叠命中同一文档时不会重复插入但若普通条目在 glob 之后又显式列出同一文档会触发duplicate_entry警告sphinx/directives/other.py 第 168174 行排除规则exclude_patterns测试根目录中为[_build]见 tests/roots/test-toctree-glob/conf.py匹配的文档会被过滤Matcher实现在 sphinx/util/matching.py 第 6985 行self与 URL 特例ref self与url_match的条目直接进入entries而不校验存在性第 147149 行因此测试文档中hyperref https://sphinx-doc.org/?qsphinx这类外部链接得以原样保留在目录中生成文档豁免StandardDomain._virtual_doc_names对应的生成文档不会进入 glob 展开结果第 114115 行避免通配模式把自动生成的虚拟文档误收入目录。六、测试如何验证这一切单元测试 tests/test_environment/test_environment_toctree.py 第 193 行起以pytest.mark.sphinx(dummy, testroottoctree-glob)挂载本测试根目录并执行构建然后逐层断言glob 展开的最终列表第 195203 行断言includefiles恰为[foo, bar/index, bar/bar_1, bar/bar_2, bar/bar_3, baz, qux/index]验证普通条目在前、bar/*按字母序展开、quux.rst因未被任何条目提及而不在列表中的行为reversed的镜像结果第 271290 行断言includefileslist(reversed(includefiles))且entries同步反转外部链接(hyperref, https://sphinx-doc.org/?qsphinx)在正常顺序下作为最后一个条目保留环境侧写第 292300 行断言app.env.toctree_includes[index]为正常顺序与反转顺序的拼接、index in app.env.glob_toctrees为真从而确认 glob 文档被登记、且该测试根目录中不涉及numbered目录树。这意味着你在自己项目中看到的目录顺序、逆序行为与警告信息都可以用同样的断言方式在 tests/test_environment/test_environment_toctree.py 中回归验证。七、实战模板与最佳实践7.1 平铺文档自动收录.. toctree:: :glob: :maxdepth: 1 *适合所有文档位于同一目录、且希望新增文件自动进入目录的场景*不匹配斜杠因此不会误收子目录内容。7.2 按前缀或子目录分组.. toctree:: :glob: intro* recipe/* api/**三个模式依次展开intro*收录以intro开头的文档recipe/*收录recipe目录下的直接子文档api/**递归收录api目录树中所有层级的文档利用**可匹配斜杠的特性。这正是官方文档示例 doc/usage/restructuredtext/directives.rst 第 206217 行的组合思路。7.3 隐藏子目录 全局导航参考本测试根目录中 qux/index.rst 的写法用:hidden:定义结构而不在页面内渲染链接配合顶层 toctree 的:includehidden:即可把隐藏树并入全局导航.. toctree:: :hidden: :glob: *7.4 更新日志置顶.. toctree:: :glob: :reversed: :maxdepth: 1 changelog/*7.5 实用建议glob 模式始终相对于包含该 toctree 指令的文档所在目录解析docname_join逻辑见 sphinx/util/init.py 第 2324 行因此嵌套目录中的 toctree 写*只匹配自己目录若同时存在普通条目与 glob 模式普通条目按书写顺序先插入glob 展开结果随后追加需要固定顺序的文档如序言请写成字面条目而非依赖排序用?与[...]可以精细控制收录范围如bar/bar_[13]只收bar_1与bar_3避免用多个*模式误收空匹配会产生警告如果某个目录暂时没有文档建议先保留占位文档或确认模式写法借助glob_toctrees的自动重读机制新增/删除文件后无需手动改动 toctree但请注意 glob 结果以构建时的found_docs为快照编译前请确认新文件确实已被扫描未被exclude_patterns排除。八、小结toctree的:glob:选项让目录树从手写维护升级为声明式自动生成它以 shell 风格通配符*、?、[...]、**匹配构建时已知的文档集合按字母序展开、支持:reversed:逆序、通过glob_toctrees在增量构建中自动重读并对空匹配、重复条目、外部链接与生成文档做了完整防护。其实现横跨 sphinx/directives/other.py指令解析、sphinx/util/matching.py模式翻译与过滤、sphinx/environment文档集合与重读登记三层并以 tests/roots/test-toctree-glob 与 tests/test_environment/test_environment_toctree.py 提供了可直接复用的验证样本。掌握了这些规则你就能在 Sphinx 项目中写出新增文档即自动入册、最新内容默认置顶的免维护目录树。赞分享文档开发工具【免费下载链接】sphinxThe Sphinx documentation generator项目地址https://gitcode.com/gh_mirrors/sp/sphinx点击查看免费下载相关推荐Sphinx autosummary 扩展实战用 :signatures: 与 :toctree: 自动生成模块摘要与文档页Sphinx autosummary 扩展实战用 :signatures: 与 :toctree: 自动生成模块摘要与文档页 本文以 Sphinx 官方仓库中文档开发工具如何用ACPI改写固件OpenCore SSDT注入与DSDT补丁完整指南如何用ACPI改写固件OpenCore SSDT注入与DSDT补丁完整指南 OpenCore bootloaderOpenCorePkg是一个用 C 语言文档开发工具Sphinx toctree 多父节点multiple parents机制解析目录树重复引用与父级选择规则实战Sphinx toctree 多父节点multiple parents机制解析目录树重复引用与父级选择规则实战 .. toctree:: 是 Sphinx文档开发工具上一篇终极指南使用ballcat实现服务网格流量镜像与A/B测试策略下一篇JavaScript栈从零构建教程打造现代化全栈开发环境创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。