Python 包发布全流程从项目结构到 PyPI 上线以及我踩过的那些坑本文不深入讲解工具本身而是以我发布的ratelimited-embedder为例完整记录一个 Python 包从编写、打包、测试到最终发布到 PyPI 的每一步并列举常见错误和解决方案帮你避开那些“坑”。前言当你写好一个 Python 工具想让全世界的人通过pip install your-package轻松安装就需要把它发布到 PyPIPython Package Index。这个过程看似简单实则有不少容易出错的地方。我在发布第一个包时就踩了 license 格式、版本号不一致、API token 混淆、换行符警告等一堆坑。本文将按时间顺序一步步带你走完整个流程并附上我当时遇到的错误和解决方法。无论你是初学者还是有一定经验的开发者相信都能从中受益。一、准备项目结构推荐使用src/布局这是现代 Python 打包的最佳实践可避免开发时意外导入本地代码而非安装的包。your-package-name/ ├── src/ │ └── your_package_name/ # 模块名与包名尽量一致 │ ├── __init__.py │ ├── core.py │ └── ... ├── tests/ # 单元测试 ├── pyproject.toml # 核心配置文件 ├── README.md ├── LICENSE # 许可证如 MIT, Apache 2.0 └── .gitignore注意包名可以使用连字符如ratelimited-embedder但导入时的模块名必须使用下划线ratelimited_embedder。二、编写pyproject.toml这是 Python 打包的“身份证”必须包含以下核心字段[build-system] requires [setuptools68.0, wheel] build-backend setuptools.build_meta [project] name ratelimited-embedder # PyPI 上的名称 version 0.1.1 # 遵循语义化版本 description 工具简短描述 readme README.md license { text Apache-2.0 } # 注意不是字符串 Apache-2.0 authors [{ name Your Name, email youexample.com }] requires-python 3.9 dependencies [ psutil5.9.0, tqdm4.65.0, ] classifiers [ Development Status :: 4 - Beta, Intended Audience :: Developers, License :: OSI Approved :: Apache Software License, Programming Language :: Python :: 3, Programming Language :: Python :: 3.9, Programming Language :: Python :: 3.10, Programming Language :: Python :: 3.11, ] [project.urls] Homepage https://github.com/yourname/your-repo Repository https://github.com/yourname/your-repo踩坑记录❌ 错误写法license MIT✅ 正确写法license { text MIT }或license { file LICENSE }缺少许可证分类器必须在classifiers中添加License :: OSI Approved :: Apache Software License对应的分类器否则twine check会警告。版本号不一致pyproject.toml中的version必须与src/your_package/__init__.py中的__version__保持一致。建议使用importlib.metadata动态读取。三、编写 README 和 LICENSEREADME.md应包含安装方法、快速示例、核心 API 说明。PyPI 支持 Markdown 渲染推荐使用。LICENSE在 GitHub 创建仓库时可以直接选择许可证模板MIT、Apache 2.0 等然后下载到本地。注意README 中的示例代码要确保可运行且与当前版本 API 一致。四、本地构建与检查1. 安装构建工具pipinstallbuild twine2. 构建分发包python-mbuild成功后会生成dist/目录内含.tar.gz源码包和.whlwheel 包。3. 检查元数据twine check dist/*如果输出PASSED说明元数据基本正确如果有警告或错误需根据提示修改pyproject.toml。常见错误long_description_content_type缺失或格式不对 → 确保 README 后缀为.md并在pyproject.toml中不设置默认会读取。缺少许可证分类器 → 添加对应 classifier。五、在 TestPyPI 上预发布TestPyPI是 PyPI 的测试实例在这里上传包不会影响正式环境非常适合演练。1. 注册账号并生成 API token访问 test.pypi.org 注册账号。登录后进入Account settings→API tokens→Add API token。选择 “Entire account”生成 token以pypi-开头复制保存只显示一次。2. 上传到 TestPyPItwine upload--repositorytestpypi dist/*输入用户名__token__密码粘贴刚才复制的 token。3. 验证安装创建一个干净的环境python-mvenv test_envsourcetest_env/bin/activate# Windows: test_env\Scripts\activatepipinstall--index-url https://test.pypi.org/simple/ your-package-name然后尝试导入确认功能正常。踩坑记录Token 搞混TestPyPI 的 token 不能用于正式 PyPI反之亦然。上传前务必确认--repository参数。包名已存在如果 TestPyPI 上已有同名包哪怕是别人占用的需要修改name。一般 TestPyPI 比较宽松但正式 PyPI 更严格。六、正式发布到 PyPI1. 注册正式 PyPI 账号并生成 token访问 pypi.org 注册不同于 TestPyPI账号不通用。同样在API tokens中创建一个 token作用域选 “Entire account”。2. 上传twine upload dist/*用户名__token__密码正式 PyPI 的 token。上传成功后访问https://pypi.org/project/your-package-name/就能看到项目页面。踩坑记录403 Forbidden常见原因有使用了 TestPyPI 的 token。token 作用域限制为某个项目而当前项目名不匹配。包名已被人注册需要改名。版本号重复PyPI 不允许覆盖已发布的版本。如果需要在同一版本上修复必须递增版本号如0.1.1→0.1.2。永远不要删除已发布的版本。七、关联 GitHub 与版本标签为了方便用户查看源码和提 issues建议将代码同步到 GitHub并在每次发布时打 tag。gitadd.gitcommit-mRelease v0.1.1gittag v0.1.1gitpush origin main--tags然后在 GitHub 仓库页面创建 Release附上打包好的dist/*文件可选。八、常见问题汇总问题原因解决方案twine upload返回 400pyproject.toml中许可证字段格式错误改为license { text MIT }pip install找不到包未上传到正确的 PyPI 仓库检查是否用了--index-url指定 TestPyPItwine check警告No classifier for licenseclassifiers缺少许可证分类器添加License :: OSI Approved :: MIT License安装后导入报ModuleNotFoundError模块名与包名不一致确保src/下的文件夹名与pyproject.toml中name的连字符转下划线一致Git 提示LF will be replaced by CRLFWindows 换行符转换警告可以忽略或设置git config core.autocrlf true上传时提示no such file or directory: dist/*没有先执行python -m build先构建分发包用户反馈安装后缺少依赖dependencies中遗漏了必备包列出所有运行时依赖包括间接依赖如langchain-core九、更新包版本当工具功能更新或修复 bug 时需要发布新版本修改pyproject.toml中的version例如0.2.0。同步修改src/your_package/__init__.py中的__version__。更新CHANGELOG.md推荐。重新构建python -m build上传twine upload dist/*PyPI 会自动索引新版本用户执行pip install --upgrade your-package即可升级。十、总结发布一个 Python 包并不复杂但细节繁多。核心步骤可以概括为准备项目 → 编写 pyproject.toml → 构建 → TestPyPI 预演 → 正式 PyPI 上传 → GitHub 关联过程中遇到错误不可怕关键是要看懂错误信息并善用搜索引擎。希望本文能帮你少走弯路顺利发布自己的第一个 PyPI 包。如果觉得有用欢迎点赞、收藏、转发。有任何问题也可以在评论区交流。文中示例工具ratelimited-embedder地址GitHub | PyPI