打包和发布
将 Python 项目打包成可安装的包,分享给他人或发布到 PyPI。
Python 包结构
my_package/
├── src/
│ └── my_package/
│ ├── __init__.py
│ ├── core.py
│ └── cli.py
├── tests/
├── pyproject.toml
├── README.md
└── LICENSEpyproject.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 twine3. 上传
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.txtpoetry(推荐)
bash
# 安装
pip install poetry
# 初始化项目
poetry init
# 添加依赖
poetry add requests
poetry add pytest --group dev
# 安装依赖
poetry install
# 构建和发布
poetry build
poetry publishpyproject.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!工具对比
| 特性 | pip | poetry | pdm |
|---|---|---|---|
| 依赖解析 | 基础 | 强大 | 强大 |
| 锁文件 | ❌ | ✅ | ✅ |
| 虚拟环境 | 手动 | 自动 | 自动 |
| 发布 | twine | 内置 | 内置 |
| 学习曲线 | 低 | 中 | 中 |
| 推荐场景 | 简单项目 | 大多数项目 | 新项目 |
小结
- pyproject.toml 是现代 Python 项目的标准配置(PEP 621)
- python -m build 构建包
- twine 发布到 PyPI
- poetry 提供完整的依赖管理和发布流程
- 语义化版本 清晰表达变更类型
- CLI 入口 通过
[project.scripts]定义
参考:
练习:答案