PR

【初心者向け】Pythonの自作パッケージをPyPIに登録する方法

OSS開発

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でも登録ができるはずです。

WordPressブロガーの方必見! 外出先でもブログ執筆作業がはかどる、 Ankerの大容量モバイルバッテリー をご紹介します。

PyPIとは?

PyPIとは、「Python Package Index」 の略で、プログラミング言語Python用のソフトウェア・リポジトリ[1]のことです。

ターミナル上でPowershellなどを使用して、単に「pip install パッケージ」と入力するだけで、対応するパッケージを簡単にインストールできます。

例えば、marktreeを試しにインストールしてみましょう。marktreeは「pyperclip」というパッケージを特定の機能の実現に使用しているため、一緒にインストールされることがわかります。

PowerShell
(.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でコピーした場合、以下のようなフォルダ構造になると思います。

PowerShell
.
├── .gitignore
├── LICENSE
└── README.md

0 directories, 3 files

1.venv で仮想環境 の作成

作業を始める前に、まず仮想環境を作成します。

仮想環境は、パッケージをグローバル環境にインストールするのではなく、プロジェクトごとに特定のフォルダ以下に保存することで、グローバル環境に影響を与えずに作業できるようにするツールです。

Pythonには標準で搭載されている「venv」という仮想環境作成ツールが含まれていますので、これを使用します。以下のコマンドを実行することで、現在のディレクトリ以下に「.venv」というフォルダが作成されます。

「python -m venv .venv」とすれば、現在ディレクトリ以下に 「.venv」 というフォルダが作成されます。

PowerShell
PS C:\Users\ユーザー名\プロジェクト> python -m venv .venv

現在、以下のようなフォルダ構造になっています。

PowerShell
.
├── .gitignore
├── .venv/
├── LICENSE
└── README.md

1 directory, 3 files

この状態で、Windowsの場合は「.\.venv\Scripts\activate」、Linux・Macの場合は「source .venv/bin/activate」とコマンドを実行すると、仮想環境に入ります。

仮想環境に入ると、プロンプトの左端に「(.venv)」と表示されます。

PowerShell
PS C:\Users\ユーザー名\プロジェクト> .\.venv\Scripts\activate
(.venv) PS C:\Users\ユーザー名\プロジェクト> 

「pip list」と実行すると、pip以外には何もインストールされていないことが確認できます。

PowerShell
(.venv) PS C:\Users\user\github\clipcount> pip list
Package Version
------- -------
pip     24.0

これにより、プロジェクトは独立した状態になりました。残りの手順では、プロジェクトに必要なツールをインストールしていきましょう。

2.Pythonプロジェクトの用意

ここにPythonプロジェクトを追加します。プロジェクトフォルダには通常、_init_.pyなどが格納されますが、これに関する詳細な説明は省略します。

PowerShell
.
├── .gitignore
├── .venv/
├── LICENSE
├── README.md
└── プロジェクト/
    └── __init__.py

2 directories, 3 files

上記のようなフォルダ構造ができたら、次のステップに進みます。

3.pyproject.toml を作成する

次に、PyPIにアップロードするための設定ファイルである「pyproject.toml」を作成します。

PowerShell
.
├── .gitignore
├── .venv/
├── LICENSE
├── README.md
├── pyproject.toml
└── プロジェクト/

2 directories, 4 files

ここに記述した内容がパッケージやPyPIに反映されるため、非常に重要なファイルです。

「pyproject.toml」は、「build-system」「project」「tool」の3つのセクションから構成されています。

TOML
[build-system]
どのビルドバックエンドを使うかを書き込む

[project]
依存関係や作者の名前など、そのプロジェクトの基本的なメタデータを指定するために書き込む

[tool]
ツールに特化したサブテーブル。省略してもいい

この解説は、下記のサイトを参考にしています。

pyproject.toml を書く - Python Packaging User Guide

[build-system]

[build-system] テーブルは、使用するビルドバックエンドを指定します。また、プロジェクトをビルドするために必要な依存関係を requires で指定します。

requires は、例えば requires = ["setuptools >= 61.0"] のようにしてバージョンを制限することもできます。

一般的に使用されるビルドバックエンドには、「hatching」「setuptools」「Flit」「PDM」などがあります。いずれか一つを選んで、[build-system] テーブルに記述してください。

TOML
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
TOML
[build-system]
requires = ["setuptools >= 61.0"]
build-backend = "setuptools.build_meta"
TOML
[build-system]
requires = ["flit_core >= 3.4"]
build-backend = "flit_core.buildapi"
TOML
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"

このテーブルは絶対に必要なので、迷った場合は「setuptools」を選んでください。

[project]

残りのほぼ全ての情報は、「project」テーブルに書き込みます。以下の内容をコピーして、必要に応じて値を設定してください。

TOML
[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
The Python Package Index (PyPI) is a repository of software for the Python programming language.

もしclassifiers一覧を素早く見たい方は、以下のページが便利です。

https://pypi.org/pypi?%3Aaction=list_classifiers

また、projectにはいくつかのサブテーブルが存在し、「project.urls」テーブルはPyPIの左欄にURLを追加するためのものです。

TOML
[project.urls]
Homepage = "ホームページを指定"
Repository = "GitHubのリポジトリを指定"


「project.scripts」テーブルでは、ファイルを実行できるコマンドを登録できます。例えば、「コマンド = “プロジェクト:関数名”」とすることで、ターミナル上でそのコマンドを実行すると、指定した関数が実行されるようになります。

通常は、「コマンド = “プロジェクト名:main”」として、main関数が実行されるようにします。コマンド名とプロジェクト名を一致させることが一般的です

TOML
[project.scripts]
コマンド = "プロジェクト名:main"

「project.optional-dependencies」は、開発用の依存パッケージを指定するテーブルです。例えば、「pip install パッケージ[dev]」とすれば、ここに記述したパッケージも一緒にインストールできるようになります。

TOML
[project.optional-dependencies]
dev = ["開発で使うパッケージ"]

[tool]

「tool」テーブルは、例えば [tool.hatch][tool.black][tool.mypy] のような、特定のツールに特化したサブテーブルを持っています[2]

正直なところ、私もそれらのツールを使用していないため、具体的な内容はよく分かりません。また、「pyproject.toml」の作成においては、Python Packaging User Guideでも割愛されていることから、必須ではないと思われます。必要最小限の内容で進めても良いでしょう。

【参考例】marktreeの場合

以下は、参考として自分が作成した「marktree」の pyproject.toml の内容です。

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 パッケージをインストールします。

PowerShell
(.venv) PS C:\Users\ユーザー名\プロジェクト> pip install build # 「.whl」 と 「.tar.gz」 を作成するためのツール

あとは、「pyproject.toml」があるフォルダで 「python -m build」 を実行するだけで、.whl と.tar.gzが生成されます。

PowerShell
(.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」フォルダも作成されています。

PowerShell
.
├── .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 を生成できるようになります。

PowerShell
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」を使用することがお勧めされています。

詳細は下記を御覧ください。

setup.py は非推奨になりましたか? - Python Packaging User Guide

5.twineでアップロード

ここまでできたら、後はアップロードするだけです。アップロードには、「twine」を使用します。

PowerShell
(.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にアップロード

まずは、下記のサイトにアクセスし、アカウントを作成しましょう。右上の「登録」をクリックしてください。

TestPyPI · The Python Package Index
The Python Package Index (PyPI) is a repository of software for the Python programming language.

アカウントが作成できたら、APIトークンを作成します。まず「アカウント設定」をクリックします。

次に、画面下部にある「APIトークンの追加」をクリックします。

APIトークンの名前とスコープを設定して、「Create Token」をクリックします。

生成されたAPIトークンは一度だけ表示されますので、コピーしてください。

C:\Users\ユーザー名」以下に .pypirc ファイルを作成します。以下の内容をコピーして貼り付けます。

PowerShell
[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」がアップロードされます。

PowerShell
(.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も同様に、まずはアカウントを作成します。下記のサイトにアクセスして、右上の「登録」からアカウントを作成してください。

PyPI · The Python Package Index
The Python Package Index (PyPI) is a repository of software for the Python programming language.

その後、同様の流れでAPIトークンを作成します。APIトークンを生成したら、コピーしておきます。

PowerShell
[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」がアップロードされます。

PowerShell
(.venv) PS C:\Users\ユーザー名\プロジェクト> twine upload --repository pypi dist/*

6.PyPI Stats で確認

アップロードは完了しましたが、PyPIでは「どれくらいインストールされているのか」や「インストールの推移」などの情報は確認できません。

そういった情報を確認したい場合は、下記のサイトにアクセスしてください。「Package:」という欄に自身のパッケージ名を入力すると、関連情報が表示されます。

PyPI Download Stats
PyPI Download Stats

ただし、アップロードしたばかりだと反映までに時間がかかることがあるので、その点は注意してください。

まとめ

この記事では、「Pythonで作ったパッケージをPyPIに登録するまでの手順」を簡単に解説しました。

手順は以下の通りです:

  1. まずは「venv」を使用して仮想環境を作成し、その中に入ります。
  2. 次に、プロジェクトを完成させて、「pyproject.toml」に必要な設定を書き込みます。
  3. 書き込みが完了したら、「build」を使用して、dist/以下に「プロジェクト-バージョン-py3-none-any.whl」と「プロジェクト-バージョン.tar.gz」を作成します。
  4. 最後に、「twine」を使用して、「プロジェクト-バージョン-py3-none-any.whl」と「プロジェクト-バージョン.tar.gz」をPyPIにアップロードして手順を完了します。

Pythonの環境や手順が頻繁に変わるため、最新の情報を確認することが重要です。この記事では、直近の経験を元にPyPIにアップロードする手順をまとめています。


  1. PyPiとは【用語集詳細】 ↩︎

  2. pyproject.toml を書く – Python Packaging User Guide ↩︎

  3. setup.py は非推奨になりましたか? – Python Packaging User Guide ↩︎

タイトルとURLをコピーしました