298 lines
7.1 KiB
Markdown
298 lines
7.1 KiB
Markdown
|
|
---
|
|||
|
|
description: 對 Python 程式碼進行全面審查,包含 PEP 8 規範、型別提示、安全性及 Python 慣用法。此指令會呼叫 python-reviewer agent。
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Python 程式碼審查 (Python Code Review)
|
|||
|
|
|
|||
|
|
此指令會呼叫 **python-reviewer** agent 來進行針對 Python 語言特性的全面審查。
|
|||
|
|
|
|||
|
|
## 此指令的功能
|
|||
|
|
|
|||
|
|
1. **識別 Python 變更**:透過 `git diff` 找出修改過的 `.py` 檔案。
|
|||
|
|
2. **執行靜態分析**:執行 `ruff`, `mypy`, `pylint`, `black --check`。
|
|||
|
|
3. **安全掃描**:檢查是否存在 SQL 注入、指令注入、不安全的反序列化。
|
|||
|
|
4. **型別安全審查**:分析型別提示 (Type hints) 與 mypy 錯誤。
|
|||
|
|
5. **Pythonic 檢查**:驗證程式碼是否遵循 PEP 8 與 Python 最佳實踐。
|
|||
|
|
6. **產生報告**:按嚴重程度對問題進行分類。
|
|||
|
|
|
|||
|
|
## 何時使用
|
|||
|
|
|
|||
|
|
在以下情況使用 `/python-review`:
|
|||
|
|
- 撰寫或修改 Python 程式碼後。
|
|||
|
|
- 提交 Python 變更前。
|
|||
|
|
- 審查包含 Python 程式碼的 Pull Request 時。
|
|||
|
|
- 進入新的 Python 專案庫時。
|
|||
|
|
- 學習 Pythonic 模式與慣用法時。
|
|||
|
|
|
|||
|
|
## 審查類別
|
|||
|
|
|
|||
|
|
### 關鍵問題 (CRITICAL - 必須修復)
|
|||
|
|
- SQL/指令注入漏洞。
|
|||
|
|
- 不安全的 `eval()`/`exec()` 使用。
|
|||
|
|
- Pickle 不安全的反序列化。
|
|||
|
|
- 硬編碼的憑據。
|
|||
|
|
- YAML 不安全的 `load()` (應使用 `safe_load()`)。
|
|||
|
|
- 隱藏錯誤的空 `except` 區塊。
|
|||
|
|
|
|||
|
|
### 高優先級 (HIGH - 建議修復)
|
|||
|
|
- 公共函式缺少型別提示。
|
|||
|
|
- 使用可變物件作為預設參數 (Mutable default arguments)。
|
|||
|
|
- 靜默吞掉異常 (Swallowing exceptions)。
|
|||
|
|
- 資源使用未採用上下文管理器 (Context managers)。
|
|||
|
|
- 使用 C 風格迴圈而非列表推導式 (Comprehensions)。
|
|||
|
|
- 使用 `type()` 而非 `isinstance()`。
|
|||
|
|
- 無鎖機制下的競態條件。
|
|||
|
|
|
|||
|
|
### 中優先級 (MEDIUM - 考慮調整)
|
|||
|
|
- 違反 PEP 8 格式規範。
|
|||
|
|
- 公共函式缺少 Docstrings。
|
|||
|
|
- 使用 `print` 語句而非 `logging`。
|
|||
|
|
- 低效的字串操作。
|
|||
|
|
- 未使用具名常數的魔術數字 (Magic numbers)。
|
|||
|
|
- 未使用 f-strings 進行格式化。
|
|||
|
|
- 不必要的列表建立。
|
|||
|
|
|
|||
|
|
## 執行的自動化檢查
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 型別檢查
|
|||
|
|
mypy .
|
|||
|
|
|
|||
|
|
# Lint 與格式檢查
|
|||
|
|
ruff check .
|
|||
|
|
black --check .
|
|||
|
|
isort --check-only .
|
|||
|
|
|
|||
|
|
# 安全掃描
|
|||
|
|
bandit -r .
|
|||
|
|
|
|||
|
|
# 依賴項稽核
|
|||
|
|
pip-audit
|
|||
|
|
safety check
|
|||
|
|
|
|||
|
|
# 測試
|
|||
|
|
pytest --cov=app --cov-report=term-missing
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 使用範例
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
使用者:/python-review
|
|||
|
|
|
|||
|
|
Agent:
|
|||
|
|
# Python 程式碼審查報告
|
|||
|
|
|
|||
|
|
## 審查檔案
|
|||
|
|
- app/routes/user.py (已修改)
|
|||
|
|
- app/services/auth.py (已修改)
|
|||
|
|
|
|||
|
|
## 靜態分析結果
|
|||
|
|
✓ ruff: 無問題
|
|||
|
|
✓ mypy: 無錯誤
|
|||
|
|
⚠️ black: 2 個檔案需要重新格式化
|
|||
|
|
✓ bandit: 無安全問題
|
|||
|
|
|
|||
|
|
## 發現問題
|
|||
|
|
|
|||
|
|
[CRITICAL] SQL 注入漏洞
|
|||
|
|
檔案: app/routes/user.py:42
|
|||
|
|
問題: 使用者輸入直接插入 SQL 查詢字串
|
|||
|
|
```python
|
|||
|
|
query = f"SELECT * FROM users WHERE id = {user_id}" # 錯誤
|
|||
|
|
```
|
|||
|
|
修復方案: 使用參數化查詢
|
|||
|
|
```python
|
|||
|
|
query = "SELECT * FROM users WHERE id = %s" # 正確
|
|||
|
|
cursor.execute(query, (user_id,))
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
[HIGH] 可變預設參數 (Mutable default argument)
|
|||
|
|
檔案: app/services/auth.py:18
|
|||
|
|
問題: 可變預設參數會導致狀態共享
|
|||
|
|
```python
|
|||
|
|
def process_items(items=[]): # 錯誤
|
|||
|
|
items.append("new")
|
|||
|
|
return items
|
|||
|
|
```
|
|||
|
|
修復方案: 使用 None 作為預設值
|
|||
|
|
```python
|
|||
|
|
def process_items(items=None): # 正確
|
|||
|
|
if items is None:
|
|||
|
|
items = []
|
|||
|
|
items.append("new")
|
|||
|
|
return items
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
[MEDIUM] 缺少型別提示
|
|||
|
|
檔案: app/services/auth.py:25
|
|||
|
|
問題: 公共函式缺少型別註解
|
|||
|
|
```python
|
|||
|
|
def get_user(user_id): # 錯誤
|
|||
|
|
return db.find(user_id)
|
|||
|
|
```
|
|||
|
|
修復方案: 加入型別提示
|
|||
|
|
```python
|
|||
|
|
def get_user(user_id: str) -> Optional[User]: # 正確
|
|||
|
|
return db.find(user_id)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
[MEDIUM] 未使用上下文管理器
|
|||
|
|
檔案: app/routes/user.py:55
|
|||
|
|
問題: 發生異常時檔案未關閉
|
|||
|
|
```python
|
|||
|
|
f = open("config.json") # 錯誤
|
|||
|
|
data = f.read()
|
|||
|
|
f.close()
|
|||
|
|
```
|
|||
|
|
修復方案: 使用 context manager
|
|||
|
|
```python
|
|||
|
|
with open("config.json") as f: # 正確
|
|||
|
|
data = f.read()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 摘要
|
|||
|
|
- CRITICAL: 1
|
|||
|
|
- HIGH: 1
|
|||
|
|
- MEDIUM: 2
|
|||
|
|
|
|||
|
|
建議: ❌ 在修復 CRITICAL 問題前,禁止合併 (Block merge)
|
|||
|
|
|
|||
|
|
## 所需格式化
|
|||
|
|
請執行:`black app/routes/user.py app/services/auth.py`
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 核准標準
|
|||
|
|
|
|||
|
|
| 狀態 | 條件 |
|
|||
|
|
|--------|-----------|
|
|||
|
|
| ✅ 核准 (Approve) | 無 CRITICAL 或 HIGH 問題 |
|
|||
|
|
| ⚠️ 警告 (Warning) | 僅存在 MEDIUM 問題 (謹慎合併) |
|
|||
|
|
| ❌ 阻斷 (Block) | 發現 CRITICAL 或 HIGH 問題 |
|
|||
|
|
|
|||
|
|
## 與其他指令的整合
|
|||
|
|
|
|||
|
|
- 先使用 `/tdd` 確保測試通過。
|
|||
|
|
- 對於非 Python 特有的通用問題,請使用 `/code-review`。
|
|||
|
|
- 在提交前使用 `/python-review`。
|
|||
|
|
- 若靜態分析工具失敗,則使用 `/build-fix`。
|
|||
|
|
|
|||
|
|
## 框架特定審查
|
|||
|
|
|
|||
|
|
### Django 專案
|
|||
|
|
審查者會檢查:
|
|||
|
|
- N+1 查詢問題 (應使用 `select_related` 與 `prefetch_related`)。
|
|||
|
|
- 模型變更但缺少 Migrations。
|
|||
|
|
- 在能使用 ORM 時使用了原生 SQL。
|
|||
|
|
- 多步驟操作缺少 `transaction.atomic()`。
|
|||
|
|
|
|||
|
|
### FastAPI 專案
|
|||
|
|
審查者會檢查:
|
|||
|
|
- CORS 配置錯誤。
|
|||
|
|
- 使用 Pydantic 模型進行請求驗證。
|
|||
|
|
- 回應模型 (Response models) 的正確性。
|
|||
|
|
- 正確使用 async/await。
|
|||
|
|
- 依賴注入模式。
|
|||
|
|
|
|||
|
|
### Flask 專案
|
|||
|
|
審查者會檢查:
|
|||
|
|
- 上下文管理 (App context, Request context)。
|
|||
|
|
- 正確的錯誤處理。
|
|||
|
|
- Blueprint 結構組織。
|
|||
|
|
- 配置管理。
|
|||
|
|
|
|||
|
|
## 相關參考
|
|||
|
|
|
|||
|
|
- Agent: `agents/python-reviewer.md`
|
|||
|
|
- 技能: `skills/python-patterns/`, `skills/python-testing/`
|
|||
|
|
|
|||
|
|
## 常見修復方法範例
|
|||
|
|
|
|||
|
|
### 加入型別提示
|
|||
|
|
```python
|
|||
|
|
# 修復前
|
|||
|
|
def calculate(x, y):
|
|||
|
|
return x + y
|
|||
|
|
|
|||
|
|
# 修復後
|
|||
|
|
from typing import Union
|
|||
|
|
|
|||
|
|
def calculate(x: Union[int, float], y: Union[int, float]) -> Union[int, float]:
|
|||
|
|
return x + y
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 使用上下文管理器
|
|||
|
|
```python
|
|||
|
|
# 修復前
|
|||
|
|
f = open("file.txt")
|
|||
|
|
data = f.read()
|
|||
|
|
f.close()
|
|||
|
|
|
|||
|
|
# 修復後
|
|||
|
|
with open("file.txt") as f:
|
|||
|
|
data = f.read()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 使用列表推導式 (List Comprehensions)
|
|||
|
|
```python
|
|||
|
|
# 修復前
|
|||
|
|
result = []
|
|||
|
|
for item in items:
|
|||
|
|
if item.active:
|
|||
|
|
result.append(item.name)
|
|||
|
|
|
|||
|
|
# 修復後
|
|||
|
|
result = [item.name for item in items if item.active]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 修正可變預設參數
|
|||
|
|
```python
|
|||
|
|
# 修復前
|
|||
|
|
def append(value, items=[]):
|
|||
|
|
items.append(value)
|
|||
|
|
return items
|
|||
|
|
|
|||
|
|
# 修復後
|
|||
|
|
def append(value, items=None):
|
|||
|
|
if items is None:
|
|||
|
|
items = []
|
|||
|
|
items.append(value)
|
|||
|
|
return items
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 使用 f-strings (Python 3.6+)
|
|||
|
|
```python
|
|||
|
|
# 修復前
|
|||
|
|
name = "Alice"
|
|||
|
|
greeting = "Hello, " + name + "!"
|
|||
|
|
greeting2 = "Hello, {}".format(name)
|
|||
|
|
|
|||
|
|
# 修復後
|
|||
|
|
greeting = f"Hello, {name}!"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 修正迴圈中的字串拼接
|
|||
|
|
```python
|
|||
|
|
# 修復前
|
|||
|
|
result = ""
|
|||
|
|
for item in items:
|
|||
|
|
result += str(item)
|
|||
|
|
|
|||
|
|
# 修復後
|
|||
|
|
result = "".join(str(item) for item in items)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Python 版本相容性
|
|||
|
|
|
|||
|
|
審查者會指示程式碼何時使用了較新版本的特性:
|
|||
|
|
|
|||
|
|
| 特性 | 最低 Python 版本 |
|
|||
|
|
|---------|----------------|
|
|||
|
|
| 型別提示 (Type hints) | 3.5+ |
|
|||
|
|
| f-strings | 3.6+ |
|
|||
|
|
| 海象運算子 (Walrus operator `:=`) | 3.8+ |
|
|||
|
|
| 僅限位置參數 (Position-only) | 3.8+ |
|
|||
|
|
| Match 語句 | 3.10+ |
|
|||
|
|
| 型別聯集 (Type unions `x | None`) | 3.10+ |
|
|||
|
|
|
|||
|
|
請確保您的 `pyproject.toml` 或 `setup.py` 指定了正確的最低 Python 版本。
|