使用 pyproject.toml 制作 Python 安装包

发布时间: 更新时间: 总字数:2205 阅读时间:5m 作者:IP:上海 网址

Python 库/模块打包(Library Packaging)在过去几年里经历了巨大的变革。随着 PEP 517 / PEP 518 以及 PEP 621 标准的普及,Python 社区已经彻底告别了过去混乱的 setup.py 时代,全面拥抱以 pyproject.toml 为核心的现代化、声明式打包方案。本文将全面总结目前 Python 库打包的核心概念、主流工具方案对比以及标准工作流。

核心概念:现代 Python 打包的基石

在了解具体工具之前,必须先理清现代 Python 打包的几个核心概念:

  1. pyproject.toml:现代 Python 项目的唯一配置入口。取代了过去的 setup.py, setup.cfg, requirements.txt, MANIFEST.in 等多个文件。
  2. 构建前端 (Build Frontend):负责调用后端的工具,例如 pipbuild。它们读取配置并告诉后端去干活。
  3. 构建后端 (Build Backend):真正执行代码打包的引擎,例如 setuptools, hatchling, poetry-core, flit-core。负责生成分发包。
  4. 分发格式
    • sdist (Source Distribution):源码包(通常是 .tar.gz),包含源代码和构建元数据。
    • wheel (Built Distribution):二进制包(.whl),一种预编译的格式,安装速度极快,无需在目标机器上执行构建过程。

主流打包工具/方案对比

目前 Python 社区有几种主流的构建后端和打包管理工具,它们各有侧重:

Hatch (当前 PyPA 官方力推的新星)

Hatch 是一个现代化的、可扩展的 Python 项目构建与管理工具。Python 官方框架(如 pip 自身、Pytest 等)正在大量迁移至 Hatch。

  • 构建后端hatchling
  • 特点
    • 全面支持 PEP 621 标准(标准化的 [project] 表)。
    • 除了打包,还内置了环境管理、脚本执行、版本号管理(Hatch-vcs)。
    • 插件系统极其强大。
  • 适用场景:推荐用于所有新项目,特别是纯 Python 库以及需要复杂环境测试的开源库。

Poetry (开发者体验最好的全能战士)

Poetry 将依赖管理和打包发布融为一体,提供了类似 Node.js 中 npm/yarn 的丝滑体验。

  • 构建后端poetry-core
  • 特点
    • 拥有强大的依赖解析器和 Lock 文件 (poetry.lock),确保环境绝对一致。
    • 命令极其简洁明了(如 poetry build, poetry publish)。
    • 早期使用私有规范 [tool.poetry],但现在也已支持标准的 [project] 规范。
  • 适用场景:既注重库的打包,又需要极其严谨的依赖管理(如带复杂依赖链的数据科学库或 Web 框架扩展)。

Setuptools (最老牌、最成熟的基石)

过去几十年的绝对霸主。虽然现在推荐用 pyproject.toml,但底层依然可以是 Setuptools。

  • 构建后端setuptools.build_meta
  • 特点
    • 对 C/C++/Cython 扩展模块支持最好、最成熟。
    • 向后兼容性极强。
    • 现在也完全支持通过 pyproject.toml 进行声明式配置,无需写 setup.py
  • 适用场景:包含复杂的 C/C++ 扩展、Cython 编译的库(如机器学习底层库),或者维护老旧项目。

Flit (最极简的纯 Python 打包器)

Flit 诞生的目的就是为了让打包“纯 Python 库”变得极致简单,没有任何历史包袱。

  • 构建后端flit_core.buildapi
  • 特点
    • 配置极简,只需几行代码。
    • 不支持 C 扩展,不支持复杂的构建步骤。
    • 直接从代码中提取 docstring 作为项目描述,提取 __version__ 作为版本。
  • 适用场景:单文件模块、轻量级的纯 Python 工具包。

PDM (支持 PEP 582 的后起之秀)

与 Poetry 类似,也是一个现代化的包和依赖管理器。

  • 构建后端pdm-backend
  • 特点
    • 原生支持 PEP 621 标准。
    • 支持 PEP 582(本地 __pypackages__ 目录,无需虚拟环境,虽然该 PEP 最终被拒绝,但 PDM 依然支持且很好用)。
  • 适用场景:喜欢 Poetry 的工作流,但更倾向于拥抱最新 PEP 标准的开发者。

包含非 Python 代码(C/Rust)的特殊方案

如果你的库为了性能需要包含 C/C++ 或 Rust 代码,通常需要特殊的构建后端:

  • Maturin / setuptools-rust:用于打包结合了 Rust 的 Python 库(如 Polars、Pydantic v2 就是用 Maturin 打包的)。Maturin 体验极佳。
  • Scikit-build-core:替代老旧的 scikit-build,结合 CMake 打包复杂的 C/C++ 扩展库。
  • Meson-python:使用 Meson 构建系统的后端,SciPy 和 NumPy 目前正在迁移使用这个方案。

现代标准打包发布工作流 (以 Hatch/Setuptools 为例)

无论您使用哪个后端,纯粹的标准化打包流程如下:

编写配置文件 pyproject.toml

这是必须的。以下是一个现代标准配置示例:

toml
[build-system]
# 选择你的构建后端,这里以 hatchling 为例
requires = [`hatchling`]
build-backend = `hatchling.build`

[project]
name = `my-awesome-lib`
version = `0.1.0`
description = `A short description of the package`
readme = `README.md`
requires-python = `>=3.8`
license = { text = `MIT` }
authors = [
  { name = `Your Name`, email = `your.email@example.com` }
]
# 声明你的库运行时需要的依赖
dependencies = [
  `requests>=2.0.0`,
]

[project.scripts]
# 可选:如果你的库包含命令行工具,在这里注册
my-cli = `my_awesome_lib.cli:main`

安装构建前端工具 build

build 是 PyPA 官方推荐的构建前端工具,取代了直接运行 python setup.py sdist bdist_wheel

bash
pip install build

执行构建

在包含 pyproject.toml 的目录下运行:

bash
python -m build

执行完毕后,会在 dist/ 目录下生成两个文件:

  • my_awesome_lib-0.1.0.tar.gz (sdist)
  • my_awesome_lib-0.1.0-py3-none-any.whl (wheel)

发布到 PyPI

使用官方推荐的上传工具 twine

bash
pip install twine
# 先在 TestPyPI 测试
twine upload --repository testpypi dist/*
# 确认无误后上传到正式 PyPI
twine upload dist/*

(注:如果您使用的是 Poetry 或 Hatch,它们自带了 poetry build/hatch buildpoetry publish/hatch publish 命令,可以一键替代上述 2, 3, 4 步。)

总结与选型建议

在 2026+ 年,如何选择适合自己的打包方案?

  1. 推荐首选Hatch。它是目前 Python 官方生态的亲儿子,轻量、标准、插件生态好。如果只是想简单开发一个纯 Python 库并发布,用 Hatch 最符合未来趋势。
  2. 团队协作/重度依赖管理PoetryPDM。如果你的项目有几十个依赖项,需要严格管控依赖版本以防环境冲突,Poetry 依然是综合体验最好的工具。
  3. 极简主义者Flit。对于单个脚本或仅有几个文件的微型库,Flit 是最快的选择。
  4. 底层性能库 (C/C++)SetuptoolsScikit-build-core
  5. 底层性能库 (Rust)Maturin

核心原则: 全面拥抱 pyproject.toml