Sphinx 4.0 版本演进全解析:核心特性、破坏性变更与修复清单
Sphinx 4.0 版本演进全解析:核心特性、破坏性变更与修复清单
Sphinx 4.0 是 Sphinx 文档生成器的重要里程碑版本,带来 C 领域关键字解析增强、Python 领域 canonical 机制、autodoc 类型注解能力升级,以及 MathJax 3 迁移等一系列关键变化。本文基于 doc/changes/4.0.rst 变更日志,结合当前仓库源码与配置文档,系统梳理 4.0 系列(4.0.0 → 4.0.3)的新特性、不兼容变更、弃用项与修复内容,帮助升级用户快速评估影响面并完成迁移。
Sphinx 4.0 系列于 2021 年 5 月正式发布(4.0.0 于 2021-05-09,随后在 5 月、7 月相继发布 4.0.1、4.0.2、4.0.3 补丁版本)。这一版本包含三个 beta 迭代(4.0.0b1/b2/b3),大量特性与变更在 beta 阶段即已确定,补丁版本主要聚焦修复。以下按版本逐层展开。
Sphinx 4.0.3:C 领域关键字扩展与回归修复
4.0.3(2021-07-05 发布)是 4.0 系列的最后一个补丁版本,重点完善了 C 领域的语法解析能力,并修复了 4.0 引入的几个回归问题。
新增特性
C23 关键字支持与 c_extra_keywords 配置项
Sphinx 的 C 领域解析器在 sphinx/domains/c/_ids.py 中维护了一份 C 语言关键字表。4.0.3 为这份表补充了 C23 标准新增的关键字 _Decimal32、_Decimal64 和 _Decimal128:
# sphinx/domains/c/_ids.py
_keywords: Set[str] = frozenset({
...
'_Decimal32', '_Decimal64', '_Decimal128',
'_Generic',
...
})
同时新增配置项 c_extra_keywords,允许用户自定义解析器识别为关键字的标识符。在 sphinx/domains/c/init.py 中,该配置的默认值被设为 _macro_keywords:
app.add_config_value(
'c_extra_keywords',
_macro_keywords,
'env',
types=frozenset({frozenset, list, set, tuple}),
)
_macro_keywords 包含只有在包含对应头文件时才具有关键字语义的宏名(见 sphinx/domains/c/_ids.py):
_macro_keywords: Set[str] = frozenset({
'alignas', 'alignof', 'bool', 'complex',
'imaginary', 'noreturn', 'static_assert', 'thread_local',
})
这些标识符(如 alignas、static_assert)严格来说不是 C 语言保留字,而是 <stdalign.h> 等头文件定义的宏,因此默认被当作"准关键字"处理。文档 doc/usage/configuration.rst 给出了完整说明:该配置项类型为 Set<a href="https://link.gitcode.com/i/b8bbea6d1401a6c56afb8d6a9bb85126" target="_blank">str] | Sequence[str],默认值为这 8 个宏名,在 4.0.3 中引入,并在 7.4 版本起允许使用 set 类型。解析器在 [sphinx/domains/c/_parser.py 中检查匹配文本是否为配置的关键字,若用户自定义的关键字与代码中实际使用的标识符冲突,会给出明确错误提示。
# 用法示例(conf.py)
c_extra_keywords = ['my_keyword', 'your_keyword']
修复的 Bug
4.0.3 修复了以下问题:
- #9330:changeset 领域中
versionchanged指令的内容为列表时,PDF 构建会报错; - #9313:LaTeX 构建中,带合并单元格的复杂表格自 4.0 起损坏,本版本修复;
- #9305:使用日文引擎构建 PDF 时,反斜杠可能引发 "Improper discretionary list" 错误;
- #9354:将特殊宏名从关键字列表中移除(呼应
c_extra_keywords的引入,把 "类关键字宏" 的处理交给用户配置); - #9322:
PropagateDescDomain变换触发KeyError。
Sphinx 4.0.2:Jinja2 3.0 兼容与 manpage 目录行为修正
4.0.2(2021-05-20 发布)以兼容性修正为主。
依赖变更
- #9216:支持 Jinja2 3.0。此前 Sphinx 与 Jinja2 3.0 存在兼容问题,4.0.2 完成适配;
- #9222:将 Underscore.js 升级到 1.13.1(HTML 主题依赖的 JavaScript 库)。
不兼容变更
- #9217:manpage 构建默认不再创建节(section)目录。这一行为通过配置项
man_make_section_directory控制(详见下文 4.0.0 部分),4.0.2 将默认值恢复为原先行为。
修复的 Bug
- #9210:并行构建时,viewcode 遇到不可导入的模块会崩溃;
- #9240:当安装了不支持
pending_xref_condition节点的扩展并注册了 missing-reference 处理器时,会抛出未知节点(Unknown node)错误。
Sphinx 4.0.1:autodoc 与 i18n 修复
4.0.1(2021-05-11 发布)是 4.0.0 发布两天后的快速修复版本,全部为 Bug 修复:
- #9189:autodoc 在从类属性(property)生成签名时抛出
ValueError会崩溃; - #9188:
autosummary_generate设置为列表值时发出警告; - #8380:HTML 搜索结果标签损坏;
- #9198:i18n 在运行
compile_catalog时 Babel 报错; - #9205:Python 领域
:canonical:选项导致 "more than one target for cross-reference" 警告; - #9201:websupport 抛出
UndefinedError: 'css_tag' is undefined。
Sphinx 4.0.0 主版本:不兼容变更全景
4.0.0(2021-05-09 发布)是包含大量破坏性变更的主版本,涉及 Python 版本支持、Docutils 依赖、HTML 输出、LaTeX 引擎、Python 领域等多个方面。升级前务必逐项核对。
依赖与运行环境变化
4.0.0 的依赖调整分为两个 beta 阶段:
4.0.0b1:
- 移除 Python 3.5 支持;
- 移除 Docutils 0.12 和 0.13 支持;
- LaTeX 新增
tex-gyre字体依赖。
4.0.0b2:
- 支持 Docutils 0.17。注意:Docutils 0.17 改变了 HTML builder 的输出,部分主题不兼容,升级时需要更新自定义 CSS。
关键不兼容变更清单
以下变更按影响面分类梳理:
autodoc 与类型注解
- #8539:当同时设置
autodoc_typehints='description'与autoclass_content='class'时,info-field-list 会生成到类描述中; - #7383:autodoc 支持为 property(属性)生成类型注解;
- #5603:允许通过 canonical 名称引用同时拥有规范名与别名的 Python 类;
- #8539:新增配置项
autodoc_typehints_description_target,用于控制autodoc_typehints=description的行为; - #8841:
autodoc_docstring_signature在没有反斜杠续行的情况下也能继续查找多行签名; - #8924:autodoc 支持
TypeVar的bound参数。
Python 领域(py domain)
- #4826:Python 对象结构改变——增加一个布尔值用于标记对象是否为 canonical(规范)对象;
- #4826:为 Python 指令新增
:canonical:选项,用于描述对象定义的位置; - #7199:新增
py:property指令,用于描述 property; - #7199:新增配置项
python_use_unqualified_type_names(实验性),当引用可以解析时抑制 Python 引用的模块名; - #5977:
:var:、:cvar:和:ivar:字段不再创建交叉引用; - #8127:info-field-list 中的省略号(Ellipsis)会触发 nitpicky 警告(b2 修复)。
HTML 输出与主题
- #7849:
html_codeblock_linenos_style默认值改为'inline'; - #8380:搜索结果由
<div>包裹改为<p>包裹; - 基础主题 layout.html 中
documentation_options.js的 script 标签移入script_files变量; - 基础主题 layout.html 中的 CSS 标签移入
css_files变量; - #8915:对
sphinx_rtd_theme0.2.4 及更早版本发出警告; - #9023:更改
cpp:expr与cpp:texpr的 CSS 类(b2)。
LaTeX
- #8508:日文文档的
latex_engine默认设置为 uplatex; - #8769:LaTeX 重构——
sphinx.sty拆分为多个文件,并重命名latex构建输出目录中的部分辅助文件; - #8937:使用显式标题替代
<no title>。
i18n 与其他
- #7784:图片 alt 文本的 msgid 改变,且默认翻译(无需
gettext_additional_targets设置); - #4550:
figure与table节点的align属性默认值由'default'改为None; - #8487:csv-table 指令的
:file:选项现在把绝对路径当作相对于源目录的路径处理; - #8326:
master_doc更名为root_doc; - #8201:toctree 包含重复条目时发出警告;
- #8342:为指令或角色指定未知领域时发出警告(如
:unknown:doc:); - #8898:extlinks 的链接标题字符串中
%s成为必需关键字(同时支持%s出现在链接标题中); - domain 的
Index类成为abc.ABC的子类,明确指示具体类必须覆盖的方法。
man_make_section_directory:一次默认值往返
manpage 目录行为的变更值得单独说明。该配置项在 3.3 引入(见 doc/changes/3.3.rst),4.0.0 将其默认值从 True 改为 False(不再创建节目录),4.0.2 又恢复为 True(见 doc/usage/configuration.rst)。
当前仓库中 sphinx/builders/manpage.py 的实现展示了该配置对输出路径的实际影响:
if self.config.man_make_section_directory:
dirname = 'man%s' % section
ensuredir(self.outdir / dirname)
targetname = f'{dirname}/{name}.{section}'
else:
targetname = f'{name}.{section}'
即当配置为 True 时,manpage 输出为 man{section}/{name}.{section} 形式;为 False 时直接输出 {name}.{section}。当前默认值为 True。该配置在 sphinx/builders/manpage.py 中注册:
'man_make_section_directory', False, '', types=frozenset({bool})
(注意注册处的默认参数 False 是 4.0.2 之后的最终值,文档中标注的默认值为 True 的差异以实际发布版本为准——这一往返变化本身正是升级时需要留意的典型不兼容点。)
弃用项(Deprecated)清单
4.0.0 正式弃用以下内容,升级到后续版本(尤其是 5.0)前应逐步清理:
| 弃用项 | 说明 |
|---|---|
html_codeblock_linenos_style |
HTML 代码块行号样式配置 |
favicon 与 logo 模板变量 |
HTML 模板变量 |
sphinx.directives.patches.CSVTable |
指令补丁 |
sphinx.directives.patches.ListTable |
指令补丁 |
sphinx.directives.patches.RSTTable |
指令补丁 |
DocumenterBridge.filename_set |
autodoc 内部接口 |
DocumenterBridge.warn() |
autodoc 内部接口 |
SphinxComponentRegistry.get_source_input() |
组件注册表接口 |
SphinxComponentRegistry.source_inputs |
组件注册表接口 |
sphinx.transforms.FigureAligner |
变换类 |
sphinx.util.pycompat.convert_with_2to3() |
兼容工具函数 |
sphinx.util.pycompat.execfile_() |
兼容工具函数 |
sphinx.util.smartypants |
工具模块 |
sphinx.util.typing.DirectiveOption |
类型定义 |
4.0.0 新增特性详解
autodoc:类型注解体系全面增强
4.0.0 是 autodoc 类型注解能力的分水岭。除上文列出的 autodoc_typehints_description_target 配置与 TypeVar bound 支持外,还包含:
- #7383:property 类型注解支持,允许在文档中直接呈现类属性的类型;
- #5603:canonical 名称引用,类存在别名时可按规范名引用;
- #8818(b2):超类包含
Any参数时不再触发 nitpicky 警告; - #9095(b2):处理损坏的 metaclass 时不再抛出
TypeError; - #9110(b2):
GenericAlias元数据在 py37+ 下作为引用渲染。
Python 领域:canonical 机制与实验性类型名优化
:canonical:选项与python_use_unqualified_type_names配置的加入,让文档作者能够更精确地控制 Python 对象定位与类型名展示;py:property指令补全了 Python 领域对 property 的描述能力;- #9121(b2):当 canonical 对象与其别名对象同时定义在文档中时,不再重复发出警告。
MathJax 2 → 3 迁移
- #7425:MathJax 从 2 升级到 3。使用自定义 MathJax 配置的用户需要将旧的 MathJax 路径指向 3,或更新配置;
- #8195(b2):
mathjax_config重命名为mathjax2_config,并新增mathjax3_config,对应两代 MathJax 的独立配置入口(详见 sphinx/ext/mathjax.py)。
HTML 搜索与主题
- #8070:支持搜索 2 字符单词;
- #9036:允许继承搜索页面;
- #2018:
html_favicon与html_logo接受 URL 形式的图片地址; - #8905(b1 修复):
html_add_permalinks=None与html_add_permalinks=""不再被忽略。
其他特性
- #7199:新增节点
sphinx.addnodes.pending_xref_condition,可按条件选择合适的引用内容; - #8942:C++ 支持 C++20 三路比较运算符
<=>(spaceship operator); - #8938:imgconverter 显示命令可用性检查的错误信息;
- #7830:为源码与模板变更检测添加调试日志;
- #7549:autosummary 的
autosummary_generate默认启用。
4.0.0 修复的 Bug(按构建目标归纳)
LaTeX 相关(数量最多,反映 4.0 对 LaTeX 后端的大量重构):
- #7241:
cpp:enumerator不换行; - #8711:代码块中的反引号在 TeXLive 2019 下触发 pdf 构建警告并改变字体;
- #8253:未指定尺寸的图片被过度放大(仅对
pdflatex/lualatex修复); - #8881:PDF 书签面板深度不足以支撑导航;
- #8874:Pygments LaTeXFormatter 两处输出问题忽略 Pygments 样式;
- #8925:3.5.0 的
verbatimmaxunderfull设置未按预期工作; - #8980:
\pysigline缺少换行; - #8995:旧版
\pysiglinewithargsret的水平空间计算错误,应使用 ragged right 样式; - #9009:release 值含下划线导致无效 LaTeX。
C/C++ 领域相关:
- #8911:
cpp_index_common_prefix改为移除最长匹配前缀而非首个匹配; - 正确拒绝将关键字用作参数名的函数声明;
- #8933:viewcode 在并行构建下无法创建回链;
- #8960:修复函数参数列表中(成员)函数指针类型的渲染;
- 修复数组声明符、指向成员(函数)的指针声明符及
sizeof...参数中的名称链接; - C 领域数组声明符中的名称链接修复;
- b2:当
alias指令是文件中第一个 C/C++ 指令、且其后还有其他 C/C++ 指令时,不再抛出KeyError。
HTML 相关:
- #9098(b2):Safari 中 doctest 的 copy-range 保护不生效;
- #9167(b3):特定页面添加 CSS 文件失败;
- #8915:
sphinx_rtd_theme的翻译失效。
autodoc 相关:
- #8917:函数
__globals__值错误时发出警告; - #8415:从其他模块导入的 TypeVar(Python 3.7+)无法解析;
- #8992:无法解析
types.TracebackType类型注解。
升级到 Sphinx 4.0 的实践建议
结合上述变更,从 3.x 升级到 4.0 时可参考以下检查清单:
- 确认运行环境:Python ≥ 3.6(3.5 已移除),Docutils ≥ 0.14 且建议升级到 0.17(注意 HTML 输出变化);
- 检查 LaTeX 构建:日文文档默认引擎变为 uplatex;
sphinx.sty已拆分重构,依赖旧辅助文件的脚本需要调整; - 核对 manpage 输出结构:
man_make_section_directory的默认值在 4.0.0 与 4.0.2 间发生往返变化,请以实际安装版本的行为为准; - 审查 Python 领域文档:
:canonical:新选项、py:property指令、python_use_unqualified_type_names(实验性)按需启用;:var:等字段不再生成交叉引用; - 迁移 MathJax:使用自定义 MathJax 配置的站点需切换到
mathjax3_config(或保留mathjax2_config); - 更新主题与 CSS:Docutils 0.17 改变 HTML 输出;基础主题的脚本/CSS 标签位置变化;检查是否依赖已弃用的模板变量
favicon/logo; - 替换弃用 API:对照上文弃用清单,清理
sphinx.util.smartypants、pycompat相关函数等调用; - 关注 C/C++ 领域:若文档涉及 C23 关键字或自定义宏名,可用
c_extra_keywords灵活配置(4.0.3+)。
结语
Sphinx 4.0 是一个"承上启下"的版本:它完成了 MathJax 3、Docutils 0.17、Jinja2 3.0 等关键依赖的现代化,重构了 LaTeX 后端与 Python 领域结构,也为后续 5.0 的大规模弃用清理铺平了道路。理解 4.0 系列逐版本的变化脉络(尤其是 4.0.0 的破坏性变更、4.0.2 的默认值回调、4.0.3 的 C 领域完善),是平滑升级与正确解读后续版本变更日志的基础。相关细节可继续查阅 doc/changes/ 目录下的系列变更记录。