# Python 项目开发准则

以下准则用于指导 AI 在参与 Python 项目开发时的行为规范，确保代码质量、架构一致性与项目长期可维护性。

---

## 1. 总体要求

- 遵循 SOLID、KISS、DRY、YAGNI 原则。
- 代码需清晰、可维护、结构化，避免不必要的复杂性。
- 所有示例代码必须可运行（除非为特意演示的伪代码）。
- 项目结构、命名、注释、接口设计必须保持一致风格。

---

## 2. 项目结构规范

推荐使用 `src/` 布局：

project_name/
├── src/project_name/
│ ├── init.py
│ ├── core/
│ ├── models/
│ ├── services/
│ ├── utils/
│ └── config.py
├── tests/
├── docs/
├── pyproject.toml
├── README.md
└── .gitignore


要求：
- `tests/` 与 `src/` 目录结构需对应。
- 所有配置文件集中管理。
- 避免深层次目录嵌套。

---

## 3. 代码规范（Coding Style）

- 遵守 PEP 8 和 PEP 257。
- 所有函数与类必须包含 docstring（Google 或 NumPy 风格）。
- 命名必须具备语义，禁止使用无意义变量。
- 模块导入顺序：
  1. 内置模块
  2. 第三方模块
  3. 本地模块

---

## 4. 类型注解与错误处理

- 所有函数必须添加类型注解。
- 捕获异常时必须提供明确的错误信息。
- 不得吞异常。
- 必要时使用自定义异常类。

示例：

```python
class ConfigLoadError(Exception):
    pass

---

## 5. 测试规范

- 使用 **pytest**。
- 单元测试与集成测试必须齐全。
- 每个功能点至少一个测试。
- 覆盖率目标 **≥ 80%**。
- 禁止空测试。

---

## 6. 文档规范

项目文档应包含：

- 项目介绍
- 安装与运行说明
- 使用示例
- API 文档（如涉及）
- 配置与架构说明

推荐使用 **mkdocs** 与 **mkdocstrings**。

---

## 7. 架构设计规范

项目应进行分层，例如：

- domain（业务逻辑）

- services（服务层）

- adapters（外部系统接口）

- infra（数据库、缓存、文件 IO）

设计要求：

- 上层不得依赖下层 **具体实现**。
- 使用接口或抽象类隔离实现。
- 禁止业务逻辑直接读写文件、网络、数据库。

---

## 8. 设计模式使用原则

推荐但谨慎使用以下模式：

- 工厂模式
- 策略模式
- 适配器模式
- 观察者模式
- 模板方法
- 建造者模式
- 单例模式（仅在特殊情况）

要求：

- 必须有明确使用动机，不得滥用。

---

## 9. 性能与可扩展性

- 优先使用 **批处理** 操作代替循环处理。
- 性能优化必须基于实际测量。
- 使用异步、并行需有明确理由。
- 避免在主流程中执行阻塞 I/O。

---

## 10. 异步编程规范

### 适用场景与工具选择

| 使用场景 | 工具 | 说明 |
|---------|------|------|
| **I/O 密集** | asyncio | 网络请求、文件读写（推荐） |
| **并发任务** | threading | 需要共享内存的并发操作 |
| **CPU 密集** | multiprocessing | 规避 GIL，用于计算密集任务 |

### 异步函数类型注解

```python
from typing import AsyncIterator, Awaitable
import asyncio

# 基础异步函数
async def fetch_data(url: str) -> dict:
    """异步获取数据

    Args:
        url: 目标 URL

    Returns:
        响应数据字典

    Raises:
        NetworkError: 网络请求失败时
    """
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.json()

# 异步生成器
async def stream_data(source: str) -> AsyncIterator[dict]:
    """流式处理数据

    Args:
        source: 数据源路径

    Yields:
        处理后的数据项
    """
    async with aiofiles.open(source) as f:
        async for line in f:
            yield json.loads(line)

# 异步上下文管理器
class AsyncDatabaseConnection:
    """异步数据库连接管理器"""

    async def __aenter__(self) -> "AsyncDatabaseConnection":
        """建立连接"""
        await self.connect()
        return self

    async def __aexit__(self, *args) -> None:
        """关闭连接"""
        await self.disconnect()

    async def connect(self) -> None:
        """连接数据库"""
        self.connection = await asyncpg.connect(self.dsn)

    async def disconnect(self) -> None:
        """断开连接"""
        await self.connection.close()
