pyproject.toml を書く

pyproject.toml は、lintersやtype checkersやその他のパッケージングツール群でも同様に使われる設定ファイルです。このファイルの中には3個の TOML テーブルを置くことが可能です。

  • [build-system] テーブルは、 強く推奨されています 。これを使うことで、どの ビルドバックエンド を使うのか、また、そのプロジェクトをビルドするためには他のどんな依存関係が必要なのかを宣言することができます。

  • [project] テーブルは、依存関係や作者の名前など、そのプロジェクトの基本的なメタデータを指定するためにほとんどのビルドバックエンドが用いるものです。

  • [tool] テーブルは、例えば [tool.hatch][tool.black][tool.mypy] のような、ツールに特化したサブテーブルを持っています。テーブルの内容がツール毎に定義されているので、ここでは簡単に触れるだけに留めます。何を含めておくことができるのかを知るためには、それぞれのツールの説明文書に当たってみてください。

注釈

[build-system] テーブルは、 ([build-system] に書くことで使用するビルドツールを 定義する ので) どんなビルドバックエンドを使っているかにかかわらず、常に存在しているべきです。

他方で、 [project] テーブルは、 ほとんどの ビルドバックエンドで理解されますが、いくつかのビルドバックエンドは異なる書式を使います。

特筆すべき例外は Poetry で、バージョン 2.0 (2025年1月5日リリース) より前は [project] テーブルを使わず、 代わりに [tool.peotry] テーブルを使っていました。バージョン 2.0 では、両方をサポートしています。また、 setuptools のビルドバックエンドは、 [project] テーブルと、 setup.cfg ないし setup.py の中のより古い書き方の両方をサポートしています。

setup.cfgsetup.py は依然として正当な書式ですが、新しいプロジェクトでは [project] テーブルを使い、何かプログラム上の設定が必要である場合に限って setup.py を維持しましょう。 setup.py は非推奨になりましたか? をみて下さい。

ビルドバックエンドを宣言する

[build-system] テーブルは、使用されるべきビルドバックエンドを指定する build-backend キーを含んでいます。また、 プロジェクトをビルドするのに必要な依存関係のリストである requires キーも含んでいます -- これは典型的にはビルドバクエンドのパッケージだけですが、追加の依存関係を含んでいてもかまいません。さらに、例えば requires = ["setuptools >= 61.0"] のようにバージョンを制限することもできます。

通常は、ビルドバックエンドの説明文書が (ビルドバックエンドを選択する) 示唆するものをコピーするだけでしょう。よく知られたバックエンドでの値をいくつか挙げておきます:

[build-system]
requires = ["hatchling >= 1.26"]
build-backend = "hatchling.build"
[build-system]
requires = ["setuptools >= 77.0.3"]
build-backend = "setuptools.build_meta"
[build-system]
requires = ["flit_core >= 3.12.0, <4"]
build-backend = "flit_core.buildapi"
[build-system]
requires = ["pdm-backend >= 2.4.0"]
build-backend = "pdm.backend"
[build-system]
requires = ["uv_build >= 0.11.7, <0.12.0"]
build-backend = "uv_build"

静的なメタデータと動的なメタデータ

このガイド文書の残りの部分は、[project] テーブルに捧げます。

ほとんどの場合、 [project] フィールドに直接に値を書き込むことになるでしょう。例えば: requires-python = ">= 3.8"version = "1.0" などです。

しかしながら、ビルドバックエンドにメタデータを計算させる方が役に立つ場合もあります。例えば: 多くのビルドバックエンドがソースコードや Git タグやその他似たようなものの中にある __version__ 要素を読み取ることができます。そのような場合には、以下の例のような方法を使ってそのフィールドを動的なものにしておくべきです、

[project]
dynamic = ["version"]

フィールドが動的となっている場合、そこを埋めるのはビルドバックエンドの責任です。どうすれば良いのかについては、ビルドバックエンドの説明文書に当たってみてください。

基本的な情報

名称

PyPI 上でのプロジェクト名称を書いてください。このフィールドは必須のもので、動的であるとマークできない唯一のフィールドです。

[project]
name = "spam-eggs"

