pyproject.toml 指南:現代 Python 項目配置
pyproject.toml 是由 PEP 518 和 PEP 621 定義的 Python 項目標準化配置文件。它作為項目元數據、依賴項、構建系統和工具設置的單一事實來源。
為什麼要使用 pyproject.toml?
傳統與現代
歷史上,Python 項目使用多個文件(setup.py、setup.cfg、requirements.txt、.flake8)。現代項目將這些整合到 pyproject.toml 中。
| 方面 | 傳統方式 | 現代方式 (pyproject.toml) |
|---|---|---|
| 格式 | Python 代碼 / INI | 聲明式 TOML |
| 位置 | 多個文件 | 單個文件 |
| 安全性 | 可執行(有風險) | 靜態(安全) |
| 標準 | 僅限 setuptools | 工具無關 (PEP) |
核心章節
[build-system]
定義項目的構建方式。
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
標準化元數據 (PEP 621)。
[project]
name = "my-package"
version = "0.1.0"
description = "我的優秀 Python 項目"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
authors = [{name = "John Doe", email = "john@example.com"}]
dependencies = [
"requests>=2.28.0",
"click>=8.0.0",
]
[project.optional-dependencies]
定義用於開發、測試或可選功能的「extras」。
[project.optional-dependencies]
dev = ["pytest", "black", "ruff"]
docs = ["sphinx", "mkdocs"]
工具配置
大多數現代 Python 工具允許直接在 pyproject.toml 中進行配置。
Ruff (代碼檢查與格式化)
Ruff 是一個現代、快速(基於 Rust)的檢查器,可替代多個傳統工具:Flake8、isort、Black 等。
[tool.ruff]
line-length = 88
target-version = "py312"
[tool.ruff.lint]
select = [
"E", "F", "W", # 默認 flake8
"I", # isort (匯入排序)
"UP", # pyupgrade
"S", # bandit (安全)
"B", # bugbear
]
[tool.ruff.lint.isort]
known-first-party = ["my_package"]
force-sort-within-sections = true
combine-as-imports = true
lines-after-imports = 2
核心匯入規則
- "I":啟用匯入排序和分組(替代 isort)
- F401:檢測未使用的匯入
- F403:檢測
from module import *(命名空間污染)
Pytest
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-ra -q"
Black
[tool.black]
line-length = 88
target-version = ['py311']
最佳實踐
- 聲明優先:除非有需要自定義構建邏輯的複雜 C 擴展,否則避免使用
setup.py。 - 標準元數據:盡可能使用
[project]章節,而不是工具特定的章節(如[tool.poetry]),以保持可移植性。 - 最小版本限制:對庫依賴項使用
>=以保持靈活性,但對應用程序使用精確版本或鎖定文件。 - 工具整合:將所有工具配置(Ruff、Mypy、Pytest)移動到
pyproject.toml中,以減少根目錄的雜亂。
遷移示例
舊的 setup.py:
from setuptools import setup
setup(name="pkg", version="0.1", install_requires=["requests"])
新的 pyproject.toml:
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "pkg"
version = "0.1"
dependencies = ["requests"]