开发者提示与技巧#
提高效率和保持理智的技巧#
在本节中,我们收集了一些有用的建议和工具,它们可以在你审阅拉取请求、运行单元测试等方面提高你的工作质量。其中一些技巧包括需要浏览器扩展程序(如 TamperMonkey 或 GreaseMonkey)的用户脚本;要设置用户脚本,你必须安装、启用并运行其中一个扩展程序。我们以 GitHub gist 的形式提供用户脚本;要安装它们,请点击 gist 页面上的“Raw”按钮。
折叠和展开拉取请求上过时的差异#
当相应的代码行在这期间发生变化时,GitHub 会隐藏 PR 上的讨论。这个 用户脚本 提供了一个快捷方式(撰写本文时是 Control-Alt-P,但请查看代码以确认)来一次性展开所有这些隐藏的讨论,以便你能够跟进。
将拉取请求作为远程跟踪分支检出#
在你的本地 fork 中,将以下行添加到你的 .git/config 文件中的 [remote "upstream"] 标题下:
fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*
然后你可以使用 git checkout pr/PR_NUMBER 导航到具有给定编号的拉取请求的代码。(在此 gist 中了解更多信息。)
在拉取请求中显示代码覆盖率#
要叠加由 CodeCov 持续集成生成的代码覆盖率报告,请考虑使用 此浏览器扩展程序。每行代码的覆盖率将作为行号后面的彩色背景显示。
有用的 pytest 别名和标志#
完整的测试套件运行时间相当长。为了加快迭代速度,可以使用 pytest 选择器来选择测试子集。特别是,可以根据 节点 ID 运行单个测试
pytest -v sklearn/linear_model/tests/test_logistic.py::test_sparsify
或者使用 -k pytest 参数 根据名称选择测试。例如,
pytest sklearn/tests/test_common.py -v -k LogisticRegression
将运行 LogisticRegression 估计器的所有 common tests。
当单元测试失败时,以下技巧可以使调试更容易
命令行参数
pytest -l指示 pytest 在发生故障时打印局部变量。参数
pytest --pdb在发生故障时进入 Python 调试器。要改为进入功能丰富的 IPython 调试器ipdb,你可以设置一个 shell 别名pytest --pdbcls=IPython.terminal.debugger:TerminalPdb --capture no
其他可能变得有用的 pytest 选项包括
-x在第一个失败的测试时退出,--lf重新运行上次运行失败的测试,--ff重新运行所有先前的测试,首先运行失败的测试,-s以便 pytest 不捕获print()语句的输出,--tb=short或--tb=line来控制日志的长度,--runxfail也运行被标记为已知故障 (XFAIL) 的测试并报告错误。
由于如果 FutureWarning 没有被正确捕获,我们的持续集成测试将会出错,因此还建议运行 pytest 时带上 -Werror::FutureWarning 标志。
用于审阅的标准回复#
将其中一些回复存储在 GitHub 的 保存回复 中以供审阅可能会有所帮助
问题:使用问题
You are asking a usage question. The issue tracker is for bugs and new features. For usage questions, it is recommended to try [Stack Overflow](https://stackoverflow.com/questions/tagged/scikit-learn) or [the Mailing List](https://mail.python.org/mailman/listinfo/scikit-learn).
Unfortunately, we need to close this issue as this issue tracker is a communication tool used for the development of scikit-learn. The additional activity created by usage questions crowds it too much and impedes this development. The conversation can continue here, however there is no guarantee that it will receive attention from core developers.
问题:欢迎你更新文档
Please feel free to offer a pull request updating the documentation if you feel it could be improved.
问题:用于 bug 的自包含示例
Please provide [self-contained example code](https://scikit-learn.cn/dev/developers/minimal_reproducer.html), including imports and data (if possible), so that other contributors can just run it and reproduce your issue. Ideally your example code should be minimal.
问题:软件版本
To help diagnose your issue, please paste the output of:
```py
import sklearn; sklearn.show_versions()
```
Thanks.
问题:代码块
Readability can be greatly improved if you [format](https://help.github.com/articles/creating-and-highlighting-code-blocks/) your code snippets and complete error messages appropriately. For example:
```python
print(something)
```
generates:
```python
print(something)
```
And:
```pytb
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'hello'
```
generates:
```pytb
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'hello'
```
You can edit your issue descriptions and comments at any time to improve readability. This helps maintainers a lot. Thanks!
问题/评论:链接到代码
Friendly advice: for clarity's sake, you can link to code like [this](https://help.github.com/articles/creating-a-permanent-link-to-a-code-snippet/).
问题/评论:链接到评论
Please use links to comments, which make it a lot easier to see what you are referring to, rather than just linking to the issue. See [this](https://stackoverflow.com/questions/25163598/how-do-i-reference-a-specific-issue-comment-on-github) for more details.
PR-NEW:更好的描述和标题
Thanks for the pull request! Please make the title of the PR more descriptive. The title will become the commit message when this is merged. You should state what issue (or PR) it fixes/resolves in the description using the syntax described [here](https://scikit-learn.cn/dev/developers/contributing.html#contributing-pull-requests).
PR-NEW:修复 #
Please use "Fix #issueNumber" in your PR description (and you can do it more than once). This way the associated issue gets closed automatically when the PR is merged. For more details, look at [this](https://github.com/blog/1506-closing-issues-via-pull-requests).
PR-NEW 或问题:维护成本
Every feature we include has a [maintenance cost](https://scikit-learn.cn/dev/faq.html#why-are-you-so-selective-on-what-algorithms-you-include-in-scikit-learn). Our maintainers are mostly volunteers. For a new feature to be included, we need evidence that it is often useful and, ideally, [well-established](https://scikit-learn.cn/dev/faq.html#what-are-the-inclusion-criteria-for-new-algorithms) in the literature or in practice. Also, we expect PR authors to take part in the maintenance for the code they submit, at least initially. That doesn't stop you implementing it for yourself and publishing it in a separate repository, or even [scikit-learn-contrib](https://scikit-learn-contrib.github.io).
PR-WIP:合并前需要什么?
Please clarify (perhaps as a TODO list in the PR description) what work you believe still needs to be done before it can be reviewed for merge. When it is ready, please prefix the PR title with `[MRG]`.
PR-WIP:需要回归测试
Please add a [non-regression test](https://en.wikipedia.org/wiki/Non-regression_testing) that would fail at main but pass in this PR.
PR-MRG:耐心等待
Before merging, we generally require two core developers to agree that your pull request is desirable and ready. [Please be patient](https://scikit-learn.cn/dev/faq.html#why-is-my-pull-request-not-getting-any-attention), as we mostly rely on volunteered time from busy core developers. (You are also welcome to help us out with [reviewing other PRs](https://scikit-learn.cn/dev/developers/contributing.html#code-review-guidelines).)
PR-MRG:添加到新内容中
Please add an entry to the future changelog by adding an RST fragment into the module associated with your change located in `doc/whats_new/upcoming_changes`. Refer to the following [README](https://github.com/scikit-learn/scikit-learn/blob/main/doc/whats_new/upcoming_changes/README.md) for full instructions.
PR:不要更改不相关的内容
Please do not change unrelated lines. It makes your contribution harder to review and may introduce merge conflicts to other pull requests.
调试 CI 问题#
CI 问题可能由各种原因引起,因此这绝不是一个全面的指南,而是一个有用的提示和技巧列表。
使用锁文件获取接近 CI 的环境#
conda-lock 可用于创建与 CI 上具有完全相同的 conda 和 pip 包的 conda 环境。例如,以下命令将创建一个名为 scikit-learn-doc 的 conda 环境,该环境类似于 CI 环境
conda-lock install -n scikit-learn-doc build_tools/circle/doc_linux-64_conda.lock
注意
它仅在你具有与 CI 构建相同的操作系统时才有效(检查锁文件中的 platform:)。例如,前面的命令仅在你使用 Linux 机器时才有效。此外,这可能无法让你重现一些与 CI 环境的特殊性更相关的问题,例如 sklearn.show_versions() 中 OpenBLAS 报告的 CPU 架构。
如果你没有与 CI 构建相同的操作系统,你仍然可以从正确的环境 yaml 文件创建 conda 环境,尽管它不会像使用关联的锁文件那样接近 CI 环境。例如,对于文档构建
conda env create -n scikit-learn-doc -f build_tools/circle/doc_environment.yml -y
由于各种原因,这可能无法为你提供与 CI 中完全相同的包版本,例如
在锁文件最后一次在
main分支中更新的时间与你运行conda create命令的时间之间,某些包可能发布了新版本。你始终可以尝试查看锁文件中的版本并手动指定你认为有助于重现问题的某些特定包的版本。根据操作系统,默认安装的包可能不同。例如,安装 numpy 时,默认的 BLAS 库在 Linux 上是 OpenBLAS,在 Windows 上是 MKL。
此外,问题可能特定于操作系统,因此唯一能够重现的方法是拥有与 CI 构建相同的操作系统。
使用 valgrind 调试 Cython 中的内存错误#
虽然 python/numpy 的内置内存管理相对健壮,但它可能会导致某些例程的性能损失。因此,scikit-learn 中的许多高性能代码都是用 cython 编写的。然而,这种性能提升也带来了一个权衡:cython 代码中很容易出现内存错误,尤其是在代码严重依赖指针运算的情况下。
内存错误可以通过多种方式表现出来。最容易调试的通常是分段错误和相关的 glibc 错误。未初始化的变量可能导致难以追踪的意外行为。在调试此类错误时,一个非常有用的工具是 valgrind。
Valgrind 是一个命令行工具,可以追踪各种代码中的内存错误。请遵循以下步骤:
在系统上安装 valgrind。
下载 python valgrind 抑制文件:valgrind-python.supp。
遵循 README.valgrind 文件中的说明来自定义你的 python 抑制。如果你不这样做,你将会有与 python 解释器相关的虚假输出,而不是你自己的代码。
按如下方式运行 valgrind
valgrind -v --suppressions=valgrind-python.supp python my_test_script.py
结果将是所有内存相关错误的列表,这些错误引用了由 cython 从你的 .pyx 文件生成的 C 代码中的行。如果你检查 .c 文件中引用的行,你将看到指示你的 .pyx 源文件中相应位置的注释。希望输出能为你提供有关内存错误来源的线索。
有关 valgrind 及其一系列选项的更多信息,请参阅 valgrind 网站 上的教程和文档。
在 x86_64 机器上构建和测试 ARM64 平台#
基于 ARM 的机器是移动、边缘或其他低能耗部署(包括在云中,例如 Scaleway 或 AWS Graviton)的流行目标。
这里是在 x86_64 主机笔记本电脑或工作站上设置本地开发环境以重现 ARM 特定错误或测试失败的说明。这基于 QEMU 用户模式仿真,为了方便起见使用了 docker(请参阅 multiarch/qemu-user-static)。
注意
以下说明以 ARM64 为例,但它们也适用于 ppc64le,只需相应更改 Docker 镜像和 Miniforge 路径即可。
在主机文件系统上准备一个文件夹并下载必要的工具和源代码
mkdir arm64
pushd arm64
wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-aarch64.sh
git clone https://github.com/scikit-learn/scikit-learn.git
使用 docker 安装 QEMU 用户模式并运行一个 ARM64v8 容器,该容器可以通过 /io 挂载点访问你的共享文件夹
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker run -v `pwd`:/io --rm -it arm64v8/ubuntu /bin/bash
在容器中,为 ARM64(又名 aarch64)架构安装 miniforge3
bash Miniforge3-Linux-aarch64.sh
# Choose to install miniforge3 under: `/io/miniforge3`
每当你重新启动一个新容器时,你需要重新初始化以前安装在 /io/miniforge3 下的 conda 环境
/io/miniforge3/bin/conda init
source /root/.bashrc
因为 /root 主文件夹是临时 docker 容器的一部分。另一方面,存储在 /io 下的每个文件或目录都是持久的。
然后你可以像往常一样构建 scikit-learn(你需要像往常一样使用 apt 或 conda 安装编译器工具和依赖项)。由于仿真层,构建 scikit-learn 需要很长时间,但是如果你将 scikit-learn 文件夹放在 /io 挂载点下,则只需执行一次。
然后使用 pytest 仅运行你感兴趣调试的模块的测试。
Meson 构建后端#
自 scikit-learn 1.5.0 起,我们使用 meson-python 作为构建工具。Meson 是 scikit-learn 和 PyData 生态系统的一个新工具。它被其他几个包使用,这些包已经撰写了关于它是什么以及它是如何工作的优秀指南。
pandas 设置文档:pandas 的设置与我们相似(没有 spin 或 dev.py)
scipy Meson 文档 提供了关于 Meson 如何在幕后工作的更多背景信息