Python 標準
此技能是 Python 工具鏈與跨專案規則的單一事實來源。架構、風格、測試與審查技能應參考此處,而非重複定義。
對於專案中的非程式碼文字,請同時載入 technical-writing。它會呼叫 humanizer,並負責文件位置、時間戳、審查中繼資料、可讀性與寫作品質。
規則優先順序
按以下順序套用規則:
- 明確的使用者或組織需求
- 儲存庫配置與已接受的架構決策
- 此技能與其他 Python 技能
- PEP 8 與工具預設值
請勿在未記錄的情況下削弱安全底線。若需例外,請在專案的決策記錄中載明:必要例外、其範圍、風險、已知負責人及移除條件。
執行環境與佈局
- 目標 Python 3.11 或更新版本。若儲存庫指定了更新版本,請遵循之。
- 當
from __future__ import annotations可改善向前相容性或解決註解順序問題時使用。請勿機械性地加入不需要的檔案。 - 對於新的可分發套件,偏好使用
src/佈局。 - 將專案中繼資料與支援的工具配置保留在
pyproject.toml中。 - 使用
uv管理環境、依賴解析、鎖定及命令執行。
支援的工具鏈
| 用途 | 預設工具 | 強制使用範圍 |
|---|---|---|
| 格式化與語法檢查 | Ruff | 所有維護中的專案 |
| 型態檢查 | mypy strict | 正式發布套件與公開 API |
| 測試與涵蓋率 | pytest, pytest-cov, coverage.py | 所有行為變更 |
| 安全性語法檢查 | Ruff S 規則與 Bandit | 正式發布套件 |
| 靜態應用程式安全測試 (SAST) | Semgrep 搭配儲存庫規則 | CI 中維護的產品 |
| 依賴稽核 | pip-audit | CI 與發布檢查 |
| 結構化日誌 | structlog | 應用程式與服務 |
| 追蹤 | OpenTelemetry | 網路服務與有追蹤的管線 |
| 套件管理 | uv | 所有專案 |
| Git 掛鉤 | pre-commit | 維護中的儲存庫 |
| 秘密傳遞 | Infisical (組織預設) | 使用秘密的工作負載 |
已接受的架構決策可選擇等效的廠商工具,或為小型本地函式庫/腳本省略不適用的營運工具。Ruff、型態檢查、測試與安全依賴處理仍為最低要求。
實驗性工具(包括基於模型的弱點掃描器與 AI 審查者)僅供參考。在團隊定義支援版本、命令、失敗政策與負責人之前,不得將其設為強制閘道。
依賴與版本政策
- 在
pyproject.toml中宣告相容的執行時期範圍。 - 對於應用程式與可重現的開發環境,請提交
uv.lock。鎖定檔案擁有精確的解析版本。 - 對於發布的函式庫,請宣告誠實的下限,測試支援的 Python 版本與重要的下限,並且不依賴鎖定檔案作為消費者合約。
- 將品質與測試工具放在具名依賴群組中。
- 透過鎖定的 uv 環境執行品質命令。請勿在 pre-commit 中維護第二組 Python 工具版本。
- 使用
uv lock --upgrade-package <name>或經過審查的完整鎖定重新整理來有計劃地升級。
用於 uv 專案的標準依賴稽核方式:
requirements_file="$(mktemp)"
trap 'rm -f "$requirements_file"' EXIT
uv export \
--frozen \
--no-dev \
--no-emit-project \
--no-hashes \
--format requirements.txt \
--output-file "$requirements_file"
uv run --frozen pip-audit \
--strict \
--no-deps \
--requirement "$requirements_file"
此匯出會稽核精確鎖定的執行時期依賴,而無需要求 pip-audit 解析第二個依賴圖。目前的 pip-audit --locked 專案發現支援 pyproject.toml 與 pylock.*.toml,但不支援 uv.lock,因此請勿對 uv 專案使用 pip-audit --locked .。
pip-audit 必須存在於品質依賴群組中。弱點豁免必須指明:建議編號、受影響範圍、補償控制措施、已知負責人,以及到期或審查日期。
標準品質命令
根據儲存庫調整套件路徑,但保留一個命令來源供本地使用與 CI 使用:
uv sync --frozen
uv run --frozen ruff check .
uv run --frozen ruff format --check .
uv run --frozen mypy <package-roots>
uv run --frozen bandit -c pyproject.toml -r <package-roots>
uv run --frozen semgrep scan --config .semgrep.yml <package-roots>
uv run --frozen pytest
# 執行上方的標準匯出鎖定依賴稽核。
CI 會記錄命令及其結果。缺少工具或配置時,狀態為 unavailable(不可用),而非通過。
Pre-commit 所有權
按發布版本鎖定非 Python 的衛生掛鉤。將 Python 品質工具作為本地掛鉤透過 uv run --frozen 呼叫,使本地掛鉤與 CI 使用 uv.lock 中的精確版本。
repos:
- repo: local
hooks:
- id: ruff-check
name: ruff check
entry: uv run --frozen ruff check --fix
language: system
types_or: [python, pyi]
- id: ruff-format
name: ruff format
entry: uv run --frozen ruff format
language: system
types_or: [python, pyi]
- id: mypy
name: mypy
entry: uv run --frozen mypy
language: system
pass_filenames: false
args: [<package-roots>]
在 CI 中執行 Bandit、Semgrep、測試與依賴稽核。僅當其延遲與依賴關係適合該儲存庫時,才將它們加入 pre-commit。
最低 pyproject.toml 配置決策
使用儲存庫的套件名稱與根目錄,而非複製預留位置。
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "B", "S", "UP", "C4", "SIM", "RUF", "D"]
ignore = ["E501"]
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.mypy]
python_version = "3.11"
strict = true
warn_return_any = true
warn_unused_configs = true
ignore_missing_imports = false
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-ra --strict-markers --tb=short --import-mode=importlib"
[tool.coverage.run]
branch = true
source_pkgs = ["your_package"]
[tool.coverage.report]
fail_under = 80
show_missing = true
[tool.bandit]
exclude_dirs = ["tests"]
skips = ["B101"]
對每個忽略規則註明其狹窄範圍與原因。偏好使用按檔案忽略規則,而非全域忽略。
結構化日誌規範
應用程式應輸出以下欄位。函式庫可使用宿主應用程式的日誌抽象層,且不得在匯入時配置全域處理器。
| 欄位 | 需求 | 意義 |
|---|---|---|
timestamp | 總是 | ISO 8601 UTC |
level | 總是 | DEBUG, INFO, WARNING, ERROR, 或 CRITICAL |
event | 總是 | 穩定的蛇形命名事件名稱 |
service | 應用程式總是需要 | 服務或應用程式名稱 |
trace_id | 存在追蹤時 | OpenTelemetry 追蹤 ID |
span_id | 存在跨度時 | OpenTelemetry 跨度 ID |
error | 失敗時 | 安全的例外類型與訊息 |
duration_ms | 測量操作時 | 經過的毫秒數 |
Structlog 的層級處理器通常接收小寫方法名稱。請在加入層級後進行正規化:
from typing import Any
import structlog
def uppercase_log_level(
_logger: Any,
_method_name: str,
event_dict: dict[str, Any],
) -> dict[str, Any]:
"""將結構化日誌層級正規化為共享綱要。"""
level = event_dict.get("level")
if isinstance(level, str):
event_dict["level"] = level.upper()
return event_dict
processors = [
structlog.processors.add_log_level,
uppercase_log_level,
structlog.processors.TimeStamper(fmt="iso", utc=True),
]
應測試最終渲染的事件,而非僅測試隔離的處理器。
安全底線
絕不:
- 提交或硬編碼憑證、Token、私鑰或真實機密值
- 將真實機密儲存在
.env或 TOML 檔案中 - 記錄機密、存取令牌、敏感個人資料或未限制的請求正文
- 將外部值插入 SQL 中
- 使用
shell=True搭配外部或可變輸入 - 反序列化不受信任的 pickle 資料
- 使用
eval、exec或compile執行不受信任的輸入 - 使用可變預設引數
- 使用萬用字元匯入,除非是已文件化的公開重新匯出
- 靜默地丟棄安全敏感的返回值或例外
- 使用裸的
except:
僅在進程、工作者、任務或框架邊界處捕獲 Exception,此時處理器會安全地記錄、然後重新拋出、將失敗映射為退出狀態,或回傳已定義的通訊協定錯誤。在應用程式邏輯中捕獲特定的例外。
將一般設定與機密引用儲存在配置檔案中。在啟動時透過 Infisical 注入或經批准的等效方式傳遞機密值。在接受工作之前驗證必要配置。