维护者/核心开发者信息#

发布流程#

本节内容涉及准备主要版本发布、次要版本递增或补丁版本递增的错误修复发布。我们的惯例是在发布最终版本之前,先发布一个或多个发布候选版本(0.RRrcN)。我们遵循 PEP101 来指示发布候选版本、后发布和次要版本。

发布前#

  1. 更新作者表:

    在 GitHub 上创建一个具有 read:org 权限的 经典令牌

    运行以下脚本,输入令牌:

    cd build_tools; make authors; cd ..
    

    并提交。仅当自上次发布以来作者有变动时才需要此步骤。有时此步骤与发布独立进行。这更新了维护者列表,而不是发布贡献者列表。

  2. 确认里程碑标记的任何阻塞问题已解决,并且其他标记为里程碑的问题可以推迟。

  3. 确保变更日志和提交记录相对应(在合理范围内!),并且变更日志经过合理整理。这些任务的一些工具包括:

    • maint_tools/sort_whats_new.py 可以将新增内容条目放入各个部分。它并不完美,需要手动检查变更。如果新增内容列表整理得很好,可能不需要此工具。

    • maint_tools/whats_missing.sh 脚本可用于识别已合并但可能未包含在新增内容中的拉取请求。

  4. 确保标记为发布的弃用、FIXME 和 TODO 已处理。

权限

发布管理员必须是 scikit-learn/scikit-learn 仓库的 维护者,才能在 pypi.orgtest.pypi.org 上发布。 (通过手动触发专用GitHub Actions工作流程).

发布管理员不需要在 pypi.org 上拥有额外的权限来发布特定版本。

发布管理员必须是 conda-forge/scikit-learn-feedstock 仓库的*维护者*。这可以通过在第一个发布拉取请求中编辑 recipe/meta.yaml 文件来更改。

准备发布PR#

主要版本发布#

在分支之前,请不要忘记准备一个可运行的示例作为发布亮点页面,并检查其HTML渲染是否正确。这些发布亮点应从 doc/whats_new/v0.99.rst 文件链接到scikit-learn的新版本。

发布例如版本 0.99.0 的第一个RC涉及在主仓库上直接创建发布分支 0.99.X ,其中 X 实际上是字母X,不是占位符0.99 的主要和次要版本的开发**也**应在 0.99.X 下进行。每个发布(rc、主要或次要)都是该分支下的一个标签。

这只会做一次,因为主要和次要版本发生在同一分支上:

# 假设upstream是主scikit-learn仓库的别名:
git fetch upstream main
git checkout upstream/main
git checkout -b 0.99.X
git push --set-upstream upstream 0.99.X

再次强调, X 在这里是字面意思, 99 被替换为发布编号。分支称为 0.19.X0.20.X 等。

在包含更改方面,第一个RC理想情况下算作*功能冻结*。每个后续的发布候选版本和最终发布之后将只包括次要的文档更改和错误修复。任何主要增强或功能都应排除在外。

然后,您可以为发布本身准备一个本地分支,例如: release-0.99.0rc1 ,将其推送到您的github fork并打开一个PR

scikit-learn/0.99.X 分支。在 Pull Request 的描述中复制 发布清单 模板以跟踪进度。

此 PR 将用于推送与发布相关的提交,如 发布制作 中所述。

你还可以从 main 创建第二个 PR,并将其目标设为 main,以增加 sklearn/__init__.pypyproject.toml 中的 __version__ 变量,以增加开发版本。这意味着在我们处于发布候选期时,最新的稳定版本比 main 分支落后两个版本,而不是一个。在此针对 main 的 PR 中,你还应该在 doc/whats_new/ 文件夹下为匹配的版本添加一个新文件,以便针对下一个版本的 PR 可以并行于发布过程中向此文件贡献其变更日志条目。

次要版本发布(也称为错误修复发布)#

