pyproject.toml能统一环境配置,但必须严格遵循PEP 621标准:Python版本和运行依赖写在[project]下,dev/test依赖用[project.optional-dependencies]声明,工具配置放[tool.*]下,且[build-system]需匹配构建后端与版本。

直接用 pyproject.toml 就能统一环境配置,但前提是别把它当“另一个 requirements.txt”来填依赖——它管的是构建、运行、开发全链路,填错位置或混用工具语义会导致 pip 安装失败、uv run 找不到入口、甚至 CI 里测试跑不起来。
把 Python 版本和基础依赖写进 [project] 而不是 [tool.poetry]
很多人从 Poetry 迁移过来,习惯性把 python = "^3.10" 写在 [tool.poetry.dependencies] 下,结果用 pip install . 安装时完全不校验 Python 版本,直到运行时报 ModuleNotFoundError 才发现是解释器太老。
-
[project]下的requires-python = ">=3.10"是 PEP 621 强制字段,pip 和 uv 都会检查,安装前就报错 -
dependencies必须写在[project]下,不是[tool.poetry.dependencies]或[tool.setuptools]—— 后者只被对应工具读,pip 不认 - 如果项目同时支持 Poetry 和标准 pip 构建,删掉整个
[tool.poetry]段,改用纯 PEP 621 语法,否则 Poetry 会覆盖[project]的依赖解析逻辑
区分 dev 和 test 依赖要用 [project.optional-dependencies]
写成 pip install -r requirements-dev.txt 是倒退。现代方式是声明式分组,然后按需激活:
- 必须用
[project.optional-dependencies],不是[tool.black]或自定义 key;否则pip install ".[dev]"会静默忽略 - 常见错误:把
pytest放进dev组却没在 CI 中加[test]组,导致pip install ".[test]"报错找不到pytest - 推荐最小分组:
dev = ["black", "ruff"]、test = ["pytest", "pytest-cov"]、docs = ["sphinx"],避免混合职责
工具配置(如 black、ruff)必须放在 [tool.<name>]</name> 下且路径正确
black 不读 [project] 下的配置,ruff 也不认 [tool.black] —— 错放位置等于没配。
立即学习“Python免费学习笔记(深入)”;
-
[tool.black]控制格式化行为,line-length = 88有效;但写成[tool.ruff.black]或[black]就完全失效 -
[tool.ruff.lint]和[tool.ruff.format]是两个独立表,select = ["E"]在 lint 下才起作用,format 下写无效 - 用
uv run black .时,uv会自动识别[tool.black],但前提是black已声明在[project.optional-dependencies.dev]里,否则命令根本不存在
[build-system] 的 requires 版本必须与实际构建兼容
写 requires = ["setuptools>=42"] 看似安全,但在 2026 年已过时:新版 setuptools 默认禁用旧插件机制,会导致 python -m build 报 ImportError: cannot import name 'find_packages'。
- 当前稳定组合是:
requires = ["setuptools>=61.0", "wheel"]或requires = ["hatchling"](更轻量) -
build-backend必须匹配requires里的包:选setuptools.build_meta就不能漏掉setuptools;选hatchling.build就得把hatchling加进requires - CI 中如果用
pip install --upgrade pip,可能意外升级到不兼容的setuptools,建议显式固定:pip install "setuptools>=61.0,
最容易被忽略的其实是 requires-python 和 optional-dependencies 的联动:当你在 GitHub Actions 里用 ubuntu-22.04 默认 Python 3.10,但本地用 3.12 开发,仅靠 pyenv 切换版本不够——pip install ".[dev]" 会在 CI 里跳过所有 platform_system == 'Darwin' 的依赖,而你根本不会意识到它们没装上。


















