跳到正文
cccskills
免费在 GitHub 公开

python-project

Modern Python project architecture guide for 2025. Use when creating Python projects (APIs, CLI, data pipelines). Covers uv, Ruff, Pydantic, FastAPI, and async patterns.

中文简介正在准备中。当前显示原文说明。

集成工具OpenAI
查看安装方法

包含的文件(28)

  • SKILL.md10.7 KB
  • reference/architecture.md10.0 KB
  • reference/extended.md2.6 KB
  • reference/patterns.md12.9 KB
  • reference/tech-stack.md8.5 KB
  • templates/api/.env.example215 B
  • templates/api/.python-version5 B
  • templates/api/Makefile1.4 KB
  • templates/api/pyproject.toml787 B
  • templates/api/src/myapp/__init__.py58 B
  • templates/api/src/myapp/__main__.py302 B
  • templates/api/src/myapp/api/__init__.py17 B
  • templates/api/src/myapp/api/deps.py525 B
  • templates/api/src/myapp/api/middleware.py662 B
  • templates/api/src/myapp/api/routes/__init__.py186 B
  • templates/api/src/myapp/api/routes/user.py978 B
  • templates/api/src/myapp/config.py713 B
  • templates/api/src/myapp/core/__init__.py278 B
  • templates/api/src/myapp/core/exceptions.py1.4 KB
  • templates/api/src/myapp/core/logging.py1.2 KB
  • templates/api/src/myapp/main.py718 B
  • templates/api/src/myapp/models/__init__.py131 B
  • templates/api/src/myapp/models/user.py679 B
  • templates/api/src/myapp/services/__init__.py103 B
  • templates/api/src/myapp/services/user.py2.1 KB
  • templates/api/tests/__init__.py21 B
  • templates/api/tests/conftest.py528 B
  • templates/api/tests/test_user.py2.9 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Python Project Architecture

Core Principles

  • Type hints everywhere — Pydantic for runtime, mypy for static
  • uv for everything — Package management, virtualenv, Python version
  • Ruff only — Replace Flake8 + Black + isort with single tool
  • src layout — All code under src/ directory
  • pyproject.toml only — No setup.py, no requirements.txt
  • Async all the way — Once async, stay async through call chain
  • No backwards compatibility — Delete, don't deprecate. Change directly
  • LiteLLM for LLM APIs — Use LiteLLM proxy for all LLM integrations

No Backwards Compatibility

Delete unused code. Change directly. No compatibility layers.

# ❌ BAD: Deprecated decorator kept around
import warnings

def old_function():
    warnings.warn("Use new_function instead", DeprecationWarning)
    return new_function()

# ❌ BAD: Alias for renamed functions
new_name = old_name  # "for backwards compatibility"

# ❌ BAD: Unused parameters with underscore
def process(_legacy_param, data):
    ...

# ❌ BAD: Version checking for old behavior
if version < "2.0":
    # old behavior
    ...

# ✅ GOOD: Just delete and update all usages
def new_function():
    ...
# Then: Find & replace all old_function → new_function

# ✅ GOOD: Remove unused parameters entirely
def process(data):
    ...

LiteLLM for LLM APIs

Use LiteLLM proxy. Don't call provider APIs directly.

# src/myapp/llm.py
from openai import AsyncOpenAI

from myapp.config import settings

# Connect to LiteLLM proxy using OpenAI SDK
client = AsyncOpenAI(
    base_url=settings.litellm_url,  # "http://localhost:4000"
    api_key=settings.litellm_api_key,
)


async def complete(prompt: str, model: str = "gpt-4o") -> str:
    """Call any LLM through LiteLLM proxy."""
    response = await client.chat.completions.create(
        model=model,  # "gpt-4o", "claude-3-opus", "gemini-pro", etc.
        messages=[{"role": "user", "content": prompt}],
    )
    return response.choices[0].message.content or ""

Quick Start

1. Initialize Project

# Install uv (if not installed)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Create new project
uv init myapp
cd myapp

# Set Python version
echo "3.12" > .python-version

# Add dependencies
uv add fastapi uvicorn pydantic sqlalchemy httpx
uv add --dev pytest pytest-asyncio ruff mypy

2. Apply Tech Stack

LayerRecommendation
Package Manageruv
Linting + FormatRuff
Type Checkingmypy
ValidationPydantic v2
Web FrameworkFastAPI
DatabaseSQLAlchemy 2.0 + asyncpg
HTTP Clienthttpx
Testingpytest + pytest-asyncio
Loggingstructlog

Version Strategy

Always use latest. Never pin in templates.

