Python のプロジェクトをパッケージングする¶
このチュートリアルでは、簡単な Python プロジェクトをどのようにしてパッケージするのかについて、一通り見て回ります。パッケージを構成するために必要なファイルやディレクトリを追加する方法や、パッケージをビルドする方法、そして、Python パッケージインデックス (PyPI) にパッケージをアップロードする方法をお見せします。
Tip
このチュートリアルに出てくるコマンドを実行したら問題が発生したという場合には、コマンドと結果出力をコピーして、 GitHub の packaging-problems リポジトリで 新たな課題 を追加してください。我々が全力であなたをお助けします!
コマンドの中のいくつかは新しめのバージョンの pip でないとだめなので、最新版をインストールして使っていることを最初に確認しておいてください:
python3 -m pip install --upgrade pip
py -m pip install --upgrade pip
単純なプロジェクト¶
このチュートリアルは、 example_package_YOUR_USERNAME_HERE
という名前の単純なプロジェクトを使っています。もしあなたのユーザ名が me
であるなら、パッケージの名前は example_package_me
となるでしょう; こうすることで、このチュートリアルに従っている他の人たちがアップロードするパッケージ群と名前が衝突することのない一意なパッケージ名を使っていることを保証できます。自分自身のプロジェクトのパッケージングを始める前に、このプロジェクト名を使ってこのチュートリアルに沿った練習をすることをお勧めします。
ローカルに以下のファイル構造を作成する:
packaging_tutorial/
└── src/
└── example_package_YOUR_USERNAME_HERE/
├── __init__.py
└── example.py
Python ファイル群を格納するディレクトリは、プロジェクト名と同じ名前であるべきです。こうすることで設定が簡単になり、また、パッケージをインストールするユーザから見てより明白になります。
__init__.py
ファイルを使用して、ユーザーはディレクトリを通常のパッケージとしてインポートできるため、 (このチュートリアルの場合のように) たとえ __init__.py
が空だとしても、 __init__.py
ファイルの作成が推奨されています。 [1]
example.py
は、パッケージの中であなたのパッケージのロジック (関数・クラス・定数・その他) を含むであろうモジュールの例です。このファイルを開いて、以下の内容を入力してください:
def add_one(number):
return number + 1
Python における モジュール や パッケージのインポート に馴染みがなければ、数分を費やして パッケージとモジュールに関する Python の説明文書 を読み通してください。
この構造さえ作れば、このチュートリアルに出てくるすべてのコマンドを packaging_tutorial
ディレクトリで実行したくなるでしょう。
パッケージファイルを作成する¶
ここで、プロジェクトの配布を準備するために使われるファイル群を追加しましょう。それが終わったら、プロジェクトの構造はこんな風になっていることでしょう:
packaging_tutorial/
├── LICENSE
├── pyproject.toml
├── README.md
├── src/
│ └── example_package_YOUR_USERNAME_HERE/
│ ├── __init__.py
│ └── example.py
└── tests/
test ディレクトリを作成する¶
tests/
は、テスト用のファイルを置くためのプレースホルダーです。現段階では、空のままにしておいてください。
ビルドバックエンドを選択する¶
pip や ビルド のようなツールは、実際にソースを 配布パッケージ (wheel のような) に変換するわけではありません。その作業は、 ビルドバックエンド によって行われます。ビルドバックエンドは、プロジェクトがメタデータ (プロジェクトについての情報、例えば PyPI に表示される名前やタグ) や入力ファイルを含むその構成を指定する方法を決定します。ビルドバックエンドは、 拡張モジュール のビルドをサポートするかどうかのような、異なる水準の機能性を持ち、必要性や好みに適切なものを選択するべきです。
多くのバックエンド群から選択することができます; このチュートリアルでは Hatchling をデフォルトとして使いますが、 Setuptools ・ Flit ・ PDM や、 メタデータ として [project]
テーブルをサポートする他のものでも同様に動作するでしょう。
注釈
ビルド・アップロード・インストールと並んでプロジェクト初期化やバージョン管理のような追加機能を伴ったコマンドラインインタフェースを提供する、もっと大きなツールの一部を構成するビルドバックエンドもあります。このチュートリアルでは、独立に動作する単一目的のツールを扱います。
pyproject.toml
は、 pip や ビルド のような ビルドフロントエンド ツールに対して、そのプロジェクトにおいてどのバックエンドを使うかを指示します。よくあるビルドバックエンドのいくつかの例を下に挙げますが、もっと詳しいことについてはバックエンド自身の説明文書を確認してください。
[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"
requires
は、そのパッケージをビルドするために必要とされるパッケージ群のリストです。 ビルドフロントエンド は、そのパッケージをビルドする際にそれらをインストールするべきです。フロントエンドは、通常、隔離された環境でビルドを実行しますので、ここに依存関係を書き忘れるとビルド時のエラーにつながります。バックエンドパッケージには常にこれを含めておくべきであり、他のビルド時の依存関係を持っているかもしれません。
build-backend
キーは、そのフロントエンドがビルドを実行するにあたって使用するであろう Python オブジェクトの名前です。
これらの両方の値は、ビルドバックエンドの説明文書によって提供されるか、そのコマンドラインインターフェースによって生成されるでしょう。これらの設定をカスタマイズする必要はないはずです。
ビルドツールの追加の設定は、 pyproject.toml
の tool
セクションか、ビルドツールによって定義された特別なファイルの中にあるでしょう。例えば、ビルドバックエンドとして setuptools
を使う時には、追加の設定を setup.py
ないし setup.cfg
ファイルに追加してもよく、ビルド中に setuptools.build_meta
を指定することでツールに対してこれらを自動的に探索して使うようにできます。
メタデータを設定する¶
pyproject.toml
を開いて、以下の内容を入力してください。 name
の値はあなたのユーザ名に書き換えてください; こうすることで、このチュートリアルを履修している他の人たちがアップロードするパッケージと衝突を起こさない一意なパッケージ名を使っていることを保証することができます。
[project]
name = "example_package_YOUR_USERNAME_HERE"
version = "0.0.1"
authors = [
{ name="Example Author", email="author@example.com" },
]
description = "A small example package"
readme = "README.md"
requires-python = ">=3.8"
classifiers = [
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
]
license = "MIT"
license-files = ["LICEN[CS]E*"]
[project.urls]
Homepage = "https://github.com/pypa/sampleproject"
Issues = "https://github.com/pypa/sampleproject/issues"
name
は、あなたのパッケージの 配布物の名前 です。これは、文字・数字・.
・_
・-
だけで構成されている限りは、どんな名前でも構いません。また、 PyPI 上に既に存在するものであってはなりません。このチュートリアルでは、あなたのユーザ名を使って更新していることを 確実にしてください 、というのは、そうすることで、既存の名前と同じ名前のパッケージのアップロードを試みることがないと保証できるからです。version
は、パッケージのバージョン番号です。 (ビルドバックエンドの中には、ファイルや Git のタグからといった別の方法で指定することができるものもあります。)authors
は、パッケージの作者を識別するために使われます; 作者の一人一人について名前と電子メールアドレスを指定します。同じフォーマットでmaintainers
を列挙することもできます。description
は、1文で短くパッケージを説明するものです。readme
は、パッケージに関する詳細な説明を含んだファイルへのパスです。 PyPI 上のパッケージ詳細のページにこの内容が表示されます。この場合、説明の文言はREADME.md
(これがよくあるパターンです) からロードされます。他にも、 pyproject.toml ガイド文書 に記述されているもっと先進的なテーブル形式があります。requires-python
は、そのプロジェクトがサポートしている Python のバージョンを与えます。 pip のようなインストーラは、 Python バージョンが合致するものを見つけるまでパッケージのバージョンを遡って探索します。classifiers
gives the index and pip some additional metadata about your package. In this case, the package is only compatible with Python 3 and is OS-independent. You should always include at least which version(s) of Python your package works on and which operating systems your package will work on. For a complete list of classifiers, see https://pypi.org/classifiers/.license
is the SPDX license expression of your package.license-files
is the list of glob paths to the license files, relative to the directory wherepyproject.toml
is located.urls
には、 PyPI で表示するその他のリンクを幾つでも列挙しておくことができます。一般的に、ソースコードや説明文書、課題追跡システムその他へのリンクを挙げておけばよいでしょう。
[project]
テーブルに定義できるこれらのフィールドやその他のフィールドについての詳しい情報が必要であれば、 pyproject.toml ガイド文書 を見てください。他のよく使われるフィールドには、検索にかかりやすくするための keywords
や、当該パッケージをインストールするために必須のパッケージを示す dependencies
があります。
README.md を作成する¶
README.md
を開いて、以下の内容を入力してください。そうしたければ、カスタマイズした内容でも構いません。
# Example Package
This is a simple example package. You can use
[GitHub-flavored Markdown](https://guides.github.com/features/mastering-markdown/)
to write your content.
LICENSE ファイルを作成する¶
Python パッケージインデックスにアップロードされた各々のパッケージにとって、ライセンス条項を明示することは重要です。こうすることで、そのパッケージをインストールするユーザに対して、どのような条件のもとでそのパッケージを使うことができるのかを伝えることができるからです。ライセンス選択の助けが必要ならば、 https://choosealicense.com/ を見てください。どのライセンスにするか選択できたら、 LICENSE
ファイルを開いてそのライセンス条項を書き込んでください。例えば、 MIT ライセンスを選択したなら次のようにします:
Copyright (c) 2018 The Python Packaging Authority
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Most build backends automatically include license files in packages. See your
backend's documentation for more details.
If you include the path to license in the license-files
key of
pyproject.toml
, and your build backend supports PEP 639,
the file will be automatically included in the package.
その他のファイルを包含する¶
上に挙げたファイル群は、 ソースコード配布物 に自動的に含まれるでしょう。他のファイルも含めておきたいなら、使っているビルドバックエンドの説明文書を見てください。
配布物アーカイブを生成する¶
次のステップでは、そのパッケージの 配布物パッケージ を生成します。これらは、 Python パッケージインデックスへアップロードされ、 pip でインストールされることができるものです。
PyPA の ビルド の最新版がインストールされていることを確認してください:
python3 -m pip install --upgrade build
py -m pip install --upgrade build
Tip
これらをインストールするのに困難を感じるようなら、 パッケージをインストールする チュートリアルを見てください。
さて、 pyproject.toml
ファイルがあるのと同じディレクトリでこのコマンドを実行しましょう:
python3 -m build
py -m build
このコマンドから多くのテキストメッセージが出力されますが、実行が終われば dist
ディレクトリにふたつのファイルが生成されていることでしょう:
dist/
├── example_package_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
└── example_package_YOUR_USERNAME_HERE-0.0.1.tar.gz
tar.gz
ファイルは ソースコード配布物 であり、 .whl
ファイルは ビルド済配布物 です。新しめのバージョンの pip では、ビルド済配布物を優先的にインストールしますが、必要であればソースコード配布物にフォールバックします。ソースコード配布物については常にアップロードするべきであり、あなたのプロジェクトが動作するはずのプラットフォーム向けのビルド済配布物についても準備するべきです。我々の例示のためのパッケージはすべてのプラットフォーム上の Python で動作するものなので、ビルド済配布物がひとつあれば十分です。
配布物アーカイブをアップロードする¶
ついにあなたのパッケージを Python パッケージインデックスへアップロードする時が来ました!
最初に実行しなければならないことは、試験や実験の場となることを意図してパッケージインデックスとは別のインスタンスとして立てられたインスタンスである TestPyPI にアカウントを登録することです。このチュートリアルのように、必ずしも実際のインデックスにアップロードしたいと思わない場合には、 (TestPI は) 最適です。アカウントを登録するためには、 https://test.pypi.org/account/register/ へ行って、そのページにあるステップを完了してください。パッケージをアップロードできるようになる前に、あなたの電子メールアドレスを検証することも必要になるでしょう。もっと詳しいことが知りたければ、 TestPyPI を使う を見てください。
あなたのプロジェクトを安全にアップロードするためには、 PyPI API トークン が必要になるでしょう。 https://test.pypi.org/manage/account/#api-tokens で、 "スコープ" として "アカウント全体" を指定して、ひとつ作成してください。 トークンをコピーして保存するまで、ページを閉じないでください — トークンは二度と表示されません。
ユーザ登録が済んだら、 twine で配布物パッケージをアップロードすることができます。Twine のインストールが必要ならこのようにしてください:
python3 -m pip install --upgrade twine
py -m pip install --upgrade twine
インストールできたら、 dist
ディレクトリ内にあるアーカイブファイルをすべてアップロードしてください:
python3 -m twine upload --repository testpypi dist/*
py -m twine upload --repository testpypi dist/*
You will be prompted for an API token. Use the token value, including the pypi-
prefix. Note that the input will be hidden, so be sure to paste correctly.
コマンド実行完了後、これに似た出力を見ることになるでしょう:
Uploading distributions to https://test.pypi.org/legacy/
Enter your API token:
Uploading example_package_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.2/8.2 kB • 00:01 • ?
Uploading example_package_YOUR_USERNAME_HERE-0.0.1.tar.gz
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.8/6.8 kB • 00:00 • ?
あなたのパッケージをアップロードしたら、 TestPyPI 上で閲覧できるようになります; 例えば: https://test.pypi.org/project/example_package_YOUR_USERNAME_HERE
。
新しくアップロードしたあなたのパッケージをインストールする¶
pip を使えば、あなたのパッケージをインストールして動作を検証することができます。 仮想環境 を作成して、 TestPyPI からあなたのパッケージをインストールしましょう:
python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps example-package-YOUR-USERNAME-HERE
py -m pip install --index-url https://test.pypi.org/simple/ --no-deps example-package-YOUR-USERNAME-HERE
パッケージ名の中にあなたのユーザ名を指定するのをお忘れなく!
pip でパッケージを TestPyPI からインストールできるはずで、その出力は何か次のようなものに見えるでしょう:
Collecting example-package-YOUR-USERNAME-HERE
Downloading https://test-files.pythonhosted.org/packages/.../example_package_YOUR_USERNAME_HERE_0.0.1-py3-none-any.whl
Installing collected packages: example_package_YOUR_USERNAME_HERE
Successfully installed example_package_YOUR_USERNAME_HERE-0.0.1
注釈
この例では --index-url
フラグを使って本番環境である PyPI の代わりに TestPyPI を指定しています。さらに、 --no-deps
も指定しています。 TestPyPI には本番環境である PyPI と同じだけのパッケージが存在しないので、依存先となるパッケージを同時にインストールしようとしても、失敗するか、または、期待していたものとは異なる何かをインストールしてしまう恐れがあります。我々の例として使っているパッケージには依存先がないので、 TestPyPI を使う時には依存先をインストールしないように指定しておくことは良いやり方です。
パッケージをインポートしてみることで、正しくインストールされたかどうかを試験することができます。まだ仮想環境内にいることを確認してから Python を走らせましょう:
python3
py
そして、パッケージをインポートしましょう:
>>> from example_package_YOUR_USERNAME_HERE import example
>>> example.add_one(2)
3
次なる一歩¶
おめでとうございます、あなたは Python のプロジェクトをパッケージングし、配布することができました! ✨ 🍰 ✨
このチュートリアルではあなたのパッケージを Test PyPI に、つまり永続的なストレージではないところにアップロードする方法について示したということを忘れないでください。テストシステムは、時折パッケージやアカウントを削除します。 Test PyPI は、このチュートリアルのような試行や実験のために使うのがベストです。
実際のパッケージを Python パッケージインデックスへアップロードする準備ができたら、このチュートリアルでやったのと概ね同じことをやれば大丈夫ですが、次のような重要な違いがあります:
あなたのパッケージ用に覚えやすくて独特な名前を付けましょう。チュートリアルでやったようにあなたのユーザ名を追記する必要はありませんが、既存の名前は使えません。
https://pypi.org でアカウントを登録しましょう - これらはふたつの相異なるサーバであって、テストサーバ側のログイン情報はメインサーバに共有されてはいません。
あなたのパッケージをアップロードするのに
twine upload dist/*
を使い、本番環境の PyPI で登録したアカウントの認証情報を入力しましょう。今回は出荷状態のパッケージをアップロードしようとしているので、--repository
を指定する必要はありません; 指定しないことでパッケージはデフォルトの https://pypi.org/ へアップロードされるでしょう。python3 -m pip install [your-package
を使って、あなたのパッケージを本番環境の PyPI からインストールしましょう。
ここまで読み進めてきて、もっと Python でのパッケージングについて読みたいのであれば、次のようなものがあります:
選択したビルドバックエンドの先進的な設定については、Hatchling ・ setuptools ・ Flit ・ PDM を読んでください。
もっと先進的な実際上の情報についてはこのサイトの 説明文書群 を、あるいは、特定の話題の説明や背景については 議論 を見てください。
hatch ・ flit ・ pdm ・ poetry のように、単一のコマンドラインインタフェースでプロジェクト管理もパッケージングもできるパッケージングツールについて検討しましょう。
ノート