SciPy 核心开发者指南#

决策流程#

SciPy 拥有正式的治理模型,记录在 SciPy 项目治理 中。下文以非正式的方式记录了在代码和提交权限决策方面的实践情况。正式治理模型具有指导意义,以下内容仅供参考。

代码#

关于添加(或不添加)新功能、破坏向后兼容性或对代码库进行其他重大更改的任何重大决策,都应在讨论(最好达成完全共识)后在 scipy-dev 论坛上做出。

任何非琐碎的更改(琐碎指拼写错误或单行维护提交)都必须通过拉取请求(PR)进入。它必须由另一位开发者进行审查。如果审查不够及时,且该 PR 的快速合并非常重要,则 PR 提交者应向论坛发送消息,说明由于原因 Y,除非有人在此之前进行审查,否则他们打算在时间 X 无需审查即合并该 PR。

更改和新增内容应经过测试。未经测试的代码即为损坏的代码。

提交权限#

谁获得提交权限由 SciPy 指导委员会决定;提交权限的变更随后将在 scipy-dev 论坛上公布。

决定新功能#

到目前为止,接受提议的新功能的通用决策规则取决于以下条件:

  1. 该方法适用于许多领域,且“公认”是有用的,

  2. 它符合子模块的主题,并且不需要广泛的支持框架即可运行,

  3. 实现看起来很稳健,并且将来不太可能需要太多调整(例如,预期的维护负担有限),

  4. 有人愿意贡献它,并且

  5. 有人愿意审查它。

最后一个标准通常是提议功能的难点。代码在经过彻底审查之前无法合并,而且总是有积压的维护任务在竞争审查者的执行时间。理想情况下,贡献者在开始工作之前应联系一位具有合适领域专业知识的审查者。

虽然很难对“普遍有用且公认有效”的含义给出严格的规则,但权衡以下几点可能会有所帮助:

  • 该方法在实践中是否被不同领域使用/有用?正确使用它需要多少特定领域的背景知识?

  • 考虑模块中已有的代码。你添加的内容是否填补了遗漏?它是否解决了你期望该模块能够解决的问题?它是否显著补充了现有功能?

  • 考虑通常预期的相似方法/功能的等价类。在它们中,原则上的最小集合是什么,以便在提供的功能中不会留下明显的遗漏?那会有多少内容?包含其中的代表性功能是否覆盖了大多数用例?原则上将最小集合中的所有内容都包含在模块中是否合理?

  • 你添加的内容在文献中是否得到了充分的理解?如果不是,你有多大把握它会取得良好的效果?与其它类似方法相比,该方法的表现如何?

  • 请注意,每半年一次的发布周期和向后兼容性策略使得日后纠正问题变得更加困难。

子模块的范围也各不相同,因此最好将每个子模块视为一个单独的项目——“特殊函数的数值评估”定义相对明确,但“常用优化算法”则不然。

在 GitHub 上进行开发#

SciPy 的开发主要在 GitHub 上进行;本节描述了议题(Issues)、拉取请求(Pull Requests)以及管理 scipy 主仓库的预期工作方式。

标签和里程碑#

每个议题和拉取请求通常至少有两个标签:一个用于主题或组件(如 scipy.statsDocumentation 等),另一个用于议题或拉取请求的性质(如 enhancementmaintenancedefect 等)。根据情况还可能添加其他标签:

  • good-first-issue:适合新贡献者解决的问题。

  • needs-work:指已有审查意见但尚未处理的拉取请求。

  • needs-decision:指需要做出决定的议题或拉取请求。

  • needs-champion:指原作者未完成,但值得接手继续完成的拉取请求。

  • backport-candidate:发布经理应考虑反向移植(backport)的缺陷修复。

为每个计划发布的版本号创建一个里程碑。特定发布版本需要解决的问题和需要合并的拉取请求应设置为相应的里程碑。合并拉取请求后,其里程碑(以及它关闭的问题的里程碑)应设置为下一个即将发布的版本——这有助于直观了解更改并将其完整列表添加到发布说明中。

拉取请求审查工作流#

审查拉取请求时,请利用拉取请求工作流功能,参见 使用工作流功能

