はじめてPyPIにPythonライブラリを登録した話
(2022年11月25日追記)
私の本が株式会社インプレス R&Dさんより出版されました。この記事の内容は含まれていませんが、ライブラリは登場します。イラストは鍋料理さんの作品です。猫のモデルはなんとうちのコです!
感想を書いていただけるととても嬉しいです!
(2022年8月3日追記)この記事で登録したライブラリを使ったWebサービスの作り方が本になりました。ただしPyPIへの登録方法は本には載っていません。
はじめに
先日、生まれてはじめてPyPIにPythonライブラリを登録しました。PyPIというのはPython Package Indexの略で、ここにパッケージを登録するとpip install
でインストールできるようになります。
経緯は以下の通りです。
- もともとIMAP4をJSON化するAPIをローカルで動かすメール受信システムがあった
- AWS LambdaとAPI Gatewayの組み合わせでサーバーレス化することになった
- Flaskで書かれたAPIサーバー部分とメール受信機能を実装した箇所が密結合していたので分離した
- メール受信機能を
pip install
でインストールできたら便利じゃない?
PyPIへの登録は一度やってみたかったので、良い機会だと思い挑戦してみました。n番煎じのネタですが、ドキュメント化しておかないと忘れそうなので、未来の自分のために記事にしました。
PyPIに登録した結果はこちらです。
ソースコードはこちらです。
手順は主にこちらの記事を参考にしました。
PyPI登録手順
ディレクトリ構成
今回登録するパッケージはimap2dict
という名前にしました。IMAP4で受信したメールデータをPython辞書形式に変換するという意味を込めています。ディレクトリ構成は以下の通りです。
.
├── .gitignore ... Gitから除外したいファイルを指定
├── LICENSE ... ライセンス定義ファイル
├── README.md ... READMEファイル
├── imap2dict ... モジュールを配置するディレクトリ
│ ├── __init__.py ... モジュール検索や名前検索の初期化等を司るファイル
│ └── mail_client.py ... 機能を提供するモジュール
├── requirements.txt ... 依存関係を記述するファイル
└── setup.py ... PyPIの設定ファイル
init.pyの作成
from .mail_client import MailClient
参考にした記事では__init__.py
にバージョン情報を記載していましたが、それをするとsetup.py
を実行したときに依存関係を解消できずにエラーが発生したのでやめました。
ライセンス定義ファイルの生成
ライセンス定義ファイルはリポジトリ作成時にGitHub上で作るのが楽です。今回はMITライセンスにしました。
README.mdの作成
最低限必要なものを書いておこうと思い、概要とインストール方法、使い方だけを記載しました。
メインモジュールの修正
ディレクトリ構成に合わせてメインモジュールのmail_client.py
を修正しました。Pythonのお作法がいまいちよくわかっていないので、ファイル名とクラス名を決めるのに悩みましたが、機能をベースとして考えて以下のような構成にしました。
class MailClient():
'''
メールクライアントクラス。
'''
host_name = ''
user_id = ''
password = ''
def __init__(self, host_name, user_id, password):
self.host_name = host_name
self.user_id = user_id
self.password = password
requirements.txtの作成
requirements.txt
はpipreqs
で自動生成してから手で修正しました。
pip install pipreqs
pipreqs .
pytz==2020.1
pytz>=2020.1
setup.pyの作成
setup.py
には以下の情報を記載しました。
setupメソッドの引数 | 内容 |
---|---|
name | ライブラリ名 |
version | バージョン |
description | 短い説明文 |
long_description | 長い説明文(README.mdの内容をファイルから読み込むようにした) |
long_description_content_type | 長い説明文の形式(今回はマークダウンなのでtext/markdown と記載する) |
author | 作者名 |
author_email | 作者のメールアドレス |
maintaner | メンテナーの名前(今回は作者と同じ) |
maintaner_email | メンテナーのメールアドレス(今回は作者と同じ) |
url | ホームページのURL(今回はGitHubリポジトリのURL) |
download_url | ダウンロード用URL(今回はGitHubリポジトリのURL) |
packages | パッケージ構成 |
classifiers | 分類情報(ライセンス情報とプログラミング言語を記載) |
license | ライセンス情報 |
keywords | 検索でヒットさせたいキーワード |
install_requires | 依存するパッケージの情報 |
実際のコードはこちらです。
# Author: TAKAHASHI Taro <takahashi.taro@takedasystem.com>
# Copyright (c) 2022- TAKAHASHI Taro
# Licence: MIT
from setuptools import setup
DESCRIPTION = 'imap2dict: Receiving and deleting email on an IMAP4 server.'
NAME = 'imap2dict'
AUTHOR = 'TAKAHASHI Taro'
AUTHOR_EMAIL = 'takahashi.taro@takedasystem.com'
URL = 'https://github.com/sikkimtemi/imap2dict'
LICENSE = 'MIT'
DOWNLOAD_URL = URL
VERSION = '0.1.0'
PYTHON_REQUIRES = '>=3.6'
INSTALL_REQUIRES = [
'pytz>=2020.1'
]
PACKAGES = [
'imap2dict'
]
KEYWORDS = 'imap imap4 json'
CLASSIFIERS=[
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3.6'
]
with open('README.md', 'r', encoding='utf-8') as fp:
readme = fp.read()
LONG_DESCRIPTION = readme
LONG_DESCRIPTION_CONTENT_TYPE = 'text/markdown'
setup(
name=NAME,
version=VERSION,
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
long_description_content_type=LONG_DESCRIPTION_CONTENT_TYPE,
author=AUTHOR,
author_email=AUTHOR_EMAIL,
maintainer=AUTHOR,
maintainer_email=AUTHOR_EMAIL,
url=URL,
download_url=URL,
packages=PACKAGES,
classifiers=CLASSIFIERS,
license=LICENSE,
keywords=KEYWORDS,
install_requires=INSTALL_REQUIRES
)
ライブラリのビルド
事前にWheelをインストールします。
pip install wheel
ソースコード配布物をビルドします。
python setup.py sdist
dist
ディレクトリとimap2dict.egg-info
ディレクトリが生成します。
Wheelパッケージをビルドします。
python setup.py bdist_wheel
build
ディレクトリが生成します。
最終的に以下のようなディレクトリ構成になります。
.
├── LICENSE
├── README.md
├── build
│ ├── bdist.macosx-12-x86_64
│ └── lib
│ └── imap2dict
│ ├── __init__.py
│ └── mail_client.py
├── dist
│ ├── imap2dict-0.1.0-py3-none-any.whl
│ └── imap2dict-0.1.0.tar.gz
├── imap2dict
│ ├── __init__.py
│ └── mail_client.py
├── imap2dict.egg-info
│ ├── PKG-INFO
│ ├── SOURCES.txt
│ ├── dependency_links.txt
│ ├── requires.txt
│ └── top_level.txt
├── requirements.txt
└── setup.py
.gitignoreの作成
ビルドによって生成したファイルやディレクトリをGitで管理しないように.gitignore
を作成します。私はこちらをもとに必要に応じて修正して使うことが多いです。
PyPIのユーザー登録
PyPIには本番環境とテスト環境があります。どちらにもユーザー登録しましょう。
本番環境はこちら。
テスト環境はこちら。
ユーザー登録が完了したらホームディレクトリに.pypirc
を作成します。
[distutils]
index-servers =
pypi
testpypi
[pypi]
repository: https://upload.pypi.org/legacy/
username: 本番環境のPyPIユーザ名
password: 本番環境のPyPIパスワード
[testpypi]
repository: https://test.pypi.org/legacy/
username: テスト環境のPyPIユーザ名
password: テスト環境のPyPIパスワード
TwineでPyPIに登録
PyPIにライブラリを登録するツールのひとつであるTwineをインストールします。
pip install twine
まずテスト環境にアップロードしてみましょう。
twine upload --repository testpypi dist/*
成功するとURLが返ってきます。
URLにアクセスするとpip
によるテストコマンドが記載されているので、テストしてみます。
pip install -i https://test.pypi.org/simple/ imap2dict
PyPIのテスト環境に存在するpytz
モジュールのバージョンが古いので依存関係でエラーになりましたが、事前にpytz
をインストールした状態でコマンドを打つとインストールに成功しました。
ではいよいよ本番環境にアップロードします。
twine upload --repository pypi dist/*
URLが返ってきたら表示を確認します。
pipでインストールできることを確認します。
pip install imap2dict
GitHubにタグをつける
最後に下図の手順でGitHubにバージョンのタグをつけます。
これで一連の作業は完了です。
Discussion