先日、PyPIにMITライセンスでTweetlというパッケージを公開しました。このパッケージを使うとツイートの取得から前処理までを簡潔なコードで行うことができます。
今回はTweetlを公開する際に学んだ「PyPIにMITライセンスで自作のパッケージを公開する方法」をご紹介します。PyPIでパッケージを公開することで自作のパッケージをpipでインストールできるようになります。

MITライセンスとは

MITライセンスは制限がほとんどない、オープンソースのライセンスです。公開したいソースコードにMITライセンスを適応するためには、LICENSE.txtにライセンス文を掲載するのと、公開するパッケージの内容についての説明文を用意し、そこにMITライセンスで公開しているということを記述しておく必要があります。

アカウントの作成

PyPIでパッケージを公開するためにはPyPIのアカウントを作る必要があります。PyPIにはテスト環境が用意されているため、テスト環境のアカウントと本番環境のアカウントを以下のリンクから用意します。アカウント作成の際に設定したユーザー名とパスワードは後から必要になりますので、忘れないようにしておいて下さい。

必要なファイルの作成

今回はソースコードをオープンソースで公開するために最低限必要な「LICENSE.txt」, 「README.md」, 「requirements.txt」, 「setup.py」を作成していきます。

.
├── LICENSE.txt
├── README.md
├── <package>
│   └── <module>.py
├── requirements.txt
└── setup.py

LICENSE.txt

こちらは冒頭で述べたMITライセンスを使用するためのファイルです。こちらのサイト等からライセンス文を取得し、1文目の「Copyright <YEAR> <COPYRIGHT HOLDER>」の箇所を書き換えて貼り付けます。

README.md

こちらはパッケージの使用方法やインストール方法等を記述するファイルです。ここにMITライセンスを適応しているという内容を記述します。
例:「This software is released under the MIT License, see LICENSE.」

requirements.txt

ここにはパッケージを動かすために必要な依存パッケージを記述します。数が少なければ1つずつ記述することもできますが、依存パッケージの数が多い場合は「pip freeze > requirements.txt」で環境内にインストールされているパッケージを書き出すことができます。その際に仮想環境を立てずにpip freeze > requirements.txtをするとローカル環境にインストールされているパッケージが全て書き出されてしまうので、必ず仮想環境を立てて必要なパッケージだけをインストールするようにして下さい。

setup.py

これまで作成した3つのファイルはソースコードをオープンソースに公開するためのファイルでしたが、このsetup.pyはPyPIにパッケージを公開するために必要なものです。様々なオプションがあるので記述の仕方は一概に言えませんが、個人的には以下のような記述で十分だと思います。

from setuptools import setup
from codecs import open
from os import path
package_name = "パッケージ名"
root_dir = path.abspath(path.dirname(__file__))
# requiwements.txtの中身を読み込む
def _requirements():
    return [name.rstrip() for name in open(path.join(root_dir, 'requirements.txt')).readlines()]
# README.mdをlong_discriptionにするために読み込む
with open('README.md', encoding='utf-8') as f:
    long_description = f.read()
setup(
    name=package_name,
    version='任意のバージョン(例: 0.0.1)',
    description='一言の説明',
    long_description=long_description,
    long_description_content_type='text/markdown',
    url='Github等のurl',
    author='作者名',
    author_email='作者メールアドレス',
    license='MIT',
    keywords='検索の際に引っかかってほしいキーワードスペース区切り',
    packages=[package_name],
    install_requires=_requirements(),
    classifiers=[
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
    ],
)

ここでsetup.pyに記述された内容がPyPIにも掲載されます。

  • long_descriptionはREADME.mdの内容にするのが一般的です。
  • install_requiresにはこのパッケージをインストールする際に同時にインストールが必要なものを記述します。依存パッケージについてはここまでで既にrequirements.txtに書き出しているので、requirements.txtの中身を読み込んだものにしています。
  • classifiersにはパッケージの機能を説明するためのタグのようなものをtrove classifiersリストから選択します。リストにないものを記述するとエラーがおきてしまうので、リストの中からコピーアンドペーストするのがおすすめです。

setup.pyには他にもオプションがあり、Pythonの公式リファレンス等から確認頂けます。

公開する

ファイルの作成が完了したら、いよいよパッケージをPyPIにあげていきます。PyPIは一つのバージョンにつき一度しかアップロードできない(上書きができない)ため、アップロードする際には不要なファイルが含まれていないか、コードが間違っていないかをしっかりと確認する必要があります。

アカウント認証ファイル作成

ホームディレクトリ直下(~/.)に「.pypirc」というファイルを作成し、以下のようにアカウント情報を記述します。

[distutils]
index-servers =
  pypi
  testpypi
[pypi]
repository: https://upload.pypi.org/legacy/
username: <本番用アカウント名>
password: <パスワード>
[testpypi]
repository: https://test.pypi.org/legacy/
username: <テスト用アカウント名>
password: <パスワード>

公開に必要なツールをインストール

公開に必要なツールをインストールします。

pip install wheel twine

wheelはパッケージ化のために必要で、twineはパッケージをPyPIにアップロードするために必要なものです。

パッケージ化と公開

以下のコマンドを実行してパッケージを作成します。

python setup.py sdist bdist_wheel

実行すると「<パッケージ名>.egg-info」と「dist」というディレクトリが作成されます。
これが問題なくできたら、PyPIのテスト環境にアップロードしてみます。以下のコマンドを実行します。

twine upload --repository testpypi dist/*

アップロードが完了したら「https://test.pypi.org/project/<パッケージ名>/」にアクセスできることと、以下のコマンドでインストールできるかを確認して下さい。ただし、requirements.txtに記述した依存パッケージがPyPIのテスト環境にないとインストールが失敗することがあるので、その際は自分のローカル環境にpipで本番環境のPyPIからインストールして下さい。

例:依存パッケージにsumyが含まれているが、sumyがPyPIのテスト環境になかった場合、手動でローカルに「pip install sumy」をする必要がある

pip --no-cache-dir install --upgrade --index-url https://test.pypi.org/simple/ <パッケージ名>

ここまでで、問題がなければ本番環境にアップロードします。以下のコマンドを実行します。

twine upload --repository pypi dist/*

アップロードが成功したら「https://pypi.org/project/<パッケージ名>/」にアクセスできることと、pipでインストールできることを確認して下さい。

バージョンアップや修正がある場合

バージョンアップやテスト環境にあげた際に修正したい箇所があった場合はパッケージのファイルを新しいバージョンのものに更新する必要があります。
まずは、setup.pyにある「version」を新しいバージョンに書き換えます。
次に「<パッケージ名>.egg-info」と「dist」の中に作成されたファイルを削除して、新しいものを作り直します。

# ファイル削除
rm -f -r <パッケージ名>.egg-info/* dist/*
# 作り直す
python setup.py sdist bdist_wheel

これで新しいバージョンのパッケージが作成されるので、PyPIにアップロードできます。