🗡️

Conda-ForgeにPythonパッケージを公開する手順

2022/05/24に公開

最近、研究で使っていた自作PythonパッケージGraphArrayをconda-forgeに公開したので、その公開方法をまとめます。

(あ、pipにも公開してます)

公開の時、方法を検索してみたのですが、ビックリするほど出てこない...というわけで、僕自身がやった方法を日本語で残しておきます。ほとんど公式ページの和訳です。

Conda-Forgeへ公開するメリット

Conda-Forgeとは、Anaconda公式ではないパッケージをAnaconda上で公開できるパッケージコレクションです。conda-forgeにパッケージを公開すると、ターミナルで

conda install -c conda-forge PACKAGE_NAME

とコマンドを実行することで、condaでパッケージをインストールできるようになります。

Anacondaは科学計算にPythonを利用する際に多く使われるので、公開するパッケージを科学計算に使ってもらうためには、Anacondaへの公開はほぼ必須だと思います。加えて、初学者むけのPythonチュートリアルでは「AnacondaインストールしてJupyter Notebookでコードを書く」という方法が多く採用されているので、こうした初学者に使ってもらえるメリットもあります。

Pythonのパッケージ共有サービスとしてはPypi(pip install PACKAGE_NAMEでインストールできるとこ)が大きく、Pypiの方がAnacondaより手軽にパッケージを公開できます。が、上に述べたような利点があるため、少し手間をかけて両方に公開しておくと良いと思います。

公開までの手順

概要

大体以下のような流れです:

  • Pypiにパッケージを公開
  • Conda-Forge向けのパッケージの"レシピ"ファイルを作成(ほぼ自動生成)
  • conda-forgeのGitHubリポジトリにレシピファイルを追加するプルリクエストを送る
  • conda-forge管理者にレシピファイルをreviewしてもらい、問題がなければ公開

以下で詳細を説明します。

Pypiにパッケージを公開

まず、Pypiにパッケージを公開しましょう。Conda-Forgeにパッケージのソース自体をアップロードするのではなく、Pypiなどでパッケージのソースを公開しておき、conda上ではそのダウンロードリンクを保持するというやり方になっているようです。おそらくGitHubのリンクなどでもできると思いますが、Pypiのダウンロードリンクを利用するのが標準のようなのでしたがっておくと楽でしょう。

Pypiへの公開方法についてはわかりやすい記事がすでにたくさん出ています。僕はこちらを参考にしました。再生産は無駄なので説明は割愛しますが、一つだけ注意点が

setup.py内でバージョンを設定するとき、前述の記事内ではパッケージ本体をsetup.py内でimportして、パッケージの__init__.pyに記載しているバージョンを読み込む方法を取っています。しかし僕の場合、この方法だと公開したパッケージが正しくインストールできず、後述するconda-forgeでのインストールテストに失敗しました。

原因と解決策はこちらの記事に詳しく書いてあります。

numpy(依存関係にあるパッケージ)をインストールするためのinstall_requiresがsetup.pyに記述してあるにも関わらず、
そのsetup.pyが実行出来ずにインストール出来ないという、「金庫の中の鍵」状態です。

いずれかの解決策で、setup.pyの中でパッケージをimportすることを避けましょう。ちなみに僕は以下のようにしました:

import grapharray
  
VERSION = grapharray.__version__

ではなく、

with open("grapharray/__init__.py") as fid:
    for line in fid:
        if line.startswith("__version__"):
            VERSION = line.strip().split()[-1][1:-1]
            break

レシピファイルの作成

Pypiに公開できたら、レシピファイルを作成します。

まず、pypiに公開されているパッケージからレシピファイルを自動生成してくれるモジュール"grayskull"をインストールします。

conda install -c conda-forge grayskull

次に、grayskullを使ってレシピファイルを生成します。your_package_nameは公開したいパッケージ名に置き換えてください。

grayskull pypi your_package_name

これで、カレントディレクトリ内にあるパッケージ名のディレクトリ(なければ生成されます)の中に、meta.yamlというファイルが生成されます。これがレシピファイルです。

僕の場合、以下のようなレシピファイルが生成されました。

{% set name = "grapharray" %}
{% set version = "1.0.2" %}


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

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

build:
  number: 0
  noarch: python
  script: {{ PYTHON }} -m pip install . -vv

