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

发布#

本节介绍如何准备一个主要版本发布、增加次要版本号或增加补丁版本号的错误修复发布。我们的惯例是,在发布最终发行版之前发布一个或多个候选版本 (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、主要或次要)都是该分支下的一个标签。

这仅执行一次,因为主要和次要版本在同一个分支上进行

# Assuming upstream is an alias for the main scikit-learn repo:
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 分支并打开一个 PR scikit-learn/0.99.X 分支。将拉取请求描述中的 发布清单 模板复制到其中,以跟踪进度。

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

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

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

次要版本应仅包含错误修复和一些相关的文档更改。任何导致行为更改的 PR,而这些更改不是错误修复,都应排除在外。例如,以下提供了有关 1.2.2 版本的说明。

  • upstream/main 创建一个分支,在您自己的分支(此处称为 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
    
  • 创建一个草稿 PR,目标为 upstream/1.2.X 分支(而不是 upstream/main),其中包含所有所需的更改。

  • 目前不要推送任何内容到该分支。

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

    git rebase -i upstream/1.2.X
    

    这将打开一个交互式重新设置基准,其中 git-rebase-todo 包含 main 上的所有最新提交。在此阶段,您必须至少与其他人一起执行此交互式重新设置基准(三个人重新设置基准更好,这样可以避免遗漏任何内容并消除任何疑虑)。

    • 不要删除行,而是通过将 pick 替换为 drop 来删除提交

    • 要为错误修复版本选择的提交通常以以下前缀开头:FIXCIDOC。它们至少应包含在 GitHub 上针对此版本里程碑化的所有已合并 PR 的提交,或在更改日志中记录为里程碑化的提交。一些错误修复可能记录在主要版本的更改日志中,而不是下一个错误修复版本的更改日志中,在这种情况下,需要先在 main 分支中移动匹配的更改日志条目,然后将其回退到发布 PR 中。

    • 要为错误修复版本删除的提交通常以以下前缀开头:FEATMAINTENHAPI。不包含它们的原因是为了防止行为更改(这只能在重大或主要版本中出现)。

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

    • 保存并退出,开始交互式重新设置基准。

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

  • 强制将重新设置基准的结果和额外的发布提交推送到发布 PR

    git push -f fork release-1.2.2:release-1.2.2
    
  • 复制 发布清单 模板,并将其粘贴到拉取请求描述中,以跟踪进度。

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

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

发布#

  1. 确保您已签出发布 PR 的分支,如上文 准备发布 PR 中所述。

  2. 更新文档。请注意,这是针对最终版本,不一定针对 RC 版本。这些更改应在 main 中进行,并在最终版本之前才樱桃选择到发布分支中。

    • 编辑 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,以更改首页的“新闻”条目(以及发布月份)。不要忘记删除旧条目(通常两到三年或三个版本就足够了),并更新正在进行的开发条目。

  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

注意

在构建轮子之前,请确保 pyproject.toml 文件是最新的,并且为每个 Python 版本使用最旧的 numpy 版本,以避免 ABI 不兼容问题。此外,对于每个新支持的 Python 版本,都需要在 pyproject.toml 文件中添加一个新行。

注意

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

  1. 一旦所有 CD 任务在 PR 中成功完成,请合并它,并在提交消息中再次使用 [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  # in the 0.99.X branch
    git push [email protected]: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.ac.cn(在“运行工作流程”表单中将“testpypi”替换为“pypi”)。

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

    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.ac.cn

    twine upload dist/*
    
  6. 对于主要/次要版本(不是错误修复版本或候选版本),请更新 stable 的符号链接以及 scikit-learn/scikit-learn.github.io 中的 latestStable 变量。

    cd /tmp
    git clone --depth 1 --no-checkout [email protected]: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
    
  7. 更新 SECURITY.md 以反映最新支持的版本。

发布清单#

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

* [ ] update news and what's new date in release branch
* [ ] update news and what's new date and sklearn dev0 version in main branch
* [ ] check that the wheels for the release can be built successfully
* [ ] merge the PR with `[cd build]` commit message to upload wheels to the staging repo
* [ ] upload the wheels and source tarball to https://test.pypi.org
* [ ] create tag on the main github repo
* [ ] confirm bot detected at
  https://github.com/conda-forge/scikit-learn-feedstock and wait for merge
* [ ] upload the wheels and source tarball to PyPI
* [ ] https://github.com/scikit-learn/scikit-learn/releases publish (except for RC)
* [ ] announce on mailing list and on Twitter, and LinkedIn
* [ ] update symlink for stable in
  https://github.com/scikit-learn/scikit-learn.github.io (only major/minor)
* [ ] update SECURITY.md in main branch (except for RC)

合并拉取请求#

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

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

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

  • 对于具有多个代码贡献者的 PR,必须小心保留 Co-authored-by: name <[email protected]> 标签在详细描述中。这将标记 PR 为具有 多个共同作者。代码贡献是否足够重要以至于需要共同署名,由维护者自行决定,与“新增内容”条目相同。

scikit-learn.org 网站#

scikit-learn 网站 (https://scikit-learn.cn) 托管在 GitHub 上,但很少通过手动推送到 scikit-learn/scikit-learn.github.io 仓库来更新。大多数更新可以通过推送到 master(用于 /dev)或发布分支(如 0.99.X)来完成,Circle CI 会从这些分支自动构建和上传文档。

实验性功能#

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

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

注意

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

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

为了避免类型检查器(例如 mypy)错误,应该在父模块中直接导入实验性估计器,并使用 if typing.TYPE_CHECKING 检查进行保护。请参阅 sklearn/ensemble/__init__.pysklearn/impute/__init__.py 以获取示例。

请按照 test_enable_hist_gradient_boosting.py 中的测试编写基本测试。

确保您编写的每个面向用户的代码都明确提到该功能是实验性的,并在代码中添加 # noqa 注释以避免与 pep8 相关的警告

# To use this experimental feature, we need to explicitly ask for it:
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.