处理拉取请求#

  • 合并贡献时,提交者负责确保其符合 贡献给 SciPy 中概述的要求。同时检查新功能和向后兼容性破坏是否已在 scipy-dev 论坛上讨论过。

  • 新代码通过拉取请求(PR)进入。

  • 使用绿色按钮合并新代码。如果出现合并冲突,请要求 PR 提交者进行 rebase(这可能需要提供一些 git 指令)。

  • 用于完成 PR 的反向移植和琐碎补充(非常琐碎,如拼写错误或 PEP8 修复)可以直接推送。

  • 对于添加新功能或在某种程度上具有复杂性的 PR,在合并之前至少等待一两天。这样,其他人在代码进入之前有机会发表意见。

  • 可以对你认为过于凌乱的 PR 进行 squash 提交或清理提交消息。但执行此操作时请务必保留原作者姓名。如果提交消息不(大致)符合 编写提交消息 中的指南,强烈建议进行 squash。

  • 确保已合并 PR 的标签和里程碑设置正确。

  • 当你想要拒绝一个 PR 时:如果原因显而易见,你可以直接关闭它并解释原因。如果原因不那么明显,那么最好先解释为什么你认为该 PR 不适合包含在 SciPy 中,然后让第二位提交者发表评论或关闭。

反向移植 (Backporting)#

所有拉取请求(无论包含功能增强、缺陷修复还是其他内容)都应针对 main 分支。只有缺陷修复才是反向移植到维护分支的候选对象。SciPy 的反向移植策略是 (a) 仅反向移植重要的修复,以及 (b) 仅在相当确定相关维护分支将发布新的修复版本时才进行反向移植。通常,合并重要修复的开发者会添加 backport-candidate 标签并提醒发布经理,由发布经理决定是否以及何时进行反向移植。反向移植完成后,必须再次移除 backport-candidate 标签。

反向移植拉取请求的一个好策略是合并多个 main 分支的拉取请求,以减轻持续集成测试的负担,并减少维护分支历史中合并提交的混乱。最好为反向移植 PR 中代表的每个主分支 PR 保留一个单独的提交。这样历史清晰,且在需要时可以简单地进行回滚。

发布说明 (Release notes)#

合并 PR 时,考虑是否需要在发布说明中提及这些更改。需要提及的内容包括:新功能、向后不兼容的更改、弃用(deprecations)以及“其他更改”(任何足够值得注意的内容,请参阅旧的发布说明以了解值得提及的事项类型)。

发布说明条目在 维基 (Wiki) 上维护。发布经理将从那里收集内容并将其集成到 HTML 文档中。我们使用这种机制是为了避免如果每个 PR 都直接修改 doc/release/ 下的同一个文件而产生的合并冲突。

