開發者提示與技巧#
提升生產力與保持理智的技巧#
在此章節中,我們收集了一些有用的建議和工具,這些建議和工具可以提高您在審查 pull request、運行單元測試等時的生活品質。其中一些技巧包含使用者腳本,這些腳本需要瀏覽器擴充功能,例如 TamperMonkey 或 GreaseMonkey;若要設定使用者腳本,您必須安裝、啟用並運行這些擴充功能之一。我們以 GitHub gist 的形式提供使用者腳本;若要安裝它們,請點擊 gist 頁面上的「Raw」按鈕。
在 pull request 上摺疊和展開過時的差異#
當 PR 中程式碼的對應行同時被更改時,GitHub 會隱藏這些行的討論。此 使用者腳本 提供了一個快捷鍵(撰寫時為 Control-Alt-P,但請查看程式碼以確保),可一次展開所有此類隱藏的討論,以便您可以趕上進度。
將 pull request 作為遠端追蹤分支簽出#
在您的本機 fork 中,將以下行添加到您的 .git/config
中的 [remote "upstream"]
標題下:
fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*
然後,您可以使用 git checkout pr/PR_NUMBER
來導覽至具有給定編號的 pull request 的程式碼。(在此 gist 中閱讀更多資訊。)
在 pull request 中顯示程式碼覆蓋率#
若要覆蓋 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
估算器的所有通用測試。
當單元測試失敗時,以下技巧可以使除錯更容易
命令列參數
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
未正確捕獲時發生錯誤,因此也建議使用 -Werror::FutureWarning
標誌來運行 pytest
。
用於審查的標準回覆#
將其中一些儲存在 GitHub 的 已儲存回覆中以供審查可能會很有幫助
Issue:使用問題
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.
Issue:歡迎您更新文件
Please feel free to offer a pull request updating the documentation if you feel it could be improved.
Issue:錯誤的獨立範例
Please provide [self-contained example code](https://scikit-learn.dev.org.tw/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.
Issue:軟體版本
To help diagnose your issue, please paste the output of:
```py
import sklearn; sklearn.show_versions()
```
Thanks.
Issue:程式碼區塊
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!
Issue/Comment:連結至程式碼
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/).
Issue/Comment:連結至註解
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.dev.org.tw/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 或 Issue:維護成本
Every feature we include has a [maintenance cost](https://scikit-learn.dev.org.tw/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.dev.org.tw/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.dev.org.tw/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.dev.org.tw/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
可用於建立一個 conda 環境,其具有與 CI 上完全相同的 conda 和 pip 套件。例如,以下命令將建立一個名為 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 特定錯誤或測試失敗的說明。這是基於使用 docker 方便的 QEMU 使用者模式模擬(請參閱 multiarch/qemu-user-static)。
注意
以下說明以 ARM64 為例,但在適當地變更 Docker 映像和 Miniforge 路徑後,也適用於 ppc64le。
在主機檔案系統上準備一個資料夾,並下載必要的工具和原始程式碼
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 如何在幕後運作的背景知識。