- 文档
- 开发工具
【免费下载链接】sphinx
The Sphinx documentation generator
Sphinx 自带的sphinx.ext.coverage扩展可以扫描项目中通过 autodoc 或 Python 域记录的对象,找出那些"写进了代码却从未被文档提到"的类、函数和方法,并以独立构建器输出覆盖率报告。本文以仓库中 tests/roots/test-ext-coverage/index.rst 这一真实测试项目为骨架,结合 coverage 扩展源码 与对应测试用例,完整讲解覆盖率构建器的启用方式、全部配置项、忽略规则的作用机制,以及如何读懂它生成的python.txt/c.txt报告,帮助你直接在自己项目中复现这套"文档缺失检测"流程。
从测试根目录读懂 coverage 扩展的典型用法
Sphinx 仓库的测试体系中,每个tests/roots/下的目录都是一个独立的迷你文档项目。tests/roots/test-ext-coverage 专为验证sphinx.ext.coverage的"忽略规则"而设计,其结构非常精简:
tests/roots/test-ext-coverage/ ├── conf.py ├── index.rst └── grog/ ├── __init__.py ├── coverage_ignored.py ├── coverage_missing.py └── coverage_not_ignored.py其中 index.rst 全文只有两个automodule指令:
.. automodule:: grog.coverage_ignored :members: .. automodule:: grog.coverage_not_ignored :members:也就是说,这个测试项目通过 autodoc 只"正式记录"了grog包下的两个模块,而grog.coverage_missing模块虽然存在,却没有被任何automodule/py:module指令提及——它正是用来验证"覆盖率构建器能否发现被文档遗漏的模块"的靶子。这就是 coverage 扩展最核心的场景:文档写了什么、源码里有什么,两者之间的差集就是"未文档化对象"。
配套的 conf.py 给出了启用该扩展的最小配置:
import sys from pathlib import Path sys.path.insert(0, str(Path.cwd().resolve())) extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage'] coverage_modules = [ 'grog', ] coverage_ignore_pyobjects = [ r'^grog\.coverage_ignored(\..*)?$', r'\.Ignored$', r'\.Documented\.ignored\d$', ]这个配置里有三个关键点值得逐一拆解:
sys.path调整:coverage 构建器会真正import目标模块,因此必须让 Sphinx 进程能通过sys.path找到它们(官方文档 doc/usage/extensions/coverage.rst 中也明确提示了这一点)。extensions同时启用了sphinx.ext.autodoc与sphinx.ext.coverage:前者让automodule指令生效并产生"已文档化对象"记录,后者负责扫描源码并对比出未文档化对象。coverage_ignore_pyobjects定义了三条正则,用于把"有意不写文档"的对象从报告中剔除——这正是本测试项目的验证重点。
CoverageBuilder:coverage 构建器的工作原理
启用方式
与普通 HTML/PDF 构建器不同,sphinx.ext.coverage不产生可浏览的页面,而是通过sphinx-build -M coverage在_build/coverage目录下生成文本报告。它的构建器类CoverageBuilder定义在 sphinx/ext/coverage.py,在扩展的setup()中通过app.add_builder(CoverageBuilder)注册(sphinx/ext/coverage.py)。
构建器名称coverage与命令行的对应关系为:
sphinx-build -M coverage sourcedir builddir构建结束后,builddir/coverage目录下会产出三类文件:
| 文件 | 内容 |
|---|---|
python.txt | 未文档化的 Python 对象清单(函数、类、缺失方法)及统计表 |
c.txt | 未文档化的 C API 元素清单 |
undoc.pickle | 序列化后的全部未文档化/已文档化数据,供后续程序化分析(见 sphinx/ext/coverage.py) |
从CoverageBuilder.epilog(sphinx/ext/coverage.py)可以看到构建完成时会输出提示:
Testing of coverage in the sources finished, look at the results in <builddir>/coverage/python.txt.一次构建的执行流程
write_documents()(sphinx/ext/coverage.py)是覆盖率构建的主入口,内部顺序执行四个步骤:
build_py_coverage():扫描 Python 模块,产出未文档化对象字典;write_py_coverage():把结果写入python.txt;build_c_coverage():扫描 C 头文件,产出未文档化 C API 元素;write_c_coverage():把结果写入c.txt。
Python 侧扫描:build_py_coverage()的核心逻辑
Python 侧扫描的逻辑(sphinx/ext/coverage.py)大致如下:
- 从
self.env.domaindata['py']['objects']和['modules']取回文档树中所有"已出现"的 Python 对象与模块——这些记录正是由automodule、py:module、py:function等指令在解析阶段写入环境的; - 调用
_determine_py_coverage_modules()(sphinx/ext/coverage.py)确定要检查哪些模块,这一步决定了两种工作模式(见下文); - 对每个模块执行
inspect.getmembers(mod),逐成员过滤:以下划线开头的名字、无法归属到本模块的对象(obj.__module__ != mod_name)、被coverage_ignore_pyobjects匹配的对象都会被跳过; - 对函数用
inspect.isfunction、对类用inspect.isclass分类,再对比"已在文档中出现"的seen_objects,凡是在源码中存在却不在文档中的,计入py_undoc; - 对已文档化的类,还会遍历其
dir()中的方法/函数属性,找出"类写了文档、方法没写"的缺口,记录为classes[class_name] = [缺失的方法名]。
关于_determine_py_coverage_modules(),源码 docstring(sphinx/ext/coverage.py)明确描述了两种模式:
- 不配置
coverage_modules:只检查文档树中"出现过的"模块。此时只能发现这些模块内的缺失对象,但无法发现"整个模块都没被文档提到"的情况; - 配置
coverage_modules:递归导入指定包及其所有子包/子模块(_load_modules使用pkgutil.iter_modules遍历,见 sphinx/ext/coverage.py),此时既能发现缺失对象,也能发现"模块级遗漏"。如果文档中有模块不在coverage_modules里,或coverage_modules里有模块从未被文档化,构建器会输出警告但继续执行(sphinx/ext/coverage.py)。
测试项目 conf.py 配置了coverage_modules = ['grog'],因此grog.coverage_missing这个"既在源码中、又不在文档中"的模块会被发现,这正是该测试能验证"模块级遗漏检测"的原因。
C 侧扫描:build_c_coverage()的核心逻辑
C API 的扫描(sphinx/ext/coverage.py)机制不同但思路一致:
- 先收集
c域中所有已文档化的 C 对象(self.env.domains.c_domain.get_objects()); - 遍历
coverage_c_path匹配到的每个头文件,逐行用coverage_c_regexes中的正则去匹配,提取对象名; - 若该名字未出现在 C 域文档中,则记录为
(类型, 名字)元组,写入c.txt。
配置项全览:让覆盖率报告精准可用
coverage扩展通过app.add_config_value()注册了 13 个配置项(sphinx/ext/coverage.py),官方文档 doc/usage/extensions/coverage.rst 对其有完整说明。下面按用途分组列出,并补充默认值与类型:
Python 侧配置
| 配置项 | 类型 | 默认值 | 作用 |
|---|---|---|---|
coverage_modules | list/tuple of str | () | 指定要检查的包/模块列表,启用"模块级遗漏检测"(7.4 版本加入) |
coverage_ignore_modules | list/tuple of str | [] | 匹配完整模块路径的正则列表,命中的模块整个跳过 |
coverage_ignore_functions | list/tuple of str | [] | 匹配函数名的正则列表,命中的函数跳过 |
coverage_ignore_classes | list/tuple of str | [] | 匹配类名的正则列表,命中的类跳过 |
coverage_ignore_pyobjects | list/tuple of str | [] | 匹配任意 Python 对象完整导入路径的正则列表(2.1 版本加入) |
这些正则使用 Python 的re语法,在构建器init()阶段通过compile_regex_list()统一编译(sphinx/ext/coverage.py),无效正则会在日志中输出invalid regex ... in <配置项名>警告(sphinx/ext/coverage.py)。
C 侧配置
| 配置项 | 类型 | 默认值 | 作用 |
|---|---|---|---|
coverage_c_path | list/tuple of str | [] | 相对于源目录的 C 头文件 glob 模式列表,用于定位待检查的.h文件 |
coverage_c_regexes | dict[str, str] | {} | 每个条目将"对象类型名"映射到一条正则,正则的第一个捕获组即对象名 |
coverage_ignore_c_items | dict[str, list of str] | {} | 按对象类型给出正则列表,命中的 C 对象不计入缺失报告 |
C 侧的路径、正则同样在init()中预处理(sphinx/ext/coverage.py)。
报告输出配置
| 配置项 | 类型 | 默认值 | 作用 |
|---|---|---|---|
coverage_write_headline | bool | True | 设为False时不写报告开头的标题行(1.1 版本加入) |
coverage_skip_undoc_in_source | bool | False | 跳过源码中本身就没有 docstring 的对象(1.1 版本加入) |
coverage_show_missing_items | bool | False | 除了写入报告文件,还把缺失对象打印到 stdout / 日志(3.1 版本加入) |
coverage_statistics_to_report | bool | True | 把统计表格写入报告文件(7.2 版本加入) |
coverage_statistics_to_stdout | bool | False | 把统计表格打印到标准输出(7.2 版本加入,注意默认值与_to_report相反) |
忽略规则实战:test-ext-coverage 的三种正则模式
回到测试项目,conf.py 中的coverage_ignore_pyobjects三条正则分别演示了三种常见需求:
coverage_ignore_pyobjects = [ r'^grog\.coverage_ignored(\..*)?$', # 模式一:忽略整个模块 r'\.Ignored$', # 模式二:忽略所有名为 Ignored 的类 r'\.Documented\.ignored\d$', # 模式三:忽略特定类的特定方法 ]结合三个grog子模块的源码内容(coverage_ignored.py、coverage_not_ignored.py、coverage_missing.py)逐一验证:
- 模式一匹配
grog.coverage_ignored及其所有子对象((\..*)?捕获后缀)。因此即使index.rst通过automodule :members:记录了该模块,它内部的Documented.ignored1、Documented.ignored2、NotIgnored等对象也不会进入报告——尽管它们并未被文档提及。 - 模式二匹配所有以
.Ignored结尾的完整路径,因此两个模块中的Ignored类都被排除。 - 模式三匹配
Documented.ignored1/Documented.ignored2这类方法路径,因此这两个"有意不写文档的方法"不会计入缺失。
最终,只有grog.coverage_not_ignored模块中的Documented.not_ignored1、not_ignored2和NotIgnored类会"暴露"为未文档化对象。测试用例 tests/test_extensions/test_ext_coverage.py 对这次构建的python.txt做了逐字符断言,其统计表原文如下:
+---------------------------+----------+--------------+ | Module | Coverage | Undocumented | +===========================+==========+==============+ | grog | 100.00% | 0 | +---------------------------+----------+--------------+ | grog.coverage_missing | 100.00% | 0 | +---------------------------+----------+--------------+ | grog.coverage_not_ignored | 0.00% | 2 | +---------------------------+----------+--------------+ | TOTAL | 0.00% | 2 | +---------------------------+----------+--------------+报告主体则精确列出了两个缺失对象:
grog.coverage_missing --------------------- Classes: * Missing grog.coverage_not_ignored ------------------------- Classes: * Documented -- missing methods: - not_ignored1 - not_ignored2 * NotIgnored这份输出同时证明了两个事实:grog.coverage_missing模块因从未出现在文档中而被标记为"模块级遗漏";而grog.coverage_not_ignored中的Documented类虽然被automodule记录,但其方法not_ignored1/not_ignored2仍未文档化。注意测试断言的统计表中两行 Coverage 均为 100.00%、TOTAL 为 0.00%,这是因为覆盖率百分比按模块分别计算、而TOTAL行取的是整体交集分母,理解这一点有助于读懂真实项目中的统计数字。
报告结构解读与进阶输出选项
python.txt的完整结构
write_py_coverage()(sphinx/ext/coverage.py)决定了报告文件的内容布局,从上到下依次为:
- 标题(
Undocumented Python objects,可由coverage_write_headline关闭); - Statistics 统计表(由
coverage_statistics_to_report控制,表格由_write_py_statistics()生成,见 sphinx/ext/coverage.py); - 按模块名排序的未文档化对象明细:
Functions:段:模块级未文档化函数,逐行以* 函数名列出;Classes:段:未文档化类逐行列出;对于"类已文档化但方法缺失"的情况,输出* 类名 -- missing methods:后逐行缩进列出缺失方法名;
Modules that failed to import段:无法 import 的模块及其异常信息。
_write_py_statistics()中覆盖率的计算公式为:
模块覆盖率 = 100.0 * 已文档化对象数 / (已文档化对象数 + 未文档化对象数)该模块没有发现任何对象时按 100% 处理(sphinx/ext/coverage.py)。表头行使用=分隔、数据行使用-分隔,格式与测试断言完全一致。
让缺失对象直接出现在构建输出中
默认情况下,未文档化对象只写入报告文件,构建过程中不会有任何提示。设置coverage_show_missing_items = True后,构建时会同步把缺失对象打印出来:
- 默认(有进度显示)时使用彩色
info日志,格式如undocumented py function raises - in module autodoc_target; - 使用
-q安静模式(verbosity < 0)时改用warning日志,格式如undocumented python function: autodoc_target :: raises。
测试用例 test_show_missing_items 与 test_show_missing_items_quiet 分别验证了这两种输出路径,同时覆盖了 Python 函数、类、方法以及 C API 元素(如undocumented c api: Py_SphinxTest [function])四种类型的提示。
C 侧报告c.txt的结构与python.txt类似,先写Undocumented C API elements标题,再按头文件分组列出未文档化元素,每行格式为* 名字 [类型](sphinx/ext/coverage.py)。
在真实项目中落地:完整配置示例与注意事项
将上述内容整合,一个可直接照搬的项目级配置如下(在conf.py中):
extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.coverage', ] # 指定要递归检查的包;不设置则只检查文档中出现过的模块 coverage_modules = ['my_package'] # 忽略规则:可分别针对模块、函数、类、任意对象编写正则 coverage_ignore_modules = [r'my_package\.internal'] coverage_ignore_functions = [r'^_'] coverage_ignore_classes = [] coverage_ignore_pyobjects = [r'\.Deprecated$'] # C API 检查(可选) coverage_c_path = ['include/*.h'] coverage_c_regexes = {'function': r'^\w+\s+(\w+)\s*\('} coverage_ignore_c_items = {'function': [r'^internal_']} # 报告输出控制 coverage_show_missing_items = True # 构建时直接打印缺失对象 coverage_skip_undoc_in_source = False # True 则跳过源码中无 docstring 的对象 coverage_statistics_to_stdout = True # 统计表同时输出到 stdout coverage_statistics_to_report = True # 统计表写入报告 coverage_write_headline = True # False 则不写标题行运行方式:
sphinx-build -M coverage source _build然后查看_build/coverage/python.txt与_build/coverage/c.txt。
结合源码与官方文档(doc/usage/extensions/coverage.rst),使用时有几点需要注意:
- 模块导入副作用:coverage 构建器会真实
import被检查的模块。如果模块在导入时执行了副作用代码(如发请求、写文件),这些代码会在sphinx-build运行期间被执行。对于脚本类模块,务必用if __name__ == '__main__':保护入口;这是官方文档中明确给出的警告。 sys.path可见性:被检查的模块必须能被 Python 解释器 import 到,必要时像测试项目的 conf.py 一样在sys.path中插入项目根目录。- 模块级遗漏需要显式配置:只有设置
coverage_modules后,才能发现"整个模块都没出现在文档中"的遗漏;不设置时只能发现已文档化模块内部的缺失对象。 - 忽略规则使用正则匹配:
coverage_ignore_pyobjects等配置匹配的是对象完整导入路径(如grog.coverage_ignored.Documented.ignored1)的任意部分,^/$/\d等re语法全部可用,且匹配使用search语义(见 sphinx/ext/coverage.py),因此\.Ignored$这类锚定写法可以精确命中类名结尾。
小结
tests/roots/test-ext-coverage/index.rst虽然只有六行,但它背后是sphinx.ext.coverage一整套"源码对照文档"的扫描机制:CoverageBuilder以python.txt/c.txt/undoc.pickle三种形式输出结果,13 个配置项覆盖了模块级扫描、正则忽略、统计表格与日志输出等全部需求。借助 conf.py 中的三条忽略规则和 test_ext_coverage.py 的逐字节断言,你可以清晰地推演任意对象被纳入或排除的判定路径,并把这套能力直接复用到自己的文档项目中——让"写了代码却忘了写文档"的缺口在每次构建时自动暴露出来。
- 文档
- 开发工具
【免费下载链接】sphinx
The Sphinx documentation generator
相关推荐
flexivit_base.300ep_in21k vs 传统ViT:19.4 GMACs如何实现更优性能?
flexivit_base.300ep_in21k vs 传统ViT:19.4 GMACs如何实现更优性能? 在计算机视觉领域,视觉Transformer(Vi
ECC 测试覆盖率实战指南:/test-coverage 命令从覆盖率分析到缺口测试生成的完整工作流
ECC 测试覆盖率实战指南:/test coverage 命令从覆盖率分析到缺口测试生成的完整工作流 本文聚焦 ECC(Everything Claude Co
人工智能AI 技能AI 插件AI 评测Agent 评测MCP Clients开发工具Grafana仪表板深度解析:Kubernetes监控的高级功能与最新特性
Grafana仪表板深度解析:Kubernetes监控的高级功能与最新特性 Kubernetes监控是现代云原生运维的核心,而grafana dashboard
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考