更改可以被监控(Atom Feed)并拉取(Wiki 也是一个 git 仓库:https://github.com/scipy/scipy.wiki.git)。

其他#

交叉引用: 在 GitHub 上交叉引用议题和拉取请求通常很有用。GitHub 允许使用 gh-xxxx#xxxxxxxx 为议题/PR 编号)来实现。强烈推荐使用 gh-xxxx 格式,因为它可以明确指向 GitHub 链接。较旧的议题包含的 #xxxx 是关于 Trac(我们在使用 GitHub 之前使用的系统)的工单。

PR 命名规范: 拉取请求、议题和提交消息通常以三个字母的缩写开始,如 ENH:BUG:。这有助于快速了解提交/PR/议题的性质。有关缩写的完整列表,请参阅 编写提交消息

许可 (Licensing)#

SciPy 采用 修订版 (3-clause) BSD 许可证 分发。除非源代码中另有明确指定,否则贡献者向 SciPy 添加的所有代码、文档和其他文件均受此许可证约束。贡献者保留其编写并提交给 SciPy 的代码的版权。

与 SciPy 使用的修订版 BSD 许可证兼容的其他许可证包括 2-clause BSD、MIT 和 PSF。不兼容的许可证包括 GPL、Apache 以及要求署名/引用或禁止商业用途的自定义许可证。

提交的 PR 经常包含从无许可证代码或与 SciPy 许可证不兼容的默认许可证代码中复制或派生的内容。例如,StackOverflow 上发布的代码受 CC-BY-SA 许可证保护,由于其中的“相同方式共享”条款,该许可证是不兼容的。除非原作者愿意将其代码以修订版 BSD(或兼容的)许可证重新授权,否则这些贡献不能被 SciPy 接受。如果原作者同意,请在源文件中添加说明评论,并将相关沟通内容转发至 scipy-dev 论坛。

另一种常见情况是代码是从 R、Octave(均为 GPL 许可)或商业应用程序中的代码翻译或派生而来的。此类代码也不能包含在 SciPy 中。但是,只要作者没有参考原始不兼容许可的源代码,仅实现与 R/Octave/... 相同的 API 功能是可以接受的。

版本编号#

SciPy 版本编号符合 PEP 440。发布的最终版本(出现在 PyPI 上的唯一版本)编号为 MAJOR.MINOR.MICRO,其中:

  • MAJOR 是表示主版本的整数。它极少更改;主版本的变动表示发生了重大的(可能是向后不兼容的)更改。

  • MINOR 是表示次版本的整数。次版本通常每年发布两次,可能包含新功能、弃用和缺陷修复。

  • MICRO 是表示缺陷修复版本的整数。缺陷修复版本根据需要发布,通常每个次版本发布一到两个。它们不能包含新功能或弃用。

发布的 alpha、beta 和 rc(候选)版本编号与最终版本相同,但分别带有后缀 a#b#rc#,其中 # 是一个整数。开发版本的后缀为 .dev0+<git-commit-hash>

有效的 SciPy 版本字符串示例包括:

0.16.0
0.15.1
0.14.0a1
0.14.0b2
0.14.0rc1
0.17.0.dev0+ac53f09

已安装的 SciPy 版本包含这些版本标识符:

scipy.__version__            # complete version string, including git commit hash for dev versions
scipy.version.short_version  # string, only major.minor.micro
scipy.version.version        # string, same as scipy.__version__
scipy.version.full_version   # string, same as scipy.__version__
scipy.version.release        # bool, development or (alpha/beta/rc/final) released version
scipy.version.git_revision   # string, git commit hash from which scipy was built

弃用 (Deprecations)#

想要移除现有功能有各种原因:它存在缺陷、API 难以理解、它被性能更好的功能取代、它需要移动到另一个 SciPy 子模块等。

通常,在没有预先警告用户的情况下移除功能并不是个好主意。因此,在从公共 API 中移除内容之前应执行以下操作:

  1. 在 scipy-dev 论坛上提议弃用该功能并获得一致同意。

  2. 为其添加 DeprecationWarning,说明该功能已被弃用以及在哪一个版本中弃用。对于 Cython API,请参阅 弃用公共 Cython API 了解具体步骤。

  3. 在那个版本的发布说明中提到该弃用。

  4. 在引入 DeprecationWarning 的版本发布日期后,至少等待 6 个月再移除该功能。

  5. 在发布说明中提到该功能的移除。

6 个月的等待期在实践中通常意味着等待两个版本发布。在引入警告时,还应确保在运行测试套件时过滤掉这些警告,以免污染输出。

对于特定的弃用,可能存在想要忽略此弃用策略的理由;这始终可以在 scipy-dev 论坛上讨论。

外部引入代码 (Vendored Code)#

SciPy 代码库的许多部分是在其他地方维护并引入 (vendor) 到 SciPy 中的。其中一些部分作为 git 子模块引入,例如 xsf,或者放在 subprojects 目录下(或两者兼有)。

尽管有维护良好的上游,但其他部分并未作为 git 子模块引入或放在 subprojects 目录下。这通常是因为:

  1. 上游仓库的一个子集是通过脚本引入的。

    (这些部分将来可能会被移动到 subprojects 下。)

  2. 代码已被复制到 SciPy 中并在此后进行了修改。

    (其中一些部分可能会将补丁贡献给上游,并在将来成为 git 子模块或被移动到 subprojects 下。)

维护者应注意 不要 在代码于上游活跃维护的情况下,在 SciPy 的这些部分接受贡献(尤其是琐碎的更改)。相反,他们应该引导贡献者去上游仓库。

通过脚本引入的代码库部分包括:

  • PRIMA,位于 scipy/_lib/pyprima

包含从上游复制的代码的部分包括:

有关仓库中引入代码的更多详情和跟踪,请参考 scipy/scipy#21232

分发 (Distributing)#

分发 Python 包并非易事——特别是对于像 SciPy 这样具有复杂构建要求的包——并且会发生变化。有关推荐工具和技术的最新概览,请参阅 Python 分发用户指南。本文讨论了 SciPy 的一些主要问题和注意事项。

依赖项 (Dependencies)#

依赖项是用户为了使用(或构建/测试)包而必须安装的东西。它们通常会带来麻烦,特别是如果它们不是可选的。SciPy 试图将其依赖项保持在最低限度;当前必需和可选的构建时依赖项可以在 SciPy 配置文件 pyproject.toml 中查看。唯一的非可选运行时依赖项是 NumPy

此外,构建 SciPy 当然需要 C、C++ 和 Fortran 编译器,但我们不认为这些是依赖项,因此在此不作讨论。详情请参见 从源码构建

当一个包提供了有用的功能并被提议作为新的依赖项时,还要考虑将其引入 (vendor)(即在 SciPy 中附带其副本)是否合理。例如, decorator 被引入在 scipy._lib 中。

依赖处理中的问题#

Python 分发工具处理项目报告的依赖项的方式存在一些问题。由于 SciPy 经常收到关于此的缺陷报告,我们在这里详细说明一下。

SciPy 通过 pyproject.toml 报告其对 NumPy 的构建依赖,并且 SciPy 还有运行时检查以确保有合适版本的 NumPy 可用。SciPy 不再使用 setup_requires(过去会调用 easy_install);构建依赖现在仅通过 pyproject.toml 处理。pyproject.toml 依赖于 PEP 517;pip--no-use-pep517--no-build-isolation 标志,可能会忽略 pyproject.toml 或以不同方式对待它——如果用户使用这些标志,他们需要负责自己安装正确的构建依赖项。

NumPy 和其他依赖项的版本范围#

对于依赖项,设置版本上下限非常重要。对于 构建时 (build-time) 依赖项,它们在 pyproject.toml 中指定,版本将 适用于 SciPy 构建本身。对于像 meson-pythonpybind11 这样的依赖项,指定版本范围或特定版本都可以。对于 NumPy,我们还必须考虑 ABI 兼容性。但是,由于 NumPy >=2.0.0rc1 保证了向后兼容性可追溯到 NumPy 1.19 系列,因此在 pyproject.toml 中不再需要指定构建时支持的最低 NumPy 版本。

对于 运行时 (run-time) 依赖项(目前仅 numpy),我们在 pyproject.tomlscipy/__init__.py 中指定版本范围。正确设置上限有点棘手。如果我们不设置任何限制,几年后一个太新的版本会被拉取进来,而到那时 NumPy 可能已经弃用并移除了 SciPy 所依赖的某些 API。另一方面,如果我们把上限设置为最新发布的版本,那么一旦新的 NumPy 版本发布,就没有与之匹配的可运行的 SciPy 版本了。鉴于 NumPy 和 SciPy 都以 6 个月为周期发布,且 NumPy 中弃用的功能应保留另外两个版本,我们将上限指定为 <2.xx+3.0(其中 xx 是最新发布的 NumPy 次版本)。

支持的 Python 和 NumPy 版本#

SciPy 支持的 Python 版本列在 pyproject.toml 的 PyPI 分类器列表中,并在每个版本的发布说明中提及。所有新发布的 Python 版本都将尽快得到支持。有关停止支持 Python 或 NumPy 版本的通用策略,请参见 NEP 29。停止支持的最终决定始终在 scipy-dev 论坛上做出。

SciPy 版本支持的最低 NumPy 版本在发布说明中提及,并编码在 pyproject.tomlscipy/__init__.py 中。通常,最新的 SciPy 版本支持约 5-7 个 NumPy 次版本:最远支持约 2.5 年前的 NumPy 版本(考虑到撰写本文时 NumPy 的发布频率约为每年 2 次),再加上未来的两个版本。

可选依赖项和编译器的支持版本记录在 工具链路线图 中。请注意,并非所有受支持的可选依赖项版本都经过了 SciPy 持续集成设置的良好测试或完全测试。与此相关的问题将在议题追踪器或论坛中出现时进行处理。

构建二进制安装程序#

注意

本节仅关于构建用于 分发 的 SciPy 二进制安装程序。有关在将要使用的机器上构建 SciPy 的信息,请参见 从源码构建

在构建二进制文件并将其分发到 PyPI 或其他地方时,有许多事项需要考虑。

通用

  • 二进制文件特定于单个(主)Python 版本(因为不同的 Python 主版本不具备 ABI 兼容性,至少直到 Python 3.12 都是如此)。

  • 针对 NumPy 2.0.0 构建,它将适用于所有具有相同主版本号的 NumPy 版本(NumPy 确实保持向后 ABI 兼容性),在撰写本文时,可向后兼容到 NumPy 1.19 系列。

  • 用于构建便携式 SciPy 二进制文件的最简单可用工具链是我们在常用平台上的 cibuildwheel 基础设施,详细信息可见我们的 CI 基础设施代码,并在 Windows、Linux 和 MacOS 上通过 cibuildwheel 命令可用,尽管在某些情况下需要额外的外部依赖。

Windows

  • 对于使用免费工具链构建的 64 位 Windows 安装程序,请使用 numpy/numpy 记录的方法。一旦明确该工具链的维护是长期可持续的,SciPy 本身也可能会采用该方法。详情请参阅 MingwPy 项目和 此讨论帖

  • 生产 64 位 Windows 安装程序的另一种方式是使用 iccifortMKL(或者用 MSVC 代替 icc)。有关 Intel 工具链的说明,请参阅 本文;有关(部分)MSVC 说明,请参阅 此维基页面

  • 较旧的 SciPy 版本包含一个 .exe "superpack" 安装程序。这些包含 3 个完整的构建(无 SSE、SSE2、SSE3),是使用 numpy/numpy-vendor 构建的。该构建设置已知不再运行良好且不再受支持。由于复杂的 DLL 分发问题(参见 gh-2829),它使用 g77 而不是 gfortran。由于工具链不再受支持,不再需要 g77 支持,SciPy 现在可以包含 Fortran 90/95 代码。

Linux

  • 兼容 PyPI 的 Linux wheel 可以通过 manylinux 项目生产,我们的 cibuildwheel 基础设施在底层使用了该项目。

其他 Linux 构建设置会导致与 PyPI 不兼容的 wheel,需要通过自定义渠道分发,例如在 Wheelhouse 中,请参阅 wheelWheelhouse 文档。

文档字符串中的交互式示例#

文档字符串中的示例可以使用 jupyterlite-sphinx 扩展 变为交互式的,该扩展实现了 .. try_examples:: 指令。当在文档字符串的“Examples”部分使用时,此指令将创建一个按钮,允许用户在交互式 JupyterLite 窗口中打开示例,或在新标签页中将其作为 Jupyter 笔记本打开。对于 SciPy,通过 doc/source/conf.py 中的 global_enable_try_examples 配置选项,此指令会自动添加到所有具有“Examples”部分的文档字符串中。

若要隐藏将文档字符串示例转换为嵌入式笔记本的按钮,在构建 HTML 文档后,编辑 scipy/doc/build/html/ 下的 try_examples.json 运行时配置文件,并将要忽略的文件 URL 路径添加到 ignore_patterns 列表中。此列表预期元素为 JavaScript 正则表达式模式。干净的文档构建中此文件的初始版本为:

{
    "global_min_height": "400px",
    "ignore_patterns": [".*"]
}

在干净的文档构建中,默认情况下隐藏了将示例部分转换为嵌入式交互式笔记本的按钮。

更多信息请参阅 jupyterlite-sphinx TryExamples 指令 的文档。

进行 SciPy 发布#

在最高层面,发布经理发布新的 SciPy 版本时的工作如下:

  1. 在 SciPy 论坛 https://discuss.scientific-python.org/ 提议发布时间表。

  2. 为发布版本创建维护分支。

  3. 标记 (Tag) 发布版本。

  4. 构建所有发布产物(源码、安装程序、文档)。

  5. 上传发布产物。

  6. 宣布发布。

  7. 将发布说明和构建脚本的相关更改合并回 main 分支。

在本指南中,我们尝试详细描述如何执行上述每个步骤。除了这些必须由发布经理执行的步骤外,以下是关于发布相关活动和惯例的说明:

提议发布时间表#

典型的发布周期如下:

  • 创建维护分支

  • 发布 beta 版本

  • 发布“发布候选版本” (RC)

  • 如果需要,发布一个或多个新的 RC

  • 一旦最后的发布候选版本没有问题,发布最终版本

上述每个步骤之间通常至少间隔一周。经验表明,一个新的次版本周期需要 4 到 8 周。缺陷修复版本不需要 beta 或 RC,可以更快完成。

理想情况下,最终发布版与最后的 RC 相同,但也可能存在细微差别——由发布经理判断其风险。通常,如果编译代码或复杂的纯 Python 代码发生了更改,则需要新的 RC,而从 main 反向移植的简单缺陷修复则不需要新的 RC。

要提议时间表,请将包含分支、beta/rc/最终版本预计日期的列表发送到 SciPy 论坛 https://discuss.scientific-python.org/。在同一条消息中,请大家检查是否有重要的议题/PR 需要包含进来,但尚未标记该版本的里程碑或“backport-candidate”标签。

创建维护分支#

在创建分支之前,确保发布说明已尽可能更新。在发布说明中包含 tools/gh_lists.pytools/authors.py 的输出。

维护分支的命名方式为 maintenance/<major>.<minor>.x(例如 0.19.x)。要创建一个,只需将具有正确名称的分支推送到 scipy 仓库。紧接着,在 main 分支上推送一个提交,增加版本号并为该新版本添加发布说明。向 SciPy 论坛 https://discuss.scientific-python.org/ 发送邮件,告知大家你已完成此操作。

更新版本切换器#

版本切换器下拉菜单仅需在 main 分支上更新新的发布信息。

  • doc/source/_static/version_switcher.json:添加新版本、新的开发版本,并将 "preferred": true 从旧版本转移到新版本。

更新依赖项的上限#

在 main 分支中我们不设置上限,因为我们想在那里测试依赖项的新版本或开发版本。但在维护分支中,目标是创建能够持续运行多年的版本。因此必须设置正确的上限。创建维护分支后必须更新以下位置:

  • pyproject.toml:所有构建时依赖项,以及支持的 Python

    和 NumPy 版本

  • scipy/__init__.py:用于 NumPy 版本检查

每个文件都有说明如何设置正确上限的注释。

标记发布版本#

首先确保你已正确设置 GPG。关于签名发布标签的讨论请参见 scipy/scipy#4919,如果你没有 GPG 密钥,请按照 https://keyring.debian.org/creating-key.html 的说明创建一个。请注意,在某些平台上,可能更适合使用 gpg2 而不是 gpg,以便按 scipy/scipy#10189 中讨论的那样由 gpg-agent 存储密码。远程准备发布时,可能需要在 ~/.gnupg/gpg-agent.conf 中设置 pinentry-mode loopback,因为否则使用 gpg2 将由于无法访问图形密码提示而受阻。

为了让你的密钥更容易被识别为你本人,可以考虑使用如下命令将你的密钥发送到公共密钥服务器:

gpg --send-keys <yourkeyid>

检查所有相关提交是否都在分支中。特别要检查该版本里程碑下的议题和 PR (scipy/scipy)、标记为 “backport-candidate” 的 PR,并检查发布说明是否是最新的且包含在 HTML 文档中。

然后更新 pyproject.toml 中的 version,并提交更改,消息如 REL: set version to <version-number>。先不要将此提交推送到 SciPy 仓库。

最后在本地使用 git tag -s <v1.x.y> 标记发布版本(-s 确保标签已签名)。如果首选 gpg2,则 git config --global gpg.program gpg2 可能更合适。继续构建发布产物(下一节)。只有在你成功构建了 sdists 和文档之后,才将发布提交推送到 scipy 仓库。然后继续构建 wheels。只有当所有 wheels 在 TravisCI 和 Appveyor 上成功构建后,才将发布标签推送到仓库(如果失败,你必须移动标签,这是不好的做法)。最后,在推送标签后,再推送第二个提交,增加版本号并在 version: 后附加 .dev0,并将 ISRELEASED 重新设置为 False。这也适用于新的发布候选版本,以及在从发布候选版切换到正式版时移除 rc 后缀。

构建发布产物#

以下是为发布版本创建的产物完整列表:

  • sdist (scipy-x.y.y.tar.gz,用于 PyPI 和 GitHub Releases)

  • 适用于 Windows、Linux 和 macOS 的二进制 wheel

  • 文档 (html)

  • 一个 README.txt 文件

  • 一个 Changelog 文件

通过运行 python -m build --sdist 生成 sdist(注意:我们仍需将其移动到 CI 任务中!),并通过在仓库根目录运行 spin notes(带标签,见 spin notes --help)构建 Changelog 和 README,产物存放在 REPO_ROOT/release/。在本地创建签名标签后执行此操作。如果完成且没有问题,将发布提交(不是标签,见上节)推送到 scipy 仓库。

要构建 wheel,向用于当前发布的分支推送一个包含文本 [wheel build] 的提交。这会触发所有所需 Python 版本和平台的 cibuildwheel 构建。NumPy 和其他依赖项的适当版本固定应在分支后立即在 pyproject.toml 中更新。如果 wheel 构建揭示了需要通过在维护分支上反向移植修复的问题,你可以移除本地标签(例如 git tag -d v1.2.0rc1)并在新的候选提交上重新开始标记。

cibuildwheel 基础设施会从构建的 wheel 运行测试,如果通过,则将 wheel 上传到 https://anaconda.org/multibuild-wheels-staging/scipy

你可以从那里下载它们以便上传到 PyPI。这可以使用 tools/download-wheels.py 以自动化方式完成。

$ python tools/download-wheels.py 1.5.0rc1 -w REPO_ROOT/release/installers

在此之后,我们要重新生成 README 文件,以便将刚下载的 wheel 的 MD5 和 SHA256 校验和包含在内。再次运行 spin notes

上传发布产物#

对于一个发布版本,目前有五个网页端位置可以上传内容:

  • PyPI (sdist, wheels)

  • GitHub Releases (sdist, release notes, Changelog)

  • scipy.org (发布公告)

  • docs.scipy.org (html 文档)

PyPI

先上传 wheel,然后再上传 sdist

twine upload REPO_ROOT/release/installers/*.whl
twine upload REPO_ROOT/release/installers/scipy-1.x.y.tar.gz

Github Releases

使用 scipy/scipy 上的 GUI 创建发布并上传所有发布产物。在此阶段,适合推送标签并在 GUI 中将新发布(候选)版本与该标签关联。例如,git push upstream v1.2.0rc1,其中 upstream 代表 scipy/scipy。检查以前的发布版本以准确确定应在 GUI 上传过程中包含哪些产物是很有用的。此外,请注意发布说明不会自动填充到 GitHub 上的发布描述中,进行一些手动 Markdown 格式调整以匹配网站上以前版本的格式会很有帮助。我们通常不会在这些 GUI 描述中包含议题和拉取请求列表。

scipy.org

该网站的源码位于 scipy/scipy.org。通过 PR 更新 content/en/news.md 中的新闻部分。这仅针对正式发布版本,而非发布候选版。

docs.scipy.org

首先通过在 scipy/doc/ 中运行 make dist 构建 scipy 文档。确认文档看起来正常后,使用 make upload USERNAME=rgommers RELEASE=0.19.0 将其上传到文档服务器。请注意,需要文档服务器的 SSH 访问权限;如果你没有权限,请咨询 @pv(服务器管理员)、@tylerjereddy 或 @rgommers(可以上传)。

网站本身的源码在 scipy/docs.scipy.org 中维护。在 index.rst 的发布版本表中添加新的 SciPy 版本。推送该提交,然后执行 make upload USERNAME=yourusername。这仅针对正式发布版本,而非发布候选版。

注意

在部署的文档上的版本切换器不会将新版本视为稳定版,直到对 version_switcher.json 的更改合并到 main 分支中(见 gh-22305)。因此,将发布说明和版本切换器更改向后移植到 main 理想情况下应与为新版本部署文档同时进行。

总结收尾#

发送消息到 https://discuss.scientific-python.org/c/announcements/ 宣布发布。

对于 beta 和 rc 版本,请大家进行测试(运行 scipy 测试并针对他们自己的代码进行测试)并在 Github 或 Discourse 上报告问题。

在最终发布完成后,将发布说明、构建脚本、tools/authors.py 中的作者姓名映射以及任何仅在维护分支上进行的更改移植到 main 分支。

通过编辑发布服务器上上传文档根目录下的运行时配置文件 try_examples.json 来启用交互式示例。必须从 ignore_patterns 列表中移除正则表达式模式 ".*"

$ ssh your-username@docs.scipy.org
$ cd /srv/docs_scipy_org/doc/scipy-1.13.1
$ vim try_examples.json  # edit the ignore list to remove: ".*"