```

### 异步并发控制

```python
# 限制并发数量
async def fetch_multiple_with_limit(
    urls: list[str],
    max_concurrent: int = 5
) -> list[dict]:
    """并发获取多个 URL，限制并发数"""
    semaphore = asyncio.Semaphore(max_concurrent)

    async def bounded_fetch(url: str) -> dict:
        async with semaphore:
            return await fetch_data(url)

    return await asyncio.gather(*[bounded_fetch(url) for url in urls])

# 超时处理
async def fetch_with_timeout(
    url: str,
    timeout: float = 30.0
) -> dict | None:
    """设置请求超时"""
    try:
        return await asyncio.wait_for(
            fetch_data(url),
            timeout=timeout
        )
    except asyncio.TimeoutError:
        logger.warning(f"请求超时: {url}")
        return None
```

### 异步测试

```python
import pytest
from pytest_asyncio import fixture

@fixture
async def async_client():
    """异步客户端 fixture"""
    client = AsyncClient()
    await client.connect()
    yield client
    await client.disconnect()

@pytest.mark.asyncio
async def test_fetch_data(async_client):
    """测试异步函数"""
    result = await async_client.fetch_data("http://example.com")
    assert result is not None
    assert "data" in result

@pytest.mark.asyncio
async def test_fetch_multiple():
    """测试异步并发"""
    urls = ["http://example.com"] * 5
    results = await fetch_multiple_with_limit(urls, max_concurrent=2)
    assert len(results) == 5
```

**配置 pytest-asyncio（pyproject.toml）：**

```toml
[tool.pytest.ini_options]
asyncio_mode = "auto"  # 自动标记异步测试
```

### 异步最佳实践

- ✅ 使用 `asyncio.gather()` 并发多个任务
- ✅ 使用 `Semaphore` 限制并发数量
- ✅ 总是设置合理的超时时间
- ✅ 在异步函数中避免 CPU 密集操作
- ❌ 不要混用同步和异步代码（会导致死锁）
- ❌ 不要在异步函数中使用 `time.sleep()`，用 `await asyncio.sleep()`

---

## 11. 数据验证规范

### 使用 Pydantic v2 进行输入验证

**Pydantic 是数据验证的标准工具，提供：**
- 运行时类型检查和数据转换
- 自动生成 JSON Schema（API 文档）
- 详细的验证错误信息
- 高性能

```python
from pydantic import BaseModel, Field, field_validator
from datetime import datetime
from typing import Optional

class UserCreate(BaseModel):
    """用户创建请求模型"""
    name: str = Field(..., min_length=1, max_length=100)
    email: str = Field(
        ...,
        pattern=r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    )
    age: int = Field(..., ge=18, le=150)
    tags: list[str] = Field(default_factory=list, max_length=10)
    created_at: datetime = Field(default_factory=datetime.now)
    profile: Optional[str] = None

    @field_validator('name')
    @classmethod
    def name_alphanumeric(cls, v: str) -> str:
        """验证名字只包含字母、数字和空格"""
        if not all(c.isalnum() or c.isspace() for c in v):
            raise ValueError('名字只能包含字母、数字和空格')
        return v.strip()

    @field_validator('tags')
    @classmethod
    def validate_tags(cls, v: list[str]) -> list[str]:
        """验证标签唯一性"""
        if len(v) != len(set(v)):
            raise ValueError('标签不能重复')
        return v

# 使用示例
try:
    user = UserCreate(
        name="John Doe",
        email="john@example.com",
        age=30,
        tags=["python", "developer"]
    )
    print(f"验证成功: {user}")
except ValueError as e:
    logger.error(f"数据验证失败: {e}")
    raise DataValidationError(str(e))
```

### 嵌套模型验证

```python
class Address(BaseModel):
    """地址模型"""
    street: str
    city: str
    postal_code: str = Field(..., pattern=r'^\d{5}$')

class UserProfile(BaseModel):
    """用户资料"""
    user: UserCreate
    address: Address
    phone: str = Field(..., pattern=r'^\+?1?\d{9,15}$')

