当前位置: 代码网 > it编程>前端脚本>Python > Python项目配置文件pyproject.toml的完全指南

Python项目配置文件pyproject.toml的完全指南

2026年02月06日 Python 我要评论
前言如果你刚接触 python 项目开发,可能会发现很多开源项目的根目录下都有一个 pyproject.toml 文件。它是什么?为什么需要它?本文将从零开始,带你全面了解这个 python 生态中的

前言

如果你刚接触 python 项目开发,可能会发现很多开源项目的根目录下都有一个 pyproject.toml 文件。它是什么?为什么需要它?本文将从零开始,带你全面了解这个 python 生态中的"配置中枢"。

一、什么是 pyproject.toml?

1.1 定义

pyproject.toml 是 python 项目的标准化配置文件,采用 toml (tom’s obvious minimal language) 格式编写。它在 2016 年通过 pep 518 被引入 python 生态。

1.2 为什么需要它?

pyproject.toml 出现之前,python 项目的配置非常混乱:

文件名作用问题
setup.py定义包的安装配置代码形式,容易出错
setup.cfgsetup.py 的配置版本格式陈旧
requirements.txt列出依赖无法表达复杂依赖关系
manifest.in指定打包文件额外文件
tox.ini测试配置专用文件
.flake8代码检查配置专用文件

问题总结

  • 配置文件分散,难以管理
  • 格式不统一(ini、python 代码、纯文本)
  • 缺乏标准化

pyproject.toml 的解决方案

  • ✅ 一个文件统一管理
  • ✅ 现代化的 toml 格式
  • ✅ python 官方标准

二、toml 格式速成

在深入 pyproject.toml 之前,先了解 toml 的基本语法:

# 这是注释

# 键值对
name = "my-project"
version = "1.0.0"

# 数组
dependencies = [
    "requests>=2.28.0",
    "numpy>=1.20.0"
]

# 表(类似于字典/对象)
[tool.black]
line-length = 88
target-version = ['py38']

# 嵌套表
[project.optional-dependencies]
dev = ["pytest>=7.0", "black>=22.0"]
docs = ["sphinx>=4.0"]

特点

  • 简洁易读
  • 支持注释
  • 类型明确(字符串、数字、布尔值、数组、表)

三、pyproject.toml 的核心结构

一个完整的 pyproject.toml 通常包含以下几个部分:

[build-system]          # 构建系统配置
[project]               # 项目元数据
[project.optional-dependencies]  # 可选依赖
[tool.xxx]              # 各种工具的配置

让我们逐一解析。

四、详细解析各个部分

4.1 [build-system] - 构建系统配置

这是 pyproject.toml必需部分,告诉 python 如何构建你的项目。

[build-system]
requires = ["setuptools>=45", "wheel"]
build-backend = "setuptools.build_meta"

字段说明

字段说明示例
requires构建项目所需的依赖包["setuptools>=45", "wheel"]
build-backend指定使用哪个构建后端setuptools.build_meta

常见构建后端

setuptools(传统方式)

[build-system]
requires = ["setuptools>=45", "wheel"]
build-backend = "setuptools.build_meta"

poetry(现代化工具)

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

flit(轻量级)