次要版本应仅包括错误修复和一些相关的文档更改。任何导致行为变化而非错误修复的 PR 都应排除。例如,给出了 1.2.2 版本的说明。

  • upstream/main 创建一个分支,**在你的个人 fork**(此处称为 fork )上进行发布。

    git fetch upstream/main
    git checkout -b release-1.2.2 upstream/main
    git push -u fork release-1.2.2:release-1.2.2
    
  • 创建一个针对 upstream/1.2.X 分支(而非 upstream/main )的 草稿 PR,包含所有期望的更改。

  • 暂时不要在该分支上推送任何内容。

  • 使用以下命令从 upstream/1.2.X 分支本地重新设置 release-1.2.2

    git rebase -i upstream/1.2.X
    

    这将打开一个包含 main 上所有最新提交的 git-rebase-todo 的交互式 rebase。在此阶段,你必须至少与其他人一起执行此交互式 rebase(最好是三个人一起,以免遗漏某些内容并避免任何疑问)。 - 不要删除行,而是通过替换 pick drop 来丢弃提交

    • 用于修复版本发布的提交 通常 带有以下前缀: FIX , CI , DOC 。它们至少应包括在 GitHub 上为此版本标记的所有合并 PR 的提交,以及/或在变更日志中记录的提交。可能有些错误修复记录在主版本发布的主要变更日志中,而不是下一个修复版本中,这种情况下,需要将相应的变更日志条目先移动到 main 分支,然后在发布 PR 中回溯。

    • 用于修复版本发布的提交 通常 带有以下前缀: FEAT , MAINT , ENH , API 。不包含它们的原因是为了防止行为变化(这些变化只应在重大或主要版本中出现)。

    • 在丢弃或选择提交后,不要退出,而是将 git-rebase-todo 消息的内容粘贴到 PR 中。 该文件位于 .git/rebase-merge/git-rebase-todo

    • 保存并退出,开始交互式重置。

    • 在发生合并冲突时解决它们。

  • 强制推送重置结果和额外的发布提交到发布 PR:

    git push -f fork release-1.2.2:release-1.2.2
    
  • 复制 发布清单 模板并粘贴到 Pull Request 的描述中以跟踪进度。

  • 审查发布中包含的所有提交,确保它们没有引入任何新功能。我们不应盲目信任提交消息前缀。

  • 移除发布 PR 的草稿状态,并邀请其他维护者审查包含的提交列表。

发布制作#

  1. 确保你已经按照上述 准备发布PR 的说明检出了发布 PR 的分支。

  2. 更新文档。注意,这是针对最终发布,不一定是针对 在RC发布之前,这些更改应该在主分支上进行,并在最终发布之前挑选到发布分支中。

    • 编辑 doc/whats_new/v0.99.rst 文件,添加发布标题和贡献者列表。 你可以使用以下命令获取贡献者名称列表:

      $ git shortlog -s 0.98.33.. | cut -f2- | sort --ignore-case | tr '\n' ';' | sed 's/;/, /g;s/, $//' | fold -s
      
      • 对于主要版本,从 doc/whats_new/v0.99.rst 文件中链接发布亮点示例。

    • whats_new.rst 中更新发布日期

    • 编辑 doc/templates/index.html 文件,更改首页的 ‘News’ 条目(包括发布月份)。不要忘记删除旧条目(通常两年或三次发布足够)并更新正在进行的开发条目。

  3. 在发布分支上,更新 sklearn/__init__.py 中的版本号, __version__ 变量,以及 pyproject.toml 中的版本号。

    对于主要版本,请在末尾添加0: 0.99.0 而不是 0.99

    对于第一个发布候选版本,在预期的最终发布版本号后使用 rc1 后缀: 0.99.0rc1

  4. 使用 [cd build] 提交标记触发轮构建器,使用以下命令:

    git commit --allow-empty -m "Trigger wheel builder workflow: [cd build]"
    

    轮构建工作流程由GitHub Actions管理,结果可以在以下网址浏览: scikit-learn/scikit-learn

Note

在构建轮之前,确保 pyproject.toml 文件是最新的,并且为每个Python版本使用最旧版本的 numpy ,以避免 ABI 不兼容问题。此外,每个新支持的Python版本都必须在 pyproject.toml 文件中包含新行。