# 验证嵌套数据
data = {
    "user": {
        "name": "Jane",
        "email": "jane@example.com",
        "age": 25
    },
    "address": {
        "street": "123 Main St",
        "city": "Springfield",
        "postal_code": "12345"
    },
    "phone": "+1234567890"
}

profile = UserProfile(**data)
```

### 自定义验证器

```python
from pydantic import model_validator

class PaymentInfo(BaseModel):
    """支付信息"""
    card_number: str
    expiry_month: int
    expiry_year: int
    cvv: str

    @model_validator(mode='after')
    def validate_expiry_date(self) -> 'PaymentInfo':
        """验证卡片是否过期"""
        from datetime import datetime
        now = datetime.now()
        if self.expiry_year < now.year or (
            self.expiry_year == now.year
            and self.expiry_month < now.month
        ):
            raise ValueError('卡片已过期')
        return self
```

### 验证错误处理

```python
from pydantic import ValidationError

def create_user_safe(data: dict) -> UserCreate | None:
    """安全的用户创建"""
    try:
        return UserCreate(**data)
    except ValidationError as e:
        # e.errors() 返回详细的错误列表
        for error in e.errors():
            field = error['loc'][0]
            msg = error['msg']
            logger.error(f"字段 {field} 验证失败: {msg}")
        return None
```

### API 验证集成

```python
from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.post("/users")
async def create_user(user: UserCreate):
    """创建用户（自动验证请求体）"""
    # FastAPI 自动使用 Pydantic 验证请求
    # 验证失败会返回 422 状态码和详细错误
    return {"status": "success", "user": user}
```

### 验证最佳实践

- ✅ 在数据进入系统时立即验证（API 入口层）
- ✅ 使用具体的验证失败异常
- ✅ 为验证失败提供详细的错误信息
- ✅ 使用 `Field()` 定义约束而非代码中硬编码
- ✅ 对外部数据源的数据进行验证
- ❌ 不要在业务逻辑层重复验证
- ❌ 不要忽略验证错误，必须记录和处理

---

## 12. 安全原则

- 禁用 `eval()`、`exec()`。
- 所有输入必须进行校验（使用 Pydantic，参见第11章）。
- 文件访问必须包含异常与权限检查。
- 禁止在仓库中包含敏感信息。
- 使用 `.env` 管理环境变量。

### 安全检查工具

```bash
# 安装安全扫描工具
uv pip install bandit pip-audit

# 检测安全漏洞
uv run bandit -r src/ -f screen

# 扫描依赖漏洞
uv run pip-audit
```

---

## 13. 依赖版本管理

### 多环境依赖分离

**requirements.txt** （生产环境）
```
pandas>=2.0.0,<3.0.0
numpy>=1.24.0,<2.0.0
requests==2.31.0
```

**requirements-dev.txt** （开发工具）
```
-r requirements.txt
pytest>=7.4.0
pytest-cov>=4.1.0
black>=23.12.0
ruff>=0.1.9
mypy>=1.8.0
```

**requirements-test.txt** （测试）
```
-r requirements.txt
pytest>=7.4.0
pytest-asyncio>=0.21.0
pytest-mock>=3.12.0
```

### 使用 pip-tools 管理版本

```bash
# 安装 pip-tools
uv pip install pip-tools

# requirements.in: 声明直接依赖
# django==4.2
# djangorestframework~=3.14
# psycopg[binary]==2.9

# 生成 requirements.txt（包含所有传递依赖）
uv run pip-compile requirements.in -o requirements.txt

# 更新依赖版本
uv run pip-compile --upgrade requirements.in

# 同步环境
uv run pip-sync requirements.txt
```

### 安全补丁更新流程

1. **每周检查**：运行 `uv pip audit` 检查漏洞
2. **补丁版本**（x.y.**z** ↑）：自动更新，无需测试
3. **次要版本**（x.**y**.z ↑）：评估兼容性，运行完整测试
4. **主版本**（**x**.y.z ↑）：需要完整回归测试和代码审查

```bash
# 检查漏洞
uv run pip-audit

# 自动修复非破坏性更新
uv run pip-audit --fix