[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"

hatchling(新兴工具)

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

4.2 [project] - 项目元数据

定义项目的基本信息和依赖关系。

[project]
name = "my-awesome-package"
version = "1.0.0"
description = "一个很棒的 python 包"
readme = "readme.md"
requires-python = ">=3.8"
license = {text = "mit"}
authors = [
    {name = "张三", email = "zhangsan@example.com"}
]
maintainers = [
    {name = "李四", email = "lisi@example.com"}
]
keywords = ["web", "api", "framework"]
classifiers = [
    "development status :: 4 - beta",
    "intended audience :: developers",
    "license :: osi approved :: mit license",
    "programming language :: python :: 3",
    "programming language :: python :: 3.8",
    "programming language :: python :: 3.9",
    "programming language :: python :: 3.10",
]

dependencies = [
    "requests>=2.28.0,<3.0.0",
    "click>=8.0.0",
    "pydantic>=2.0.0"
]

[project.urls]
homepage = "https://github.com/username/my-awesome-package"
documentation = "https://my-awesome-package.readthedocs.io"
repository = "https://github.com/username/my-awesome-package"
changelog = "https://github.com/username/my-awesome-package/blob/main/changelog.md"

字段详解

字段必需?说明
name包名(发布到 pypi 的名称)
version版本号(遵循 semver 规范)
description简短描述
readmereadme 文件路径
requires-python支持的 python 版本
license开源协议
authors作者列表
dependencies运行时依赖

4.3 [project.optional-dependencies] - 可选依赖

用于定义不同场景下的额外依赖,比如开发、测试、文档等。

[project.optional-dependencies]
# 开发依赖
dev = [
    "pytest>=7.0",
    "pytest-cov>=4.0",
    "black>=22.0",
    "ruff>=0.1.0",
    "mypy>=1.0"
]

# 测试依赖
test = [
    "pytest>=7.0",
    "pytest-asyncio>=0.21.0",
    "httpx>=0.24.0"
]

# 文档依赖
docs = [
    "sphinx>=4.0",
    "sphinx-rtd-theme>=1.0"
]

# 所有依赖
all = [
    "my-awesome-package[dev,test,docs]"
]

使用方式

# 安装基础依赖
pip install my-awesome-package

# 安装开发依赖
pip install my-awesome-package[dev]

# 安装多个可选依赖组
pip install my-awesome-package[dev,test]

# 安装所有依赖
pip install my-awesome-package[all]

4.4 [project.scripts] - 命令行入口

定义安装后可在命令行直接调用的命令。

[project.scripts]
my-cli = "my_package.cli:main"
my-tool = "my_package.tools:run"

示例场景

假设你有以下代码结构:

my_package/
  ├── __init__.py
  └── cli.py

cli.py 内容:

def main():
    print("hello from my-cli!")

if __name__ == "__main__":
    main()

安装后,用户可以直接运行:

my-cli
# 输出:hello from my-cli!

4.5 [tool.*] - 工具配置

这是 pyproject.toml 最强大的功能之一:集中管理各种开发工具的配置。

4.5.1 pytest(测试框架)

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["test*"]
python_functions = ["test_*"]
addopts = [
    "--cov=my_package",
    "--cov-report=html",
    "--cov-report=term-missing",
    "-v"
]

4.5.2 black(代码格式化)

[tool.black]
line-length = 88
target-version = ['py38', 'py39', 'py310']
include = '\.pyi?$'
extend-exclude = '''
/(
  # 排除的目录
  \.eggs
  | \.git
  | \.venv
  | build
  | dist
)/
'''

4.5.3 ruff(快速 linter)

[tool.ruff]
line-length = 88
target-version = "py38"

[tool.ruff.lint]
select = [
    "e",   # pycodestyle errors
    "w",   # pycodestyle warnings
    "f",   # pyflakes
    "i",   # isort
    "b",   # flake8-bugbear
    "c4",  # flake8-comprehensions
]
ignore = [
    "e501",  # 行过长(由 black 处理)
    "b008",  # 函数调用中的参数默认值
]

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["f401"]  # 允许未使用的导入

4.5.4 mypy(类型检查)

[tool.mypy]
python_version = "3.8"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
no_implicit_optional = true

[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false

4.5.5 coverage(代码覆盖率)

[tool.coverage.run]
source = ["my_package"]
omit = [
    "*/tests/*",
    "*/__init__.py"
]

[tool.coverage.report]
exclude_lines = [
    "pragma: no cover",
    "def __repr__",
    "raise assertionerror",
    "raise notimplementederror",
    "if __name__ == .__main__.:",
]

五、实战案例:完整的 pyproject.toml

下面是一个生产环境级别的完整示例:

[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "data-processor"
version = "2.3.1"
description = "一个强大的数据处理库"
readme = "readme.md"
requires-python = ">=3.8"
license = {text = "mit"}
authors = [
    {name = "数据团队", email = "data@company.com"}
]
keywords = ["data", "processing", "etl", "pipeline"]
classifiers = [
    "development status :: 5 - production/stable",
    "intended audience :: developers",
    "license :: osi approved :: mit license",
    "programming language :: python :: 3",
    "programming language :: python :: 3.8",
    "programming language :: python :: 3.9",
    "programming language :: python :: 3.10",
    "programming language :: python :: 3.11",
    "topic :: software development :: libraries :: python modules",
]

dependencies = [
    "pandas>=2.0.0,<3.0.0",
    "numpy>=1.24.0",
    "sqlalchemy>=2.0.0",
    "pydantic>=2.0.0",
    "click>=8.0.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.4.0",
    "pytest-cov>=4.1.0",
    "pytest-asyncio>=0.21.0",
    "black>=23.0.0",
    "ruff>=0.1.0",
    "mypy>=1.5.0",
    "pre-commit>=3.3.0",
]
postgres = [
    "psycopg2-binary>=2.9.0",
]
mysql = [
    "pymysql>=1.1.0",
]
all = [
    "data-processor[dev,postgres,mysql]"
]

[project.urls]
homepage = "https://github.com/company/data-processor"
documentation = "https://data-processor.readthedocs.io"
repository = "https://github.com/company/data-processor"
issues = "https://github.com/company/data-processor/issues"

[project.scripts]
data-process = "data_processor.cli:main"
dp = "data_processor.cli:main"

# pytest 配置
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = [
    "--cov=data_processor",
    "--cov-report=html",
    "--cov-report=term-missing:skip-covered",
    "-v",
    "--strict-markers",
]
markers = [
    "slow: 标记慢速测试",
    "integration: 集成测试",
    "unit: 单元测试",
]

# black 配置
[tool.black]
line-length = 100
target-version = ['py38', 'py39', 'py310', 'py311']
include = '\.pyi?$'

# ruff 配置
[tool.ruff]
line-length = 100
target-version = "py38"

[tool.ruff.lint]
select = ["e", "f", "i", "b", "c4", "up"]
ignore = ["e501"]

[tool.ruff.lint.isort]
known-first-party = ["data_processor"]

# mypy 配置
[tool.mypy]
python_version = "3.8"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
plugins = ["pydantic.mypy"]

# coverage 配置
[tool.coverage.run]
source = ["data_processor"]
omit = ["*/tests/*", "*/__init__.py"]

[tool.coverage.report]
precision = 2
show_missing = true
skip_covered = false

六、pyproject.toml vs 传统方式对比

6.1 依赖管理对比

传统方式(requirements.txt)

requests>=2.28.0
numpy>=1.20.0
pandas>=2.0.0

问题:

  • 无法区分生产依赖和开发依赖
  • 不支持可选依赖组
  • 缺少项目元数据

现代方式(pyproject.toml)

[project]
dependencies = [
    "requests>=2.28.0",
    "numpy>=1.20.0",
    "pandas>=2.0.0",
]

[project.optional-dependencies]
dev = ["pytest>=7.0", "black>=22.0"]

优势:

  • ✅ 清晰分类
  • ✅ 灵活安装
  • ✅ 完整的项目信息

6.2 工具配置对比

传统方式

需要多个配置文件:

  • .flake8
  • pytest.ini
  • mypy.ini
  • tox.ini

现代方式

一个 pyproject.toml 搞定:

[tool.pytest.ini_options]
# pytest 配置

[tool.black]
# black 配置

[tool.mypy]
# mypy 配置

七、最佳实践

7.1 版本管理

使用语义化版本(semver):

[project]
version = "主版本.次版本.修订号"  # 如 "2.3.1"
  • 主版本:不兼容的 api 修改
  • 次版本:向下兼容的功能新增
  • 修订号:向下兼容的问题修正

7.2 依赖版本约束

dependencies = [
    "requests>=2.28.0,<3.0.0",  # 推荐:指定范围
    "numpy>=1.20.0",            # 可以:仅指定最低版本
    "pandas==2.0.0",            # 避免:固定版本(除非必要)
]

7.3 项目结构建议

my_project/
├── pyproject.toml          # 项目配置
├── readme.md               # 项目说明
├── license                 # 开源协议
├── .gitignore              # git 忽略文件
├── src/
│   └── my_package/         # 源代码
│       ├── __init__.py
│       └── ...
└── tests/                  # 测试代码
    └── ...

7.4 使用 src 布局

pyproject.toml 中配置:

[tool.setuptools]
package-dir = {"" = "src"}

[tool.setuptools.packages.find]
where = ["src"]

优势:

  • 避免测试时导入本地未安装的包
  • 确保测试的是安装后的版本

八、常见问题 faq

q1: pyproject.toml 和 setup.py 可以共存吗?

:可以,但不推荐。如果两者都存在,建议逐步迁移到 pyproject.toml

q2: 如何从 setup.py 迁移到 pyproject.toml?

  1. 创建 pyproject.toml
  2. setup() 中的参数转换为对应的 toml 格式
  3. 测试构建:pip install -e .
  4. 确认无误后删除 setup.py

q3: poetry 和 setuptools 选哪个?

  • poetry:现代化,功能丰富,适合新项目
  • setuptools:传统,兼容性好,适合维护老项目

q4: pyproject.toml 中的依赖和 requirements.txt 的关系?

  • pyproject.toml:定义抽象依赖和项目元数据
  • requirements.txt:可选,用于锁定具体版本

推荐工作流:

# 从 pyproject.toml 生成 requirements.txt
pip-compile pyproject.toml -o requirements.txt

九、工具推荐

9.1 poetry

一站式项目管理工具,自动生成 pyproject.toml

# 安装
pip install poetry

# 初始化项目
poetry init

# 添加依赖
poetry add requests

# 安装依赖
poetry install

9.2 flit

轻量级打包工具,配置简单。

# 安装
pip install flit

# 发布到 pypi
flit publish

9.3 hatch

现代化项目管理工具。

# 安装
pip install hatch

# 创建项目
hatch new my-project

十、总结

pyproject.toml 是 python 项目管理的未来趋势,它带来了:

统一配置:一个文件管理所有配置
标准化:python 官方推荐的标准
现代化:更清晰的语法和更强大的功能
工具支持:主流工具都已支持

学习路径建议

  1. 初级:理解基本结构,能读懂常见配置
  2. 中级:为自己的项目编写 pyproject.toml
  3. 高级:掌握各种工具配置,优化项目管理流程

最后的建议:如果你正在开始一个新的 python 项目,从第一天就使用 pyproject.toml。它不仅让你的项目更专业,也为未来的维护和协作打下良好基础。

以上就是python项目配置文件pyproject.toml的完全指南的详细内容,更多关于python配置文件pyproject.toml的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com