BiocondaへPyPIパッケージを登録する手順

先日、自分が作成したPyPI上のPythonパッケージ`GBKviz` ([GitHub](https://github.com/moshi4/GBKviz), [紹介記事](https://qiita.com/moshi/items/3443fc887ef1119a7a9c))をBiocondaに登録してみました。Biocondaのパッケージ登録に関する記事は少ないので、自身の経験も踏まえて登録手順を紹介してみようと思います。

:::note info
自分は「Pythonパッケージ開発からPyPIへの登録」まで[Poetry](https://python-poetry.org/docs/)を利用しています。pip(setup.py)やpipenvで開発・登録をしている方とは若干の違いがあるかもしれませんが、おおよそ本記事と同様の手順でBiocondaへ登録できると思います。
:::

# 前提知識・条件

本記事では、以下のことを経験済あるいは理解している人を対象として手順を解説します。

- Pythonパッケージ開発
- PyPI(Python Package Index)へのパッケージ登録
- Git・GitHubの基本的操作

# Biocondaについて

[Bioconda]((https://bioconda.github.io/))はバイオインフォマティクス関連ツールに特化したcondaパッケージの登録・管理を行うチャンネル(リポジトリ)の一つです。Biocondaを利用することで、複雑な依存関係をもつバイオインフォツールであっても、言語やOSの違いにとらわれずにコマンドから簡単にインストールすることができます。面倒な環境構築作業の手間を大幅に減らすことができることから、バイオインフォ分野の研究で広く利用されています。

# BiocondaへのPyPIパッケージ登録手順

基本的に[公式ガイドライン](https://bioconda.github.io/contributor/)に沿って、BiocondaへPyPIパッケージを登録する手順を説明していきます。

## 1. 登録環境セットアップ

Biocondaの各パッケージのレシピ情報はGitHubリポジトリ([biconda-recipes](https://github.com/bioconda/bioconda-recipes))上で管理されています。登録環境セットアップのため、GitHub上でbioconda-recipesリポジトリをフォークして、ローカル環境にクローンします。

ローカル環境へのクローン及びリモートリポジトリ登録を公式ガイドライン記載の通りに以下のようなコマンドで実行します。
```shell
git clone git@github.com:<USERNAME>/bioconda-recipes.git # or, git clone https://github.com/<USERNAME>/bioconda-recipes.git
cd bioconda-recipes
git remote add upstream git@github.com:bioconda/bioconda-recipes.git # or, git remote add upstream https://github.com/bioconda/bioconda-recipes.git
```
フォーク＆クローン直後には特に必要ないですが、以下のコマンドでローカルリポジトリが本家リポジトリより更新が遅れている場合に最新版へ更新することができます。
```shell
git checkout master
git pull upstream master
git push origin master
```
この後にパッケージ登録作業を行っていくブランチの作成・チェックアウトを実行します。ブランチ名の指定は特にないですが、自分の登録するパッケージ名(例：gbkviz)にしておくと分かりやすいと思います。
```
git checkout -b <package name>
```

## 2. Condaレシピテンプレート生成

Condaパッケージは[**`meta.yaml`**](https://docs.conda.io/projects/conda-build/en/latest/resources/define-metadata.html)というYAML形式ファイルのレシピを元に作成されます。そのため、Condaパッケージ登録をするにはレシピを作成する必要があります。そのレシピのテンプレートは[Grayskull](https://github.com/conda-incubator/grayskull)を利用することで簡単に作成でき、`pip install grayskull`あるいは`conda install -c conda-forge grayskull`でインストールします。

`bioconda-recipes/recipes`ディレクトリで下記のレシピテンプレート生成コマンドを実行します。
```shell:PyPIパッケージのCondaレシピテンプレート生成コマンド
grayskull pypi <package name> # 例: <package name> = 'gbkviz'
```
実行後、\<package name>ディレクトリが作成され、その中にmeta.yamlが生成されているはずです。

:::note warn
Biocondaの[登録ガイドライン](https://bioconda.github.io/contributor/workflow.html#make-some-edits)(2022年4月時点)では、**conda skeleton**によるレシピテンプレート生成方法が記載されています。一方、conda-forgeでは従来のconda skeletonではなく、**Grayskull**をレシピテンプレート生成に利用することを推奨しています ([参考](https://github.com/conda-forge/staged-recipes#grayskull---recipe-generator-for-python-packages-on-pypi))。
Grayskullはskeletonと比較して、1. レシピ生成速度、2. レシピ品質(= 必要な情報が網羅され、かつ不要な記述が少ない)、3. 今後の発展性、等の観点から明確に優れているので、Grayskullを利用することを推奨します。
:::

## 3. Condaレシピ設定

Grayskullで生成したCondaレシピテンプレート(meta.yaml)の各種設定書き換え・追加について、GBKvizパッケージ登録時の例を交えて、以降に記載します。

なお、パッケージ開発に**Poetryを利用していない**、あるいは登録パッケージにNCBI-BLASTのような**外部実行プログラムへの依存やテストコードが存在しない**のであれば、「Ⅰ. レシピ管理者設定」以外の設定は基本的に不要かと思います。

<details><summary>Condaレシピテンプレート設定前後の全体差分 (個々の設定詳細は後述)</summary><div>

```diff_yaml:meta.yaml
{% set name = "gbkviz" %}
{% set version = "1.1.5" %}

package:
  name: {{ name|lower }}
  version: {{ version }}

source:
  url: https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/GBKviz-{{ version }}.tar.gz
  sha256: bd7cb015f1b4ebb66ac7b9d2df2a8135a39c89f823afc8013c3ed9800912b4ae

build:
  entry_points:
    - gbkviz_webapp = gbkviz.scripts.launch_gbkviz_webapp:main
  noarch: python
  script: {{ PYTHON }} -m pip install . -vv
  number: 0

requirements:
  host:
    - pip
+   - poetry
    - python >=3.6,<4.0
  run:
    - biopython >=1.79,<2.0
    - python >=3.6,<4.0
    - reportlab >=3.5.68,<4.0.0
    - streamlit >=1.5.0,<2.0.0
+   - mummer4 >=4.0.0rc1

test:
  imports:
    - gbkviz
  commands:
    - pip check
    - gbkviz_webapp --help
  requires:
    - pip
+   - pytest
+ source_files:
+   - tests/

about:
  home: https://github.com/moshi4/GBKviz/
  summary: Simple web application to visualize and compare genomes in Genbank files
  license: MIT
  license_file: LICENSE

extra:
  recipe-maintainers:
-   - ADD_YOUR_GITHUB_ID_HERE
+   - moshi4
```
</div></details>

### Ⅰ. レシピ管理者設定 (必須)

テンプレートに書いてある通り、レシピ管理者設定項目を自分のGitHub IDへ書き換える。

```diff_yaml:meta.yaml (extra section)
extra:
  recipe-maintainers:
-   - ADD_YOUR_GITHUB_ID_HERE
+   - moshi4
```

### Ⅱ. Poetry利用設定

パッケージ開発にPoetryを利用している人はホスト環境要件項目にPoetryを追加する。

```diff_yaml:meta.yaml (requirements section)
requirements:
  host:
    - pip
+   - poetry
    - python >=3.6,<4.0
  run:
    - biopython >=1.79,<2.0
    - python >=3.6,<4.0
    - reportlab >=3.5.68,<4.0.0
    - streamlit >=1.5.0,<2.0.0
```

### Ⅲ. 外部実行プログラム依存関係設定

テンプレートでは、実行要件項目にはPython依存パッケージ一覧が記載されています。登録パッケージにNCBI-BLASTのような外部実行プログラムへの依存関係がある場合は、この項目にその依存設定を追加していく必要があります。

GBKvizでは、実行要件に`MUMmer`(ゲノム比較ツール)のインストールが含まれます。そのため、MUMmerをインストールする設定を実行要件項目へ下記のように追加しました。

```diff_yaml:meta.yaml (requirements section)
requirements:
  host:
    - pip
    - poetry
    - python >=3.6,<4.0
  run:
    - biopython >=1.79,<2.0
    - python >=3.6,<4.0
    - reportlab >=3.5.68,<4.0.0
    - streamlit >=1.5.0,<2.0.0
+   - mummer4 >=4.0.0rc1
```
バージョン情報(>=4.0.0rc1)の記載はなくても問題なかったと思いますが、自分のローカル環境で利用していたバージョン以上のものを一応指定しました。バージョン情報の指定・記述形式がよく分からなければ、対象ツールのレシピサイトを参考にするとよいです(例：[MUMmer4 Conda Recipe](https://bioconda.github.io/recipes/mummer4/README.html))。`bioconda [ツール名] recipe`でググれば出てくると思います。

### Ⅳ. テスト実行設定

テンプレートでは、テスト項目にはパッケージ依存関係確認(`pip check`)やヘルプコマンドの動作確認(`command --help`)の設定などが記載されます。pytestのようなツールでテスト実行したい場合には、テスト環境要件項目へのpytest・テストソースの設定や別途テスト実行用のレシピスクリプト`run_test.sh`を用意する必要があります。

GBKvizはpytestを利用したテストコードを書いているので、テスト項目へ下記のように追加し、テスト実行用スクリプトとして`run_test.sh`を新規作成しました。

```diff_yaml:meta.yaml (test section)
test:
  imports:
    - gbkviz
  commands:
    - pip check
    - gbkviz_webapp --help
  requires:
    - pip
+   - pytest
+ source_files:
+   - tests/
```

```diff_shell:run_test.sh
+ pytest tests
```

:::note warn
Bioconda上のテスト環境でpytestなどでテスト実行をするためには、テストコードをPyPIパッケージに含めておく必要がある点に注意してください 。
=> Poetryの場合は、pyproject.tomlに`include = ["tests"]`と記載する必要があります。
:::

## 4. Condaレシピ(パッケージ)登録

前項までに作成したCondaレシピをコミット＆プッシュして、GitHub上からプルリクエスト(PR)を行います。
```shell:コミット＆プッシュの実行コマンド例 ('bioconda-recipes/recipes'ディレクトリで実行している想定)
git add <package name>
git commit -m "Add <package name>"
git push
```
PR後、自動的に登録レシピの文法・整合性チェック、及びレシピを元にしたCondaパッケージビルドテストが行われます。レシピチェック・ビルドテストを問題なく通過した後は、`@BiocondaBot please add label`とコメントして、レビュー・マージ待ちであることを示す`please review & merge`ラベルをPRに付与します。ラベル付与後、レビュアーの方によるレビューが行われ、問題なければマージしてくれます。レビューは遅くても1〜2日以内には対応してくれると思います。

本家のbioconda-recipesリポジトリへのマージが完了すると、biocondaチャンネルにパッケージが登録されます。登録されてから少し時間が経過すると、`conda install -c bioconda <package name>`でインストールできるようになり、パッケージ登録作業は完了となります。

:::note warn
**レシピ(パッケージ)登録時のエラー対応**
初めてのBiocondaへのパッケージ登録かつある程度レシピの設定記述が必要な人は、レシピチェック・ビルドテストで一度くらいは失敗するんじゃないかなと思います。自分は単純な記述ミスも含めて、5回ほど失敗しました。GitHub上のPR画面リンクからテスト実行ログを参照できるので、エラー発生時は実行ログからエラー原因を特定し、エラー原因箇所のレシピ修正をしてリトライすることになります。エラー時のテスト実行ログを見ると、`〜〜〜 not found.`のような記述があることが多いので、エラー原因はなんとなく分かるかと思います。
:::

- [(参考) GBKviz初回登録PR](https://github.com/bioconda/bioconda-recipes/pull/33967)
- [(参考) GBKvizレシピ登録先](https://github.com/bioconda/bioconda-recipes/tree/master/recipes/gbkviz)

# 補足: Condaレシピ(パッケージ)更新

Biocondaへパッケージ登録後、どこかのタイミングで更新したくなる場面があると思います。そのため、パッケージ更新についても補足で説明しておきます。

BiocondaではPyPI上のパッケージ更新を自動的に検知し、更新情報をBiocondaに自動で反映する仕組みが構築されています(メール通知有)。PyPIパッケージ更新によりBiocondaのレシピ・パッケージも自動更新(PR作成→マージ)されるので、実は開発者は何もしなくとも更新がされます。
ただし、パッケージ更新で各種の依存関係に変更があった場合には、Biocondaの自動更新時テストでエラーが発生し、自動更新内容がマージされないこともあります。自動更新失敗時はテスト実行ログからレシピのエラー原因を特定して、エラー修正済レシピの更新PRを新たに作成すればOKです。

- [(参考) GBKviz自動更新失敗PR](https://github.com/bioconda/bioconda-recipes/pull/34047)
- [(参考) GBKviz自動更新エラー修正PR](https://github.com/bioconda/bioconda-recipes/pull/34058)

# おわりに

BiocondaへPyPIパッケージの登録をするために色々と調査する過程で、Condaへの理解をある程度深めることができました。Biocondaではパッケージ登録時に自動テスト・レビューを受ける必要があるので、どんなパッケージでも自由に登録できるPyPIと比較してハードルが少し高かったですが、そこまで難しいわけではないなと感じました。この記事がBiocondaへのパッケージ登録を考えている他の方の参考になればいいなと思います。

Condaの利用経験がそれほどない人間が書いた記事なので、色々と至らない点があるかもしれません。抜け漏れや間違いがあれば、ご指摘いただけると助かります。