跳至主要内容

pyproject.toml 指南:現代 Python 項目配置

pyproject.toml 是由 PEP 518 和 PEP 621 定義的 Python 項目標準化配置文件。它作為項目元數據、依賴項、構建系統和工具設置的單一事實來源。

為什麼要使用 pyproject.toml?

傳統與現代

歷史上,Python 項目使用多個文件(setup.pysetup.cfgrequirements.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']

最佳實踐

  1. 聲明優先:除非有需要自定義構建邏輯的複雜 C 擴展,否則避免使用 setup.py
  2. 標準元數據:盡可能使用 [project] 章節,而不是工具特定的章節(如 [tool.poetry]),以保持可移植性。
  3. 最小版本限制:對庫依賴項使用 >= 以保持靈活性,但對應用程序使用精確版本或鎖定文件。
  4. 工具整合:將所有工具配置(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"]