プロジェクトの名称は、ASCII文字・数字・アンダースコア "_"・ハイフン "-"・ピリオド "." だけで構成されていなければなりません。また、先頭や末尾にアンダースコア・ハイフン・ピリオドを使ってはいけません。

プロジェクト名の比較では、大文字小文字を区別せず、また、アンダースコア・ハイフン・ピリオドは何文字連続していても同じものとして扱います。例えば、あなたが cool-stuff という名前のプロジェクトを登録したなら、利用者がダウンロードしたり依存関係を宣言したりするのに、次に挙げる綴りのいずれであっても使うことができます: Cool-Stuffcool.stuffCOOL_STUFFCoOl__-.-__sTuFF

version

プロジェクトのバージョンを書いてください。

[project]
version = "2020.0.0"

(アルファ版のリリース用の) 2020.0.0a1 のようなもっと込み入ったバージョン指定子も可能ですので、 詳細については 仕様 を見てください。

動的であるとマークされることがしばしばではありますが、このフィールドは必須のものです

[project]
dynamic = ["version"]

これによって、 __version__ 要素や Git のタグからバージョンを充当するような使い方が可能になります。もっと詳しいことは、 プロジェクトのバージョン番号をひとつの源から取得する の議論を見てみてください。

依存関係と要求事項

dependencies/optional-dependencies

もしプロジェクトに依存関係があるなら、このように列挙してください:

[project]
dependencies = [
  "httpx",
  "gidgethub[httpx]>4.0.0",
  "django>2.1; os_name != 'nt'",
  "django>2.0; os_name == 'nt'",
]

バージョンに制限をかけるために使えるあらゆるシンタックスについては、 依存関係指定子 を参照してください。

パッケージの特定の機能にのみ必要なものであれば、依存関係のうちのいくつかをオプションにしたい時があるかもしれません。そのような場合には、 optional-dependencies に置きましょう。

[project.optional-dependencies]
gui = ["PyQt5"]
cli = [
  "rich",
  "click",
]

キーのぞれぞれが "余分のパッケージング <packaging extra>" を定義します。上の例では、プロジェクトを例えば GUI サポート付きでインストールするためには pip install your-project-name[gui] を使うことができます。

requires-python

これによってサポートされている Python の下限のバージョンを宣言することができます [1]

[project]
requires-python = ">= 3.8"

実行可能なスクリプトを作成する

パッケージの一部としてコマンドをインストールするためには、 [project.scripts] テーブルで宣言してください。

[project.scripts]
spam-cli = "spam:main_cli"

この例では、プロジェクトをインストールした後に spam-cli コマンドが利用できるようになるでしょう。このコマンドを実行することで、 import sys; from spam import main_cli; sys.exit(main_cli()) と同等のことを行うでしょう。

Windows では、このやり方でパッケージされたスクリプト群はターミナルを必要としますので、グラフィカルなアプリケーションの内部から起動した場合にはターミナルがポップアップすることでしょう。これが起きないようにするためには、 [project.scripts] の代わりに [project.gui-scripts] テープルを使ってください。

[project.gui-scripts]
spam-gui = "spam:main_gui"

そうすることで、コマンドラインからスクリプトを起動してスクリプトがバックグラウンドで走らせることですぐに制御を取り戻すことができるでしょう。

Windows 上では、 [project.scripts][project.gui-scripts] の間の差異だけが実質的に効果を持ちます。

あなたのプロジェクトについて

authors/maintainers

これらのフィールドは両方とも名前とメールアドレスの両方またはいずれかで識別される人々のリストを含みます。

[project]
authors = [
  {name = "Pradyun Gedam", email = "pradyun@example.com"},
  {name = "Tzu-Ping Chung", email = "tzu-ping@example.com"},
  {name = "Another person"},
  {email = "different.person@example.com"},
]
maintainers = [
  {name = "Brett Cannon", email = "brett@example.com"}
]

説明 <description>

これは、PyPI におけるプロジェクトページの "ヘッドライン" () や検索結果 () のような他の場所で表示されるものなので、1行でプロジェクトの説明をしたものであるべきです。

[project]
description = "Lovely Spam! Wonderful Spam!"

readme

