以前から自分で作成したPythonパッケージをPyPIにリリースしていた。

https://note.yu9824.com/howto/2021/07/23/pypi-package-release/

したがって、pip install <package-name>とすることでインストールできた。しかし、この度conda install -c conda-forge <package-name>でインストールしたいという要望をいただいたのでanaconda cloudにパッケージをアップロードする方法を学んだ。

https://github.com/yu9824/kennard_stone/issues/5

このときの手順をメモした。


環境

M1チップ搭載のMacbook Air 2020を使用。

% sw_vers
ProductName:	macOS
ProductVersion:	12.3.1
BuildVersion:	21E258

経緯

PyPIにパッケージをリリースしていれば比較的簡単にアップロードできるようになっている。

このやり方に関して公式が説明してくれているサイト(英語)がある。

日本語では、この記事でパッケージをリリースする方法が書かれている。しかしこれはWindowsであり、少し状況が異なる。

したがって、自分で試行錯誤した結果をメモする。

ちなみに、Anacona cloudにアップロードするとき、自分自身のチャンネルにアップロードする場合とconda-forgeチャンネルにアップロードする方法とがある。

途中まで共通のため、まず自分用チャンネルにアップロードする方法から示す。

自分用チャンネルにアップロードする手順

やり方の概略は以下。

  1. ターミナル上でconda activate baseなどを実行し、base (環境によってはroot) 環境に入る
  2. conda install conda-buildをして、conda-buildパッケージをインストールする
  3. conda skeleton pypi <package-name>を実行し、レシピを作成する
  4. レシピをもとにパッケージを作成し、Anaconda cloudにアップロードする

パッケージの作成も正しいレシピが作成できていれば簡単なので肝はレシピの生成段階であると個人的には考えている。

なお、<package-name>と書いた部分はご自身の行いたいパッケージの名前に変えて実行していただきたい。

1. base環境に入る

(base)....@...となっていれば問題ない。インストールして、特に設定をいじっていなければ自動で入る設定になっている。

なお、base環境に勝手に入らないようにする設定もある。詳しくは以下。

https://note.yu9824.com/howto/2022/04/15/migration-my-setup-macbook.html#miniforge

2. conda-buildパッケージをインストールする

以下のコマンドをターミナルで実行し、インストール。

conda install conda-build

このパッケージはbase (root) 環境でないとインストールできない(らしい)。

3. レシピ (meta.yaml) を生成

正式なやり方(個人的に非推奨)

conda skeleton pypi <package-name>

このコマンドにより、パッケージ生成のためのレシピが生成される。

注意点

<package-name>のディレクトリがカレントディレクトリの直下に生成されるので、同じ名前のディレクトリがないことを確認したのちに実行する必要がある。
そうでないとエラーを生じる。

特に重要なのはmeta.yaml。必要であればここを書き換える必要がある。

自分は生成されたレシピを以下のように書き換えた。

https://github.com/conda-forge/kennard-stone-feedstock/blob/main/recipe/meta.yaml

個人的に非推奨にしている理由

私の確認した限り、特定の環境では失敗してしまう。
これについて以下の記事で検討した。

https://note.yu9824.com/error/2022/05/06/conda-skeleton-error/

端的に言えば、Python 3.7以上もしくは、ARMチップである場合に正常に動作しない。さらにパッケージ名に”-“(ハイフン)が入っている場合も問題が生じる場合がある。

これを解決するためにdockerコンテナ上にPython3.6、AMDプロセッサ環境を構築し、かつ”-“を処理するシェルスクリプトを書いて対応した…

が、このような面倒な作業などする必要がなく、grayskullパッケージを使用することで解決できる。

個人的に推奨する方法

grayskullはconda-forgeチャンネルから簡単にダウンロードできる。

conda install -c conda-forge grayskull

あとは、以下の通りgrayskullコマンドを実行すれば自動的にmeta.yamlファイルを生成してくれる。

grayskull pypi <package-name>

これはあとから気づいたのだが--strict-conda-forgeというオプションをつけて実行するとconda-forge向けのより良いmeta.yamlが生成できるよう。

注意点

このときも<package-name>のディレクトリがカレントディレクトリの直下に生成されるので、同じ名前のディレクトリがないことを確認したのちに実行する必要がある。

4. レシピをもとにパッケージを作成 + Anaconda cloudへのアップロード(自分用のチャンネル)

conda-forgeチャンネルの場合はこちら

これ以降の工程に関しては、自分のチャンネルでインストールできるようにしたいか、conda-forgeチャンネルでインストールできるようにしたいかでやり方が異なる。

レシピをもとにパッケージを作成

以下のコマンドでアップロードするためのパッケージファイルを作成する。

conda build <package-name>

依存するパッケージをconda-forgeチャンネル経由でインストールする必要がある場合は、以下のようにチャンネルを指定しても良い。

conda build -c conda-forge <package-name>
作成の成功可否を確認する方法