# 查看可更新的包
uv pip list --outdated
```

### Python 版本升级

**支持的 Python 版本：**
- 最小版本：Python 3.10
- 推荐版本：Python 3.11+
- 最新版本：Python 3.12+

**升级检查清单：**
- [ ] 使用 `python -W all` 检查废弃警告
- [ ] 更新类型注解（使用 `list[int]` 而非 `List[int]`）
- [ ] 利用新特性（match-case 语句、新的联合类型等）
- [ ] 更新 pyproject.toml 中的 `requires-python`
- [ ] 运行完整测试套件
- [ ] 检查依赖对新版本的支持

---

## 14. API 设计规范

### REST API 端点命名约定

```python
from fastapi import FastAPI, HTTPException

app = FastAPI()

# 列表
@app.get("/api/v1/users")
async def list_users(skip: int = 0, limit: int = 100):
    """获取用户列表"""
    pass

# 创建
@app.post("/api/v1/users")
async def create_user(user: UserCreate):
    """创建用户"""
    pass

# 详情
@app.get("/api/v1/users/{user_id}")
async def get_user(user_id: int):
    """获取单个用户"""
    pass

# 完全更新
@app.put("/api/v1/users/{user_id}")
async def update_user(user_id: int, user: UserUpdate):
    """完全更新用户"""
    pass

# 部分更新
@app.patch("/api/v1/users/{user_id}")
async def partial_update_user(user_id: int, user: UserPartialUpdate):
    """部分更新用户"""
    pass

# 删除
@app.delete("/api/v1/users/{user_id}")
async def delete_user(user_id: int):
    """删除用户"""
    pass
```

### 统一错误响应格式

```python
from pydantic import BaseModel
from datetime import datetime

class ErrorDetail(BaseModel):
    """单个错误详情"""
    field: str
    message: str
    code: str

class ErrorResponse(BaseModel):
    """统一的错误响应"""
    code: str  # 错误代码（如 "VALIDATION_ERROR"）
    message: str  # 用户友好的消息
    details: list[ErrorDetail] = []
    timestamp: str = Field(default_factory=lambda: datetime.now().isoformat())

# 实现示例
@app.exception_handler(ValidationError)
async def validation_exception_handler(request, exc: ValidationError):
    """处理 Pydantic 验证错误"""
    errors = [
        ErrorDetail(
            field=str(error['loc'][0]),
            message=error['msg'],
            code=error['type']
        )
        for error in exc.errors()
    ]
    return JSONResponse(
        status_code=422,
        content=ErrorResponse(
            code="VALIDATION_ERROR",
            message="Request validation failed",
            details=errors
        ).dict()
    )
```

### HTTP 状态码使用规范

| 状态码 | 场景 | 说明 |
|--------|------|------|
| 200 | 成功 | GET、PUT、PATCH 成功时 |
| 201 | 创建成功 | POST 创建资源成功 |
| 204 | 无内容 | DELETE 成功、或不返回内容 |
| 400 | 请求错误 | 客户端语法错误 |
| 401 | 未认证 | 需要身份验证 |
| 403 | 禁止访问 | 已认证但没有权限 |
| 404 | 资源不存在 | 查询不到请求的资源 |
| 422 | 无法处理 | 请求格式正确但语义错误（验证失败） |
| 429 | 速率限制 | 请求过于频繁 |
| 500 | 服务器错误 | 服务器内部错误 |

### API 文档生成（OpenAPI/Swagger）

```python
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

app = FastAPI(
    title="AutoReport API",
    description="自动报告生成系统",
    version="1.0.0"
)

# FastAPI 自动生成 OpenAPI 文档
# Swagger UI: http://localhost:8000/docs
# ReDoc: http://localhost:8000/redoc

# 自定义 OpenAPI 配置
def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema

    openapi_schema = get_openapi(
        title="AutoReport API",
        version="1.0.0",
        description="Professional report generation system",
        routes=app.routes,
    )
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi
```

### API 版本管理

**推荐：使用 URL 路径版本控制**
```python
@app.get("/api/v1/users/{user_id}")
async def get_user_v1(user_id: int):
    """v1 API - 返回基础信息"""
    pass

@app.get("/api/v2/users/{user_id}")
async def get_user_v2(user_id: int):
    """v2 API - 返回扩展信息"""
    pass
```

### API 速率限制和认证

```python
from slowapi import Limiter
from slowapi.util import get_remote_address
from fastapi_jwt_bearer import HTTPBearer

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

