1. 项目初始化与依赖管理
1.1 设定构建系统与依赖
在 Python 打包全流程中,pyproject.toml 是核心配置文件,PEP 517/518 指引了构建过程的边界与职责。本文围绕标题 Python 项目打包全流程:setuptools 与 wheel 的实战指南,从开发到发布并实现 CI/CD 自动化 来展开,帮助你从开发阶段就把依赖与构建系统定型。
为了实现一致的打包体验,需在项目根目录添加一个pyproject.toml,并明确使用的构建后端。这样,setuptools 与 wheel 可以在同一套配置下协同工作,减少环境差异带来的问题。
1.2 配置构建后端与依赖版本
在 pyproject.toml 中声明构建后端与最小依赖版本,这是开启后续打包流程的关键步骤。通过明确指定 setuptools 与 wheel 的版本,可以保证本地、CI 与发布环境的一致性。
[build-system]
requires = ["setuptools>=61","wheel"]
build-backend = "setuptools.build_meta"
此外,推荐将开发阶段的依赖放在一个独立区域,例如 tool.setuptools 或 extras_require,以便在持续集成阶段仅安装所需的打包相关组件。
1.3 包结构与元数据规划
清晰的包结构有助于后续的打包产物兼容性提升。src/ 包目录、tests/、以及 README、LICENSE 等元数据文件应明确分离。通过在源码中暴露 版本号,并在打包时自动解析,可以避免手动同步版本造成的混乱。
2. 从开发到打包:使用 setuptools 构建与发布
2.1 最小化 setup.py 与包结构
尽管未来可能以 pyproject.toml 为核心,setup.py 仍然是许多现有项目的落地点。一个简洁的示例有助于理解打包入口:定义包名、版本、包目录、以及运行时依赖。
在 setup.py 中,您可以通过 find_packages() 自动发现包,install_requires 列出运行时依赖,extras_require 提供可选依赖集,以供测试或开发使用。
from setuptools import setup, find_packages
setup(
name="your_package",
version="0.1.0",
packages=find_packages(),
install_requires=[
"requests>=2.25.0",
],
extras_require={
"dev": ["pytest", "black"]
},
)
注意:尽量通过 find_packages() 发现子包,避免手动维护包列表导致的错漏。
2.2 通过 pyproject.toml 配置打包信息
为了统一打包流程,您可以将打包相关信息进一步转移到 pyproject.toml,如指定前端工具、元数据与打包行为。这样在本地开发、CI 运行以及发布阶段都保持一致。
[tool.setuptools]
packages = { find = true }
[tool.setuptools_scm]
version_scheme = "guess-next-dev"
local_scheme = "no-local-version"
版本管理方案 在打包中扮演重要角色,合理的版本号策略有助于后续的升级与回滚。
2.3 构建前的测试与验证
在正式打包前,执行一次本地的 单元测试 与 静态检查,确保打包产物不带有明显错误。CI 之前先在本地完成验证,是一个稳健的工作流要点。
3. 打包产物与版本控制策略
3.1 生成 sdist 与 wheel
常见的打包产物包括 sdist(源码包)与 bdist_wheel(轮子包)。在开发阶段,最常用的命令是 python -m build,它会同时生成 dist/ 目录下的两类产物。
产物的存在形式决定了二进制兼容性与跨平台传播的能力,wheel 提供了更快的安装速度与更少的编译需求,因此应优先构建它。
python -m build
3.2 版本控制与自动化版本号
本节强调将版本号与代码仓库的状态绑定。用 setuptools_scm 这样的工具,可以基于 git 标签 自动推导版本,有助于避免人工维护版本的错误。
# pyproject.toml
[tool.setuptools_scm]
version_scheme = "guess-next-dev"
local_scheme = "no-local-version"
版本一致性 对于发布流程至关重要,确保你在打包前后版本号与实际功能一致。
4. 自动化构建:CI/CD 流水线的实现
4.1 使用 GitHub Actions 自动化构建
将打包与发布工作流化,可以显著减少人工干预。一个典型的 CI 流水线会在 Push 到主分支时,执行依赖安装、构建产物、以及对外发布的步骤。
通过 GitHub Actions,您可以缓存依赖、并指定 Python 版本,确保跨环境的一致性。
name: Build and Publish
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install build tools
run: python -m pip install --upgrade pip setuptools wheel
- name: Build
run: python -m build
- name: Publish
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
env:
PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }}
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python -m pip install --upgrade twine
python -m twine upload dist/* -u "$PYPI_USERNAME" -p "$PYPI_PASSWORD"
CI/CD 的核心 是通过流水线实现从代码提交到打包再到发布的全自动化。
4.2 连接到 PyPI 的发布流程
在发布阶段,建议先使用 Test PyPI 进行试水,确保产物在真实环境中的安装与解包没有问题。
# 上传到 Test PyPI
python -m twine upload --repository testpypi dist/* -u __token__ -p
凭证管理 应通过安全的方式保存,如在 CI 中使用 secrets,避免把真实凭证硬编码在仓库内。
5. 发布到 PyPI 的安全与最佳实践
5.1 测试环境的严格验证
在正式发布前,务必完成对安装、导入、功能调用的完整性验证。通过 Test PyPI 的经历,可以发现潜在的打包配置问题,避免将有缺陷的产物投放到生产环境。
同时,必须确保打包产物的 兼容性标签、依赖范围 与目标 Python 版本一致,以提升用户安装成功率。
5.2 安全性与凭证最佳实践
发布到 PyPI 时,请始终通过 twine 上传,并使用受保护的令牌或账户凭证。将凭证保存在 CI 秘钥 或本地安全环境变量中,避免公开暴露。
# 本地发布到 PyPI 的常见方式
python -m twine upload dist/* -u __token__ -p
通过本系列步骤,您可以实现一个完整的 Python 项目打包全流程:setuptools 与 wheel 的实战指南,从开发到发布并实现 CI/CD 自动化,从开发阶段的结构化配置,到持续集成的自动发布,全链路闭环,降低人工错误,提升发布节奏和产品质量。


