build 和 twine 是当前推荐的 pypi 打包与上传组合,替代了存在安全风险、不可复现且已被标记为 legacy 的 setup.py;它基于 pep 517/518,通过 pyproject.toml 声明配置、build 实现隔离构建、twine 安全上传。

build 和 twine 是当前推荐的 PyPI 打包与上传组合,替代了旧式 python setup.py sdist bdist_wheel 流程。它更干净、可复现,且默认不执行任意代码(避免 setup.py 中恶意逻辑风险)。
为什么不用 setup.py 了?
Python 官方自 PEP 517/518 起明确转向声明式配置,setup.py 已被标记为 legacy。它的主要问题包括:
-
setup.py是可执行脚本,运行时可能触发副作用(如动态生成版本号、联网拉取依赖) - 无法保证构建环境隔离,容易因本地
sys.path或已安装包干扰打包结果 - 不支持多后端并行(比如同时用
setuptools和flit)
而 pyproject.toml + build 强制使用构建隔离环境,所有依赖按需安装,输出结果稳定可验证。
pyproject.toml 必须包含的最小配置项
不是所有字段都可省略。漏掉关键项会导致 build 失败或上传后 pip install 报错。
-
[build-system]:必须声明构建依赖和后端,例如:[build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta"
-
[project]:至少要有name、version、description、readme、requires-python;name必须符合 PyPI 命名规范(小写字母、数字、下划线、连字符),不能含空格或大写 - 如果项目源码在
src/下(强烈推荐),需加packages = [{include = "your_package_name", from = "src"}],否则find_packages()不会自动找到
build 命令执行失败的常见原因
build 报错通常不是语法问题,而是路径或元数据缺失导致的静默失败。
- 运行
python -m build时提示No module named build:先装pip install build,不要只装setuptools - 报
ModuleNotFoundError: No module named 'your_package_name':检查packages配置是否匹配实际目录结构,尤其注意from = "src"是否存在且拼写正确 - 生成的
.whl包里没代码:确认__init__.py文件存在(哪怕为空),且不在src/外层误放 -
build成功但pip install后 import 报错:检查[project.optional-dependencies]是否误把核心依赖写进extras,导致用户不指定[xxx]就装不上
twine upload 前必须做的三件事
twine upload 不校验内容,传错就直接上 PyPI —— 没有撤回按钮,只能 yank(隐藏)版本。
- 用
twine check dist/*验证long_description渲染是否合法(比如 README.md 含非法 rst 语法会导致 PyPI 页面空白) - 上传前务必用
twine upload --repository testpypi dist/*先推到 test.pypi.org,再手动pip install -i https://www.php.cn/link/79304cca1ad8a247a9bafffd5f4db436/simple/ your-package-name验证安装和导入 - 必须用 API token(而非账号密码)上传:PyPI 已禁用密码直传。token 在 Account Settings → API tokens 创建,作用域选
Entire account或限定到具体项目
最后提醒一句:版本号一旦发布就不能覆盖。哪怕只是改了个 typo,也得升 0.1.1 再 build/upload —— PyPI 认为同名同版本的包是完全等价的,不会重新分发。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