security = HTTPBearer()

@app.get("/api/v1/users")
@limiter.limit("100/minute")
async def list_users(request: Request, credentials=Depends(security)):
    """获取用户列表（需要认证，限流 100/分钟）"""
    pass
```

---

## 15. 日志规范

### 日志级别使用指南

| 级别 | 何时使用 | 示例 |
|------|---------|------|
| **DEBUG** | 开发调试 | 变量值、函数调用栈、详细追踪 |
| **INFO** | 重要信息 | 应用启动、重要里程碑、配置加载 |
| **WARNING** | 警告 | 降级处理、重试操作、使用默认值 |
| **ERROR** | 可恢复错误 | 业务逻辑失败、数据处理异常 |
| **CRITICAL** | 不可恢复 | 系统宕机、数据库连接失败 |

### 日志配置

```python
import logging
import json
from logging.handlers import RotatingFileHandler
from datetime import datetime

# 标准格式日志配置
def setup_logging(app_name: str, log_level: str = "INFO") -> logging.Logger:
    """配置应用日志"""
    logger = logging.getLogger(app_name)
    logger.setLevel(getattr(logging, log_level))

    # 格式化器
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )

    # 控制台处理器
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)

    # 文件处理器（自动轮转）
    file_handler = RotatingFileHandler(
        f"{app_name}.log",
        maxBytes=10_000_000,  # 10MB
        backupCount=5
    )
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    return logger

logger = setup_logging("autoreport")
```

### 结构化日志（JSON）

```python
import structlog

# 配置结构化日志
structlog.configure(
    processors=[
        structlog.stdlib.filter_by_level,
        structlog.stdlib.add_logger_name,
        structlog.stdlib.add_log_level,
        structlog.stdlib.PositionalArgumentsFormatter(),
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.StackInfoRenderer(),
        structlog.processors.format_exc_info,
        structlog.processors.UnicodeDecoder(),
        structlog.processors.JSONRenderer()
    ],
    context_class=dict,
    logger_factory=structlog.stdlib.LoggerFactory(),
    cache_logger_on_first_use=True,
)

logger = structlog.get_logger()

# 使用
logger.info(
    "user_created",
    user_id=123,
    email="user@example.com",
    source="api",
    timestamp=datetime.now().isoformat()
)

# 输出：
# {"event": "user_created", "user_id": 123, "email": "user@example.com", "source": "api", "timestamp": "2024-01-15T..."}
```

### 日志最佳实践

```python
# ✅ 好的日志
logger.info(f"处理用户 {user_id}，邮箱: {user_email}", extra={"user_id": user_id})

logger.error(
    "数据库连接失败",
    exc_info=True,  # 记录完整堆栈跟踪
    extra={"retry_count": 3}
)

# ❌ 不好的日志
logger.info("处理完毕")  # 太模糊
logger.error(str(exception))  # 没有上下文
logger.debug(f"密码: {password}")  # 记录敏感信息

# 避免在日志中记录敏感信息
def mask_email(email: str) -> str:
    """掩码邮箱地址"""
    parts = email.split('@')
    return f"{parts[0][:2]}***@{parts[1]}"

logger.info(f"用户邮箱: {mask_email(user_email)}")
```

---

## 16. 清洁代码规则

- 每个函数尽量不超过 **40 行**。
- 类的职责必须 **单一**。
- 禁止魔法数字，必须使用常量。
- 避免重复代码（DRY 原则）。
- 配置与逻辑分离。

### 代码复杂度控制

```bash
# 安装 radon 检查代码复杂度
uv pip install radon

# 分析循环复杂度（应 ≤ 10）
uv run radon cc src/ -a -nb

