twine是python官方唯一推荐且默认要求的pypi上传工具,因其强制https加密、端到端安全、凭据不落地、支持签名与元数据校验,而setup.py upload因http不安全已被pypi彻底禁用。

twine 是目前唯一被 Python 官方推荐、且默认要求用于上传包到 PyPI 的工具。直接用 setup.py upload 已被弃用,不仅不安全,还会被 PyPI 拒绝。
为什么必须用 twine 而不是 python setup.py upload
PyPI 自 2020 年起彻底禁用了 HTTP 上传接口,而旧版 setup.py upload 默认走 HTTP(即使你加了 --repository-url https://...,底层仍可能降级或泄露凭据)。twine 强制 HTTPS、校验服务器证书、不缓存凭据、不拼接 URL——这才是真正端到端加密的上传方式。
常见错误现象:HTTPError: 403 Client Error: Invalid or non-existent authentication information 或 Connection refused,基本都是因为误用了过时命令或凭据配置错位。
-
twine上传时凭据只在内存中短暂存在,不写入日志或进程环境(除非你手动export) - 它会对每个
.whl和.tar.gz文件做 PGP 签名验证(如果提供)、校验sha256、检查元数据字段是否缺失(比如description为空会报错) - 不支持“动态生成包再传”,必须先生成好
dist/下的文件,再由twine读取——这反而避免了构建过程中的中间态污染
twine upload 命令必须带 --repository 参数吗
不是必须,但强烈建议显式指定。默认行为是上传到正式 PyPI(https://upload.pypi.org/legacy/),但如果你没注意当前配置,或机器上残留了 .pypirc 里指向 testpypi 的配置,就可能误发到测试站。
安全做法是:始终用完整 URL 显式声明目标:
twine upload --repository https://upload.pypi.org/legacy/ dist/*
上传到 TestPyPI 测试时则用:
twine upload --repository https://test.pypi.org/legacy/ dist/*
注意两点:
- URL 末尾的
/legacy/不能省——PyPI 不接受/simple/或根路径 - 别用
--repository-url(旧参数名),它已被废弃,某些twine版本会静默忽略
凭据怎么配才不暴露 password 字符串
绝对不要把密码明文写进命令行(如 twine upload -u __token__ -p pypi-xxx dist/*),shell 历史和进程列表都会泄露。
正确方式只有两种,且都优先级高于命令行参数:
- 用
~/.pypirc文件(仅限当前用户可读:chmod 600 ~/.pypirc):[pypi]<br>username = __token__<br>password = pypi-AbcDef123456
- 用环境变量(适合 CI/CD):
export TWINE_USERNAME=__token__export TWINE_PASSWORD=pypi-AbcDef123456
关键点:username 必须是 __token__(两个下划线),不是你的 PyPI 用户名;password 是从 https://pypi.org/manage/account/token/ 生成的 API token(scope 选 “Entire account” 或限定项目),不是登录密码。
twine check 报 InvalidDistribution 怎么快速定位
这个错误通常不是代码问题,而是 setup.py 或 pyproject.toml 里漏了必填字段,或者 README 渲染失败。
最常踩的坑:
-
long_description用了open("README.md").read(),但没设long_description_content_type="text/markdown"→ PyPI 拒收纯文本当 Markdown 渲染 -
classifiers缺少"Programming Language :: Python :: 3"→ 被判定为不支持 Python 3 -
pyproject.toml中[project]下没写name和version→ 构建出的包元数据为空 - 包名含大写字母或下划线(如
MyPackage)→ PyPI 强制小写 + 连字符规范,上传会 400
运行 twine check dist/* 后,它会逐个打印每个文件的校验结果。只要有一项 fail,整个命令返回非零退出码,CI 就该中断——别跳过这步。
classifiers)的校验发生在上传前的 API 请求头解析阶段,而不是文件上传后。也就是说,twine upload 失败时,错误信息往往来自元数据解析,而非网络或权限——先盯住 twine check 的输出,比反复试传更省时间。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











