- 测试
- 开发工具
【免费下载链接】hypothesis
The property-based testing library for Python
导读
Hypothesis 是一个基于属性的 Python 测试库,其持续交付依赖一套严格的"单文件驱动发布"机制:每一次代码变更都必须伴随一份由贡献者撰写的RELEASE.rst,描述该变更对公共 API 的影响,随后由 CI 工具链自动完成版本递增、changelog 生成与 PyPI 发布。本文以仓库中的模板文件 RELEASE-sample.rst 为骨架,完整解析该模板的每一行语义、SemVer 版本判定规则、Sphinx 交叉引用指令的用法,并结合 release.py 源码与配套测试,带你从"照着填模板"进阶到"理解整条发布流水线",从而为 Hypothesis 贡献代码时一次通过发布检查。
一、RELEASE-sample.rst 在仓库中的定位
在 Hypothesis 仓库中,贡献者提交 PR 时并不直接编辑docs/changelog.rst,而是写入位于hypothesis/目录下的RELEASE.rst。为了让贡献者知道该写什么、怎么写,仓库提供了模板文件RELEASE-sample.rst。两者关系如下:
| 文件 | 作用 |
|---|---|
| RELEASE-sample.rst | 只读模板/样例,永远保留在仓库中供参考 |
| RELEASE.rst | 实际发布描述文件,由贡献者按模板复制创建 |
| changelog.rst | 官方 changelog,PR 合并后自动吸收RELEASE.rst的内容 |
这一点在工具源码中有硬性保证:release.py 分别将RELEASE.rst、RELEASE-sample.rst、docs/changelog.rst定义为三个关键路径常量,而配套测试 test_release_files.py 明确要求:RELEASE-sample.rst 必须存在且只能被复制(copy)而不能被移动(move)到 RELEASE.rst,否则直接判为测试失败。
二、第一行:RELEASE_TYPE 与语义化版本判定
模板第一行是发布类型的声明:
RELEASE_TYPE: patch模板正文随后解释:当变更对公共 API 可见时,将patch替换为minor;当存在破坏性变更时替换为major;并且major 版本只能由维护者(maintainers)发布,普通贡献者不应发起 major 发布。
源码中的解析与校验
从源码看,第一行并非自由文本,而是被严格校验的:
- release.py 定义了正则
^RELEASE_TYPE: +(major|minor|patch)与合法取值集合("major", "minor", "patch"); - parse_release_file_contents() 会读取文件首行并匹配该正则,若首行缺失或类型不在集合内,直接抛出
ValueError并给出明确提示(应如何书写第一行); - 解析成功后,第一行会被从正文中剔除,剩余内容即 changelog 正文。
测试 test_release_management.py 专门验证了非法输入(如RELEASE_TYPE: wrong、空文件)会抛出ValueError,合法输入(patch/minor/major及各种空白布局)则被正确解析。
版本号如何被递增
bump_version_info() 实现了语义化版本递增逻辑:
patch:第三位 +1(如6.168.0→6.168.1);minor:第二位 +1,后续位清零(如6.167.1→6.168.0);major:第一位 +1,后续位清零。
测试 test_bump_minor_version() 验证了(1, 1, 1)在minor下得到1.2.0,与语义化版本约定完全一致。注意当前版本号并非维护在version.py中,而是由 Rust 原生模块提供(见 version.py),发布时通过 cargo.write_version() 同步更新 Cargo.toml 与锁文件。
三、changelog 正文的写作规范
模板中第一行之后的所有内容,就是本次发布的 changelog 文本。模板给出了三条硬性规范:
- 聚焦公共 API:简洁描述"公共 API 发生了什么变化、为什么"。内部实现的变化可以写成类似 "This release improves an internal invariant."(该写法取自 6.99.11 版本的完整 changelog)。
- verbatim 代码用双反引号:例如
from_type、hypothesis.extra.*,以便 Sphinx 正确渲染成行内代码。 - 涉及函数或类必须使用 Sphinx 交叉引用,而非裸写名称或外部链接。
模板中的示例正文是:
This patch improves import-detection in the Ghostwriter (:issue:`3884`), particularly for from_type and strategies from hypothesis.extra.*.这展示了两种典型写法:用:issue:关联 issue 编号;正文中引用 API 名称时保持与文档一致的可读描述。真实的成功案例可参考当前仓库中的 RELEASE.rst(例如We now publish abi3 wheels for Linux s390x (manylinux) and Linux i686 (musllinux).——一句话讲清发布内容,不啰嗦)。
四、Sphinx 交叉引用指令完整参考
模板后半部分集中列出了所有允许使用的 Sphinx 交叉引用指令,这是本模板最具技术含量的部分,逐条拆解如下:
| 指令 | 用途 | 示例效果 |
|---|---|---|
:pypi:package`` | 链接到外部 PyPI 包 | 链接文本为包名 |
:func:package.function`` | 链接到函数 | 链接文本为package.function |
:func:~package.function`` | 链接到函数(缩写) | 链接文本仅显示function |
:class:package.class`` | 链接到类 | 可同样用~缩写 |
:issue:issue-number`` | 引用 GitHub issue | 渲染为 issue 链接 |
:pull:pr-number`` | 引用 PR | 通常不首选 |
:v:6.98.9`` | 引用版本号 | 指向 changelog 对应锚点,对最终用户更有意义 |
:doc:link text <chapter#anchor>`` | 引用文档章节 | 指向文档内锚点 |
link text <https://...>__ | 通用 Web 地址 | 双层下划线结尾的显式链接 |
其中:v:角色并非 Sphinx 内置,而是 Hypothesis 在 conf.py 中自定义的版本引用角色,它会将版本号渲染为指向changelog.html#vX.Y.Z锚点的链接。模板特别提示:引用 PR 时优先用:v:引用版本号而非:pull:,因为版本号对最终用户更有意义。
五、致谢与首次贡献者清单
模板要求 changelog 正文以维护者的感谢语结尾,格式为:
Thanks to <contributor's name or handle> for this <contribution/fix/feature>!同时提醒:如果是首次贡献,别忘了把自己加入 AUTHORS.rst。这是开源项目维护贡献者名单的标准做法,该文件位于仓库根目录。
六、PR 合并后的自动化发布管线
模板末尾的关键说明是:"After the PR is merged, the contents of this file (except the first line) are automatically added todocs/changelog.rst."。结合源码,这条"自动"路径实际由 do_publish() 串联完成:
- 解析并更新版本:update_changelog_and_version() 解析
RELEASE.rst得到发布类型,调用bump_version_info计算新版本号,并写入 changelog 顶部——新条目以.. _vX.Y.Z:锚点开头,配-构成的边框线与X.Y.Z - YYYY-MM-DD标题行(格式由 CHANGELOG_ANCHOR/CHANGELOG_BORDER/CHANGELOG_HEADER 三个正则约束); - 同步元数据:更新 Cargo.toml 与锁文件(cargo.write_version())、替换源码中的
since="RELEASEDAY"占位日期(release.py)、重写 pyproject.toml 的allextras 与 README 内嵌内容; - 提交并打 tag:commit_pending_release() 移除
RELEASE.rst并提交(commit message 含[skip ci]),随后git tag vX.Y.Z并推送; - 发布产物:上传 sdist/wheel 到 PyPI(upload_distribution_to_pypi(),要求
ACTIONS_ID_TOKEN_REQUEST_TOKEN环境变量以启用 trusted publishing),并创建 GitHub release 触发 Zenodo DOI 生成(create_github_release(),需要GH_TOKEN)。
此外,文档构建也直接依赖RELEASE.rst:changelog.rst 通过.. only:: has_release_file指令与.. include:: ../RELEASE.rst把"当前 PR 的发布说明"实时嵌入文档,而 conf.py 的setup()会在检测到RELEASE.rst存在时向 Sphinx 添加has_release_filetag——这就是为什么模板要求"复制而非移动":文件必须常驻仓库,文档构建才能正确开关该区块。
七、发布文件的自动检查与防回归保障
整仓测试对发布文件有一套"零容忍"检查,理解这些检查能帮你一次通过 CI:
- test_release_files.py 的
test_release_file_exists_and_is_valid:只要源码(hypothesis/src)有变更,就必须存在RELEASE.rst,且其内容必须能被parse_release_file()成功解析,否则构建直接失败; - 同文件的
test_release_file_has_no_merge_conflicts:禁止<<<合并冲突残留;发布说明不得与最近 12 个版本中的任意一条重复(防重复发布),也不得反向包含(防复制粘贴 merge 错误);自动更新消息(如升级依赖、更新 TLD 列表时由 get_autoupdate_message() 自动生成的模板文本)例外放行。
这意味着:提交 PR 前请务必检查git status中是否有hypothesis/src下的改动;若有,则必须照模板新建RELEASE.rst,否则会卡在发布检查环节。
八、从模板到实战:一份合格 RELEASE.rst 的核对清单
综合模板规范与源码约束,写一份合格发布说明可对照以下清单:
- 首行
RELEASE_TYPE: patch(或minor;major仅限维护者); - 一句话说清公共 API的变化及原因,内部改动用 "This release improves an internal invariant." 这类表述;
- 代码标识用双反引号包裹;
- 函数/类引用使用
:func:/:class:(需要缩写时加~); - issue 用
:issue:,PR 用:pull:,版本引用优先用:v:; - 外部包用
:pypi:,文档章节用:doc:; - 以感谢语结尾,首次贡献者加入
AUTHORS.rst; - 不要包含合并冲突标记,不要复制已发布版本的旧文本。
遵循这套流程写出的发布说明,会在 PR 合并后自动变成docs/changelog.rst中最顶部那条带锚点的正式记录——正如 changelog.rst 中6.168.0 - 2026-09-08条目所展示的最终形态,你在模板里写的每一行,最终都会成为数百万用户阅读的官方发布历史。
- 测试
- 开发工具
【免费下载链接】hypothesis
The property-based testing library for Python
相关推荐
Hypothesis 的 RELEASE.rst 发布说明机制:从补丁记录到版本发布的完整工作流
Hypothesis 的 RELEASE.rst 发布说明机制:从补丁记录到版本发布的完整工作流 导读 Hypothesis 是 Python 生态中最具影响力
测试开发工具Hypothesis 文档写作与 Changelog 规范:从 Sphinx 交叉引用到 RELEASE.rst 发布条目实战指南
Hypothesis 文档写作与 Changelog 规范:从 Sphinx 交叉引用到 RELEASE.rst 发布条目实战指南 导读 本文基于 Hypoth
测试开发工具Hunk 发布说明生成管线:从 CHANGELOG.md 到 hunk.dev/changelog 的自动化实践
Hunk 发布说明生成管线:从 CHANGELOG.md 到 hunk.dev/changelog 的自动化实践 导读:Hunk 以每两周约两次的节奏发布数十个
开发工具代码评审CLIAI 应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考