PyPIパッケージ登録に必要なもの
整理した。
PyPIパッケージ登録に必要なもの
まとめ。
必要なもの
1. アカウント
各サイトに従って取得する。
2. ツール
- git
- python, python3
- twine, wheel
3. ファイル
GitHubリポジトリの中にPyPIパッケージをそのまま含める。
- {git_repo}/
- {package}/
- __init__.py
- {module}.py
- tests/
- __init__.py
- tests_{module}.py
- setup.py
- requirements.txt
- LICENSE.txt
- README.md
- CHANGES.md
- MANIFEST.in
- .gitignore
- {package}/
{package}/__init__.py
from {module} import * __version__ = '0.0.1' __author__ = 'ytyaru' __author_email__ = 'pypi1@outlook.jp' __copyright__ = 'Copyright (C) 2020 ytyaru' __license__ = 'GNU Affero General Public License Version 3 (AGPL-3.0)' __url__ = '' __all__ = ['{module}']
setup.py
import setuptools setuptools.setup( name=package_name, version=version, author=author, author_email=author_email, description=description, long_description=long_description, long_description_content_type="text/markdown", keywords="pypi,pip,practice,test,package,module", url="https://github.com/ytyaru/Python.PyPI.mypack", # download_url="", packages=setuptools.find_packages(), classifiers=[ "Development Status :: 4 - Beta", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "License :: OSI Approved :: GNU Affero General Public License v3", "Operating System :: OS Independent", "Intended Audience :: Developers", "Topic :: Utilities", ], python_requires='>=2.7', )
setup.cfg
という中間ファイルで管理することもできるらしい。
これをPythonやBashなどで読み込んで使えるなら、こちらのほうが一元管理できて良いかもしれない。だが、特殊な記法であるためPythonで書いたほうが応用が効くかも? 将来、異なる形式になる可能性まで示唆されている。要検討。
requirements.txt
依存パッケージ一覧を作る。
pip freeze > requirements.txt
それを元に一括インストールする。
pip install -r requirements.txt
LICENSE.txt
適当にググってテンプレを入手する。GitHubでもテンプレ作成できると思う。
README.md
適当にググってテンプレを入手する。プロジェクトごとに項目を埋める。他のところでも共通の内容が多数含まれる。なんとかして一元管理したい。
[ja](./README.ja.md) # {{package_name}} {{description}} # DEMO (None) # Features * \_\_init\_\_.py * setup.py * Includes unit test code. # Requirement * [Raspbierry Pi](https://ja.wikipedia.org/wiki/Raspberry_Pi) 4 Model B Rev 1.2 * [Raspbian](https://ja.wikipedia.org/wiki/Raspbian) buster 10.0 2019-09-26 <small>[setup](http://ytyaru.hatenablog.com/entry/2019/12/25/222222)</small> * Python 2.7.16 * Python 3.7.3 # Installation \`\`\`sh pip install {{package_name}} \`\`\` # Usage a.py \`\`\`python import mypack mypack.mymethod() \`\`\` \`\`\`sh python a.py \`\`\` \`\`\`sh mymethod return. \`\`\` # Note * Register for the first time with PyPI. There may be mistakes or better ways # Author {{author}} * [![github](http://www.google.com/s2/favicons?domain=github.com)](https://github.com/ytyaru "github") * [![hatena](http://www.google.com/s2/favicons?domain=www.hatena.ne.jp)](http://ytyaru.hatenablog.com/ytyaru "hatena") * [![mastodon](http://www.google.com/s2/favicons?domain=mstdn.jp)](https://mstdn.jp/web/accounts/233143 "mastdon") # License This software is CC0 licensed. [![CC0](http://i.creativecommons.org/p/zero/1.0/88x31.png "CC0")](http://creativecommons.org/publicdomain/zero/1.0/deed.en)
他の項目との共通点は以下のように多数ある。なんとかして一元管理したい。
- {{package_name}}
- {{description}}
- Requirement
- OS
- Python version
- Installation
- 自パッケージ
- 依存パッケージ
- {{author}}
- License
他、パッケージごとに別途記載する項目は以下。これはREADME.mdのみにある内容。
- DEMO
- Features
- Usage
- Note
CHANGES.md
# CHANGELOG ## V0.0.2 * Commit Message 3 * Commit Message 4 ## v0.0.1 * Commit Message 1 * Commit Message 2
gitのコミットメッセージ、タグ名と一致する。
MANIFEST.in
include LICENSE.txt include README.md include CHANGES.md include *.md exclude .gitignore include tests.sh exclude release.sh
PyPIパッケージとして追加したいものはinclude
、排除したいものはexclude
。最低限必要なファイルは勝手にinclude
してくれるため明記不要。
.gitignore
*.pyc *.egg-info/ dist/ build/
GitHubにアップロードするとき対象外とするファイル一覧。ここではPythonのキャッシュやPyPI用ビルドしたときの各種ファイルを除外する。GitHubにアップすべきはソースコードのみ。コマンドさえ叩けば自動作成されるようなファイルはすべて除外する。
4. データ
- Python
- メタ情報
パッケージ名
最重要メタデータ。以下は共通する。
パッケージ名は以下に従わねばならない。
- PyPIで未登録の名前であること
[a-zA-Z0-9]+
に一致すること
この制約、かなり厳しい。特にPyPIでの重複チェック。世界中から集まるため、1秒後には重複するかもしれない。時間が経つほど飽和するため、いずれわかりにくくて長い名前しか使えなくなるだろう。その上、使える文字に記号がない。飽和するのが早まる。
早めに名前だけでも確保すべき? だが実装のメドが立たないうちにそんなことをしたら世界的損失。さっさとコードを書くべき。
そもそもメタデータ作成に時間を使いたくない。名前チェックは自動化したい。
グローバル名前空間上の公開API名(import
,__all__
)
最重要実データ。実際にPythonから本パッケージを使用するときに用いる名前。グローバル名前空間において本パッケージを参照するための名前である。
{package}/__init__.py
from {package} import {module} __all__ = ['{module}']
名前汚染対策:1つのパッケージにつき1モジュールにまとめたい。
1つのパッケージにつき1モジュールにまとめたい。もし複数のモジュールを作るならサブパッケージにし、表出するのはトップモジュール1つだけにしたい。そのほうが名前汚染を最小限にできるから。
Pythonの名前汚染問題は深刻である印象。たとえば既存モジュール名と同一のモジュール名にすると誤動作してしまう。これでハマったことが何度もある。できるだけグローバル名前空間には新しい名前を追加しない方向が好ましい。たとえname.name.name
のように階層が深くなったとしても。
そうすればパッケージのインポート処理も最初に書いたように簡略化できる。
自動化したい。
__all__
だけなら以下で可能。
import os, glob __all__ = [ os.path.split(os.path.splitext(file)[0])[1] for file in glob.glob(os.path.join(os.path.dirname(__file__), '*.py')) ]
カレントディレクトリ直下にある*.py
ファイル名の配列を返す。拡張子は省かれる。
ただ、from {package} import {module}
と連携せねばならないため不十分。__init__.py
ファイルをまるごと作成するようにしたほうが現実的か。
version
パッケージ名に次ぐ重要メタデータ。
PyPIでパッケージ更新するときは必ずインクリメントせねばならない。同一バージョン値は1回しか使えない。当然の制約だが、思わぬ失敗の原因になる。インクリメントを忘れたり、メタデータ変更しただけでインクリメントせねばならず思い通りの採番ができなかったり。
バージョン値の決定方法にはセマンティック バージョニングを用いる。ただしプレリリース識別子は使わないほうが無難。以下のように数値とドットのみで表現するほうがよい。
0.0.1 # 正式リリース前 0.1.0 # 正式リリース前 1.0.0 # 正式リリース(最初)
gitコミット時に自動でインクリメントしてくれると嬉しい。ついでにコミットメッセージをCHANGES.md
に自動で反映してほしい。
いくつかコミットしたあと、一定のメドが立ったらgit tab -a -m
でバージョンタグを付与する。その後twineでPyPIにアップロードすれば、リリースとなる。そんな流れを自動化したい。
プレリリース識別子
プレリリース識別子
正式版リリース前に、以下のようなバージョンとして指定することもできる。
ただしSemVerとPEP440で表現方法に違いがある。よって、混乱を避けるためプレリリース識別子は使わないほうが無難。
GitHub Release
GitHub Release
git tag
をつけるとリリース機能が使える。その時点におけるソースコード一式を圧縮ファイルでダウンロードできる。このときタグはv1.0.0
のようにする。SemVerの前にv
を付与する。
以下のようにすることで、カレントディレクトリであるリポジトリのタグを最新順で表示できる。
git tag | sort -Vr
python_requires='>=2.7',
重要メタデータ。この値や環境によっては本パッケージをインストールできなくなる。
PythonのAPIによって使えるAPIが異なる。また、バージョン差異によって名前や結果が異なる。様々なバージョン差異があるため、最低限必要なバージョンを指定することになる。それが本データ。
できるだけ低いほうが多くの環境で使える。ただし実装は大変になる。こんなことはPython自身に管理してほしいのが本音。人間技ではムリ。だがやらねばならぬ。開発者にとって甚大な負担となる項目のひとつ。
パッケージ説明
これは至るところで共通するはず。
その他、CUIアプリケーションならヘルプの内容に記載するかもしれない。なんとかして一元管理したい。
長い説明(setup.py
,setuptools.setup()
,long_description
)は、README.mdをそのままぶち込めばいい。
URL
パッケージ説明の総本山を示すアドレス。以下の箇所で共通するはず。
URLはホームページのこと。専用ページをつくる気がないならGitHubのリポジトリURLにでもしておくと良さそう。以下のような候補がありうる。
setup.py
には他にもdownload_url
がある。これをGitHubのダウンロードURLにすればGitHubAPIでダウンロード数を取得できると考えた。しかしGitHubのリリース機能から最新リンクを取得したかったができなかったため断念。Webスクレイピングすれば不可能ではないが、サイト構成が変更されると破綻するため自動化できるとは言い難い。やむなくダウンロード数の集計は諦める。
ライセンス
重要。本パッケージを使うかどうかはライセンスで判断されることもあるはず。
LICENSE.txt
内にて著作者名、メールアドレス、コピーライトが必要になることがある。コピーライトは、著作者名が必要。任意でメールアドレスを<>
で囲って表記することもある。つまり上記のような包含関係になる。
ライセンスの選択については、頑張ってライセンスを学習するしかない。法律にまで手を伸ばせば本筋からかけ離れてしまうため、適当に決める。たとえば以下から探す。MIT
がよく使われている。
- https://help.github.com/ja/github/creating-cloning-and-archiving-repositories/licensing-a-repository
- https://pypi.org/pypi?%3Aaction=list_classifiers
__license__
の文字列には明確なルールがないと思われる。マシンリーダブルでなく人間が読めればそれでいい感じ。でもそれだと毎回なにを入力すればいいか迷って面倒。やはり自動化したい。
その他PyPI検索ヒント
PyPIでパッケージ検索するときに役立つ。
- 検索キーワード
classifiers
Development Status
Environment
Framework
Intended Audience
License
Natural Language
Operating System
Programming Language
Topic
Typing
重要度は低い。適当にデフォルト値にしつつ、必要に応じて変更できるようにするのがよいか。
あるいはバージョン値の状態によってDevelopment Status
を自動的に繰り上げるようにすべきか。他にもPythonのバージョンなど他の項目と重複する部分がある。一元管理することで連動させるのが理想。
対象環境
- Raspbierry pi 4 Model B
- Raspbian buster 10.0 2019-09-26 ※
- bash 5.0.3(1)-release
$ uname -a Linux raspberrypi 4.19.75-v7l+ #1270 SMP Tue Sep 24 18:51:41 BST 2019 armv7l GNU/Linux