# 分析可维护性指数（应 ≥ 70）
uv run radon mi src/ -nb
```

---

## 17. AI 使用方式（核心）

当 AI 参与开发时必须遵守：

- 自动检查自己生成内容是否违反以上规范。
- 在回答前先分析需求、提炼结构、规划输出。
- 如果用户需求不合理或影响架构，应主动提出改进方案。
- 所有输出应附上设计意图或结构化说明（如适用）。
- AI 不得生成与项目规范冲突的文件或代码。

### AI 自检清单

每次生成代码前，AI 必须检查：

- [ ] **编码规范**：PEP 8、命名规范、导入排序
- [ ] **类型注解**：所有函数都有完整的参数和返回类型
- [ ] **文档字符串**：所有公开函数/类都有 Google 风格 docstring
- [ ] **异常处理**：捕获具体异常，不使用裸 `except:`
- [ ] **日志记录**：关键操作有日志，避免敏感信息
- [ ] **测试用例**：为新功能编写 ≥ 80% 覆盖率的测试
- [ ] **安全检查**：没有硬编码敏感信息、SQL 注入、XSS 等风险
- [ ] **性能考虑**：没有明显的性能问题或 N+1 查询
- [ ] **架构一致性**：遵循项目分层架构，不跨层依赖

---

## 18. 用于提示 AI 的启动语句（可直接复制）

**完整版本（适用于新功能开发）：**

```
请严格遵守《Python 项目开发准则》完成以下任务：

## 开发规范
- 所有代码必须符合 PEP 8 和项目编码规范
- 所有函数、类必须添加完整的类型注解
- 所有公开 API 必须有 Google 风格的 docstring
- 异常处理必须捕获具体异常，禁止使用裸 except:
- 关键操作必须有日志记录（避免敏感信息）

## 架构要求
- 遵循项目的分层架构（domain → services → adapters → infra）
- 上层代码不得依赖下层具体实现，使用接口隔离
- 业务逻辑禁止直接读写文件、网络、数据库

## 数据验证
- 使用 Pydantic v2 进行输入验证（参见第11章）
- 验证错误必须被捕获并记录
- 返回结构化的错误响应

## 测试和质量
- 编写单元测试，覆盖率 ≥ 80%
- 运行 black、ruff、mypy 检查
- 通过 pytest 测试

## 若需求不合理
- 请主动提出更佳的架构或实现方案
- 说明改进的原因和好处

## 输出内容需要包括
- 实现代码（可运行、无占位符）
- 类型注解和 docstring
- 单元测试用例
- 设计意图说明（如涉及架构决策）
```

**快速版本（适用于小的修复/改进）：**

```
请遵守《Python 项目开发准则》：
- 完整类型注解 + docstring
- 异常处理规范、关键操作有日志
- 可运行的代码，包含单元测试（≥80% 覆盖率）
```

**代码审查版本（审查现有代码）：**

```
请按照《Python 项目开发准则》审查以下代码：
1. 检查是否符合 PEP 8 和命名规范
2. 验证类型注解和 docstring 的完整性
3. 评估异常处理和日志的适当性
4. 检查架构一致性（是否遵循分层）
5. 指出改进建议（附上修复示例）
```

---

## 19. 快速检查清单

### 提交代码前必须验证

```bash
# 1. 代码格式化
uv run black src/ tests/ --check

# 2. 代码检查和自动修复
uv run ruff check src/ tests/
uv run ruff format src/ tests/

# 3. 类型检查
uv run mypy src/

# 4. 单元测试
uv run pytest tests/ --cov=src/autoreport --cov-fail-under=80

# 5. 安全检查（可选但推荐）
uv run bandit -r src/ -f screen
uv run pip-audit
```

### 代码质量管理脚本

**创建 `scripts/check.py` 进行统一检查：**

```python
#!/usr/bin/env python3
"""统一的代码质量检查脚本"""

import subprocess
import sys
from pathlib import Path

def run_check(name: str, cmd: list[str]) -> bool:
    """运行单个检查"""
    print(f"\n{'='*60}")
    print(f"运行: {name}")
    print(f"{'='*60}")
    result = subprocess.run(cmd)
    return result.returncode == 0

def main() -> int:
    checks = [
        ("Black 代码格式检查", ["black", "--check", "src", "tests"]),
        ("Ruff 代码检查", ["ruff", "check", "src", "tests"]),
        ("Ruff 代码格式", ["ruff", "format", "--check", "src", "tests"]),
        ("MyPy 类型检查", ["mypy", "src"]),
        ("Pytest 单元测试（覆盖率≥80%）",
         ["pytest", "--cov=src", "--cov-fail-under=80", "tests"]),
        ("Bandit 安全检查", ["bandit", "-r", "src"]),
    ]

    results = [run_check(name, cmd) for name, cmd in checks]

    print(f"\n{'='*60}")
    print(f"总体结果: {sum(results)}/{len(results)} 项通过")
    print(f"{'='*60}")

    return 0 if all(results) else 1