Note

[cd build] 中的缩写 CD 代表 持续交付 ,指的是用于生成发布工件(二进制和源包)的自动化。这可以看作是 CI( 持续集成 )的扩展。GitHub Actions 上的 CD 工作流程也用于自动创建 scikit-learn 开发分支的夜间构建并发布包。请参阅 安装 nightly builds

  1. 一旦 PR 中的所有 CD 作业都成功完成,再次合并它,并在提交消息中使用 [cd build] 标记。这次结果将上传到暂存区。

    然后,你应该能够使用以下 GitHub Actions 工作流程的“运行工作流程”表单将生成的工件(.tar.gz 和 .whl 文件)上传到 https://test.pypi.org

    scikit-learn/scikit-learn

  2. 如果一切顺利,你可以继续打标签。请谨慎操作。理想情况下,标签应在几乎确定发布准备就绪时创建,因为为主仓库添加标签可能会触发某些自动化流程。

    创建标签并推送它(如果是 RC,可以是 0.xx.0rc1 等):

    git tag -a 0.99.0  # 在 0.99.X 分支中
    git push git@github.com:scikit-learn/scikit-learn.git 0.99.0
    
  3. 确认机器人已在 conda-forge feedstock 仓库中检测到标签: conda-forge/scikit-learn-feedstock。如果没有,请提交一个 PR 进行发布。如果你想在 conda-forge 上发布 RC 版本,PR 应针对 rc 分支而不是 main 分支。否则,这两个分支需要保持同步。

  4. 再次触发 GitHub Actions 工作流程,但这次是为了上传工件。 到真实的 https://pypi.org(在“运行工作流”表单中将“testpypi”替换为“pypi”)。

  5. 步骤7的替代方案:可以在本地收集生成的二进制轮包和源码压缩包,并通过在scikit-learn源码文件夹(已检出到发布标签)中运行以下命令将它们全部上传到PyPI:

    rm -r dist
    pip install -U wheelhouse_uploader twine
    python -m wheelhouse_uploader fetch \
      --version 0.99.0 \
      --local-folder dist \
      scikit-learn \
      https://pypi.anaconda.org/scikit-learn-wheels-staging/simple/scikit-learn/
    

    此命令将下载在 anaconda.org托管服务上的暂存区中累积的所有二进制包 ,并将它们放入本地的 ./dist 文件夹中。

    检查 ./dist 文件夹的内容:它应包含所有轮包以及源码压缩包(”scikit-learn-RRR.tar.gz”)。

    确保该文件夹中没有开发者版本或旧版本的scikit-learn包。

    在上传到pypi之前,可以先测试上传到test.pypi.org:

    twine upload --verbose --repository-url https://test.pypi.org/legacy/ dist/*
    

    一次性上传所有内容到https://pypi.org:

    twine upload dist/*
    
  6. 对于主要/次要版本(非错误修复版本或发布候选版本),更新 stable 的符号链接和 latestStable 变量在https://github.com/scikit-learn/scikit-learn.github.io:

    cd /tmp
    git clone --depth 1 --no-checkout git@github.com:scikit-learn/scikit-learn.github.io.git
    cd scikit-learn.github.io
    echo stable > .git/info/sparse-checkout
    git checkout main
    rm stable
    ln -s 0.999 stable
    

sed -i “s/latestStable = ‘.*/latestStable = ‘0.999’;/” versionwarning.js git add stable versionwarning.js git commit -m “Update stable to point to 0.999” git push origin main

  1. 更新 SECURITY.md 以反映最新支持的版本。

发布清单#

以下 GitHub 清单可能在发布 PR 时有所帮助:

* [ ] 在发布分支中更新新闻和最新动态日期
* [ ] 在主分支中更新新闻和最新动态日期以及 sklearn dev0 版本
* [ ] 检查发布版本的 wheel 是否能成功构建
* [ ] 使用 `[cd build]` 提交消息合并 PR 以将 wheel 上传到暂存仓库
* [ ] 将 wheel 和源码包上传到 https://test.pypi.org
* [ ] 在主 GitHub 仓库中创建标签
* [ ] 确认机器人已在
  https://github.com/conda-forge/scikit-learn-feedstock 检测到并等待合并
