python-packaging について
Pythonライブラリをビルド・インストール可能にし、成果物を検証するスキルです。プロジェクトメタデータ、ビルドバックエンドの選択、uvによる依存管理、sdistとwheelの検査を扱います。
主な機能
- 01pyproject.tomlへのパッケージ設定集約
- 02PEP 517ビルドバックエンドの選択
- 03src/レイアウトとuvの利用
- 04メタデータとビルド成果物の検証
- 05wheelの内容とインポートの確認
活用シーン
- 01新しいPythonライブラリのパッケージ化
- 02旧式のパッケージ設定からの移行
- 03wheelとsdistの内容確認
- 04パッケージファイル欠落の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ paldom/ python-skills --skill python-packagingインストール後、Claude Code で/python-packagingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonreferences/build-backends.mdscripts/check_wheel.py詳細
python-packaging
検証済み成果物を使って Python ライブラリをインストール可能かつビルド可能にします。単一の信頼できる情報源となる pyproject.toml、意図的に選択した PEP 517 ビルドバックエンド、src/ レイアウト、ロックファイルをコミットした uv 管理の依存関係を使用し、内容を想定に頼らず検証した sdist と wheel を作成します。このスキルで防ぐ問題は、宣言したファイル(py.typed、データファイル)が wheel に気付かれず含まれないこと、プロジェクトのレイアウトや拡張機能を扱えないバックエンド、解決を検証する前にバックエンドを切り替える Poetry からの移行、uv 管理の環境との同期がずれる pip の呼び出しです。
使用しない場合
- PyPI への公開、バージョンの更新、変更履歴、git タグ、Trusted Publishing には、インストールされている場合は python-release スキルを使用してください。成果物の検証後に終了してください。
- 型チェッカーの選択や設定、
py.typedを同梱するかどうか、および同梱方法には、python-typing スキルを使用してください。このスキルでは、既存のpy.typedがビルドした wheel に実際に含まれていることだけを検証します。 [tool.ruff]の設定には python-lint を使用してください。pytest/coverage の設定には python-testing、GitHub Actions には python-ci、依存関係の脆弱性監査には python-supply-chain を使用してください。- 依存関係が必要なだけの単一ファイルスクリプトには、パッケージ化は一切不要です。PEP 723 のインラインスクリプトメタデータと
uv run script.pyで対応できます。
ワークフロー
1. 既存の内容を確認する
ls setup.py setup.cfg MANIFEST.in requirements*.txt poetry.lock Pipfile uv.lock 2>/dev/null
grep -n "build-backend\|tool.poetry\|dependency-groups\|optional-dependencies" pyproject.toml 2>/dev/null
find . -name "*.pyx" -o -name "*.c" -o -name "Cargo.toml" | grep -v .venv | head
変更を加える前に、次の 3 点を記録します。(a)ネイティブ拡張機能か純粋な Python か。これによってバックエンドが決まります。(b)フラットレイアウトか src/ レイアウトか。(c)リポジトリで既に使用している開発依存関係の規約([dependency-groups]、[project.optional-dependencies] の下の dev エクストラ、または従来の [tool.uv] dev-dependencies)。既存の規約に合わせるか、まとめて移行し、混在させないでください。
2. ビルドバックエンドを選ぶ
| バックエンド | 選択する場合 | 避ける場合 |
|---|---|---|
uv_build | 純粋な Python ライブラリ。設定なしで src/ を検出し、メタデータを厳密に検証します | C/Cython/Rust の拡張モジュールがある場合(未対応)、VCS タグによる動的バージョン管理が必要な場合 |
hatchling | hatch-vcs による git タグからの動的バージョン管理が重要な場合。一般的なガイダンスで広くデフォルトとして扱われており、プラグインのエコシステムもあります | uv_build のより厳密な検証と設定不要の運用を求める場合 |
setuptools | 拡張モジュール(ext_modules)や、複雑なレガシー設定がある場合 | 新規の純粋な Python プロジェクト。検証がより緩やかで、自動検出に予期せぬ結果が生じることがあります |
新しいプロジェクトでは poetry-core を採用しないでください。エコシステムでは PEP 621 の [project] メタデータに一本化されています。uv build はバックエンドに依存しない PEP 517 フロントエンドであり、hatchling や setuptools も同様に実行できる点に注意してください。そのため、プロジェクトマネージャーとして uv を採用しても、バックエンドの移行を強制されるわけではありません。移行は別の手順として扱い、検証してください。
[build-system]
requires = ["uv_build>=0.12,<0.13"]
build-backend = "uv_build"
uv_build には上限を設定してください。uv のバージョン管理方針ではマイナーリリースで破壊的変更が入る可能性があるため、上限のない要件では新しいバージョンがリリースされた日にビルドが壊れることがあります。hatchling と setuptools では互換性に関する規範がより保守的で、下限(例:hatchling>=1.27)を指定するのが一般的です。リスクの捉え方として、uv 全体は 1.0 未満ですが、uv_build バックエンド自体は PyPI で Production/Stable とされ、2025 年半ば以降は uv init のデフォルトです。どちらの方向にも両者を混同しないでください。
各バックエンドのトレードオフ、[tool.uv.build-backend] のキー、バックエンドごとのファイル同梱設定の詳細については、references/build-backends.md を参照してください。
3. パッケージの構成(src/)
my-package/
├── pyproject.toml
├── README.md
├── src/
│ └── my_package/
│ ├── __init__.py
│ └── py.typed # only if the project already ships one
└── tests/
ライブラリには src/ を使用してください。そうすれば、テストやツールはインストール済みのパッケージをインポートします。フラットレイアウトでは、ビルドした wheel が壊れていたりファイルが欠けていたりしても、import my_package は作業ディレクトリ内のコピーを解決してしまいます。そのため、パッケージ化の問題がリリースまで見えません。新規プロジェクトでは、uv init --lib my-package を使うと、src/、py.typed、uv_build バックエンドを一度に用意できます。
uv_build は、正規化されたプロジェクト名にちなんだモジュール名の src/<module>/__init__.py を想定します。インポート名が異なる場合は、次のように宣言してください。
[tool.uv.build-backend]
module-name = "actual_import_name"
4. [project] のメタデータを記述する
公開に必要な最小限のセットです。validate-pyproject(ステップ 6)で検証されます。
[project]
name = "my-package"
version = "0.1.0"
description = "One line, benefit first."
readme = "README.md"
license = "MIT" # SPDX expression (PEP 639; needs a current backend)
requires-python = ">=3.10"
authors = [{ name = "Your Name", email = "[email protected]" }]
dependencies = ["httpx>=0.27"]
classifiers = ["Programming Language :: Python :: 3"]
[project.scripts]
my-cli = "my_package.cli:main" # callable must take no required args; parse sys.argv inside
[dependency-groups]
dev = ["pytest>=8"]
開発用ツールは、公開する追加依存関係ではなく、PEP 735 の [dependency-groups] に記述します(uv add --dev が記述します)。[project.optional-dependencies] の追加依存関係は PyPI から利用者がインストールできますが、依存関係グループはインストールできません。dev 追加依存関係を指定すると、下流の依存関係解決にツールチェーンが混入します。追加依存関係を使うのは、任意の 実行時 機能(例:my-package[cli])です。
5. uv でプロジェクトを管理する
uv init --lib my-package # new projects only (uv >= 0.12 also declares a build system for plain `uv init`; `--no-package` opts out)
uv add httpx # runtime dep -> [project.dependencies] + uv.lock
uv add --dev pytest # dev dep -> [dependency-groups].dev
uv sync # build .venv from uv.lock (--no-dev in production)
uv lock --upgrade-package httpx # targeted upgrade; rest of the lockfile intact
uv run pytest # run tools in the env, no activation
uv.lock をコミットし、手動で編集しないでください。uv は毎回 uv run の前に、ロックファイルが最新の pyproject.toml と一致するか、また環境がロックファイルと一致するかを検証します。これにより結果を再現可能にできます。uv プロジェクト内では pip を決して呼び出さないでください。ロックファイルを介さずに .venv が変更されます。
移行:
- setup.py/setup.cfg からの移行 — まずすべてのセクションを確認します。
[options]のメタデータは[project]に移し、package_data/MANIFEST.inの指定はバックエンドのファイル包含設定に移し、ツールのセクション([tool:pytest]、[flake8]、[mypy])はpyproject.tomlまたは各ツールのスキルに移します。旧設定と新設定で一度ずつビルドし、wheel/sdist の一覧を比較してから、setup.py、setup.cfg、MANIFEST.inを削除します(ステップ 6~8 で結果を検証します)。例外:C 拡張を含む setuptools では、ext_modulesのためにsetup.pyが引き続き必要です。その部分だけ残してください。 - Poetry からの移行 —
uvx 'migrate-to-uv==0.12.0'を実行します(バージョンを固定してください。固定しないuvxは、直近に PyPI に公開されたものを実行するため、再現性がなく、サプライチェーン上のリスクにもなります。ピン留めしたバージョンは意図的に更新してください)。[tool.poetry.*]を PEP 621 に、poetry.lockをuv.lockにマッピングします。[build-system]をpoetry-coreから切り替えるのは 最後 にしてください。uv lock && uv syncで正常に解決できることを確認してから切り替えます。先にバックエンドを切り替えると、2 つの移行を同時にデバッグすることになります。 - requirements.txt からの移行 —
uv add -r requirements.txt(constraints.txtがある場合は-c constraints.txtも指定)を実行し、その後ファイルを削除します。下流のツールで引き続き必要な場合は、uv exportで生成してください。
6. メタデータを検証する
uvx --from 'validate-pyproject[all]==0.26' validate-pyproject pyproject.toml
pyproject.toml が有効な TOML として解析できても、パッケージングの PEP スキーマに違反している場合があります(ライセンスの形式が不正、キーの配置が誤っている、エントリーポイントが不正など)。この検証では、フォーマッターや TOML パーサーでは検出できない問題を見つけられます。メタデータを編集するたびに実行してください。コストはわずかです。
7. ビルドする
uv build # sdist (.tar.gz) + wheel (.whl) into dist/
任意のフロントエンドで uv_build をデバッグするには、RUST_LOG=uv=debug を設定します。uv を使わない場合の代替手段(uv が利用できない環境で一度のみ):python -m pip install build==1.6.0 && python -m build で同じ成果物を生成できます。また、pip install -e . --group dev(pip >= 25.1。グループは追加依存関係ではありません)で開発用インストールにおける uv sync を置き換えられますが、ロックファイルによる再現性は失われます。
8. 成果物を検証する — 決して省略しない
同梱のチェッカーを実行します(パスはこのスキルのフォルダーからの相対パスです)。
python3 "${CLAUDE_SKILL_DIR}/scripts/check_wheel.py" --project-root /path/to/project /path/to/project/dist
このチェッカーは読み取り専用です。wheel に METADATA/WHEEL/RECORD がない場合、ソースツリー内に存在する py.typed が wheel にない場合、tests/、docs/ などのディレクトリが wheel に混入している場合、または sdist に pyproject.toml がない場合に、ERROR 行を出力してゼロ以外の終了コードで終了します。同等の手動確認コマンド:unzip -l dist/*.whl と tar -tzf dist/*.tar.gz。
次に、ソースツリーではなく wheel 自体をスモークテストします。
uv run --isolated --no-project --with dist/my_package-0.1.0-py3-none-any.whl \
python -c "import my_package; print(my_package.__name__)"
完了時の出力仕様
pyproject.tomlだけがパッケージング設定として存在します。setup.py/setup.cfg/MANIFEST.in/requirements.txtは削除されます(ext_modulesのためだけに残すsetup.pyを除く)。validate-pyprojectが終了コード 0 で終了します。uv buildによりdist/*.tar.gzとdist/*.whlの両方が生成されます。scripts/check_wheel.pyが終了コード 0 で終了します。期待されるファイル(ソースにpy.typedが含まれる場合はそれも)が wheel 内にあることが検証され、テストやドキュメントは混入していません。- ビルドした wheel を隔離環境でインポートできます。
uv.lockが存在し、コミットされています。
失敗しやすい点と注意事項
- リポジトリには
py.typedがあるのに、ホイールには含まれていません。 任意の.py以外のファイルを同梱できるバックエンドはないと考えてください。setuptools では[tool.setuptools.package-data]が必要です。hatchling では、ホイールのターゲットがパッケージディレクトリを指している場合に限り、その中のファイルが同梱されます。uv_build はモジュールルート以下のファイルを含めます。このマーカーのないホイールを使うと、利用側では API 全体が暗黙的にAnyになります。ソースツリーではなく、成果物を検証してください。バックエンドごとの設定例はreferences/build-backends.mdを参照してください。 - uv_build で「module not found」またはメタデータ検証エラーが発生します。 デフォルトでは、正規化されたプロジェクト名と同じ名前の単一モジュールが
src/<module>/または./<module>/にあることを想定します。別の名前、複数のモジュール、または名前空間パッケージを使う場合は、[tool.uv.build-backend]のmodule-name = [...]/module-root/namespaceを宣言してください(安全性チェックが無効になるnamespace = trueより、明示的なリストを推奨します)。 - uv のリリース後にビルドが失敗します。
requires = ["uv_build"]のバージョン範囲が無制限になっています。>=X,<X+1の範囲指定を復元してください(手順 2)。 - Poetry の移行が中途半端です。
[build-system]を切り替えた一方で、実際の依存関係リストが[tool.poetry.dependencies]に残っており、成果物のメタデータが誤っていたり、欠落したりします。まずメタデータを整え、依存関係の解決を検証してから、最後にバックエンドを切り替えてください。 - 再現しにくい環境の不具合が発生します。 誰かが uv プロジェクトで
pip installを実行すると、次のuv runで変更が気づかれないまま元に戻ります。どちらの方向でも不安定な動作に見えます。環境を変更するのはuv add/uv syncのみです。 - テストは通るのに、インストールしたパッケージが壊れています。 フラットレイアウトでは作業ディレクトリ内のコピーがインポートされ、ホイールにないファイルが隠れてしまいます。
src/レイアウトと手順 8 のホイールのスモークテストで検出できます。 tests/がホイールに含まれています。 setuptools の自動検出では、インポート可能なトップレベルディレクトリがすべて見つかります。検出範囲を制限する([tool.setuptools.packages.find] where = ["src"])か、src/レイアウトに移行してください。check_wheel.pyで混入を検出できます。- 開発用の追加依存関係が PyPI に公開されています。
[project.optional-dependencies] devで宣言した開発ツールは、すべての利用者がインストールできる追加依存関係になります。ツールには[dependency-groups]を使い、追加依存関係は実行時のオプション機能に限ってください。 - TOML としては有効でも、メタデータとしては無効です。 フォーマッターや TOML パーサーは、パッケージングのスキーマに違反するファイルも受け付けます。そのために手順 6 があります。
- パフォーマンスに関する根拠のない定説です。 uv_build でビルド速度が大幅に向上するという主張は、管理されたベンチマークではなく、実践者のブログ記事に基づいています。あくまで目安として扱い、具体的な数値を事実として繰り返さないでください。
同梱ファイル
- references/build-backends.md — バックエンドのトレードオフの詳細、
[tool.uv.build-backend]のリファレンス、バックエンドごとのファイル同梱方法(py.typed、データファイル)、移行手順、旧ツールから uv へのコマンド対応表。 scripts/check_wheel.py— sdist/ホイールを読み取り専用で検証します。ビルドのたびに実行してください。失敗時は、機械可読なERROR行を出力してゼロ以外の終了コードを返します。