作成したパッケージファイルが、正しく作成できたかを確認するためには、適当な仮想環境を新しく作成して--use-localオプションつきでconda installを実行することで確認できる。正しく作成が行うことができていれば、インストールすることができる。

たとえば、以下のように行う。

conda create -n test    # testという名前の仮想環境を作成。名前はなんでも良い。
conda activate test     # 先ほど作成した仮想環境に入る。
conda install --use-local -c conda-forge <package-name> # ローカルのレシピを使用してパッケージをインストールする。チャンネルはconda buildを実行したときに使用したチャンネルを指定すると良い。

正しく作成できていることが確認できた場合は以下のコマンドでbase環境に戻っておく。

conda deactivate
conda activate base

Anaconda cloudへのアップロード

事前にAnaconda cloudでアカウントを登録しておく必要がある。

現在base環境にきちんといることを確認して以下のコマンドを実行し、anaconda-clientパッケージをインストールする。

conda install anaconda-client

インストール完了後、以下のコマンドを実行してターミナル上で先ほど登録したAnaconda cloudアカウントにログインする。

anaconda login

求められる通りにユーザー名とパスワードを入力する。

その後、conda buildしたときに生成したXXX.tar.bz2を探し、それを以下のコマンドでアップロードする。

anaconda upload /path/to/<package-name>-<version>-XXXX.tar.bz2

私の環境ではconda-bldディレクトリの下にアーキテクチャごと(もしくはnoarch)に生成されていた。そのファイルのパスを指定してuploadすることで完了する。

アップロードできたかはhttps://anaconda.org/<Username>/<package-name>にアクセスして確認する。

conda-forgeチャンネルの場合

— ここまで共通 —

4. レシピをもとにパッケージを作成 + Anaconda cloudへのアップロード(conda-forgeチャンネル)

conda-forgeチャンネルの場合は、conda-forgeが作成したGithub Actionsを使用してパッケージの作成およびアップロードがなされる。

それらを実行する手順について以下に示す。

conda-forge/staged-recipesをfork&clone

以下のレポジトリをforkする。

https://github.com/conda-forge/staged-recipes

これをcloneする。

git clone [email protected]:<your-github-id>/staged-recipes.git

ブランチを切って、レシピを移動し、commit

先ほどcloneしたリポジトリに移動する。

cd /path/to/staged-recipes

次に、以下のコマンドなどを利用して新しいブランチを作成した上で、そのブランチに移動する。

git checkout -b <package-name>

その後、レシピ(meta.yaml)をリポジトリ内の/recipes/<package-name>/meta.yamlに移動させる。Finderを使ってもmkdirでディレクトリを作成したあとにmvコマンドやcpコマンドを使用してもOK。

これをaddしてcommitする。

git add .
git commit -m "Add recipe of my <package-name> package."

pushしてpull requestを送る

git push origin <package-name>  # originの後ろは、新しく作成したブランチ名

そうするとgithub上にpull request(以下PR)を送るボタンが出てくるので、送る。わからない場合は、公式サイトのドキュメントが詳しい。

チェックリストやレビュー、テストの結果を元に修正を加える

PRを送ると勝手にテストをしてくれ、かつチェックリストが作成される。チェックリストに準拠するようにPRのタイトルやmeta.yamlを修正する。テストを通過し、チェックリストすべてを確認してチェックをいれると、reviewerに診てもらえる。

修正した場合、pushすれば勝手にPRに反映され、テストがスタートする。

@conda-forge/help-python to let them know that your recipe is ready for review.

How to publish a Python package on conda-forge

とあるが、自分は使わなかった。これをせずとも診てもらえた。

mergeされればめでたくpublishとなる。

参考のため、自分が実際に送ったPRを以下に示す。

https://github.com/conda-forge/staged-recipes/pull/18779

パッケージの更新方法

めでたくpublishされると、<package-name>-feedstockという名前のrepositoryが作成される。

自分の例だと以下。

https://github.com/conda-forge/kennard-stone-feedstock

パッケージの更新はこれに対してPRを送ることで行える。

手順は以下。

  1. feedstock repositoryをfork&clone
  2. ブランチを切る
  3. meta.yamlを新しいものに置き換える(生成方法は3. レシピ (meta.yaml) を生成と同様)
  4. 変更をcommit&push
  5. fork元リポジトリへPull Requestして指示に従う

肝はmeta.yamlを再度コマンドで生成し直すこと。手でファイルの一部を変更するだけでは基本的に成功しない。

もっと簡単にできるかも?

上記の手順を踏んだ後に気づいたのだが@conda-forge-admin, please add bot automergeとタイトルにつけて<package-name>-feedstockにてissueを立てればbotが自動的にPRを作成してくれるらしい。

参考

次更新する際は試してみたい。

参考

関連

https://note.yu9824.com/howto/2021/07/23/pypi-package-release/