手把手教你打包Python项目到PyPI
这篇博文将带你一步步完成从项目准备到成功发布到 PyPI 的全过程,包括使用现代化的打包工具和最佳实践,例如利用 pyproject.toml
、build
工具以及通过 TestPyPI 进行安全测试。
核心工具: pyproject.toml
, setuptools
, build
, twine
, uv
(或 pip
)
第一步:规划你的项目结构
一个清晰的项目结构是成功打包的基础。推荐使用 src
布局,它能很好地将你的实际包代码与项目其他文件(如测试、文档、配置文件)隔离开来。
假设你的包名叫 mytoolpack
:
mytoolpack_project/
├── src/
│ └── mytoolpack/ <-- 这是你的实际包代码
│ ├── __init__.py # 包初始化文件,让目录成为一个包
│ └── module.py # 你的核心代码,例如包含一个 cool_function
├── tests/ <-- 测试代码
│ └── test_module.py
├── .gitignore
├── LICENSE <-- 选择一个开源许可证!
├── README.md <-- 详细的项目说明
└── pyproject.toml <-- 打包和项目配置的核心文件
第二步:pyproject.toml
pyproject.toml
文件是现代 Python 打包的基石 (PEP 517/518/621)。它定义了项目的构建系统、元数据(如名称、版本、作者)以及依赖项。
这是一个 pyproject.toml
的示例:
# mytoolpack_project/pyproject.toml
[build-system]
requires = ["setuptools>=61.0", "wheel"] # 声明构建依赖
build-backend = "setuptools.build_meta"
backend-path = ["."] # 可选,确保 setuptools 能找到
[project]
name = "mytoolpack" # PyPI 上的名字,也是用户导入的名字
version = "0.1.0" # 遵循语义化版本 (semver.org)
authors = [
{ name="你的名字", email="你的邮箱@example.com" },
]
description = "一个能做很酷事情的示例工具包。"
readme = "README.md" # 指向你的 README 文件
requires-python = ">=3.8" # 项目支持的 Python 版本
license = { file = "LICENSE" } # 指向你的许可证文件,或使用 {text = "MIT"} 等
classifiers = [ # PyPI 分类器,帮助用户找到你的包
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License", # 与你选择的许可证对应
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Utilities",
]
keywords = ["tool", "utility", "example", "packaging"] # 包的关键词
# 项目的运行时依赖
dependencies = [
# "requests>=2.20.0", # 例如:如果你的包需要 requests
# "numpy",
]
[project.urls] # 可选链接
"Homepage" = "https://github.com/你的用户名/mytoolpack_project"
"Bug Tracker" = "https://github.com/你的用户名/mytoolpack_project/issues"
"Documentation" = "https://readthedocs.org/projects/mytoolpack/" # 如果有文档
# --- Setuptools 特定配置 (用于 src-layout) ---
[tool.setuptools.packages.find]
where = ["src"] # 告诉 setuptools 在 src 目录下寻找包
# include = ["mytoolpack*"] # 更精确地指定
关键点:
[build-system]
: 指定构建项目所依赖的build工具。[project]
: 包含所有关于你项目的重要元数据。name
: PyPI 上的唯一名称。version
: 包的版本号,每次发布新版本时都需要更新。dependencies
: 你的包运行时所依赖的其他包。
[tool.setuptools.packages.find]
: 帮助setuptools
找到你的包代码,特别是当你使用src
布局时。
第三步:让你的代码可导入
在 src/mytoolpack/__init__.py
文件中,你可以控制当用户导入你的包时,哪些功能是可用的:
# src/mytoolpack/__init__.py
from .module import cool_function # 从同目录下的 module.py 导入 cool_function
__version__ = "0.1.0" # 与 pyproject.toml 中的版本保持一致
__all__ = ['cool_function'] # 定义 `from mytoolpack import *` 时导入的内容
假设 src/mytoolpack/module.py
内容如下:
# src/mytoolpack/module.py
def cool_function():
print("这是一个很酷的功能!")
return True
第四步:构建你的分发包
现在你的项目结构和配置文件都准备好了,是时候构建你的分发包了。这些是最终上传到 PyPI 的文件。
-
安装构建工具
build
: 如果你还没有安装build
包,可以使用uv
(或pip
) 安装它:uv python install build # 或者 pip install build
-
运行构建命令: 在你的项目根目录 (
mytoolpack_project/
) 下运行:python -m build
这个命令会调用
pyproject.toml
中指定的构建后端 (这里是setuptools
) 来创建分发文件。成功后,你会在项目根目录下看到一个新的dist/
目录,其中包含两个文件:- 一个
.tar.gz
文件 (源码分发 sdist) - 一个
.whl
文件 (wheel 包,预编译的二进制分发)
- 一个
第五步:在TestPyPI上测试你的包
在直接将包上传到真正的PyPI之前,强烈建议先在 TestPyPI (test.pypi.org
) 上进行测试。TestPyPI 是 PyPI 的一个独立测试实例,你可以随意上传、删除包,而不会弄乱官方仓库。
-
注册 TestPyPI 账号: 前往 test.pypi.org 并注册一个账户。
-
安装
twine
:twine
是用于将包安全上传到 PyPI (和 TestPyPI) 的工具。uv python install twine # 或者 pip install twine
-
上传到 TestPyPI: 使用
twine
将dist/
目录下的文件上传到 TestPyPI。你需要使用之前注册的 TestPyPI 用户名和密码(或者创建一个 API Token)。twine upload --repository testpypi dist/*
按照提示输入你在 TestPyPI的API token
-
从 TestPyPI 安装并测试: 上传成功后,尝试在一个新的虚拟环境中从 TestPyPI 安装你的包,以验证一切是否按预期工作:
# 创建并激活新虚拟环境 (使用 uv 或 venv) # uv venv .test_env # source .test_env/bin/activate uv python install -i https://test.pypi.org/simple/ mytoolpack # 或者 pip install -i https://test.pypi.org/simple/ mytoolpack # 现在测试你的包 # python -c "import mytoolpack; mytoolpack.cool_function()"
如果安装和基本功能都正常,那么你的包很可能已经准备好进入真正的 PyPI 了!
第六步:发布到 PyPI!
一旦你在TestPyPI 上确认一切顺利,就可以将你的包发布到官方的 PyPI (pypi.org
)。
-
注册 PyPI 账号: 前往 pypi.org 并注册一个账户(如果你还没有的话)。与 TestPyPI 账号是独立的。
-
创建 API Token (推荐): 为了安全起见,不要直接使用你的 PyPI 用户名和密码上传。在你的 PyPI 账户设置中创建一个 API Token。创建时,可以限制其权限范围(比如只允许上传特定项目)。创建后立即复制并保存好这个 Token,因为它只显示一次。
-
上传到 PyPI:
twine upload dist/*
当
twine
提示输入用户名时,输入__token__
。当提示输入密码时,粘贴你刚刚创建的 PyPI API Token。如果你的
~/.pypirc
文件正确配置了 PyPI 和 TestPyPI 的 token,twine
可能会自动选择。但通常手动指定或依赖__token__
方式更清晰。
恭喜你! 你的Python包现在已经发布到 PyPI,全世界的Python用户都可以通过 pip install mytoolpack
来安装和使用它了!
打包进阶与最佳实践
- 选择一个独特的包名: 在
pyproject.toml
中选择name
之前,先去PyPI.org 搜索一下,确保你选择的名字还没有被占用。 - 优秀的
README.md
: 这是用户了解你项目的第一扇窗,确保它清晰、详尽。 - 包含
LICENSE
文件: 选择一个合适的开源许可证,并在pyproject.toml
中声明它。 - 版本控制: 遵循语义化版本(例如
1.0.1
,1.1.0
,2.0.0
),并在每次发布新版本时更新pyproject.toml
(以及__init__.py
中的__version__
)。 - 持续集成/持续部署 (CI/CD): 对于更成熟的项目,可以考虑设置CI/CD流水线 (如 GitHub Actions, GitLab CI)来自动化测试、构建和发布流程。
总结
将 Python 项目打包并发布到PyPI可能看起来有些复杂,但一旦你掌握了现代化的工具和流程,它就会变得非常直接。通过使用 pyproject.toml
进行清晰的配置,利用 build
工具构建,借助TestPyPI 进行安全测试,以及通过 twine
上传,你的代码就在PyPi中被别人使用。