if __name__ == "__main__":
    sys.exit(main())
```

**使用方法：**
```bash
uv run python scripts/check.py
```

---

## 20. 常见错误和避坑指南

### ❌ 常见违规

| 违规 | 问题 | 改正 |
|------|------|------|
| `except:` 或 `except Exception:` | 捕获所有异常，隐藏 bug | 捕获具体异常：`except ValueError as e:` |
| 函数没有类型注解 | 无法静态检查，易出错 | 添加：`def fn(x: int) -> str:` |
| 缺少 docstring | 不知道函数做什么 | 添加 Google 风格 docstring |
| 硬编码配置值 | 代码不可复用 | 使用 `.env` 或配置文件 |
| 直接修改传入列表 | 副作用难以追踪 | 返回新列表：`return [x+1 for x in items]` |
| `global` 变量 | 增加耦合度 | 用参数或类属性代替 |
| 未验证用户输入 | 安全漏洞 | 使用 Pydantic 验证 |
| 日志中包含密码 | 安全泄露 | 掩码敏感信息 |

### ✅ 最佳实践示例

**错误的方式：**
```python
# ❌ 多个问题
def process(data):
    try:
        result = json.loads(data)
        DB_PASSWORD = "admin123"  # 硬编码
        save_to_db(result, DB_PASSWORD)
    except:  # 捕获所有异常
        print("错误")
    return result
```

**正确的方式：**
```python
# ✅ 规范的写法
import logging
from pydantic import BaseModel, ValidationError
import os

logger = logging.getLogger(__name__)

class DataRequest(BaseModel):
    """数据请求"""
    content: str

def process(data: str) -> dict:
    """处理数据

    Args:
        data: JSON 格式的数据字符串

    Returns:
        处理结果字典

    Raises:
        ValidationError: 数据验证失败
        DatabaseError: 数据库操作失败
    """
    try:
        # 1. 验证输入
        request = DataRequest(content=data)

        # 2. 处理数据
        result = json.loads(request.content)

        # 3. 存储数据（从环境变量读密码）
        db_password = os.getenv("DB_PASSWORD")
        save_to_db(result, db_password)

        logger.info(f"数据处理成功，项目数: {len(result)}")
        return result

    except ValidationError as e:
        logger.error(f"输入验证失败: {e}")
        raise
    except DatabaseError as e:
        logger.error(f"数据库错误: {e}", exc_info=True)
        raise
```

---

## 21. 持续改进

### 定期代码审查

**审查频率：** 每周一次

**审查内容：**
- [ ] 是否所有函数都有类型注解和 docstring？
- [ ] 是否有重复代码应该提取？
- [ ] 是否有函数超过 40 行应该拆分？
- [ ] 是否有硬编码的值应该使用常量？
- [ ] 是否有不必要的复杂性可以简化？

### 技术债务跟踪

使用以下标签标记需要改进的代码：

```python
# TODO: 添加用户输入验证
# FIXME: 这里有性能问题
# HACK: 临时方案，待重构
# BUG: 已知的 bug，需要修复
```

### 参考资源

- [PEP 8 风格指南](https://www.python.org/dev/peps/pep-0008/)
- [Google Python 风格指南](https://google.github.io/styleguide/pyguide.html)
- [Clean Code in Python](https://www.oreilly.com/library/view/clean-code-in/9781788835831/)
- [Architecture Patterns with Python](https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/)

---

## 最终提醒 ⚡

**这不是建议，而是必须严格执行的开发标准！**

每次编写代码时，都要问自己：

1. ✅ 这段代码是否符合 PEP 8？
2. ✅ 是否添加了类型注解和 docstring？
3. ✅ 是否处理了所有异常情况？
4. ✅ 是否编写了 ≥80% 覆盖率的测试？
5. ✅ 是否存在安全隐患（硬编码、注入等）？
6. ✅ 六个月后的我能看懂这段代码吗？
7. ✅ 通过了所有质量检查（black、ruff、mypy、pytest）？

**目标：编写让团队赞赏、未来的自己感谢的高质量代码！** 🎯