Use Cases (更新: 2026/6/7)

Claude CodeのPython開発を2026年版に。uv・ruff・pytestで足場から作る

Claude CodeでPython開発する2026年の型。uvで環境、ruffでlintと整形、pytestでテスト駆動、pyproject.toml一本化まで、コピペで動くコードで解説。

Claude CodeのPython開発を2026年版に。uv・ruff・pytestで足場から作る

「Pythonアプリ作って」とだけ頼んだら、Claude Codeがpippoetryrequirements.txtを全部混ぜた、奇妙なプロジェクトを置いていきました。

しかも、テストはあるのにimportで落ちる。動かして確かめようとした僕は、原因が依存関係なのか、フォルダ構成なのか、生成コードそのものなのか、まったく切り分けられませんでした。30分溶かして、結局ゼロから作り直しました。

このとき気づいたのは、賢いAIに丸投げしても、土台がぐらぐらだと逆に時間が増えるということです。Pythonの開発って、書き始める前の「環境とルール」で勝負の8割が決まる。Claude Codeを使うなら、なおさらです。

そこでこの記事では、2026年のPython開発で僕が実際に固定している型を、コピペで動く形でまとめます。uvで環境、ruffでlintと整形、pytestでテスト、設定はpyproject.tomlに一本化。この順番さえ守れば、Claude Codeは「それっぽいコード製造機」ではなく「テストまで通す実装担当」に変わります。

この記事の要点

  • Pythonの土台は4点セットで固定する。uv(環境と依存)、ruff(lint+整形)、pytest(テスト)、pyproject.toml(設定の一本化)。
  • 2026年の新規プロジェクトはuvが速くて説明も楽。会社PCで入れられないなら標準のvenvで十分。どちらを使うかをClaude Codeに必ず明示する。
  • ruffはlintと整形を1つのツールで兼ねる。blackflake8isortを別々に入れる時代は終わった。
  • Claude Codeにはテスト駆動でやらせる。「先に失敗するテスト→実装→pytestが緑になるまで」という段取りを依頼文に書く。
  • 失敗は「コマンド単位」で渡す。エラー全文ではなく「落ちたコマンド・期待・触ってよい範囲」を添えると、無関係な大改修を避けられる。

なぜ2026年は uv と ruff なのか

少し前まで、Python環境は道具の寄せ集めでした。仮想環境はvenv、依存解決はpip、ロックはpip-tools、整形はblack、import並べ替えはisort、静的チェックはflake8。新人に説明するたびに、僕は5つのツールの名前を並べていました。覚えることが多すぎる。

ここを一気に畳んだのが、Astral社のuvruffです。どちらもRustで書かれていて、とにかく速い。

uvは環境作成・依存解決・ロック・Pythonのバージョン管理までを1つで担います。pipの代替として広く使われるようになりました(公式はAstralのuvドキュメント)。

ruffは公式の言葉を借りると「極めて高速なPythonのlinterかつフォーマッター」です(Ruff公式)。lintと整形を1つのツールで兼ねるのがポイント。今までflake8で警告を見て、blackで整形して、isortでimportを並べていた作業が、ruffだけで完結します。