requirements:
  host:
    - pip
    - python >=3.8
  run:
    - networkx >=2.6.2
    - numpy >=1.20.3
    - python >=3.8
    - scipy >=1.7.1

test:
  imports:
    - grapharray
  commands:
    - pip check
  requires:
    - pip

about:
  home: https://pypi.org/project/grapharray/
  summary: 'GraphArray : Python package for treating arrays defined on a network, which allows for fast computation and easy visualization.'
  license: MIT
  license_file: LICENSE

extra:
  recipe-maintainers:
    - Geb-algebra

ここから、必要に応じて微修正を施します。僕はaboutのhomeに記載されているリンクをGitHubリンクに変更しました。他の人たちがGitHubを載せているケースが多かったから真似しただけで、特に意味はないです。

grayskullを使うのは必須ではなく、meta.yamlを一から書いても構いません。

conda-forgeのリポジトリにプルリクエストを送る

以下の手順で行います。公式

  1. staged-recipesリポジトリForkし、ローカルにcloneする。
  2. Forkしたリポジトリで、mainブランチから新しいブランチを作成する
  3. 作成したブランチ上で、staged-recipes/recipesディレクトリ内に新しいディレクトリ(ディレクトリ名はなんでもいいのかな?僕はパッケージ名にしました)を作成する
  4. 作成したディレクトリ内に、先ほど生成したmeta.yamlをコピーする
  5. GitHub上で、作成したブランチからプルリクエストを作成する

僕はGitHub上での共同開発をしたことがなかったので、フォークとプルリクエストの機能は今回初めて利用しました。同じような方が読んでいることを想定して補足説明しておきます。

フォークとは他の人が作ったGitHubリポジトリをコピーした新たなリポジトリを自分のリポジトリとして作成する機能です。これにより、元のリポジトリに影響を与えずにそのリポジトリ内のコードを自分の好きに修正することができます。

プルリクエストとは、自分のアカウントにフォークしたリポジトリに加えた修正を、元のリポジトリに反映してくれと要求する機能です。当然自動的に反映されることはなく、反映するかどうかは元のリポジトリの管理者が判断します。つまり、元のリポジトリの管理者がそのプルリクエストの内容を確認し、元のリポジトリに反映しても問題ないと判断した場合のみ、リクエストが承認されて変更が反映されます。

今回のConda-Forgeへのアップロードでは、

  1. conda-forgeチームが作成したstaged-recipesリポジトリを自分のアカウントにフォークし、
  2. そこに「自分のパッケージレシピを追加する」という変更を加え、
  3. プルリクエストを送ってconda-forgeチームのリポジトリに自分のレシピを追加してもらう

という流れになります。

conda-forge管理者のreview

プルリクエストを送ると、まずmeta.yamlの構文チェックと、Windows/Mac/Linuxの各環境でパッケージをインストールできるかどうかのチェックが自動で行われます。

チェックが通らなかった場合は、通るようにmeta.yamlを修正して、フォークしたリポジトリに再度commit/pushします。各環境でのパッケージインストールで失敗している場合、そのログを見てエラー箇所を確認することができます。そのためには、プルリクエストのページのchecksタブをクリックし、n errors/n warningsをクリックします。

するとAzure DevOpsというサービスの画面が表示されるので、x が出ているところをクリックしていけば、ログ画面にたどり着きます。

見ても何が何だかわかりませんが頑張って修正しましょう。まあ、Pypiから正しくインストールできるようになっていればそのまま通ると思いますが。

チェックが全て通ったらあとは待つだけ。しばらくすると、Conda-Forgeチームによるレビューが行われます。レビューと言ってもパッケージの完成度とか有用性が厳しく指摘されるわけではなく、作成したレシピファイルmeta.yamlが正しく記載されているかを確認される程度です。

レビュワーの指示に従ってさらに修正を加え、レビュワーがOKを出すと、しばらくしてプルリクエストが承認され、めでたくconda-forgeにパッケージが公開されます!僕は最初にプルリクエストを送ってから公開まで3日かかりました。

おわりに

conda-forgeにパッケージが公開されると、conda-forgeのメンバーに追加され、自分のGitHubアカウントのOrganizations欄にconda-forgeが追加されます。

ちょっと嬉しいですね。

Discussion