[project]
dependencies = [
    "fastapi",      # uv resolves to latest
    "pydantic",
    "sqlalchemy",
]
  • uv add fetches latest compatible versions
  • uv.lock ensures reproducible builds
  • uv sync installs exact locked versions

3. Use Standard Structure (src layout)

myapp/
├── pyproject.toml         # Single config file
├── uv.lock                # Lock file (commit this)
├── .python-version        # Python version for uv
├── src/
│   └── myapp/
│       ├── __init__.py
│       ├── __main__.py    # Entry point
│       ├── main.py        # FastAPI app
│       ├── config.py      # Pydantic Settings
│       ├── models/        # Pydantic models
│       │   ├── __init__.py
│       │   └── user.py
│       ├── services/      # Business logic
│       │   ├── __init__.py
│       │   └── user.py
│       ├── repositories/  # Data access
│       │   ├── __init__.py
│       │   └── user.py
│       ├── api/           # HTTP layer
│       │   ├── __init__.py
│       │   ├── deps.py    # Dependencies
│       │   └── routes/
│       │       ├── __init__.py
│       │       └── user.py
│       └── core/          # Shared utilities
│           ├── __init__.py
│           ├── exceptions.py
│           └── logging.py
├── tests/
│   ├── __init__.py
│   ├── conftest.py        # Fixtures
│   └── test_user.py
└── Makefile

Architecture Layers

main.py — FastAPI Application

# src/myapp/main.py
from contextlib import asynccontextmanager

from fastapi import FastAPI

from myapp.api.routes import router
from myapp.config import settings
from myapp.core.logging import setup_logging
from myapp.db import engine


@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup
    setup_logging()
    yield
    # Shutdown
    await engine.dispose()


app = FastAPI(
    title=settings.app_name,
    lifespan=lifespan,
)

app.include_router(router, prefix="/api/v1")


@app.get("/health")
async def health():
    return {"status": "ok"}

config.py — Pydantic Settings

# src/myapp/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
    )

    app_name: str = "myapp"
    debug: bool = False

    # Database
    database_url: str = "postgresql+asyncpg://localhost/myapp"

    # LiteLLM
    litellm_url: str = "http://localhost:4000"
    litellm_api_key: str = ""


settings = Settings()

models/ — Pydantic Models

# src/myapp/models/user.py
from datetime import datetime
from uuid import UUID

from pydantic import BaseModel, EmailStr, Field


class UserBase(BaseModel):
    email: EmailStr
    name: str = Field(min_length=2, max_length=100)


class UserCreate(UserBase):
    pass


class UserUpdate(BaseModel):
    email: EmailStr | None = None
    name: str | None = Field(default=None, min_length=2, max_length=100)


class User(UserBase):
    id: UUID
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}

services/ — Business Logic

# src/myapp/services/user.py
from uuid import UUID

from myapp.core.exceptions import NotFoundError, ConflictError
from myapp.models.user import User, UserCreate, UserUpdate
from myapp.repositories.user import UserRepository


class UserService:
    def __init__(self, repo: UserRepository):
        self.repo = repo

    async def get(self, id: UUID) -> User:
        user = await self.repo.get(id)
        if not user:
            raise NotFoundError("user", str(id))
        return user

    async def create(self, data: UserCreate) -> User:
        existing = await self.repo.get_by_email(data.email)
        if existing:
            raise ConflictError("email already exists")
        return await self.repo.create(data)

    async def update(self, id: UUID, data: UserUpdate) -> User:
        user = await self.get(id)
        return await self.repo.update(user, data)

    async def delete(self, id: UUID) -> None:
        user = await self.get(id)
        await self.repo.delete(user)

api/routes/ — HTTP Handlers

# src/myapp/api/routes/user.py
from uuid import UUID

from fastapi import APIRouter, Depends, status

from myapp.api.deps import get_user_service
from myapp.models.user import User, UserCreate, UserUpdate
from myapp.services.user import UserService

router = APIRouter(prefix="/users", tags=["users"])


@router.get("/{id}", response_model=User)
async def get_user(
    id: UUID,
    service: UserService = Depends(get_user_service),
):
    return await service.get(id)


@router.post("", response_model=User, status_code=status.HTTP_201_CREATED)
async def create_user(
    data: UserCreate,
    service: UserService = Depends(get_user_service),
):
    return await service.create(data)


@router.patch("/{id}", response_model=User)
async def update_user(
    id: UUID,
    data: UserUpdate,
    service: UserService = Depends(get_user_service),
):
    return await service.update(id, data)


@router.delete("/{id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(
    id: UUID,
    service: UserService = Depends(get_user_service),
):
    await service.delete(id)