やりたいこと昔(寄せ集め)2026年(Astral)
仮想環境python -m venvuv(自動で作る)
依存の追加pip installuv add
依存のロックpip-toolsuvuv.lockを自動生成)
コード整形blackruff format
import並べ替えisortruff check(ルールI
静的チェックflake8ruff check

Claude Codeとの相性も、この一本化がよく効きます。ツールが分かれていると、AIは「整形はblack、lintはflake8で」と毎回判断を迫られ、たまに古い流儀を持ち出します。uvruffに絞ると、依頼文も短くなるし、生成結果がぶれません。

まず動く最小単位を決める

道具の前に、ゴールです。Claude Codeはコードを書けますが、初心者がいきなり認証・DB・Docker・CIまで頼むと、エラーが出たときに原因を切り分けられません。冒頭で僕がやらかしたのが、まさにこれです。

最初の完成形は、次の4点で十分。これが全部緑になったら「動くプロジェクト」と呼びます。

  • uv run pytest でテストが通る
  • uv run ruff check . で警告ゼロ
  • uv run ruff format . が整形を終える
  • FastAPIなら /tasks で1件作れる(CLIなら task-api add "買い物" が動く)

この4点を、Claude Codeへの依頼書(ブリーフ)の冒頭にそのまま書きます。ブリーフとは、AIへの作業依頼書のこと。目的・触ってよいファイル・使うPythonバージョン・確認コマンドを並べた、短いメモです。harness(エージェントが作業するための足場)という言葉を使うなら、初心者チーム向けには「足場」と言い換えておくとレビューが楽になります。

uv で環境を作る(venv の道も残す)

2026年の個人開発や教材ならuvが速くて説明も短い。ただし会社PCで新しいツールを入れられない人もいます。大事なのは、どちらを使うかをClaude Codeに明示すること。ここを曖昧にすると、AIは勝手にpoetryを持ち出したりします。

macOS / Linux なら、この流れです。

mkdir task-api
cd task-api
uv init --app --python 3.12
uv add "fastapi[standard]"
uv add --dev pytest ruff
mkdir -p src/task_api tests
touch src/task_api/__init__.py

Windows PowerShell ならディレクトリ作成だけ書き換えます。

mkdir task-api
cd task-api
uv init --app --python 3.12
uv add "fastapi[standard]"
uv add --dev pytest ruff
New-Item -ItemType Directory -Force src/task_api, tests
New-Item -ItemType File -Force src/task_api/__init__.py

uvが使えない環境向けに、標準venvの最小手順も置いておきます。研修資料やチーム記事では、こちらを併記しておくとWindows利用者が詰まりにくい。

python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install "fastapi[standard]" pytest ruff
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install "fastapi[standard]" pytest ruff

ひとつ実感を書くと、uvに切り替えてからは「環境がずれてテストが落ちる」系の事故がほぼ消えました。uv runを頭に付けるだけで、その場で正しい仮想環境を使ってくれるからです。activateを忘れて素のPythonで実行する、というありがちなミスがそもそも起きません。

pyproject.toml に設定を集める

初心者がいちばん溶かすのは、requirements.txtsetup.cfgpytest.ini.ruff.tomlが散らばって「どれを直せばいいの?」と迷う時間です。僕も昔は4つのファイルを行ったり来たりしていました。

答えはシンプルで、pyproject.tomlに全部まとめる。これ1つを見れば、依存もテストもlintも分かる状態にします。

[project]
name = "task-api"
version = "0.1.0"
description = "Small FastAPI and CLI sample for Claude Code practice"
requires-python = ">=3.11"
dependencies = [
  "fastapi[standard]>=0.115.0",
]

[project.scripts]
task-api = "task_api.cli:main"

[dependency-groups]
dev = [
  "pytest>=8.0.0",
  "ruff>=0.8.0",
]

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

[tool.hatch.build.targets.wheel]
packages = ["src/task_api"]

[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]

[tool.ruff]
line-length = 100
target-version = "py311"

[tool.ruff.lint]
# E,F=基本のエラー, I=import並べ替え(isort相当), B=バグ気配, UP=新しい書き方への更新
select = ["E", "F", "I", "B", "UP"]

[tool.ruff.lint]selectが、ruffの性格を決める一行です。Iを入れるとisortの役目(importの並べ替え)までruffが拾います。UPは古い書き方を新しい構文に直す提案をしてくれるので、地味に勉強になります。

この形にしておくと、Claude Codeへ「pyproject.tomlの設定に従って直して」と一言で頼めます。設定が分散しているより、差分レビューが圧倒的に楽です。

Claude Code にテスト駆動で書かせる

ここがこの記事の核心です。Claude Codeに何度も修正させるなら、テストとlintを先に置く。緑か赤かで会話できるようにしておくと、AIの暴走が止まります。

僕が使っている依頼文の骨格はこれです。長くする必要はありません。

このリポジトリにPython 3.12向けの小さなタスク管理APIを追加してください。

進め方(テスト駆動):
1. まず tests/ に失敗するテストを書く(POST /tasks と GET /tasks、404系)
2. 次に src/task_api/ に最小実装を書く
3. uv run pytest が全部緑になるまで直す
4. uv run ruff check . と uv run ruff format . を通す
5. 変更後、実行した確認コマンドの結果を報告する

条件:
- パッケージ管理は uv、設定は pyproject.toml に集約
- FastAPI で POST /tasks と GET /tasks を実装
- API仕様は勝手に増やさない

触ってよい範囲:
- pyproject.toml
- src/task_api/**
- tests/**

狙いは、Claude Codeを「それっぽいコード生成」から「検証まで回す実装担当」に変えることです。テストを先に書かせると、AIは自分の出力を自分で採点しながら進みます。緑にならない限り終われないので、薄い実装でお茶を濁せません。

次が、AIに生成させたい最小実装の見本です。DBを使わないインメモリ版で、本番用ではありませんが、HTTP・型ヒント・テスト・エラー処理を学ぶ足場には十分。src/task_api/main.pyに置きます。

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field

app = FastAPI(title="Task API")


class TaskCreate(BaseModel):
    title: str = Field(min_length=1, max_length=80)


class Task(BaseModel):
    id: int
    title: str
    done: bool = False


# DBの代わりにメモリ上の辞書で持つ(学習用。再起動で消える)
_tasks: dict[int, Task] = {}
_next_id = 1


@app.post("/tasks", response_model=Task, status_code=201)
def create_task(payload: TaskCreate) -> Task:
    global _next_id
    task = Task(id=_next_id, title=payload.title)
    _tasks[task.id] = task
    _next_id += 1
    return task


@app.get("/tasks", response_model=list[Task])
def list_tasks() -> list[Task]:
    return list(_tasks.values())


@app.patch("/tasks/{task_id}/done", response_model=Task)
def mark_done(task_id: int) -> Task:
    task = _tasks.get(task_id)
    if task is None:
        raise HTTPException(status_code=404, detail="Task not found")
    updated = task.model_copy(update={"done": True})
    _tasks[task_id] = updated
    return updated

そして、ペアになるテストです。tests/test_main.pyに置きます。pytestの基本(fixtureで状態をリセット、assertで検証)が一通り入っています。

import pytest
from fastapi.testclient import TestClient

from task_api import main
from task_api.main import app


@pytest.fixture(autouse=True)
def clean_tasks() -> None:
    # 各テストの前にメモリをまっさらに戻す。テスト同士が干渉しないように
    main._tasks.clear()
    main._next_id = 1


def test_create_and_list_tasks() -> None:
    client = TestClient(app)

    response = client.post("/tasks", json={"title": "Write pytest"})
    assert response.status_code == 201
    assert response.json()["title"] == "Write pytest"

    list_response = client.get("/tasks")
    assert list_response.status_code == 200
    assert len(list_response.json()) == 1


def test_mark_done_returns_404_for_missing_task() -> None:
    client = TestClient(app)

    response = client.patch("/tasks/999/done")

    assert response.status_code == 404
    assert response.json()["detail"] == "Task not found"

確認コマンドは固定します。この3行を「終わったかどうかの判定基準」にします。

uv run pytest
uv run ruff check .
uv run ruff format .

ローカルでAPIを触りたいときは、こうです。

uv run fastapi dev src/task_api/main.py

ブラウザでhttp://127.0.0.1:8000/docsを開くと、自動生成されたドキュメント画面からPOSTを試せます。ここまで緑にしてからDBを足すと、Claude Codeの修正も追いやすい。テスト戦略をもっと広げたいならClaude Codeのテスト戦略に、正常系だけで終わらせない観点をまとめています。

こんな場面で効く(3つ)

1. 学習用のAPI教材 FastAPIのルーティング、Pydanticの入力検証、pytestの基本を一度に学べます。DBなしで始め、緑になってからSQLiteやPostgreSQLを足す。最初から全部入れると、落ちたときに何が原因か分からず、学習になりません。

2. 業務の小さな自動化CLI CSVの整形、ファイル名の一括変更、社内レポートの前処理。GUIを作るよりCLIのほうが速いことが多い。Claude Codeにargparse・ログ・エラー時の終了コードまで指定すると、使い捨てスクリプトから一段上がります。下のCLIサンプルがそのたたき台です。

import argparse
import json
from pathlib import Path

DB_PATH = Path("tasks.json")


def load_tasks() -> list[dict[str, object]]:
    if not DB_PATH.exists():
        return []
    return json.loads(DB_PATH.read_text(encoding="utf-8"))


def save_tasks(tasks: list[dict[str, object]]) -> None:
    DB_PATH.write_text(json.dumps(tasks, ensure_ascii=False, indent=2), encoding="utf-8")


def add_task(title: str) -> dict[str, object]:
    tasks = load_tasks()
    task = {"id": len(tasks) + 1, "title": title, "done": False}
    tasks.append(task)
    save_tasks(tasks)
    return task


def main() -> None:
    parser = argparse.ArgumentParser(description="Task CLI")
    subparsers = parser.add_subparsers(dest="command", required=True)

    add_parser = subparsers.add_parser("add")
    add_parser.add_argument("title")

    args = parser.parse_args()
    if args.command == "add":
        task = add_task(args.title)
        print(f"Added #{task['id']}: {task['title']}")


if __name__ == "__main__":
    main()

src/task_api/cli.pyに置けば、pyproject.toml[project.scripts]経由でこう動きます。

uv run task-api add "pytestを書く"

3. 既存コードへのテスト追加 動いているけど怖くて触れないPythonコード。ここでClaude Codeに「先に現状を固定するテストを書いて」と頼みます。いきなりリファクタリングさせるのは事故のもと。壊れていないと証明する足場が先です。API側を広げる段階ならClaude CodeでAPI開発を速くするも合わせてどうぞ。

僕がPythonでやらかしたClaude Code失敗3つ

正直に書きます。最初のころは事故ばかりでした。

ひとつ目は、パッケージ管理を指定しなかったこと。冒頭の話そのままです。「Pythonアプリ作って」だけだとpippoetryuvrequirements.txtが混ざる。今は依頼文の1行目で「uvを使う」と必ず宣言します。

ふたつ目は、srcレイアウトなのにテストからimportできなかったことfrom task_api import mainModuleNotFoundErrorで落ちる、あれです。pyproject.tomlpythonpath = ["src"]を入れたら一瞬で直りました。importエラーは初心者が最も時間を溶かす場所なので、設定で先に潰しておきます。

みっつ目は、ruffの自動修正をレビューせず受け入れたこと。整形は便利ですが、「未使用import」として、あとで使う予定だったコードまで消えたことがあります。今はClaude Codeに「ruffの差分を説明してから適用して」と頼みます。便利な道具ほど、無言で全部任せない。

よくある質問

Q. uv と venv、結局どっちを使えばいい? 新規プロジェクトや教材ならuvが速くて説明も短いです。会社PCで新しいツールを入れられないなら標準venvで十分。どちらでも、Claude Codeに「こっちを使う」と明示するのが最重要です。

Q. ruff があれば black と flake8 はいらない? 基本的に不要です。ruff formatblack相当の整形、ruff checkflake8相当の静的チェックとisort相当のimport並べ替えを兼ねます。ツールが減るぶん、設定も依頼文もシンプルになります。

Q. 型ヒントと mypy はどう足す? まず関数の引数と戻り値に型ヒントを付けるところから。本文の実装も全部付けています。チェックを厳しくするならuv add --dev mypymypyを足し、uv run mypy srcを確認コマンドに加えます。最初から完璧を狙わず、緑のテストができてからで十分です。

Q. Claude Code がテストを書かずに実装だけ進めてしまう。 依頼文に「まず失敗するテストを書く→次に実装→pytestが緑になるまで」と番号で順番を固定してください。順番を書かないと、AIは手早く実装に飛びがちです。

Q. pytest がエラーで落ちたら、エラー全文を貼ればいい? 貼らないほうが直りが速いです。「落ちたコマンド」「期待した結果」「触ってよい範囲」を添えて、uv run pytestの何件目だけを直してほしいと頼む。全文を丸ごと渡すと、AIが無関係な場所まで大改修しがちです。

実際に試した結果

この型は、僕が初心者向けのPython題材を作るときに毎回使う順番で確かめたものです。uvpyproject.tomlpytestruffを先に固定すると、Claude Codeの生成結果が驚くほどレビューしやすくなりました。緑か赤かで会話できるからです。

特に効いたのは3点。「FastAPIを先に小さく動かす」「DBや認証を後回しにする」「失敗はコマンド単位で頼む」。この3つだけで、学習者が詰まった場所をその場で説明できるようになりました。冒頭で30分溶かした“ツール混在事故”も、依頼文の1行目にuvと書くだけで二度と起きていません。

まとめると、Claude CodeでPython開発をするなら、魔法のプロンプトより小さな足場が先です。環境・設定・実装・テスト・整形・確認コマンドを1つの流れにしてから、機能を少しずつ足す。CLAUDE.mdに同じルールを書いておけば毎回説明せずに済むので、CLAUDE.mdの書き方も合わせて整えておくと楽です。型化したブリーフやテスト依頼のテンプレートが欲しくなったら、Claude Code教材一覧ものぞいてみてください。

#Claude Code #Python #uv #ruff #pytest
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。