packaging-python-libraries について
Pythonライブラリ開発者向けのパッケージ化とリリースのガイドです。`pyproject.toml`、ビルド、PyPI公開、依存関係を扱い、wheelの内容確認とクリーン環境での検証を重視します。
主な機能
- 01`pyproject.toml`の設定
- 02`uv`による配布物のビルド
- 03PyPI公開メタデータの確認
- 04依存関係とパッケージデータの設定
- 05wheelの内容確認
- 06クリーン環境でのインストール検証
活用シーン
- 01Pythonライブラリのリリース設定を準備
- 02sdistとwheelをビルドして確認
- 03配布物から欠落したサブパッケージやデータを特定
- 04公開前にインストール済みパッケージの実モジュールを検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ wdm0006/ python-skills --skill packaging-python-librariesインストール後、Claude Code で/packaging-python-librariesを入力して読み込まれたか確認します。
同梱ファイルCONDA.md
詳細
Python ライブラリのパッケージ化
pyproject.toml の基本
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
version = "1.0.0"
description = "Short description"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT"}
dependencies = []
[project.optional-dependencies]
dev = ["pytest>=7.0", "ruff>=0.1", "mypy>=1.0"]
[project.urls]
Homepage = "https://github.com/user/package"
Documentation = "https://package.readthedocs.io"
[project.scripts]
mycli = "my_package.cli:main"
[tool.setuptools.packages.find]
where = ["src"]
ビルド
uv build # Creates sdist + wheel in dist/
uvx twine check dist/* # Validate metadata
PyPI への公開
CI からのトラステッドパブリッシング(トークンを保存しない方法)を推奨します。詳しくは以下の CI セクションをご覧ください。手動で公開する場合は、uvx 経由で twine を使ってアップロードします。
uvx twine upload --repository testpypi dist/* # Test first
uvx twine upload dist/* # Production (uses a PyPI token)
GitHub Actions(トラステッドパブリッシング)
公開は、managing-python-releases スキルにある、タグをトリガーとする標準リリースワークフローによって自動化されています。1 つのパイプラインで uv を使ってビルドし、トラステッドパブリッシングで公開します。../release-management/AUTOMATION.md をご覧ください。ここに別のコピーを管理しないでください。
依存関係のベストプラクティス
# DO: Minimum versions
dependencies = ["requests>=2.28", "click>=8.0"]
# DON'T: Exact pins (locks users)
dependencies = ["requests==2.28.1"]
# DO: Optional for features
[project.optional-dependencies]
cli = ["click>=8.0"]
パッケージデータの同梱
[tool.setuptools.package-data]
my_package = ["py.typed", "data/*.json"]
from importlib.resources import files
data = files("my_package.data").joinpath("file.json").read_text()
直接参照の依存関係には実際のビルドが必要です
toolkit @ https://example.com/toolkit.whl のような依存関係は、ビルドバックエンドを呼び出さずにインストールのドライランで解決される場合があります。Hatchling を使用している場合、直接参照を明示的に許可しないと、実際の wheel ビルドで失敗します。
[project]
dependencies = [
"toolkit @ https://example.com/releases/toolkit.whl",
]
[tool.hatch.metadata]
allow-direct-references = true
このケースでは、パッケージ化の確認に uv pip install --dry-run . を使わないでください。プロジェクトをビルドせずに成功と報告する可能性があります。uv build(または実際に uv pip install . を実行)して、設定済みのバックエンドにメタデータを検証させてください。
uv build
uvx twine check dist/*
詳細なテンプレートについては、以下をご覧ください。
- ../project-setup/PYPROJECT.md - 注釈付きの完全な pyproject.toml(標準)
- CONDA.md - Conda / conda-forge のパッケージ化ガイド
ビルドしたアーティファクトを検証する(ビルドの成功は、正しい wheel の証明にはなりません)
uv build が成功したということは、バックエンドが実行されたことを示すだけで、wheel にコードが含まれていることを示すものではありません。ビルドバックエンドは設定に基づいてファイルを選択します。Hatchling では [tool.hatch.build.targets.wheel](only-include / packages / include)、setuptools では [tool.setuptools.packages.find] が該当します。この設定を誤ると、サブパッケージやデータファイルが欠落した wheel が、エラーなしでそのまま出荷されてしまいます。twine check でも検出できません。検証するのはメタデータであり、内容ではないからです。
公開前に、必ず wheel の中身を確認し、クリーンな環境にインストールしてください。
uv build
uv run python -m zipfile -l dist/*.whl # list every file the wheel contains
# ^ confirm ALL your subpackages (my_pkg/, my_pkg/sub/) and data files are there,
# not just the top-level module.
よくある落とし穴は、ファイルの選択範囲を狭くしすぎることです。次の設定では server.py だけが含まれ、server/ パッケージ全体と data/ が気付かないうちに除外されます。
# DON'T — over-narrow include drops everything else
[tool.hatch.build]
only-include = ["server.py"]
# DO — include the package (and any data dirs); let the backend walk it
[tool.hatch.build.targets.wheel]
packages = ["src/my_pkg"]
**名前の衝突に関する落とし穴:**トップレベルのモジュール foo.py とパッケージディレクトリ foo/ の両方を、絶対に同梱しないでください。パッケージがモジュールを隠すため、import foo は(多くの場合、ほとんど空の)foo/__init__.py を読み込みます。また、コンソールエントリポイント foo = "foo:main" は、そのパッケージに main がないため失敗します。どちらか一方(通常はパッケージ)を選び、もう一方を削除してください。
次に、ソースツリーではなくクリーンな環境へのインストールで動作を確認してください。
uv venv /tmp/verify && uv pip install --python /tmp/verify/bin/python dist/*.whl
cd /tmp && /tmp/verify/bin/python -c "import my_pkg; my_pkg.submodule.real_func"
mycli --help # exercise each console script too
リポジトリのルート以外のディレクトリから実行してください。そうしないと、wheel が空でも import my_pkg は sys.path 上のソースツリーを読み込んで「動作」してしまいます。また、単にトップレベルの名前をインポートできるかではなく、実在するシンボル(my_pkg.submodule.real_func)を検証してください。隠れている空のパッケージに対して import foo が成功しても、何の証明にもなりません。import foo; print("ok") だけを実行する CI のスモークテストは、誤った成功判定です。配布パッケージが使用可能かどうかに関係なく成功してしまいます。
チェックリスト
Before Release:
- [ ] pyproject.toml valid
- [ ] README.md informative
- [ ] LICENSE file exists
- [ ] Version set correctly
- [ ] twine check passes
- [ ] `uv run python -m zipfile -l dist/*.whl` shows every subpackage + data file
- [ ] Direct-reference dependencies pass a real backend build (not only install dry-run)
- [ ] No module/package name collision (no foo.py AND foo/)
- [ ] Installed the wheel into a clean venv and imported a real submodule
symbol from a directory outside the repo (not just the top-level name)
- [ ] Each console script runs after a clean install
After Release:
- [ ] pip install works
- [ ] Import works
- [ ] GitHub release created
詳細情報
このスキルは、Will McGinnis による Guide to Developing High-Quality Python Libraries の Distribution セクションに基づいています。詳しくは、以下の記事をご覧ください。