본문으로 건너뛰기
cccskills
무료GitHub에 공개

python-packaging

適切なプロジェクト構造、setup.py/pyproject.toml、PyPIへの公開を使用して配布可能なPythonパッケージを作成。Pythonライブラリのパッケージング、CLIツールの作成、Pythonコードの配布時に使用。

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md19.9 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

English | 日本語

Pythonパッケージング

モダンなパッケージングツール、pyproject.toml、PyPIへの公開を使用した、Pythonパッケージの作成、構造化、配布に関する包括的なガイド。

このスキルを使用するタイミング

  • 配布用のPythonライブラリの作成
  • エントリーポイント付きコマンドラインツールの構築
  • PyPIまたはプライベートリポジトリへのパッケージの公開
  • Pythonプロジェクト構造のセットアップ
  • 依存関係を含むインストール可能なパッケージの作成
  • ホイールとソースディストリビューションの構築
  • Pythonパッケージのバージョニングとリリース
  • 名前空間パッケージの作成
  • パッケージメタデータとclassifierの実装

コア概念

1. パッケージ構造

  • ソースレイアウト: src/package_name/(推奨)
  • フラットレイアウト: package_name/(よりシンプルだが柔軟性が低い)
  • パッケージメタデータ: pyproject.toml、setup.py、またはsetup.cfg
  • 配布フォーマット: wheel(.whl)とソースディストリビューション(.tar.gz)

2. モダンなパッケージング標準

  • PEP 517/518: ビルドシステム要件
  • PEP 621: pyproject.tomlのメタデータ
  • PEP 660: 編集可能インストール
  • pyproject.toml: 設定の単一ソース

3. ビルドバックエンド

  • setuptools: 従来型、広く使用されている
  • hatchling: モダン、意見が固定的
  • flit: 軽量、純粋Python用
  • poetry: 依存関係管理 + パッケージング

4. 配布

  • PyPI: Python Package Index(公開)
  • TestPyPI: 本番前のテスト
  • プライベートリポジトリ: JFrog、AWS CodeArtifactなど

クイックスタート

最小限のパッケージ構造

my-package/
├── pyproject.toml
├── README.md
├── LICENSE
├── src/
│   └── my_package/
│       ├── __init__.py
│       └── module.py
└── tests/
    └── test_module.py

最小限のpyproject.toml

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "my-package"
version = "0.1.0"
description = "A short description"
authors = [{name = "Your Name", email = "you@example.com"}]
readme = "README.md"
requires-python = ">=3.8"
dependencies = [
    "requests>=2.28.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0",
    "black>=22.0",
]

パッケージ構造パターン

パターン1: ソースレイアウト(推奨)

my-package/
├── pyproject.toml
├── README.md
├── LICENSE
├── .gitignore
├── src/
│   └── my_package/
│       ├── __init__.py
│       ├── core.py
│       ├── utils.py
│       └── py.typed          # 型ヒント用
├── tests/
│   ├── __init__.py
│   ├── test_core.py
│   └── test_utils.py
└── docs/
    └── index.md

利点:

  • ソースから誤ってインポートするのを防ぐ
  • よりクリーンなテストインポート
  • より良い分離

ソースレイアウト用のpyproject.toml:

[tool.setuptools.packages.find]
where = ["src"]

パターン2: フラットレイアウト

my-package/
├── pyproject.toml
├── README.md
├── my_package/
│   ├── __init__.py
│   └── module.py
└── tests/
    └── test_module.py

よりシンプルですが:

  • インストールせずにパッケージをインポートできる
  • ライブラリにとってはあまりプロフェッショナルではない

パターン3: マルチパッケージプロジェクト

project/
├── pyproject.toml
├── packages/
│   ├── package-a/
│   │   └── src/
│   │       └── package_a/
│   └── package-b/
│       └── src/
│           └── package_b/
└── tests/

完全なpyproject.toml例

パターン4: 全機能pyproject.toml

