PyPIは、Pythonで作成したパッケージを公開し、pip install パッケージを使用して簡単にダウンロードできるようにするツールです。簡潔に言えば、「AndroidのPlayストア」や「iPhoneのAppストア」のようなものです。
この記事では、 「Pythonで作ったパッケージをPyPIに登録するまでの手順」 を簡単に解説します。
具体的な手順は以下の通りです。まず、Pythonプロジェクトを用意した後、設定ファイルとして「pyproject.toml
」を作成します。その後、「build」パッケージを使用して、設定どおりに.pyproject.tomlから.whlファイル
と.tar.gzアーカイブ
を生成します。
生成された.whlファイル
と.tar.gzアーカイブ
を、「twine」パッケージを利用して「TestPyPI」にアップロードし、動作を確認した後、本番環境である「PyPI」にアップロードする流れとなります。
環境はWindowsですが、同じ手順でMacやLinuxでも登録ができるはずです。
PyPIとは?
PyPIとは、「Python Package Index」 の略で、プログラミング言語Python用のソフトウェア・リポジトリ[1]のことです。
ターミナル上でPowershellなどを使用して、単に「pip install パッケージ
」と入力するだけで、対応するパッケージを簡単にインストールできます。
例えば、marktreeを試しにインストールしてみましょう。marktree
は「pyperclip」というパッケージを特定の機能の実現に使用しているため、一緒にインストールされることがわかります。
(.venv) PS C:\Users\user\テスト> pip install marktree
Collecting marktree
Using cached marktree-1.1.0-py3-none-any.whl.metadata (5.7 kB)
Collecting pyperclip>=1.8.2 (from marktree)
Using cached pyperclip-1.8.2-py3-none-any.whl
Using cached marktree-1.1.0-py3-none-any.whl (6.1 kB)
Installing collected packages: pyperclip, marktree
Successfully installed marktree-1.1.0 pyperclip-1.8.2
上記の手順では、Pythonにデフォルトで搭載されている仮想環境作成ツールであるvenv
を使用してインストールしています。ただし、グローバル環境にインストールする場合は、管理者権限を持つターミナルでインストールしてください。
PyPIに登録する手順
【前準備】フォルダ構造の確認
GitHubでリポジトリを作成し、git clone
でコピーした場合、以下のようなフォルダ構造になると思います。
.
├── .gitignore
├── LICENSE
└── README.md
0 directories, 3 files
1.venv で仮想環境 の作成
作業を始める前に、まず仮想環境を作成します。
仮想環境は、パッケージをグローバル環境にインストールするのではなく、プロジェクトごとに特定のフォルダ以下に保存することで、グローバル環境に影響を与えずに作業できるようにするツールです。
Pythonには標準で搭載されている「venv」という仮想環境作成ツールが含まれていますので、これを使用します。以下のコマンドを実行することで、現在のディレクトリ以下に「.venv」というフォルダが作成されます。
「python -m venv .venv」とすれば、現在ディレクトリ以下に 「.venv」 というフォルダが作成されます。
PS C:\Users\ユーザー名\プロジェクト> python -m venv .venv
現在、以下のようなフォルダ構造になっています。
.
├── .gitignore
├── .venv/
├── LICENSE
└── README.md
1 directory, 3 files
この状態で、Windowsの場合は「.\.venv\Scripts\activate
」、Linux・Macの場合は「source .venv/bin/activate
」とコマンドを実行すると、仮想環境に入ります。
仮想環境に入ると、プロンプトの左端に「(.venv)」と表示されます。
PS C:\Users\ユーザー名\プロジェクト> .\.venv\Scripts\activate
(.venv) PS C:\Users\ユーザー名\プロジェクト>
「pip list」と実行すると、pip以外には何もインストールされていないことが確認できます。
(.venv) PS C:\Users\user\github\clipcount> pip list
Package Version
------- -------
pip 24.0
これにより、プロジェクトは独立した状態になりました。残りの手順では、プロジェクトに必要なツールをインストールしていきましょう。
2.Pythonプロジェクトの用意
ここにPythonプロジェクトを追加します。プロジェクトフォルダには通常、_init_.pyなどが格納されますが、これに関する詳細な説明は省略します。
.
├── .gitignore
├── .venv/
├── LICENSE
├── README.md
└── プロジェクト/
└── __init__.py
2 directories, 3 files
上記のようなフォルダ構造ができたら、次のステップに進みます。
3.pyproject.toml を作成する
次に、PyPIにアップロードするための設定ファイルである「pyproject.toml」を作成します。
.
├── .gitignore
├── .venv/
├── LICENSE
├── README.md
├── pyproject.toml
└── プロジェクト/
2 directories, 4 files
ここに記述した内容がパッケージやPyPIに反映されるため、非常に重要なファイルです。
「pyproject.toml」は、「build-system」「project」「tool」の3つのセクションから構成されています。
[build-system]
どのビルドバックエンドを使うかを書き込む
[project]
依存関係や作者の名前など、そのプロジェクトの基本的なメタデータを指定するために書き込む
[tool]
ツールに特化したサブテーブル。省略してもいい
この解説は、下記のサイトを参考にしています。
[build-system]
[build-system] テーブルは、使用するビルドバックエンドを指定します。また、プロジェクトをビルドするために必要な依存関係を requires
で指定します。
requires
は、例えば requires = ["setuptools >= 61.0"]
のようにしてバージョンを制限することもできます。
一般的に使用されるビルドバックエンドには、「hatching」「setuptools」「Flit」「PDM」などがあります。いずれか一つを選んで、[build-system] テーブルに記述してください。
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[build-system]
requires = ["setuptools >= 61.0"]
build-backend = "setuptools.build_meta"
[build-system]
requires = ["flit_core >= 3.4"]
build-backend = "flit_core.buildapi"
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"
このテーブルは絶対に必要なので、迷った場合は「setuptools」を選んでください。
[project]
残りのほぼ全ての情報は、「project」テーブルに書き込みます。以下の内容をコピーして、必要に応じて値を設定してください。
[project]
name = "プロジェクトの名前"
version = "バージョン"
dependencies = [
"依存しているパッケージ"
]
requires-python = "Pythonのバージョン要件"
authors = [
{name="作成者の名前"},
{email="作成者のメールアドレス"}
]
description = "プロジェクトの説明"
readme = "PyPIに掲載するREADMEファイル"
license = {file = "ライセンスファイル"}
keywords = [
"キーワードの指定"
]
classifiers = [
"Development Status :: 開発状況",
"Intended Audience :: 誰向けのパッケージなのか",
"Topic :: どんなテーマのパッケージか",
"License :: OSI Approved :: ライセンス",
"Programming Language :: 使用プログラミング言語"
]
classifiers
はPyPIで使用される分類子を指定できます。分類子についての詳細は、PyPIのドキュメントをご参照ください。
もしclassifiers一覧を素早く見たい方は、以下のページが便利です。
また、project
にはいくつかのサブテーブルが存在し、「project.urls」テーブルはPyPIの左欄にURLを追加するためのものです。
[project.urls]
Homepage = "ホームページを指定"
Repository = "GitHubのリポジトリを指定"
「project.scripts」テーブルでは、ファイルを実行できるコマンドを登録できます。例えば、「コマンド = “プロジェクト:関数名”」とすることで、ターミナル上でそのコマンドを実行すると、指定した関数が実行されるようになります。
通常は、「コマンド = “プロジェクト名:main”」として、main
関数が実行されるようにします。コマンド名とプロジェクト名を一致させることが一般的です。
[project.scripts]
コマンド = "プロジェクト名:main"
「project.optional-dependencies」は、開発用の依存パッケージを指定するテーブルです。例えば、「pip install パッケージ[dev]」とすれば、ここに記述したパッケージも一緒にインストールできるようになります。
[project.optional-dependencies]
dev = ["開発で使うパッケージ"]
[tool]
「tool」テーブルは、例えば [tool.hatch]
や [tool.black]
、[tool.mypy]
のような、特定のツールに特化したサブテーブルを持っています[2]。
正直なところ、私もそれらのツールを使用していないため、具体的な内容はよく分かりません。また、「pyproject.toml」の作成においては、Python Packaging User Guideでも割愛されていることから、必須ではないと思われます。必要最小限の内容で進めても良いでしょう。
【参考例】marktreeの場合
以下は、参考として自分が作成した「marktree」の pyproject.toml
の内容です。
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "marktree"
version = "1.1.0"
dependencies = [
"pyperclip >= 1.8.2"
]
requires-python = ">=3.8"
authors = [
{name="yusu79"},
{email="oss@yusu79.com"}
]
description = "convert headings in a Markdown file (.md) into a tree-like structure and output."
readme = "README_en.md"
license = {file = "LICENSE"}
keywords = [
"markdown",
"tree",
"pyperclip"
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Other Audience",
"Topic :: Terminals",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python"
]
[project.urls]
Homepage = "https://yusu79.com"
Repository = "https://github.com/yusu79/marktree"
[project.scripts]
marktree = "marktree:main"
[project.optional-dependencies]
dev = [
"build",
"twine",
]
ちなみに、marktree
はMarkdownファイル(.md)を読み込んで「#」の数に応じてtreeを出力するパッケージです。
4..whl と .tar.gz を作成する
pyproject.toml
が完成したら、プロジェクトから .whl
ファイルと .tar.gz
ファイルを生成します。これらをPyPIにアップロードします。
これらを生成するには、「build」 パッケージを使用します。まず最初に、build
パッケージをインストールします。
(.venv) PS C:\Users\ユーザー名\プロジェクト> pip install build # 「.whl」 と 「.tar.gz」 を作成するためのツール
あとは、「pyproject.toml」があるフォルダで 「python -m build」 を実行するだけで、.whl と.tar.gzが生成されます。
(.venv) PS C:\Users\ユーザー名\プロジェクト> python -m build
* Creating venv isolated environment...
* Installing packages in isolated environment... (setuptools)
* Getting build dependencies for sdist...
(中略)
Successfully built プロジェクト-バージョン.tar.gz and プロジェクト-バージョン-py3-none-any.whl
生成されたファイルは、dist
フォルダ以下に「プロジェクト-バージョン-py3-none-any.whl」と「プロジェクト-バージョン.tar.gz」が作成されます。また、「プロジェクト.egg-info」フォルダも作成されています。
.
├── .gitignore
├── .venv/
├── LICENSE
├── README.md
├── プロジェクト.egg-info/
├── dist/
│ ├── プロジェクト-バージョン-py3-none-any.whl
│ └── プロジェクト-バージョン.tar.gz
├── pyproject.toml
└── プロジェクト/
4 directories, 4 files
次のステップでは、生成された「プロジェクト-バージョン-py3-none-any.whl」と「プロジェクト-バージョン.tar.gz」をPyPIにアップロードします。
今は、wheelよりもbuild!?
以前はこの作業を 「wheel」 パッケージで行っていました。
wheelをインストールすると、「python setup.py sdist」で.tar.gzを、「python setup.py bdist_wheel」で .whl を生成できるようになります。
pip install wheel # wheelのインストール
python setup.py sdist # .tar.gzの生成
python setup.py bdist_wheel # .whlの生成
しかし、現在wheel
は非推奨となっています。その理由は、python setup.py
および setup.py
をコマンドラインツールとして使うことは非推奨[3]となったからです。つまり、以下のコマンドは全て非推奨となりました。
python setup.py install
python setup.py develop
python setup.py sdist
python setup.py bdist_wheel
よって、wheel
の代わりに公式で推奨されている方法として、「python -m build」を使用することがお勧めされています。
詳細は下記を御覧ください。
5.twineでアップロード
ここまでできたら、後はアップロードするだけです。アップロードには、「twine」を使用します。
(.venv) PS C:\Users\ユーザー名\プロジェクト> pip install twine # PyPIへのアップロードに使用するツール
後は、「twine upload --repository testpypi dist/*
」とすればTestPyPIに、そして「twine upload --repository pypi dist/*
」と入力すれば、PyPIに .whl と .tar.gz がアップロードされます。
ただし、それぞれのWEBサイトでアカウントを作成する必要があります。また、それぞれのアカウント先でAPIキーを作成し、その鍵IDを「C:\Users\ユーザー名\.pypirc
」というファイルに記述しておく必要があります。
TestPyPIにアップロード
まずは、下記のサイトにアクセスし、アカウントを作成しましょう。右上の「登録」をクリックしてください。
アカウントが作成できたら、APIトークンを作成します。まず「アカウント設定」をクリックします。
次に、画面下部にある「APIトークンの追加」をクリックします。
APIトークンの名前とスコープを設定して、「Create Token」をクリックします。
生成されたAPIトークンは一度だけ表示されますので、コピーしてください。
「C:\Users\ユーザー名
」以下に 「.pypirc
」 ファイルを作成します。以下の内容をコピーして貼り付けます。
[distutils]
index-servers =
testpypi
[testpypi]
repository = https://test.pypi.org/legacy/
username = ここにコピーしたAPIトークンを貼り付ける!
上記で、[testpypi]
の username
にはAPIトークンを貼り付けます。このAPIトークンがパスワードの代わりとなります。
そして、「twine upload --repository testpypi dist/*
」 を実行することで、TestPyPIに dist
フォルダ以下の「プロジェクト-バージョン-py3-none-any.whl」と「プロジェクト-バージョン.tar.gz」がアップロードされます。
(.venv) PS C:\Users\ユーザー名\プロジェクト> twine upload --repository testpypi dist/*
TestPyPIにアップロードしたパッケージのページ(https://test.pypi.org/project/プロジェクト/バージョン/
)にアクセスすると、黄色で囲まれた箇所にインストールコマンドが表示されます。これをクリックして貼り付けることで、インストールが可能です。
実際にインストールして動作確認ができたら、本番環境の「PyPI」にアップロードします。
TestPyPIの注意点
実はTestPyPIにはひとつ欠点があります。それは依存関係を正しく処理できないことです。
pyproject.tomlの「project」テーブルの「dependencies」に記載したパッケージを正しくインストールできるとは限りません。そのため、TestPyPIにアップロードしたパッケージをインストールすると、エラーになることがあります。
しかし、これはTestPyPIが依存関係を正しく処理できないために起こる問題であり、本番環境のPyPIにアップロードすると、通常はうまく処理されます。
PyPIにアップロード
PyPIも同様に、まずはアカウントを作成します。下記のサイトにアクセスして、右上の「登録」からアカウントを作成してください。
その後、同様の流れでAPIトークンを作成します。APIトークンを生成したら、コピーしておきます。
[distutils]
index-servers =
testpypi
pypi
[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = TestPyPIのAPIトークン
[pypi]
repository = https://upload.pypi.org/legacy/
username = __token__
password = ここにコピーしたAPIトークンを貼り付ける!
最後に、「twine upload –repository pypi dist/*」を実行すれば、PyPIに dist
フォルダ以下の「プロジェクト-バージョン-py3-none-any.whl」と「プロジェクト-バージョン.tar.gz」がアップロードされます。
(.venv) PS C:\Users\ユーザー名\プロジェクト> twine upload --repository pypi dist/*
6.PyPI Stats で確認
アップロードは完了しましたが、PyPIでは「どれくらいインストールされているのか」や「インストールの推移」などの情報は確認できません。
そういった情報を確認したい場合は、下記のサイトにアクセスしてください。「Package:」という欄に自身のパッケージ名を入力すると、関連情報が表示されます。
ただし、アップロードしたばかりだと反映までに時間がかかることがあるので、その点は注意してください。
まとめ
この記事では、「Pythonで作ったパッケージをPyPIに登録するまでの手順」を簡単に解説しました。
手順は以下の通りです:
- まずは「venv」を使用して仮想環境を作成し、その中に入ります。
- 次に、プロジェクトを完成させて、「
pyproject.toml
」に必要な設定を書き込みます。 - 書き込みが完了したら、「build」を使用して、
dist/
以下に「プロジェクト-バージョン-py3-none-any.whl
」と「プロジェクト-バージョン.tar.gz
」を作成します。 - 最後に、「twine」を使用して、「
プロジェクト-バージョン-py3-none-any.whl
」と「プロジェクト-バージョン.tar.gz
」をPyPIにアップロードして手順を完了します。
Pythonの環境や手順が頻繁に変わるため、最新の情報を確認することが重要です。この記事では、直近の経験を元にPyPIにアップロードする手順をまとめています。