一、准备工作
1. 注册 PyPI 账号
这是最基础的步骤:
2. 生成 API Token
登录后进入 API Token 管理页面:
- 点击 “Create API token”,填一个 Token name
- Scope 选择 “Entire account”(或指定项目)
- 复制生成的 Token(格式:
pypi-AgEIcHlwaS5vcmc...)
3. 配置认证(推荐)
创建 ~/.pypirc 文件(Windows 为 %USERPROFILE%\.pypirc):
1 2 3 4 5 6 7 8 9
| [pypi] repository = https://upload.pypi.org/legacy/ username = __token__ password = pypi-你的完整Token
[testpypi] repository = https://test.pypi.org/legacy/ username = __token__ password = testpypi-你的Token
|
二、项目配置
1. pyproject.toml(必须)
创建或修改 pyproject.toml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| [build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta"
[project] name = "your-package-name" version = "0.1.0" description = "你的包描述" authors = [ { name="Your Name", email="your@email.com" } ] readme = "README.md" license = "MIT" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ] requires-python = ">=3.9" dependencies = [ ]
[project.urls] "Homepage" = "https://github.com/your-username/your-repo"
|
2. MANIFEST.in(可选但推荐)
创建 MANIFEST.in 控制 sdist 包含的文件:
1 2 3 4 5 6 7 8 9 10 11
| include README.md include LICENSE include pyproject.toml
recursive-include your_package_name *.py
exclude *.whl exclude node_modules/
|
三、构建脚本
我写了一个通用的 build_wheel.py 脚本,可以直接复制使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| """ 通用 Python 包构建脚本 支持清理、构建 wheel 和 sdist """
import os import shutil import subprocess import argparse
def clean_dist(): """清理 dist 目录""" if os.path.exists("dist"): shutil.rmtree("dist") print("已清理 dist/ 目录")
def build_wheel(): """构建 wheel""" print("开始构建 wheel...") result = subprocess.run( ["python", "-m", "build", "--wheel"], capture_output=True, text=True ) if result.returncode != 0: print(f"构建失败:\n{result.stderr}") exit(1) print("wheel 构建成功")
def build_sdist(): """构建 sdist""" print("开始构建 sdist...") result = subprocess.run( ["python", "-m", "build", "--sdist"], capture_output=True, text=True ) if result.returncode != 0: print(f"sdist 构建失败:\n{result.stderr}") exit(1) print("sdist 构建成功")
def show_dist(): """显示构建产物""" if os.path.exists("dist"): print("\n构建产物:") for f in os.listdir("dist"): fpath = os.path.join("dist", f) size = os.path.getsize(fpath) / (1024 * 1024) print(f" - {f} ({size:.1f} MB)")
def main(): parser = argparse.ArgumentParser(description="构建 Python 包") parser.add_argument( "--clean", action="store_true", help="先清理 dist 目录" ) parser.add_argument( "--wheel-only", action="store_true", help="只构建 wheel" ) args = parser.parse_args()
try: import build except ImportError: print("安装 build 工具...") subprocess.run(["pip", "install", "build"], check=True)
if args.clean: clean_dist()
build_wheel() if not args.wheel_only: build_sdist() show_dist()
if __name__ == "__main__": main()
|
保存为 tools/build_wheel.py,使用方式:
1 2 3 4 5
| python tools/build_wheel.py --clean
python tools/build_wheel.py --clean --wheel-only
|
四、发布流程
1. 安装上传工具
2. 构建包
1
| python tools/build_wheel.py --clean --wheel-only
|
3. 上传到 PyPI
1 2 3 4 5
| twine upload dist/*
twine upload dist/* -u __token__ -p pypi-你的Token
|
4. 验证发布
访问 https://pypi.org/project/your-package-name/ 查看结果。
五、多平台构建
如果需要支持多个平台,可以使用 cibuildwheel:
安装
1
| pip install cibuildwheel
|
配置 pyproject.toml
1 2 3
| [tool.cibuildwheel] build = "cp39-* cp310-* cp311-*" skip = ["*-musllinux_*"]
|
构建所有平台
1
| cibuildwheel --output-dir wheelhouse
|
上传多平台 wheel
1
| twine upload wheelhouse/*.whl
|
六、完整发布清单
每次发布新版本时按这个顺序来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
git add . git commit -m "Release v0.1.0" git tag v0.1.0
python tools/build_wheel.py --clean --wheel-only
twine upload dist/*.whl
git push origin main git push origin v0.1.0
|
七、FAQ
Q: 上传时报错 403 Forbidden?
- 邮箱未验证 → 登录 PyPI 验证邮箱
- Token 错误 → 重新生成 Token
- 用户名错误 → 必须是
__token__,不是账号名
Q: 上传时报错 400 File too large?
- 默认单文件限制 100 MB
- 解决方案:只上传 wheel(sdist 通常不需要)
Q: 如何测试发布?
使用 TestPyPI:
1 2
| twine upload --repository testpypi dist/*.whl pip install your-package --index-url https://test.pypi.org/simple/
|
Q: wheel 和 sdist 的区别?
- wheel:预编译二进制包,安装快,跨平台(带平台标记)
- sdist:源码包,用户安装时需要编译,通常较小
总结
发布 Python 包并不复杂,关键步骤:
- 配置好
pyproject.toml
- 写个构建脚本方便复用
- 使用
twine 上传
- 遇到问题优先查 PyPI 官方文档