Hydra 发布流程实战指南:从版本号维护、towncrier 变更记录到 PyPI 打包上传
2026/9/16 16:24:37 网站建设 项目流程

Hydra 发布流程实战指南:从版本号维护、towncrier 变更记录到 PyPI 打包上传

【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra

本篇技术指南围绕 Hydra 官方仓库中 1.0 版本的发布流程文档 展开,完整梳理 Hydra 版本发布的核心操作链路:检出发布分支、更新版本号、用 towncrier 生成变更记录、构建 pip 包并上传 PyPI。文章结合仓库源码(版本读取、打包命令、towncrier 配置)逐层深入,帮助维护者或对 Hydra 工程实践感兴趣的读者掌握一套可复制的 Python 开源项目发布方法论,同时了解该流程在后继版本中如何演进为工具化、自动化。

一、文档定位:Hydra 1.0 时代的五步发布流程

version-1.0 发布流程文档 是一份非常精炼的维护者操作手册,全文只有五个步骤,原文如下:

  1. 检出 master 分支(Checkout master)
  2. hydra/__init__.py中更新 Hydra 版本号
  3. 使用 towncrier 更新NEWS.md
  4. 为 hydra-core 创建 pip 包:python setup.py sdist bdist_wheel
  5. 上传 pip 包:python -m twine upload dist/*

文档同时注明"发布流程未来可能自动化"(The release process may be automated in the future)。这份文档的价值在于它完整勾勒了 Python 开源项目手工发布的黄金流程——尽管后续 Hydra 已将其升级为基于tools/release/release.py与 GitHub Actions 的自动化发布(详见 当前发布文档),但"版本号单一来源 + 变更记录自动生成 + 标准打包上传"的核心思想一脉相承。下文将逐步拆解每一步的底层实现与仓库证据。

二、第一步:从干净分支开始(Checkout master)

发布必须基于一个干净、经过充分测试的分支。在 1.0 时代,Hydra 的默认主干分支名为master;在当前的仓库中,CONTRIBUTING.md 已改为要求"从main创建功能分支",主干分支更名为main

# 获取最新代码(以当前仓库为例) git clone https://gitcode.com/GitHub_Trending/hyd/hydra cd hydra git checkout master # 1.0 时代的主干分支;当前仓库请使用 main git pull --ff-only

分支纪律是发布质量的第一道防线:只有通过持续集成验证的提交才应进入发布流程,任何未合并的功能、未完成的重构都不应出现在发布分支上。

三、第二步:更新版本号——hydra/__init__.py是唯一事实来源

文档明确要求更新hydra/__init__.py中的版本号。查看当前仓库的 hydra/init.py:

# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved # Source of truth for Hydra's version __version__ = "1.4.0.dev9" from hydra import utils ...

文件头部用注释标注了# Source of truth for Hydra's version(Hydra 版本号的唯一事实来源),这正是整个发布流程的锚点。

3.1 setup.py 如何消费这个版本号

setup.py 并不硬编码版本,而是通过build_helpers中的find_version()__init__.py正则提取:

version=find_version("hydra", "__init__.py"),

build_helpers/build_helpers.py 中find_version的实现:

def find_version(*file_paths: str) -> str: with codecs.open(os.path.join(*file_paths), "r") as fp: version_file = fp.read() version_match = re.search(r"^__version__ = '\"['\"]", version_file, re.M) if version_match: return version_match.group(1) raise RuntimeError("Unable to find version string.")

这意味着:只改hydra/__init__.py一处,setup.py构建出的包元数据就会自动携带新版本号,彻底避免"源码版本与包版本不一致"的经典事故。这也是"单一事实来源(Single Source of Truth)"原则在发布工程中的典型应用。

3.2 版本号的拼写规范

Hydra 采用 PEP 440 版本语法,例如1.4.0.dev91.4.0rc11.4.01.4.1。当前发布文档进一步明确了发布类型的推导规则:

  • .devN后缀 → 开发版(dev release)
  • rcN后缀 → 发布候选版(release candidate)
  • x.y.0→ 正式稳定版
  • x.y.z(z>0)→ 补丁版(patch release)

从 hydra/version.py 可以看到仓库对版本字符串的解析正则,用于主/次版本号提取,这从侧面印证了版本字符串在 Hydra 运行时中也被广泛消费。

3.3 插件包的版本管理

hydra-core 之外,仓库中的各插件(如 hydra_optuna_sweeper、hydra_submitit_launcher)各自拥有独立的包与版本号,定义在hydra_plugins/<plugin>/__init__.py中。在协调发布(coordinated release)时,核心与所有插件需要同步提升版本,这一需求后来催生了 release.py 中的action=set_versionset=hydra-full-release机制(见本文第七节)。

四、第三步:用 towncrier 更新 NEWS.md

"Update NEWS.md with towncrier"是文档给出的第二步,其含义是:使用 towncrier 工具把散落在news/目录下的变更片段(news fragment)汇总渲染进NEWS.md

4.1 towncrier 配置:全部定义在 pyproject.toml

pyproject.toml 中[tool.towncrier]段完整声明了 Hydra 的变更记录管线:

[tool.towncrier] package = "hydra" package_dir = "" filename = "NEWS.md" directory = "news/" title_format = "{version} ({project_date})" template = "news/_template.rst" issue_format = "[#{issue}](https://github.com/hydra-ecosystem/hydra/issues/{issue})" start_string = "<!-- TOWNCRIER -->\n"

关键字段说明:

  • directory = "news/":变更片段存放目录,即仓库根目录下的 news/ 文件夹;
  • filename = "NEWS.md":渲染结果写入的发布说明文件,即仓库根目录的 NEWS.md;
  • title_format = "{version} ({project_date})":每个版本标题的格式,例如1.3.2 (2023-02-22)——这与 NEWS.md 开头"1.3.2 (2023-02-22)"的样式完全吻合,是配置生效的直接证据;
  • template = "news/_template.rst":渲染模板,仓库中的 news/_template.rst 按分类生成 "Features"、"Bug Fixes" 等小节;
  • issue_format:为每条变更自动附加 issue/PR 编号链接。

4.2 news fragment:以编号.类型命名的变更片段

CONTRIBUTING.md 对变更片段有明确规范:所有非平凡的用户可见变更都应添加一个 news fragment,文件名采用<issue或PR编号>.<类型>,例如news/1234.bugfix。仓库 news/ 目录中现存的片段(如1431.bugfix1781.maintenance2577.feature3206.feature等)正是这一约定的实况。

towncrier 支持七种变更类型(在 pyproject.toml 的[[tool.towncrier.type]]中定义):

目录名变更类型
feature新功能
api_changeAPI 变更(重命名、弃用、移除)
bugfix缺陷修复
plugin插件相关
config配置结构变更
docs文档改进
maintenance维护性改动

CONTRIBUTING.md 还规定:一个 PR 可同时创建多个片段(例如同时存在1234.feature1234.api_change),且跨插件与核心的变更应分别放到对应目录的news/下。渲染时 towncrier 会按类型聚合这些片段并自动去重。

4.3 渲染产物:NEWS.md 的长期累积

NEWS.md 是 towncrier 渲染结果的累积档案,目前已有 700 余行,覆盖从早期到 1.3.x 的全部版本发布说明,例如:

1.3.2 (2023-02-22) ================== ### Features - Add a `hydra.utils.get_object` function ... (#2139)

发布时以目标版本号运行 towncrier 后,新的版本章节会被插入<!-- TOWNCRIER -->标记处(即start_string指定的位置),随后在版本提交中一并推送。

五、第四步:构建 pip 包——python setup.py sdist bdist_wheel

文档给出的打包命令是:

python setup.py sdist bdist_wheel

该命令一次性生成两类分发包:

  • sdist:源码分发包dist/hydra_core-<version>.tar.gz
  • bdist_wheel:构建好的 wheel 包dist/hydra_core-<version>-py3-none-any.whl

5.1 setup.py 背后的自定义构建命令

Hydra 的打包远非"默认 setuptools 行为"这么简单。setup.py 通过cmdclass注册了五个自定义命令:

cmdclass={ "antlr": ANTLRCommand, "clean": CleanCommand, "sdist": SDistCommand, "build_py": BuildPyCommand, "develop": Develop, },

从 build_helpers/build_helpers.py 的实现可以看到构建链路的核心逻辑:

  • BuildPyCommand(继承build_py.build_py):运行时先执行clean,再运行 antlr 生成解析器,最后执行标准 build;
  • SDistCommand(继承sdist.sdist):同样先clean再运行 antlr;
  • Develop(继承develop.develop):用于pip install -e .开发模式,也需要 antlr 生成;
  • ANTLRCommand:调用java -jar build_helpers/bin/antlr-4.11.1-complete.jar,针对 OverrideLexer.g4 与 OverrideParser.g4 生成 Python3 解析器到hydra/grammar/gen/,随后通过_fix_imports()将生成代码中的import antlr4改写为from omegaconf.vendor import antlr4(使用 OmegaConf 内置的 vendor 版本,避免外部依赖);
  • CleanCommand:清理__pycache__.egg-infobuildmultirunoutputs等发布无关的垃圾文件。

因此,python setup.py sdist bdist_wheel实际执行的是一条"清理 → 生成 ANTLR 语法解析器 → 修复导入 → 构建 sdist 与 wheel"的完整流水线,保证发布产物中语法解析代码与源码始终同步。

5.2 发布产物应包含哪些文件

MENIFEST.in(MANIFEST.in)控制 sdist 中收录的额外文件:

include hydra/py.typed include requirements/requirements.txt global-exclude *.pyc global-exclude __pycache__ recursive-include hydra/* * recursive-include build_helpers *.py *.jar

其中hydra/py.typed是 PEP 561 类型标注标记,build_helpers下的*.jar则是 antlr 构建所需。构建完成后应核对dist/目录,确认包名、版本号与预期一致。

六、第五步:上传 PyPI——python -m twine upload dist/*

最后一步将dist/下全部构建产物上传至 PyPI:

python -m twine upload dist/*

twine 是 PyPI 官方推荐的包上传工具(相比直接setup.py upload更安全,支持 HTTPS 与凭证管理)。执行前需确认:

  • 本机已安装 twine:pip install twine
  • 已配置 PyPI 凭证(~/.pypirc或环境变量TWINE_USERNAME/TWINE_PASSWORD);
  • 目标版本在 PyPI 上尚未被占用(重复上传同版本会失败)。

发布完成后应做冒烟验证:在全新虚拟环境中pip install hydra-core==<新版本>,运行一个最简单的@hydra.main应用确认可用,再回到开发分支把版本号推进到下一个开发版本。

6.1 重要演进:1.0 之后"不再本地 twine"

需要特别指出的是,这份 1.0 文档描述的"本地 twine upload"流程在当前仓库中已被废弃。当前 发布文档 明确写道:

Do not runtwine uploadlocally for Hydra releases.(Hydra 发布不得在本地执行 twine upload。)

原因在于发布上传环节已迁移到 GitHub Actions 的 Trusted Publishing(可信发布)机制:维护者只负责准备与校验,真正的 PyPI 上传由 CI 工作流完成,凭证不再暴露在本地环境。这是"文档第一行所说'未来可能自动化'"在仓库中的实际兑现。

七、流程演进:从手工五步到 release.py + GitHub Actions

1.0 文档开头那句 "The release process may be automated in the future" 在后继版本中逐渐成真。当前仓库已经沉淀出一套半自动化发布工具链:

7.1 工具入口:tools/release/release.py

tools/release/release.py 定义了六种发布动作:

class Action(Enum): check = 1 build = 2 bump = 3 set_version = 4 validate_versions = 5 dev_release = 6

其中set_version对应手工流程中的"更新版本号",build对应"构建包",check则承担"上传前核对"职责——例如action=check会通过 PyPI JSON API(get_metadata,见 release.py)比较所选包在目标仓库的已发布版本,避免重复发布。

7.2 配置化:包集合(package set)

发布工具的默认配置见 tools/release/conf/config.yaml,其中defaults默认选择set: hydra-full-release;hydra-full-release.yaml 定义了该集合由 hydra-core 加九个捆绑插件组成(hydra_ax_sweeperhydra_colorloghydra_joblib_launcherhydra_nevergrad_sweeperhydra_optuna_sweeperhydra_ray_launcherhydra_rq_launcherhydra_submitit_launcher等,对应 conf/packages/ 下的包配置)。

一个典型的发布准备命令:

python tools/release/release.py \ action=check \ set=hydra-full-release \ repository=pypi

这实际上是把 1.0 文档中的"人工核对"升级为"程序化核对":校验发布线、推导目标分支、比对 PyPI 已发布版本、运行发布级检查矩阵,但上传动作交给Publish to PyPI工作流通过 Trusted Publishing 完成

7.3 与 1.0 流程的对照

1.0 手工流程(本文档)当前工具化流程
git checkout master按发布线(main/x.y_branch)由工具推导目标分支
手工改hydra/__init__.py版本号action=set_version批量设置核心与插件版本
手工跑 towncrier 更新 NEWS.md稳定版发布时仍由 towncrier 生成 NEWS.md
python setup.py sdist bdist_wheelaction=build(带clean_build_dirrequire_artifactsbuild_policy等策略)
python -m twine upload dist/*GitHub ActionsPublish to PyPI+ Trusted Publishing,禁止本地 twine

八、发布前自检清单

将 1.0 文档的五个步骤与仓库现状结合,可沉淀为一份通用发布检查清单:

  1. 分支:确认在干净的主干/发布分支上,工作树无未提交改动;
  2. 版本号hydra/__init__.py__version__为预期的 PEP 440 版本;插件协调发布时同步各插件版本;
  3. 变更记录news/目录已按<编号>.<类型>添加全部片段,运行 towncrier 渲染后确认NEWS.md包含本版本全部条目(可参考 news/_template.rst 与 NEWS.md 的既有格式);
  4. 构建python setup.py sdist bdist_wheel成功,antlr 解析器正常生成,dist/下 sdist 与 wheel 齐全;
  5. 上传:1.0 流程为python -m twine upload dist/*;当前仓库则交由 GitHub Actions 发布,绝不本地 twine upload;
  6. 收尾:发布成功后立即将版本号推进到下一个开发版本(如1.4.0.dev31.4.0.dev4),保证开发分支报告的版本永远"尚未发布"。

这套流程虽然源自 Hydra 1.0 时代的手工操作文档,但其"单一版本来源、变更记录工具化、标准构建产物、受控上传"四要素,对任何想要规范发布 Python 包的开源项目维护者都具有直接的参考价值;而仓库后续的 release.py 与 当前发布文档 则展示了同一流程在规模化、多包场景下如何优雅演进。

【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询