* [ ] 将 wheel 和源码包上传到 PyPI
* [ ] 在 https://github.com/scikit-learn/scikit-learn/releases 发布(RC 除外)
* [ ] 在邮件列表、Twitter 和 LinkedIn 上宣布
* [ ] 更新 https://github.com/scikit-learn/scikit-learn.github.io 中的 stable 符号链接(仅限主版本/次版本)
* [ ] 在主分支中更新 SECURITY.md(RC 除外)

合并拉取请求#

在 GitHub 上合并拉取请求 (PR) 时,单个提交会被压缩。在合并之前,

  • 如果需要,可以编辑生成的提交标题。请注意,这将默认重命名 PR 标题。

  • 包含所有提交标题的详细描述可以编辑或删除。

  • 对于有多个代码贡献者的 PR,必须注意保留 Co-authored-by: name <name@example.com> 标签在详细描述中。这将标记 PR 具有 多个共同作者

代码贡献是否足够重要以获得共同作者身份,由维护者自行决定,与“新增内容”条目相同。

scikit-learn.org 网站#

scikit-learn 网站(https://scikit-learn.org)托管在 GitHub 上,但应很少通过推送至 scikit-learn/scikit-learn.github.io 仓库手动更新。大多数更新可以通过推送至主分支(用于 /dev)或类似 0.99.X 的发布分支进行,Circle CI 会自动构建并上传文档。

实验性功能#

sklearn.experimental 模块在 0.21 版本中引入,包含实验性功能/估计器,这些功能/估计器可能会在没有弃用周期的情况下发生变化。

要创建一个实验性模块,您可以复制并修改 enable_halving_search_cv.pyenable_iterative_imputer.py 的内容。

Note

这些是 0.24 版本中的永久链接,因为这些估计器仍然是实验性的。它们可能在阅读时已经稳定,因此是永久链接。请参阅下面的说明,了解从实验性到稳定的过渡。

请注意,公共导入路径必须指向一个公共子包(如 sklearn/ensemblesklearn/impute ),而不仅仅是一个 .py 模块。此外,导入的(私有)实验性功能必须位于公共子包的子模块/子包中,例如 sklearn/ensemble/_hist_gradient_boosting/sklearn/impute/_iterative.py 。这是为了确保在未来这些功能不再是实验性时,序列化对象仍然有效。

为了避免类型检查器(例如 mypy)错误,实验性功能的直接导入 估计器应在父模块中完成,受 if typing.TYPE_CHECKING 检查保护。参见 sklearn/ensemble/__init__.py , 或 sklearn/impute/__init__.py 作为示例。

请根据 test_enable_hist_gradient_boosting.py 中的内容编写基本测试。

确保你编写的面向用户的代码明确提及该功能是实验性的,并添加 # noqa 注释以避免 pep8 相关的警告:

# 要使用此实验性功能,我们需要明确请求它:
from sklearn.experimental import enable_hist_gradient_boosting  # noqa
from sklearn.ensemble import HistGradientBoostingRegressor

为了使文档正确渲染,请在 doc/conf.py 中导入 enable_my_experimental_feature ,否则 Sphinx 将无法导入相应的模块。请注意,使用 from sklearn.experimental import * 不起作用

请注意,某些实验性类/函数未包含在 sklearn.experimental 模块中: sklearn.datasets.fetch_openml

一旦该功能变得稳定,请移除 scikit-learn 代码中所有 enable_my_experimental_feature (包括功能亮点等),并将 enable_my_experimental_feature 变为仅引发警告的无操作: enable_hist_gradient_boosting.py 。该文件应无限期保留,因为我们不希望破坏用户代码:我们只是通过警告鼓励他们移除该导入。 同样地,相应地更新测试: test_enable_hist_gradient_boosting.py