core/exceptions.py — Custom Exceptions

# src/myapp/core/exceptions.py
from fastapi import HTTPException, status


class AppError(Exception):
    """Base application error."""

    def __init__(self, message: str, code: str):
        self.message = message
        self.code = code
        super().__init__(message)


class NotFoundError(AppError):
    def __init__(self, resource: str, id: str):
        super().__init__(f"{resource} not found: {id}", "NOT_FOUND")


class ConflictError(AppError):
    def __init__(self, message: str):
        super().__init__(message, "CONFLICT")


class ValidationError(AppError):
    def __init__(self, message: str):
        super().__init__(message, "VALIDATION_ERROR")


# FastAPI exception handler
def app_error_to_http(error: AppError) -> HTTPException:
    status_map = {
        "NOT_FOUND": status.HTTP_404_NOT_FOUND,
        "CONFLICT": status.HTTP_409_CONFLICT,
        "VALIDATION_ERROR": status.HTTP_400_BAD_REQUEST,
    }
    return HTTPException(
        status_code=status_map.get(error.code, status.HTTP_500_INTERNAL_SERVER_ERROR),
        detail={"message": error.message, "code": error.code},
    )

pyproject.toml

[project]
name = "myapp"
version = "0.1.0"
description = "My application"
requires-python = ">=3.12"
dependencies = [
    "fastapi",
    "uvicorn[standard]",
    "pydantic",
    "pydantic-settings",
    "sqlalchemy[asyncio]",
    "asyncpg",
    "httpx",
    "structlog",
]

[tool.uv]
dev-dependencies = [
    "pytest",
    "pytest-asyncio",
    "pytest-cov",
    "ruff",
    "mypy",
]

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

[tool.ruff.lint]
select = [
    "E",   # pycodestyle errors
    "F",   # pyflakes
    "I",   # isort
    "UP",  # pyupgrade
    "B",   # flake8-bugbear
    "SIM", # flake8-simplify
]

[tool.ruff.lint.isort]
known-first-party = ["myapp"]

[tool.mypy]
strict = true
python_version = "3.12"

[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]

Extended Reference

Detailed material starting at ## Testing has been moved to reference/extended.md to keep this skill concise. Load that reference when the task requires the moved examples, command catalogs, checklists, platform details, or implementation templates.

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Audit and organize AI coding-agent instructions, including AGENTS.md, CLAUDE.md, skills, and agent definitions. Use when the user asks to diagnose conflicting instructions, excessive approval pauses, broad skill triggers, duplicate guidance, or broken instruction references, or to clean up that instruction set. Ordinary code review, Markdown editing, or application debugging alone does not trigger this workflow. Inspection stays read-only; apply changes when authorized.

中文简介正在准备中。当前显示原文说明。

majiayu000/spellbook2882026年10月8日 更新

Generate or update repository-specific AGENTS.md instruction files from real repo evidence. Use when asked to create, design, scaffold, split, or improve root or scoped AGENTS.md files for Codex/Claude/agent workflows, especially when a repo needs directory-specific rules, validation commands, generated-file boundaries, or a short agent onboarding router.

中文简介正在准备中。当前显示原文说明。

majiayu000/spellbook2882026年10月8日 更新

REST/GraphQL/gRPC API design best practices. Use when designing APIs, defining contracts, handling versioning. Covers OpenAPI 3.2, GraphQL Federation, gRPC streaming.

中文简介正在准备中。当前显示原文说明。

majiayu000/spellbook2882026年10月8日 更新

Mobile app UI design expert for iOS and Android. Use when designing app interfaces, creating design systems, ensuring accessibility, or following platform guidelines. Covers Material Design 3, Human Interface Guidelines, color theory, typography, and 2025 trends.

中文简介正在准备中。当前显示原文说明。

majiayu000/spellbook2882026年10月8日 更新

End-to-end app feature inventory and user-story testing workflow with a canonical tracker. Use when the user asks to audit every feature, derive expected behavior from code, test user journeys, or explicitly fix and retest documented UX or logistical defects.

中文简介正在准备中。当前显示原文说明。

majiayu000/spellbook2882026年10月8日 更新

Design architecture foundations before implementation. Use when asked to design or refactor architecture, choose Rust/Go crate, package, module, runtime, workflow, or service boundaries, compare mature project architecture, prevent stacked one-off PRs, audit migration debt in existing repos, or produce a spec before coding.

中文简介正在准备中。当前显示原文说明。

majiayu000/spellbook2882026年10月8日 更新

查看 majiayu000 的全部技能

报告此技能的问题