これはプロジェクトの長めの説明文で、PyPI のプロジェクトページに表示されます。典型的には、プロジェクトには README.mdREADME.rst のファイルが存在するものなので、その場合にはここにはそのファイル名だけを書いておけば良いでしょう。

[project]
readme = "README.md"

README のフォーマットは拡張から自動的に検出されます:

次のようにしてフォーマットを明示的に指定することもできます:

[project]
readme = {file = "README.txt", content-type = "text/markdown"}
# or
readme = {file = "README.txt", content-type = "text/x-rst"}

licenselicense-files

PEP 639 によれば、ライセンスはふたつのフィールドで宣言されるべきです:

以前の PEP では、 licensefile キーもしくは text キーを伴ったテーブルであると指定していましたが、この書式は現在では非推奨になっています。ほとんどの build backends は、今では、以下のテーブルに示される新書式をサポートしています。

PEP 639 のサポートを導入したビルドバックエンドのバージョン

hatchling

setuptools

flit-core [2]

pdm-backend

poetry-core

uv-build

1.27.0

77.0.3

3.12

2.4.0

2.2.0

0.7.19

ライセンス

licanse のための新書式は、ひとつもしくはそれ以上の ライセンス識別子 から構成される正当な SPDX ライセンス表現 です。ライセンスの完全なリストは、 SPDX ライセンスリストページ で利用可能です。サポートされているリストバージョンは 3.17 かそれ以降の互換性のあるものです。

[project]
license = "GPL-3.0-or-later"
# or
license = "MIT AND (Apache-2.0 OR BSD-2-Clause)"

注釈

license が辞書かテーブルであるべきだとのビルドエラーを受け取るようなら、そのビルドバックエンドは、まだ、新書式をサポートしていません。さらなる文脈的理解のためには、 above section を見て下さい。今では非推奨となった書式は、 PEP 621 に述べられています

一般的な規則としては、標準的でよく知られたライセンスを使うことは良い考えです、というのは、混乱を避けることにもなるし、中には内部で認可済みのライセンスでなければソフトウェアを使えない組織もあるからです。

配布物アーカイブ が使っているライセンスが既存の SPDX 識別子を持っていない時は、 LicenseRef-[idstring] の書式で作成することができます。カスタム識別子は、バージョン 2.2 かそれより新しい互換のバージョンの clause 10.1 という SPDX 仕様に従わなければなりません。

[project]
license = "LicenseRef-My-Custom-License"

license-files

これは、そのパッケージとともに配布したいと望む、ライセンスファイルとその他の法律関係の情報を含むファイルのリストです。

[project]
license-files = ["LICEN[CS]E*", "vendored/licenses/*.txt", "AUTHORS.md"]

glob パターンは、次の仕様に従わなければなりません:

  • 英数字・アンダースコア (_) ・ハイフン (-) ・ドット (.) が文字通りに合致するでしょう。

  • 特殊文字: *?** と文字の帯域: [] がサポートされています。

  • パスデリミタは、正スラッシュ (/) でなければなりません。

  • パターンは、 pyproject.toml を含むディレクトリに対する相対パスで、従ってスラッシュ文字で始まることはできません。

  • 親ディレクトリ表示子 (..) を使用してはなりません。

  • 各 glob は、少なくとも一つのファイルにマッチしなければなりません。

字義通りのパスは、正当な glob です。この仕様でカバーされていない文字や文字の並びは、すべて、正当なものではありません。

keywords

これは、 PyPI 上の検索でキーワードが与えられた時にこのプロジェクトをサジェストするのを助けます。

[project]
keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"]

分類詞 <classifiers>

プロジェクトに合致する PyPI 分類子 <classifier> のリスト。 可能な分類子のリスト を参照してください。

[project]
classifiers = [
  # How mature is this project? Common values are
  #   3 - Alpha
  #   4 - Beta
  #   5 - Production/Stable
  "Development Status :: 4 - Beta",

  # Indicate who your project is intended for
  "Intended Audience :: Developers",
  "Topic :: Software Development :: Build Tools",

  # Specify the Python versions you support here.
  "Programming Language :: Python :: 3",
  "Programming Language :: Python :: 3.6",
  "Programming Language :: Python :: 3.7",
  "Programming Language :: Python :: 3.8",
  "Programming Language :: Python :: 3.9",
]

