Skip to content

打包和发布 ​

将 Python 项目打包成可安装的包,分享给他人或发布到 PyPI。

Python 包结构 ​

my_package/
├── src/
│   └── my_package/
│       ├── __init__.py
│       ├── core.py
│       └── cli.py
├── tests/
├── pyproject.toml
├── README.md
└── LICENSE

pyproject.toml(PEP 621) ​

现代 Python 项目配置:

toml
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "my-awesome-package"
version = "0.1.0"
description = "A package that does awesome things"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT"}
authors = [
    {name = "Your Name", email = "you@example.com"}
]
keywords = ["example", "package"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Programming Language :: Python :: 3",
    "License :: OSI Approved :: MIT License",
]

dependencies = [
    "requests>=2.31.0",
    "click>=8.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0",
    "black>=23.0",
]

[project.urls]
Homepage = "https://github.com/yourusername/my-awesome-package"
Documentation = "https://my-awesome-package.readthedocs.io"

[project.scripts]
my-cli = "my_package.cli:main"

构建包 ​

安装构建工具 ​

bash
pip install build

构建 ​

bash
# 在项目根目录
python -m build

生成文件:

  • dist/my_awesome_package-0.1.0.tar.gz(源码包)
  • dist/my_awesome_package-0.1.0-py3-none-any.whl(wheel 包)

本地安装测试 ​

bash
# 开发模式(可编辑)
pip install -e .

# 或安装构建的包
pip install dist/my_awesome_package-0.1.0-py3-none-any.whl

发布到 PyPI ​

1. 创建 PyPI 账号 ​

访问 pypi.org 注册账号。

2. 安装 twine ​

bash
pip install twine

3. 上传 ​

bash
# 检查包
twine check dist/*

# 上传到 Test PyPI(推荐先测试)
twine upload --repository testpypi dist/*

# 上传到正式 PyPI
twine upload dist/*

4. 安装验证 ​

bash
pip install my-awesome-package

依赖管理工具 ​

pip(默认) ​

bash
pip install package_name
pip install -r requirements.txt
pip freeze > requirements.txt

poetry(推荐) ​

bash
# 安装
pip install poetry

# 初始化项目
poetry init

# 添加依赖
poetry add requests
poetry add pytest --group dev

# 安装依赖
poetry install

# 构建和发布
poetry build
poetry publish

pyproject.toml(poetry):

toml
[tool.poetry]
name = "my-package"
version = "0.1.0"
description = ""

[tool.poetry.dependencies]
python = "^3.10"
requests = "^2.31.0"

[tool.poetry.group.dev.dependencies]
pytest = "^7.0"

pdm(新兴) ​

bash
# 安装
pip install pdm

# 初始化
pdm init

# 添加依赖
pdm add requests
pdm add -d pytest

# 安装
pdm install

版本管理 ​

语义化版本(Semantic Versioning) ​

格式:MAJOR.MINOR.PATCH

  • MAJOR:不兼容的 API 变更
  • MINOR:向后兼容的功能新增
  • PATCH:向后兼容的问题修复

示例:

  • 1.0.0 → 1.0.1(修复 bug)
  • 1.0.1 → 1.1.0(新增功能)
  • 1.1.0 → 2.0.0(破坏性变更)

动态版本 ​

python
# src/my_package/__init__.py
__version__ = "0.1.0"
toml
# pyproject.toml
[project]
dynamic = ["version"]

[tool.setuptools.dynamic]
version = {attr = "my_package.__version__"}

实战案例:发布 CLI 工具 ​

python
# src/my_package/__init__.py
__version__ = "0.1.0"

# src/my_package/cli.py
import click

@click.command()
@click.option('--name', default='World', help='Name to greet')
def main(name):
    """Simple CLI tool"""
    click.echo(f'Hello, {name}!')

if __name__ == '__main__':
    main()
toml
# pyproject.toml
[project]
name = "my-cli-tool"
version = "0.1.0"
dependencies = ["click>=8.0"]

[project.scripts]
greet = "my_package.cli:main"

构建和安装:

bash
python -m build
pip install dist/my_cli_tool-0.1.0-py3-none-any.whl

# 使用
greet --name Alice
# 输出:Hello, Alice!

工具对比 ​

特性pippoetrypdm
依赖解析基础强大强大
锁文件❌✅✅
虚拟环境手动自动自动
发布twine内置内置
学习曲线低中中
推荐场景简单项目大多数项目新项目

小结 ​

  • pyproject.toml 是现代 Python 项目的标准配置(PEP 621)
  • python -m build 构建包
  • twine 发布到 PyPI
  • poetry 提供完整的依赖管理和发布流程
  • 语义化版本 清晰表达变更类型
  • CLI 入口 通过 [project.scripts] 定义

回到 工程实践概览 或查看 练习答案。


参考:

练习:答案

用心记录每一步成长