scikit-imageへの貢献方法#
コミュニティの一員としてオープンソースソフトウェアを開発することは、楽しく、そして多くの場合、非常に教育的です!
GitHubを使用して作業を調整しています。そこでは、未解決の問題と新しい機能リクエストのリストを見つけることができます。
ディスカッションに参加したり、開発チームと連絡を取り合ったりするには、scikit-image開発者フォーラムとZulipチャットに参加してください。
質問はこれらの公開フォーラムに投稿してください(開発者に直接連絡するのではなく)。そうすることで、誰もが回答から恩恵を受けることができ、開発者は自分の空き時間に回答できます。遠慮しないでください、チームはとてもフレンドリーです!
開発プロセス#
以下は、ソースコードとドキュメントへの変更をscikit-imageに貢献する方法についての簡単な概要です。
初めて貢献する場合
scikit-image/scikit-imageにアクセスし、「フォーク」ボタンをクリックしてプロジェクトの独自の複製を作成します。
プロジェクトソースを含むリポジトリをローカルコンピュータに複製(ダウンロード)します。
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
はあなたの個人用フォークを参照します。
次に、ビルド環境を設定します。
最後に、
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のあなたのフォークにプッシュバックします。
git push origin transform-speedups
GitHubのユーザー名とパスワードを入力します(繰り返し貢献者または上級ユーザーは、SSHを使用してGitHubに接続することでこのステップを削除できます)。
GitHubにアクセスします。新しいブランチが緑色の「プルリクエスト」ボタンとともに表示されます。それをクリックします。
必要に応じて、開発者フォーラムに投稿して、変更内容を説明したり、レビューを依頼したりできます。
より詳細な説明については、scikit-image
でGitを使用する方法に関するこれらの詳細なドキュメント(scikit-imageソースコードの操作)をお読みください。
レビュープロセス
レビューアー(他の開発者や関心のあるコミュニティメンバー)は、実装、ドキュメント、スタイルの改善に役立つように、プルリクエスト(PR)にインラインコメントや一般的なコメントを書き込みます。プロジェクトで作業しているすべての開発者はコードレビューを受けており、私たちはそれを、全員が学び、全体的なコード品質が向上するフレンドリーな会話と考えています。そのため、レビューによって貢献をためらわないでください。その目的はプロジェクトの品質を向上させることであり、批判することではありません(結局のところ、あなたの寄付してくれた時間には非常に感謝しています!)。
プルリクエストを更新するには、ローカルリポジトリに変更を加えてコミットします。それらの変更が(以前と同じブランチに)プッシュされるとすぐに、プルリクエストは自動的に更新されます。
各プルリクエストの送信後、継続的インテグレーション(CI)サービスがトリガーされ、パッケージのビルド、単体テストの実行、コードカバレッジの測定、ブランチのコーディングスタイル(PEP8)のチェックが行われます。PRをマージするには、テストに合格する必要があります。CIが失敗した場合は、「失敗」アイコン(赤いバツ印)をクリックしてビルドとテストのログを検査することで、原因を特定できます。
プルリクエストは、マージされる前に2人のコアチームメンバーによって承認される必要があります。
ドキュメントの変更
変更によって非推奨化が導入された場合は、将来チームが非推奨になった機能を削除するためのリマインダーを
TODO.txt
に追加します。scikit-imageは、changelistを使用して、プルリクエストからリリースノートのリストを自動的に生成します。デフォルトでは、changelistはプルリクエストのタイトルとそのGitHubラベルを使用して、適切なセクションに分類します。ただし、より複雑な変更については、プルリクエストの説明内の
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を行うことをお勧めしますが、いずれにしてもほとんどのPRはsquash and mergeします。
ガイドライン#
すべてのコードにはテストが必要です(詳細については、以下のテストカバレッジを参照してください)。
すべてのコードは、NumPyとSciPyと同じ標準で文書化される必要があります。
新しい機能については、常にギャラリーに例を追加してください(詳細については、以下のギャラリーを参照してください)。
2人のコアチームメンバーによるレビューと承認なしで変更がマージされることはありません。このルールには2つの例外があります。まず、ドキュメントのみに影響を与えるプルリクエストは、ほとんどの場合、1人のコアチームメンバーによるレビューと承認のみが必要です。メンテナが変更が大きい、または論争の的になる可能性があると判断した場合は、2つのレビューを依然として推奨する必要があります。2番目のケースは、CIを動作状態に復元するマイナーな修正です。これはかなり迅速にマージする必要があります。開発者フォーラムで、プルリクエストへの応答がない場合はご連絡ください。**決して自分のプルリクエストをマージしないでください。**
スタイルガイドライン#
エディターを設定して、末尾の空白を削除します。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 skimage._shared import xyz
ではなくfrom .._shared import xyz
など、相対モジュールインポートを使用します。APIを定義する純粋なPython関数でCythonコードをラップします。これにより、多くの場合Cythonコードを認識しないコードイントロスペクションツールとの互換性が向上します。
Cython関数は、可能な限り`with nogil:`を使ってGILを解放してください。
テスト#
プルリクエストをマージするには、テストスイートがパスする必要があります。また、動作の変更をすべて網羅するテストを追加する必要があります。
テストフレームワークには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 -- 任意の pytest 引数
。すべてのテストとdoctestの実行:
spin test -- --doctest-plus skimage
テストフェーズでの警告#
デフォルトでは、テストスイートによって発生した警告はエラーになります。環境変数SKIMAGE_TEST_STRICT_WARNINGS
を0
に設定することで、この動作を無効にすることができます。
テストカバレッジ#
モジュールのテストは、理想的にはそのモジュールのすべてのコードを網羅する必要があります。つまり、ステートメントカバレッジは100%である必要があります。
テストカバレッジを測定するには、以下のコマンドを実行します。
$ spin test --coverage
これにより、テストが実行され、skimage
内の各ファイルについて1行のレポートが表示され、テストカバレッジの詳細が示されます。
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インチにする必要があります。ギャラリーエントリのサムネイルを変更することもできます。
警告の修正#
“citation not found: R###” ドキュメント文字列の最初の行で参照の後にアンダースコアが付いている可能性があります(例:[1]_)。ソースファイルを見つけるには、この方法を使用します。`$ cd doc/build; grep -rin R####`
“Duplicate citation R###, other instance in…”” ドキュメント文字列のいずれかに[1]がないのに[2]がある可能性があります。
画像には、sphinx処理前のパス(_imagesディレクトリではない)を使用してください。
非推奨化サイクル#
関数の呼び出し方法を変更する必要がある場合は、ユーザーに警告するために非推奨化サイクルに従う必要があります。
非推奨化サイクルは、以下の場合に必要ありません。
新しい関数の追加、または
関数のシグネチャの末尾に新しいキーワード引数を追加する場合、または
予期しない動作または誤った動作を修正する場合。
非推奨化サイクルは、以下の場合に必要です。
キーワード引数の名前変更、または
引数またはキーワードの順序の変更、または
関数の引数の追加、または
関数の名前または場所の変更、または
関数引数またはキーワードのデフォルト値の変更。
通常、非推奨化警告は変更が行われる前に2つのリリースの間有効です。
例として、関数シグネチャのデフォルト値の変更を考えてみましょう。バージョン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
は、APIの変更を強調するためにFutureWarning
を発生させます。例:
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
のデータレジストリを更新できます。
ベンチマーク#
ほとんどのプルリクエストでは必須ではありませんが、パフォーマンス関連のPRには、最適化の対象となるユースケースを明確に示すためにベンチマークを含めるようお願いします。スナップショットの履歴ビューは、次のウェブサイトにあります。
このセクションでは、ベンチマークのセットアップ方法と、spin asv -- dev
、spin asv -- run
、spin asv -- continuous
の3つのコマンドについて説明します。
前提条件#
まず、開発環境に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
ディレクトリにファイルを追加します。このファイルには、1つのsetup
メソッドと、time_
で始まるメソッドを少なくとも1つ含むクラスが含まれている必要があります。
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メソッド自体がNotImplementedErrorを発生させることができます。登録モジュールに関する次の例を参照してください。
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
ファイルで指定された環境を構築し、現在のコミットとメインブランチのコードとの間のベンチマークのパフォーマンスを比較します。
出力は次のようになる場合があります。
$ 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とメインブランチの違いは、airspeed velocityが報告するには不十分です。
asv compare
コマンドを使用すると、以前にベンチマーク結果が実行された2つの特定のリビジョンについて、結果を比較することもできます。
spin asv -- compare v0.14.5 v0.17.2
最後に、コミットハッシュまたはリリースタグに^!
を追加することで、特定のコミットハッシュまたはリリースタグに対してのみASVベンチマークを実行することもできます。たとえば、リリースv0.17.2でskimage.filterモジュールのベンチマークを実行するには、
spin asv -- run -b Filter v0.17.2^!