あるプロジェクトが Python のどのバージョンをサポートしているのかを宣言するために分類子 <classifiers> がよく使われますが、この情報は PyPI 上のプロジェクトを検索し閲覧するためにのみ使われるのであって、プロジェクトをインストールするためには使われません。あるプロジェクトが Python のどのバージョンでならインストールされ得るのかを実際に制約するためには、 requires-python 引数を使ってください。

パッケージが PyPI にアップロードされるのを防ぐには、 Private :: Do Not Upload 分類子を使いましょう。Private :: で始まる分類子を付けられたパッケージを PyPI は常に拒否します。

urls

プロジェクトに関連のある URL のリストで、PyPI 上のプロジェクトページの左サイドバーに表示されるもの。

注釈

PyPI やその他のパッケージングツールがそれぞれどのラベルを認識するかについてのリストを見たければ よく知られたラベル を、 PyPI に特有の URL 処理について見たければ PyPI のプロジェクトメタデータ説明文書 を見て下さい。

[project.urls]
Homepage = "https://example.com"
Documentation = "https://readthedocs.org"
Repository = "https://github.com/me/spam.git"
Issues = "https://github.com/me/spam/issues"
Changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md"

もしラベルが空白文字を含んでいるなら、例えば Website = "https://example.com" ではなくて "Official Website" = "https://example.com" のように引用符で囲む必要があります。

(パッケージインデックスのような) メタデータの消費者側がその存在を特別なものにすることができるように、ユーザにはそのプロジェクトの適切な URL のために よく知られたラベル を使用することを推奨します。

後続するメタデータの中での例としては、 MyHomepage"Download Link" のいずれもよく知られたラベルではなく、従って、これらは文字通りに展開されます:

[project.urls]
MyHomepage = "https://example.com"
"Download Link" = "https://example.com/abc.tar.gz"

一方で、このメタデータ HomePage および DOWNLOAD は、どちらにも、よく知られた同等物 (homepagedownload) があり、そのような文脈で提示され得ることを心に留めておいて下さい (順にそれぞれプロジェクトのホームページ、および、その外部のダウンロードできる場所)。

[project.urls]
HomePage = "https://example.com"
DOWNLOAD = "https://example.com/abc.tar.gz"

先進的なプラグイン

パッケージの中にはプラグインを使って拡張できるものがあります。例としては、PytestPygments が挙げられます。そのようなプラグインを作成するためには、以下のように [project.entry-points] のサブテーブルで宣言する必要があります:

[project.entry-points."spam.magical"]
tomatoes = "spam:main_tomatoes"

詳しくは、 プラグインガイド を見てください。

完全な例

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "spam-eggs"
version = "2020.0.0"
dependencies = [
  "httpx",
  "gidgethub[httpx]>4.0.0",
  "django>2.1; os_name != 'nt'",
  "django>2.0; os_name == 'nt'",
]
requires-python = ">=3.8"
authors = [
  {name = "Pradyun Gedam", email = "pradyun@example.com"},
  {name = "Tzu-Ping Chung", email = "tzu-ping@example.com"},
  {name = "Another person"},
  {email = "different.person@example.com"},
]
maintainers = [
  {name = "Brett Cannon", email = "brett@example.com"}
]
description = "Lovely Spam! Wonderful Spam!"
readme = "README.rst"
license = "MIT"
license-files = ["LICEN[CS]E.*"]
keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"]
classifiers = [
  "Development Status :: 4 - Beta",
  "Programming Language :: Python"
]

[project.optional-dependencies]
gui = ["PyQt5"]
cli = [
  "rich",
  "click",
]

[project.urls]
Homepage = "https://example.com"
Documentation = "https://readthedocs.org"
Repository = "https://github.com/me/spam.git"
"Bug Tracker" = "https://github.com/me/spam/issues"
Changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md"

[project.scripts]
spam-cli = "spam:main_cli"

[project.gui-scripts]
spam-gui = "spam:main_gui"

[project.entry-points."spam.magical"]
tomatoes = "spam:main_tomatoes"