[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "my-awesome-package"
version = "1.0.0"
description = "An awesome Python package"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
authors = [
    {name = "Your Name", email = "you@example.com"},
]
maintainers = [
    {name = "Maintainer Name", email = "maintainer@example.com"},
]
keywords = ["example", "package", "awesome"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
]

dependencies = [
    "requests>=2.28.0,<3.0.0",
    "click>=8.0.0",
    "pydantic>=2.0.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0.0",
    "pytest-cov>=4.0.0",
    "black>=23.0.0",
    "ruff>=0.1.0",
    "mypy>=1.0.0",
]
docs = [
    "sphinx>=5.0.0",
    "sphinx-rtd-theme>=1.0.0",
]
all = [
    "my-awesome-package[dev,docs]",
]

[project.urls]
Homepage = "https://github.com/username/my-awesome-package"
Documentation = "https://my-awesome-package.readthedocs.io"
Repository = "https://github.com/username/my-awesome-package"
"Bug Tracker" = "https://github.com/username/my-awesome-package/issues"
Changelog = "https://github.com/username/my-awesome-package/blob/main/CHANGELOG.md"

[project.scripts]
my-cli = "my_package.cli:main"
awesome-tool = "my_package.tools:run"

[project.entry-points."my_package.plugins"]
plugin1 = "my_package.plugins:plugin1"

[tool.setuptools]
package-dir = {"" = "src"}
zip-safe = false

[tool.setuptools.packages.find]
where = ["src"]
include = ["my_package*"]
exclude = ["tests*"]

[tool.setuptools.package-data]
my_package = ["py.typed", "*.pyi", "data/*.json"]

# Black設定
[tool.black]
line-length = 100
target-version = ["py38", "py39", "py310", "py311"]
include = '\.pyi?$'

# Ruff設定
[tool.ruff]
line-length = 100
target-version = "py38"

[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "UP"]

# MyPy設定
[tool.mypy]
python_version = "3.8"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true

# Pytest設定
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
addopts = "-v --cov=my_package --cov-report=term-missing"

# Coverage設定
[tool.coverage.run]
source = ["src"]
omit = ["*/tests/*"]

[tool.coverage.report]
exclude_lines = [
    "pragma: no cover",
    "def __repr__",
    "raise AssertionError",
    "raise NotImplementedError",
]

パターン5: 動的バージョニング

[build-system]
requires = ["setuptools>=61.0", "setuptools-scm>=8.0"]
build-backend = "setuptools.build_meta"

[project]
name = "my-package"
dynamic = ["version"]
description = "Package with dynamic version"

[tool.setuptools.dynamic]
version = {attr = "my_package.__version__"}

# またはgitベースのバージョニングにsetuptools-scmを使用
[tool.setuptools_scm]
write_to = "src/my_package/_version.py"

init.py内:

# src/my_package/__init__.py
__version__ = "1.0.0"

# またはsetuptools-scmで
from importlib.metadata import version
__version__ = version("my-package")

コマンドラインインターフェース(CLI)パターン

パターン6: ClickによるCLI

# src/my_package/cli.py
import click

@click.group()
@click.version_option()
def cli():
    """私の素晴らしいCLIツール。"""
    pass

@cli.command()
@click.argument("name")
@click.option("--greeting", default="Hello", help="使用する挨拶")
def greet(name: str, greeting: str):
    """誰かに挨拶する。"""
    click.echo(f"{greeting}, {name}!")

@cli.command()
@click.option("--count", default=1, help="繰り返す回数")
def repeat(count: int):
    """メッセージを繰り返す。"""
    for i in range(count):
        click.echo(f"Message {i + 1}")

def main():
    """CLIのエントリーポイント。"""
    cli()

if __name__ == "__main__":
    main()

pyproject.tomlに登録:

[project.scripts]
my-tool = "my_package.cli:main"

使用法:

pip install -e .
my-tool greet World
my-tool greet Alice --greeting="Hi"
my-tool repeat --count=3

パターン7: argparseによるCLI

# src/my_package/cli.py
import argparse
import sys

def main():
    """メインCLIエントリーポイント。"""
    parser = argparse.ArgumentParser(
        description="私の素晴らしいツール",
        prog="my-tool"
    )

    parser.add_argument(
        "--version",
        action="version",
        version="%(prog)s 1.0.0"
    )

    subparsers = parser.add_subparsers(dest="command", help="コマンド")

    # サブコマンドを追加
    process_parser = subparsers.add_parser("process", help="データを処理")
    process_parser.add_argument("input_file", help="入力ファイルパス")
    process_parser.add_argument(
        "--output", "-o",
        default="output.txt",
        help="出力ファイルパス"
    )

    args = parser.parse_args()

    if args.command == "process":
        process_data(args.input_file, args.output)
    else:
        parser.print_help()
        sys.exit(1)

def process_data(input_file: str, output_file: str):
    """入力から出力へデータを処理。"""
    print(f"Processing {input_file} -> {output_file}")

if __name__ == "__main__":
    main()

ビルドと公開

パターン8: ローカルでパッケージをビルド

# ビルドツールをインストール
pip install build twine

# ディストリビューションをビルド
python -m build

# これにより作成される:
# dist/
#   my-package-1.0.0.tar.gz (ソースディストリビューション)
#   my_package-1.0.0-py3-none-any.whl (wheel)

# ディストリビューションをチェック
twine check dist/*

パターン9: PyPIへの公開

# 公開ツールをインストール
pip install twine

# まずTestPyPIでテスト
twine upload --repository testpypi dist/*

# TestPyPIからインストールしてテスト
pip install --index-url https://test.pypi.org/simple/ my-package

# 問題なければ、PyPIに公開
twine upload dist/*

APIトークンの使用(推奨):

# ~/.pypircを作成
[distutils]
index-servers =
    pypi
    testpypi

[pypi]
username = __token__
password = pypi-...your-token...

[testpypi]
username = __token__
password = pypi-...your-test-token...

パターン10: GitHub Actionsによる自動公開

# .github/workflows/publish.yml
name: Publish to PyPI

on:
  release:
    types: [created]

jobs:
  publish:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.11"

      - name: Install dependencies
        run: |
          pip install build twine

      - name: Build package
        run: python -m build

      - name: Check package
        run: twine check dist/*

      - name: Publish to PyPI
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
        run: twine upload dist/*

高度なパターン

パターン11: データファイルの含める

[tool.setuptools.package-data]
my_package = [
    "data/*.json",
    "templates/*.html",
    "static/css/*.css",
    "py.typed",
]

データファイルへのアクセス:

# src/my_package/loader.py
from importlib.resources import files
import json

def load_config():
    """パッケージデータから設定をロード。"""
    config_file = files("my_package").joinpath("data/config.json")
    with config_file.open() as f:
        return json.load(f)

# Python 3.9+
from importlib.resources import files

data = files("my_package").joinpath("data/file.txt").read_text()

パターン12: 名前空間パッケージ

複数のリポジトリに分割された大規模プロジェクト用:

# パッケージ1: company-core
company/
└── core/
    ├── __init__.py
    └── models.py

# パッケージ2: company-api
company/
└── api/
    ├── __init__.py
    └── routes.py

名前空間ディレクトリ(company/)に__init__.pyを含めないでください:

# company-core/pyproject.toml
[project]
name = "company-core"

[tool.setuptools.packages.find]
where = ["."]
include = ["company.core*"]

# company-api/pyproject.toml
[project]
name = "company-api"

[tool.setuptools.packages.find]
where = ["."]
include = ["company.api*"]

使用法:

# 両方のパッケージを同じ名前空間でインポート可能
from company.core import models
from company.api import routes

パターン13: C拡張

[build-system]
requires = ["setuptools>=61.0", "wheel", "Cython>=0.29"]
build-backend = "setuptools.build_meta"

[tool.setuptools]
ext-modules = [
    {name = "my_package.fast_module", sources = ["src/fast_module.c"]},
]

またはsetup.pyで:

# setup.py
from setuptools import setup, Extension

setup(
    ext_modules=[
        Extension(
            "my_package.fast_module",
            sources=["src/fast_module.c"],
            include_dirs=["src/include"],
        )
    ]
)

バージョン管理

パターン14: セマンティックバージョニング

# src/my_package/__init__.py
__version__ = "1.2.3"

# セマンティックバージョニング: MAJOR.MINOR.PATCH
# MAJOR: 破壊的変更
# MINOR: 新機能(後方互換)
# PATCH: バグ修正

依存関係のバージョン制約:

dependencies = [
    "requests>=2.28.0,<3.0.0",  # 互換範囲
    "click~=8.1.0",              # 互換リリース(~= 8.1.0は>=8.1.0,<8.2.0を意味)
    "pydantic>=2.0",             # 最小バージョン
    "numpy==1.24.3",             # 正確なバージョン(可能なら避ける)
]

パターン15: Gitベースのバージョニング

[build-system]
requires = ["setuptools>=61.0", "setuptools-scm>=8.0"]
build-backend = "setuptools.build_meta"

[project]
name = "my-package"
dynamic = ["version"]

[tool.setuptools_scm]
write_to = "src/my_package/_version.py"
version_scheme = "post-release"
local_scheme = "dirty-tag"

次のようなバージョンを作成:

  • 1.0.0(gitタグから)
  • 1.0.1.dev3+g1234567(タグ後3コミット)

インストールのテスト

パターン16: 編集可能インストール

# 開発モードでインストール
pip install -e .

# オプション依存関係付き
pip install -e ".[dev]"
pip install -e ".[dev,docs]"

# これでソースコードの変更がすぐに反映される

パターン17: 隔離環境でのテスト

# 仮想環境を作成
python -m venv test-env
source test-env/bin/activate  # Linux/Mac
# test-env\Scripts\activate  # Windows

# パッケージをインストール
pip install dist/my_package-1.0.0-py3-none-any.whl

# 動作をテスト
python -c "import my_package; print(my_package.__version__)"

# CLIをテスト
my-tool --help

# クリーンアップ
deactivate
rm -rf test-env

ドキュメント

パターン18: README.mdテンプレート

# My Package

[![PyPI version](https://badge.fury.io/py/my-package.svg)](https://pypi.org/project/my-package/)
[![Python versions](https://img.shields.io/pypi/pyversions/my-package.svg)](https://pypi.org/project/my-package/)
[![Tests](https://github.com/username/my-package/workflows/Tests/badge.svg)](https://github.com/username/my-package/actions)

パッケージの簡単な説明。

## インストール

```bash
pip install my-package

クイックスタート

from my_package import something

result = something.do_stuff()

機能

  • 機能1
  • 機能2
  • 機能3

ドキュメント

完全なドキュメント: https://my-package.readthedocs.io

開発

git clone https://github.com/username/my-package.git
cd my-package
pip install -e ".[dev]"
pytest

ライセンス

MIT


## 共通パターン

### パターン19: マルチアーキテクチャホイール

```yaml
# .github/workflows/wheels.yml
name: Build wheels

on: [push, pull_request]

jobs:
  build_wheels:
    name: Build wheels on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]

    steps:
      - uses: actions/checkout@v3

      - name: Build wheels
        uses: pypa/cibuildwheel@v2.16.2

      - uses: actions/upload-artifact@v3
        with:
          path: ./wheelhouse/*.whl

パターン20: プライベートパッケージインデックス

# プライベートインデックスからインストール
pip install my-package --index-url https://private.pypi.org/simple/

# またはpip.confに追加
[global]
index-url = https://private.pypi.org/simple/
extra-index-url = https://pypi.org/simple/

# プライベートインデックスにアップロード
twine upload --repository-url https://private.pypi.org/ dist/*

ファイルテンプレート

Pythonパッケージ用の.gitignore

# ビルド成果物
build/
dist/
*.egg-info/
*.egg
.eggs/

# Python
__pycache__/
*.py[cod]
*$py.class
*.so

# 仮想環境
venv/
env/
ENV/

# IDE
.vscode/
.idea/
*.swp

# テスト
.pytest_cache/
.coverage
htmlcov/

# 配布
*.whl
*.tar.gz

MANIFEST.in

# MANIFEST.in
include README.md
include LICENSE
include pyproject.toml

recursive-include src/my_package/data *.json
recursive-include src/my_package/templates *.html
recursive-exclude * __pycache__
recursive-exclude * *.py[co]

公開チェックリスト

  • コードがテストされている(pytestパス)
  • ドキュメントが完全(README、docstring)
  • バージョン番号が更新されている
  • CHANGELOG.mdが更新されている
  • ライセンスファイルが含まれている
  • pyproject.tomlが完全
  • パッケージがエラーなくビルドできる
  • クリーンな環境でインストールがテストされている
  • CLIツールが動作する(該当する場合)
  • PyPIメタデータが正しい(classifier、keywords)
  • GitHubリポジトリがリンクされている
  • まずTestPyPIでテストされている
  • リリース用のgitタグが作成されている

リソース

ベストプラクティス概要

  1. src/レイアウトを使用より、クリーンなパッケージ構造のため
  2. pyproject.tomlを使用、モダンなパッケージングのため
  3. ビルド依存関係をピン留め、build-system.requiresで
  4. 適切にバージョン管理、セマンティックバージョニングで
  5. すべてのメタデータを含める(classifier、URLなど)
  6. クリーンな環境でインストールをテスト
  7. PyPIに公開する前にTestPyPIを使用
  8. READMEとdocstringで徹底的に文書化
  9. LICENSEファイルを含める
  10. CI/CDで公開を自動化

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Migrate from AngularJS to Angular using hybrid mode, incremental component rewriting, and dependency injection updates. Use when upgrading AngularJS applications, planning framework migrations, or modernizing legacy Angular code.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

amurata/cc-tools62025년 11월 28일 업데이트

ハイブリッドモード、段階的コンポーネント書き換え、依存性注入更新を使用してAngularJSからAngularへ移行します。AngularJSアプリケーションのアップグレード、フレームワーク移行の計画、またはレガシーAngularコードのモダナイゼーション時に使用します。

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

amurata/cc-tools62025년 11월 28일 업데이트

開発者を喜ばせる直感的でスケーラブルで保守可能なAPIを構築するために、RESTとGraphQL APIの設計原則をマスターします。新しいAPIの設計、API仕様のレビュー、またはAPI設計標準の確立時に使用してください。

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

amurata/cc-tools62025년 11월 28일 업데이트

Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

amurata/cc-tools62025년 11월 28일 업데이트

Implement proven backend architecture patterns including Clean Architecture, Hexagonal Architecture, and Domain-Driven Design. Use when architecting complex backend systems or refactoring existing applications for better maintainability.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

amurata/cc-tools62025년 11월 28일 업데이트

クリーンアーキテクチャ、ヘキサゴナルアーキテクチャ、ドメイン駆動設計を含む実証済みのバックエンドアーキテクチャパターンを実装します。複雑なバックエンドシステムの設計や、保守性向上のための既存アプリケーションのリファクタリング時に使用します。

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

amurata/cc-tools62025년 11월 28일 업데이트

amurata의 스킬 모두 보기

이 스킬의 문제 신고