Python 项目打包发布指南:从结构创建到 PyPI 上传
将开发完成的 Python 项目打包并发布,是与其他开发者共享代码、构建生态的重要步骤。本文将详细介绍如何创建一个标准的 Python 包,配置必要的元数据,构建分发包,并最终上传至 Python 包索引(PyPI)或测试环境 TestPyPI。
Python 项目的打包发布全流程,涵盖项目目录结构搭建、pyproject.toml 元数据配置、构建后端选择、许可证设置、生成分发档案以及通过 twine 上传至 TestPyPI 和正式 PyPI 的具体操作。内容包含虚拟环境隔离、API 令牌安全认证、依赖管理及版本控制等关键技术点,旨在帮助开发者建立规范的发布工作流。

将开发完成的 Python 项目打包并发布,是与其他开发者共享代码、构建生态的重要步骤。本文将详细介绍如何创建一个标准的 Python 包,配置必要的元数据,构建分发包,并最终上传至 Python 包索引(PyPI)或测试环境 TestPyPI。
在开始之前,请确保你的开发环境已安装最新版本的 Python 和 pip。建议创建一个独立的虚拟环境以避免依赖冲突。
# Unix/macOS
python3 -m pip install --upgrade pip
# Windows
py -m pip install --upgrade pip
推荐使用 venv 模块创建隔离环境:
python3 -m venv venv
source venv/bin/activate # Linux/macOS
venv\Scripts\activate # Windows
现代 Python 项目推荐采用 src 布局,这有助于避免本地导入与包导入的混淆,并简化命名空间管理。
在根目录下创建如下结构:
packaging_tutorial/
└── src/
└── example_package_YOUR_USERNAME_HERE/
├── __init__.py
└── example.py
打开 example.py 并添加基础功能:
def add_one(number):
"""
接收一个数字并返回加一后的结果。
Args:
number (int): 输入的数字
Returns:
int: 加一后的数字
"""
return number + 1
Python 包的配置主要依赖于 pyproject.toml 文件,它定义了构建系统、项目元数据和依赖项。
构建后端负责将源代码转换为分发包(如 .whl 或 .tar.gz)。目前主流的后端包括 Hatchling、Setuptools、Flit 和 PDM。
在 pyproject.toml 中指定构建后端:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
其他常见配置示例:
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
在 pyproject.toml 中添加 [project] 部分,定义包的名称、版本、作者等关键信息。
[project]
name = "example_package_YOUR_USERNAME_HERE"
version = "0.0.1"
description = "A small example package demonstrating best practices"
readme = "README.md"
requires-python = ">=3.7"
license = {text = "MIT"}
authors = [
{ name="Example Author", email="[email protected]" },
]
maintainers = [
{ name="Example Maintainer", email="[email protected]" },
]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = []
[project.urls]
Homepage = "https://github.com/yourusername/example_package"
Documentation = "https://github.com/yourusername/example_package#readme"
Repository = "https://github.com/yourusername/example_package.git"
Changelog = "https://github.com/yourusername/example_package/blob/main/CHANGELOG.md"
BugTracker = "https://github.com/yourusername/example_package/issues"
字段说明:
.、_ 和 -。主版本号。次版本号.修订号。为了符合开源规范并提供良好的用户体验,需要创建以下文件。
这是用户查看包详情时首先看到的内容,应包含安装方法、使用示例和贡献指南。
# Example Package
This is a simple example package.
## Installation
Install the latest version from PyPI:
```bash
pip install example-package-your-username-here
from example_package_your_username_here import example
result = example.add_one(2)
print(result) # Output: 3
This project is licensed under the MIT License.
### 4.2 LICENSE
每个上传到 PyPI 的包都必须包含许可证文件,明确用户使用条款。常见的开源许可证有 MIT、Apache 2.0、GPL 等。
例如 MIT 许可证内容:
Copyright (c) 2024 Your Name
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
### 4.3 测试目录
创建 `tests/` 目录用于存放单元测试,虽然构建时默认不包含,但对质量保证至关重要。
packaging_tutorial/ ├── src/ │ └── example_package... ├── tests/ │ └── test_example.py ├── pyproject.toml ├── README.md └── LICENSE
## 5. 生成分发档案
构建工具会将源代码转换为分发包,主要包括源分发包(`.tar.gz`)和构建分发包(`.whl`)。
### 5.1 安装构建工具
确保安装了最新的 `build` 工具:
```bash
python3 -m pip install --upgrade build
在项目根目录运行构建命令:
python3 -m build
构建完成后,会在 dist/ 目录下生成两个文件:
dist/
├── example_package_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
└── example_package_YOUR_USERNAME_HERE-0.0.1.tar.gz
最佳实践:始终同时上传两种格式,以确保最大兼容性。
由于安全策略升级,PyPI 不再允许使用用户名和密码直接上传,必须使用 API 令牌进行身份验证。
TestPyPI 是 PyPI 的测试实例,适合在正式发布前验证流程。
Twine 是官方推荐的上传工具。
python3 -m pip install --upgrade twine
创建或修改 ~/.pypirc 配置文件以存储凭据:
[testpypi]
username = __token__
password = pypi-AgENdGVzdC5weXBpLm9xxxxxxxxxxxxxxx
注意:密码字段填入完整的 API 令牌,用户名固定为 __token__。
使用 Twine 上传 dist 目录下的所有文件:
python3 -m twine upload --repository testpypi dist/*
上传成功后,可在 TestPyPI 上查看包详情。
上传后,建议在虚拟环境中验证包是否可正常安装和使用。
python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps example-package-YOUR-USERNAME-HERE
--index-url: 指定 TestPyPI 源。--no-deps: 避免安装 TestPyPI 上不存在的依赖项导致失败。from example_package_your_username_here import example
assert example.add_one(2) == 3
print("Installation verified successfully!")
当测试无误后,可发布到正式的 Python Package Index。
--repository 参数,默认上传至 PyPI。python3 -m twine upload dist/*
注意事项:
如果提示包名已被占用,请更换名称或在 PyPI 申请重命名(仅限特定情况)。建议使用带有个人标识的前缀。
setup.cfg 或 pyproject.toml 中的字符集为 UTF-8。requires 字段是否包含了构建所需的依赖包。readme 和 license 文件路径正确且存在。.pypirc 中的密码是否为完整令牌,且未过期。发布后,定期维护包对于保持用户信任至关重要。
CHANGELOG.md 中记录变更日志。通过遵循上述步骤,您可以规范地创建、测试并发布高质量的 Python 包,使其成为您技术资产的一部分。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online