如何貢獻至 scikit-image#
作為社群的一份子開發開源軟體很有趣,而且通常也很有教育意義!
我們使用 GitHub 協調我們的工作,您可以在其中找到 開啟的問題和 新功能請求的清單。
若要追蹤討論,或與開發團隊聯繫,請加入我們的 scikit-image 開發人員論壇和 Zulip 聊天。
請將問題發佈到這些公開論壇 (而不是直接聯繫開發人員);這樣一來,每個人都可以從答案中獲益,而且開發人員可以根據他們的時間回覆。別害羞,團隊非常友善!
開發流程#
以下是如何將原始碼和文件變更貢獻至 scikit-image 的簡要概述。
如果您是第一次貢獻者
前往 scikit-image/scikit-image 並按一下「fork」按鈕,建立您自己的專案副本。
將專案原始碼的儲存庫複製 (下載) 到您的本機電腦
git clone https://github.com/your-username/scikit-image.git
變更到複製的儲存庫的根目錄
cd scikit-image
新增上游儲存庫
git remote add upstream https://github.com/scikit-image/scikit-image.git
現在,您有以下名為
upstream
的遠端儲存庫,指的是scikit-image
儲存庫,以及origin
,指的是您的個人 fork。
接下來,設定您的建置環境。
最後,我們建議您使用預先提交鉤子,每次您執行
git commit
時,都會執行程式碼檢查器和格式化器pip install pre-commit pre-commit install
開發您的貢獻
從上游提取最新的變更
git checkout main git pull upstream main
為您要處理的功能建立分支。使用合理名稱,例如「transform-speedups」
git checkout -b transform-speedups
在您進展時在本機提交 (使用
git add
和git commit
)。請撰寫 良好的提交訊息。
若要提交您的貢獻
將您的變更推送回您在 GitHub 上的 fork
git push origin transform-speedups
輸入您的 GitHub 使用者名稱和密碼 (重複貢獻者或進階使用者可以透過 使用 SSH 連接至 GitHub 來移除此步驟)。
前往 GitHub。新的分支將會顯示綠色的「pull request」按鈕,按一下它。
如果您願意,請在 開發人員論壇上發文,說明您的變更或要求審閱。
如需更詳細的討論,請閱讀這些關於如何搭配 scikit-image
使用 Git 的 詳細文件 (使用 scikit-image 原始碼)。
審閱流程
審閱者 (其他開發人員和感興趣的社群成員) 將在您的 pull request (PR) 上撰寫內嵌和/或一般意見,以協助您改善其實作、文件和風格。專案中工作的每一位開發人員都會審閱其程式碼,而且我們已經將其視為友善的對話,從中我們都可以學習,並讓整體程式碼品質受益。因此,請不要讓審閱阻礙您貢獻:其唯一目的是改善專案的品質,而不是批評 (畢竟,我們非常感謝您捐贈的時間!)。
若要更新您的 pull request,請在您的本機儲存庫中進行變更並提交。只要將這些變更推送上來 (與之前相同的分支),pull request 就會自動更新。
每次提交 pull request 後,都會觸發持續整合 (CI) 服務,以建置套件、執行單元測試、測量程式碼覆蓋率,並檢查您分支的程式碼風格 (PEP8)。測試必須通過,您的 PR 才能合併。如果 CI 失敗,您可以按一下「失敗」圖示 (紅色叉號) 並檢查建置和測試記錄,找出失敗的原因。
pull request 必須在合併前由兩位核心團隊成員核准。
文件變更
如果您的變更引入了棄用,請在
TODO.txt
中新增提醒,讓團隊在未來移除棄用的功能。scikit-image 使用 changelist 從 pull request 自動產生發行說明清單。根據預設,changelist 將使用 pull request 的標題及其 GitHub 標籤,將其排序到適當的章節中。但是,對於更複雜的變更,我們鼓勵您使用 pull request 說明中的
release-note
程式碼區塊,更詳細地描述它們;例如```release-note Remove the deprecated function `skimage.color.blue`. Blend `skimage.color.cyan` and `skimage.color.magenta` instead. ```
您可以參考 發行說明 中的範例,以及參考 changelist 的文件以取得更多詳細資訊。
注意
給審閱者:如果 PR 說明不明顯,請確保合併訊息中說明了變更的原因和內容。
upstream main
和您的功能分支之間的差異#
如果 GitHub 指出您的 PR 分支無法再自動合併,請將 main 分支合併到您的分支中
git fetch upstream main
git merge upstream/main
如果發生任何衝突,則需要先修正這些衝突才能繼續。使用以下命令查看哪些檔案有衝突
git status
這會顯示類似以下的訊息
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: file_with_conflict.txt
在衝突的檔案內,您會找到如下的區段
The way the text looks in your branch
選擇應該保留的文字版本,並刪除其餘部分
The way the text looks in your branch
現在,新增修正的檔案
git add file_with_conflict.txt
在修正所有合併衝突後,執行
git commit
注意
我們鼓勵進階 Git 使用者使用 rebase 而非 merge,但我們無論如何都會 squash 並合併大多數 PR。
準則#
所有程式碼都應有測試 (如需更多詳細資訊,請參閱下方的 測試覆蓋率)。
所有程式碼都應記錄在案,其 標準與 NumPy 和 SciPy 相同。
對於新功能,務必將範例新增至展示區 (如需更多詳細資訊,請參閱下方的 展示區)。
未經兩位核心團隊成員的審閱和核准,任何變更都不得合併。此規則有兩個例外。首先,在大多數情況下,僅影響文件的 pull request 只需要一位核心團隊成員的審閱和核准。如果維護者認為變更很大或可能引起爭議,仍應鼓勵進行兩次審閱。第二種情況是修復次要錯誤,使其恢復 CI 的工作狀態,因為這些錯誤應盡快合併。如果您沒有收到 pull request 的回覆,請在 開發人員論壇上發文。永遠不要合併您自己的 pull request。
風格指南#
設定您的編輯器以移除尾隨空白。遵循 PEP08。
使用 numpy 資料類型而非字串 (
np.uint8
而非"uint8"
)。使用以下匯入慣例
import numpy as np import matplotlib.pyplot as plt import scipy as sp import skimage as ski sp.ndimage.label(...) ski.measure.label(...) # only in Cython code cimport numpy as cnp cnp.import_array()
在記錄陣列參數時,使用
image : (M, N) ndarray
,然後在 docstring 中參照M
和N
(如果必要)。將陣列維度參照為 (平面)、列、欄,而不是 x、y、z。如需更多資訊,請參閱使用者指南中的 座標慣例。
函式應支援所有輸入影像 dtype。使用
img_as_float
等公用函式來協助轉換為適當的類型。輸出格式可以是任何最有效率的格式。這可讓我們將數個函式串連成管線,例如hough(canny(my_image))
在 C/C++ 和 Cython 程式碼中,使用
Py_ssize_t
作為所有索引、形狀和大小變數的資料類型。使用相對模組匯入,亦即
from .._shared import xyz
,而不是from skimage._shared import xyz
。將 Cython 程式碼包裝在純 Python 函式中,以定義 API。這可改善與程式碼內省工具的相容性,這些工具通常不了解 Cython 程式碼。
對於 Cython 函式,請盡可能使用
with nogil:
來釋放 GIL。
測試#
在合併 Pull Request 之前,測試套件必須通過,並且應加入測試以涵蓋所有行為上的修改。
我們使用 pytest 測試框架,測試位於各個 skimage/submodule/tests
資料夾中。
測試所需套件列在 requirements/test.txt
中。執行
所有測試:
spin test
針對子模組的測試:
spin test skimage/morphology
從特定檔案執行測試:
spin test skimage/morphology/tests/test_gray.py
執行檔案內的某個測試:
spin test skimage/morphology/tests/test_gray.py::test_3d_fallback_black_tophat
使用任意 ``pytest`` 選項執行測試:
spin test -- any pytest args you want
。執行所有測試和 doctest:
spin test -- --doctest-plus skimage
測試階段的警告#
預設情況下,測試套件產生的警告會導致錯誤。您可以將環境變數 SKIMAGE_TEST_STRICT_WARNINGS
設定為 0
來關閉此行為。
測試覆蓋率#
模組的測試理想情況下應涵蓋該模組中的所有程式碼,即語句覆蓋率應為 100%。
要測量測試覆蓋率,請執行
$ spin test --coverage
這將執行測試並列印一份報告,其中包含 skimage
中每個檔案的測試覆蓋率詳細資訊。
Name Stmts Exec Cover Missing
------------------------------------------------------------------------------
skimage/color/colorconv 77 77 100%
skimage/filter/__init__ 1 1 100%
...
建置文件#
要建置 HTML 文件,請執行
spin docs
輸出位於 scikit-image/doc/build/html/
中。加入 --clean
標記以從頭開始建置,刪除任何快取的輸出。
範例展示#
範例展示使用 Sphinx-Gallery 建置。有關完整的使用說明,請參閱其文件,以及 doc/examples
中的現有範例。
範例展示的圖片最大寬度應為 8 英吋。您也可以變更展示項目的縮圖。
修正警告#
「找不到引用:R###」docstring 第一行中的參照後方可能有一個底線 (例如 [1]_)。使用此方法尋找來源檔案:$ cd doc/build; grep -rin R####
「重複引用 R###,其他實例位於…」其中一個 docstring 中可能有一個 [2],而沒有 [1]
請務必使用 pre-sphinxification 的影像路徑 (而不是 _images 目錄)
棄用週期#
如果必須變更函式的呼叫方式,則必須遵循棄用週期來警告使用者。
在以下情況下,不需要棄用週期
新增函式,或
在函式簽名的結尾新增新的關鍵字引數,或
修正非預期或不正確的行為。
在以下情況下,需要棄用週期
重新命名關鍵字引數,或
變更引數或關鍵字的順序,或
將引數新增至函式,或
變更函式的名稱或位置,或
變更函式引數或關鍵字的預設值。
通常,棄用警告會在兩個版本中生效,然後才會進行變更。
例如,考慮修改函式簽名中的預設值。在版本 N 中,我們有
def some_function(image, rescale=True):
"""Do something.
Parameters
----------
image : ndarray
Input image.
rescale : bool, optional
Rescale the image unless ``False`` is given.
Returns
-------
out : ndarray
The resulting image.
"""
out = do_something(image, rescale=rescale)
return out
在版本 N+1 中,我們會將其變更為
def some_function(image, rescale=None):
"""Do something.
Parameters
----------
image : ndarray
Input image.
rescale : bool, optional
Rescale the image unless ``False`` is given.
.. warning:: The default value will change from ``True`` to
``False`` in skimage N+3.
Returns
-------
out : ndarray
The resulting image.
"""
if rescale is None:
warn('The default value of rescale will change '
'to `False` in version N+3.', stacklevel=2)
rescale = True
out = do_something(image, rescale=rescale)
return out
在版本 N+3 中
def some_function(image, rescale=False):
"""Do something.
Parameters
----------
image : ndarray
Input image.
rescale : bool, optional
Rescale the image if ``True`` is given.
Returns
-------
out : ndarray
The resulting image.
"""
out = do_something(image, rescale=rescale)
return out
以下是 3 版本棄用週期的流程
在函式中,如果 rescale 為
None
,則將其設定為True
,並警告預設值將在 N+3 版本中變更為False
。在
doc/release/release_dev.rst
中,於棄用之下加入「在some_function
中,rescale
引數在 N+3 中預設為False
。」在
TODO.txt
中,於與版本 N+3 相關的區段中建立一個項目,並寫入「將 some_function 中的 rescale 預設值變更為 False」。
請注意,3 版本棄用週期並非嚴格規則,在某些情況下,開發人員可以同意不同的程序。
引發警告#
skimage
引發 FutureWarning
s 來強調其 API 的變更,例如
from warnings import warn
warn(
"Automatic detection of the color channel was deprecated in "
"v0.19, and `channel_axis=None` will be the new default in "
"v0.22. Set `channel_axis=-1` explicitly to silence this "
"warning.",
FutureWarning,
stacklevel=2,
)
stacklevel 有點技術性,但可確保警告指向使用者呼叫的函式,而不是指向內部的公用程式函式。
在大多數情況下,請將 stacklevel
設定為 2
。當警告源自 scikit-image 程式庫內部的輔助常式時,請將其設定為 3
。
若要測試您的警告是否正確發出,請嘗試從 IPython 主控台呼叫函式。它應該會將您指向主控台輸入本身,而不是由 scikit-image 程式庫中的檔案發出
良好:
ipython:1: UserWarning: ...
不良:
scikit-image/skimage/measure/_structural_similarity.py:155: UserWarning:
棄用關鍵字和函式#
移除關鍵字或整個函式時,可以使用 skimage._shared.utils.deprecate_parameter
和 skimage._shared.utils.deprecate_func
公用程式函式來執行上述程序。
新增資料#
程式碼託管於 github 上,範例資料集則位於 gitlab 上。存取 skimage.data.*
時,會使用 pooch 提取這些資料集。
新的資料集會在 gitlab 上提交,合併後,可以更新主要 GitHub 儲存庫中的資料登錄 skimage/data/_registry.py
。
效能基準#
雖然並非大多數 Pull Request 的強制要求,但我們要求與效能相關的 PR 包含效能基準,以便清楚描述正在優化的使用案例。我們快照的歷史檢視可以在以下網站上找到。
在本節中,我們將回顧如何設定效能基準,以及三個命令 spin asv -- dev
、spin asv -- run
和 spin asv -- continuous
。
先決條件#
首先,在您的開發環境中安裝 airspeed velocity。安裝之前,請務必啟用您的開發環境,然後如果使用 venv
,您可以使用
source skimage-dev/bin/activate
pip install asv
如果您使用的是 conda,則此命令
conda activate skimage-dev
conda install asv
更為適當。安裝完成後,執行命令
spin asv -- machine
以讓 airspeed velocity 了解更多關於您的電腦的資訊,會很有幫助。
撰寫效能基準#
若要撰寫效能基準,請在 benchmarks
目錄中新增一個檔案,其中包含一個類別,其中包含一個 setup
方法和至少一個以 time_
為首碼的方法。
time_
方法應僅包含您想要進行效能評測的程式碼。因此,將所有準備效能評測情境的程式碼移至 setup
方法中會很有幫助。此函式會在呼叫 time_
方法之前呼叫,且其執行時間不會計入效能評測中。
以 TransformSuite
效能評測為例
import numpy as np
from skimage import transform
class TransformSuite:
"""Benchmark for transform routines in scikit-image."""
def setup(self):
self.image = np.zeros((2000, 2000))
idx = np.arange(500, 1500)
self.image[idx[::-1], idx] = 255
self.image[idx, idx] = 255
def time_hough_line(self):
result1, result2, result3 = transform.hough_line(self.image)
在此範例中,影像的建立是在 setup
方法中完成,並未包含在效能評測的回報時間中。
也可以對諸如記憶體峰值用量等功能進行效能評測。如需深入瞭解這些功能,請參閱官方 airspeed velocity 文件。
此外,在對舊版 scikit-image 進行效能評測時,效能評測檔案需要是可匯入的。因此,如果任何 scikit-image 的內容在頂層匯入,則應按照以下方式進行:
try:
from skimage import metrics
except ImportError:
pass
效能評測本身不需要針對遺失的功能進行任何保護,只有頂層匯入需要。
為了讓較新函數的測試在舊版本中標記為「n/a」(不可用)而不是「失敗」,setup 方法本身可以引發 NotImplemented 錯誤。請參閱以下關於註冊模組的範例
try:
from skimage import registration
except ImportError:
raise NotImplementedError("registration module not available")
在本機測試效能評測#
在執行真正的效能評測之前,通常值得測試程式碼是否沒有錯字。為此,您可以使用以下命令
spin asv -- dev -b TransformSuite
上面的 TransformSuite
會在您目前的環境中執行一次,以測試一切是否正常。
執行您的效能評測#
上面的命令速度很快,但並未充分測試程式碼的效能。為了做到這一點,您可能希望在您目前的環境中執行效能評測,以查看您在開發新功能時的變更效能。命令 asv run -E existing
將指定您希望在您現有的環境中執行效能評測。由於建置 scikit-image 可能非常耗時,這將節省大量時間
spin asv -- run -E existing -b TransformSuite
將結果與主分支比較#
通常,PR 的目標是將修改在速度方面的結果與 scikit-image
儲存庫主分支中的程式碼快照進行比較。命令 asv continuous
在此處會有所幫助
spin asv -- continuous main -b TransformSuite
此呼叫將會建置在 asv.conf.json
檔案中指定的環境,並比較您目前 commit 和主分支中程式碼之間的效能評測效能。
輸出看起來可能像這樣
$ spin asv -- continuous main -b TransformSuite
· Creating environments
· Discovering benchmarks
·· Uninstalling from conda-py3.7-cython-numpy1.15-scipy
·· Installing 544c0fe3 <benchmark_docs> into conda-py3.7-cython-numpy1.15-scipy.
· Running 4 total benchmarks (2 commits * 2 environments * 1 benchmarks)
[ 0.00%] · For scikit-image commit 37c764cb <benchmark_docs~1> (round 1/2):
[...]
[100.00%] ··· ...ansform.TransformSuite.time_hough_line 33.2±2ms
BENCHMARKS NOT SIGNIFICANTLY CHANGED.
在這種情況下,HEAD 和 main 之間的差異不夠顯著,無法讓 airspeed velocity 回報。
也可以使用 asv compare
命令,取得先前已執行效能評測的兩個特定修訂版本的結果比較
spin asv -- compare v0.14.5 v0.17.2
最後,也可以僅針對特定 commit hash 或發佈標籤執行 ASV 效能評測,方法是將 ^!
附加到 commit 或標籤名稱。例如,要在發佈版本 v0.17.2 上執行 skimage.filter 模組的效能評測
spin asv -- run -b Filter v0.17.2^!