项目管理与工作流
2026/3/20大约 10 分钟
项目管理与工作流
使用 uv 高效管理 Python 项目的完整指南
项目初始化
创建新项目
uv 提供了多种项目模板,适用于不同场景:
# 创建应用项目(默认)
uv init myapp
# 创建库项目(用于发布到 PyPI)
uv init --lib mylib
# 创建可打包项目
uv init --package mypackage
# 在当前目录初始化
uv init
项目类型对比
应用项目结构
uv init myapp
生成结构:
myapp/
├── .python-version # Python 版本
├── pyproject.toml # 项目配置
├── README.md # 说明文档
└── hello.py # 入口脚本
pyproject.toml 内容:
[project]
name = "myapp"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
库项目结构
uv init --lib mylib
生成结构:
mylib/
├── .python-version
├── pyproject.toml
├── README.md
└── src/
└── mylib/
├── __init__.py
└── py.typed # 类型标记文件
pyproject.toml 内容:
[project]
name = "mylib"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
包项目结构
uv init --package mypackage
生成结构:
mypackage/
├── .python-version
├── pyproject.toml
├── README.md
└── src/
└── mypackage/
├── __init__.py
└── __main__.py # 支持 python -m 调用
pyproject.toml 包含入口点配置:
[project]
name = "mypackage"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
[project.scripts]
mypackage = "mypackage:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
初始化选项
# 指定 Python 版本
uv init --python 3.11 myproject
# 指定项目名称(与目录名不同)
uv init --name my-awesome-project myproject
# 不创建 README
uv init --no-readme myproject
# 指定虚拟环境路径
uv init --venv .venv myproject
# 指定作者信息
uv init --author "Your Name" --author-email "you@example.com" myproject
依赖管理
添加依赖
基本添加
# 添加单个依赖
uv add requests
# 添加多个依赖
uv add flask sqlalchemy redis
# 添加时指定版本约束
uv add "requests>=2.28"
uv add "flask>=2.0,<3.0"
uv add "django~=4.2" # 兼容版本 (>=4.2, <5.0)
uv add "numpy==1.24.0" # 精确版本
版本说明符
| 说明符 | 含义 | 示例 |
|---|---|---|
>= | 大于等于 | requests>=2.28 |
<= | 小于等于 | requests<=2.30 |
> | 大于 | requests>2.28 |
< | 小于 | requests<3.0 |
== | 精确版本 | requests==2.28.0 |
!= | 不等于 | requests!=2.28.0 |
~= | 兼容版本 | requests~=2.28 → >=2.28,<2.29 |
^ | 语义化兼容 | requests^2.28 → >=2.28,<3.0 |
添加开发依赖
# 添加开发依赖
uv add --dev pytest
uv add --dev black ruff mypy
# 查看 pyproject.toml 中的配置
[tool.uv]
dev-dependencies = [
"pytest>=7.0",
"black>=23.0",
"ruff>=0.1.0",
"mypy>=1.0",
]
添加可选依赖组
# 添加到指定的可选依赖组
uv add --optional docs sphinx sphinx-rtd-theme
uv add --optional test pytest pytest-cov pytest-asyncio
# 查看 pyproject.toml 中的配置
[project.optional-dependencies]
docs = [
"sphinx>=6.0",
"sphinx-rtd-theme>=1.0",
]
test = [
"pytest>=7.0",
"pytest-cov>=4.0",
"pytest-asyncio>=0.21",
]
添加特殊来源的依赖
# 从 Git 仓库添加
uv add git+https://github.com/user/repo.git
uv add git+https://github.com/user/repo.git@main
uv add git+https://github.com/user/repo.git@v1.0.0
uv add git+https://github.com/user/repo.git@abc123
# 从 URL 添加
uv add https://example.com/package.tar.gz
# 从本地路径添加
uv add ./path/to/local/package
uv add ../sibling-package
# 添加可编辑依赖(开发时)
uv add --editable ./path/to/local/package
移除依赖
# 移除依赖
uv remove requests
# 移除多个依赖
uv remove flask sqlalchemy
# 移除开发依赖
uv remove --dev pytest
# 移除可选依赖组中的包
uv remove --optional docs sphinx
更新依赖
# 更新锁文件中的所有依赖
uv lock --upgrade
# 更新指定依赖
uv lock --upgrade-package requests
# 更新多个依赖
uv lock --upgrade-package requests --upgrade-package flask
# 查看可更新的依赖
uv pip list --outdated
查看依赖
# 查看依赖树
uv tree
# 示例输出
myproject v0.1.0
├── flask v3.0.0
│ ├── blinker v1.7.0
│ ├── click v8.1.7
│ ├── itsdangerous v2.1.2
│ ├── jinja2 v3.1.2
│ │ └── markupsafe v2.1.3
│ └── werkzeug v3.0.1
│ └── markupsafe v2.1.3
└── requests v2.31.0
├── certifi v2023.11.17
├── charset-normalizer v3.3.2
├── idna v3.6
└── urllib3 v2.1.0
# 反向依赖查询(谁依赖这个包)
uv tree --invert
# 只显示指定包的依赖
uv tree --package flask
同步与锁定
理解锁文件
uv 使用 uv.lock 文件来记录精确的依赖版本和来源:
# uv.lock 示例(部分)
version = 1
requires-python = ">=3.12"
[[package]]
name = "flask"
version = "3.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "blinker" },
{ name = "click" },
{ name = "itsdangerous" },
{ name = "jinja2" },
{ name = "werkzeug" },
]
sdist = { url = "...", hash = "sha256:..." }
wheels = [
{ url = "...", hash = "sha256:..." },
]
同步命令详解
# 基本同步(安装所有依赖)
uv sync
# 包含开发依赖
uv sync --dev
# 包含可选依赖组
uv sync --extra docs
uv sync --extra test --extra docs
# 包含所有可选依赖
uv sync --all-extras
# 冻结模式(严格使用锁文件,不更新)
uv sync --frozen
# 离线模式(只使用缓存)
uv sync --offline
# 不安装项目本身(只安装依赖)
uv sync --no-install-project
# 不安装开发依赖
uv sync --no-dev
锁定命令详解
# 更新锁文件
uv lock
# 升级所有依赖到最新兼容版本
uv lock --upgrade
# 升级指定包
uv lock --upgrade-package flask
uv lock --upgrade-package "requests>=2.30"
# 检查锁文件是否最新
uv lock --check
# 显示锁文件更新内容
uv lock --dry-run
同步与锁定的工作流
运行项目
uv run 命令
uv run 是 uv 的核心命令之一,用于在项目环境中运行命令:
# 运行 Python 脚本
uv run python app.py
# 运行模块
uv run python -m mypackage
# 运行 pytest
uv run pytest
# 运行 Python 交互式解释器
uv run python
# 运行任意命令
uv run ruff check .
uv run black .
自动环境管理
uv run 的智能行为:
临时依赖
使用 --with 添加临时依赖(不写入 pyproject.toml):
# 临时使用 rich 库
uv run --with rich python -c "from rich import print; print('[bold]Hello![/bold]')"
# 临时使用多个库
uv run --with httpx --with beautifulsoup4 python scrape.py
# 临时使用特定版本
uv run --with "requests>=2.30" python test_requests.py
环境覆盖
# 使用不同的 Python 版本运行
uv run --python 3.11 python --version
# 使用指定的虚拟环境
uv run --directory /path/to/project python app.py
# 不同步直接运行(假设环境已准备好)
uv run --frozen python app.py
构建与发布
构建分发包
# 构建 sdist 和 wheel
uv build
# 只构建 wheel
uv build --wheel
# 只构建 sdist
uv build --sdist
# 指定输出目录
uv build --out-dir ./dist
构建产物:
dist/
├── mypackage-0.1.0-py3-none-any.whl # wheel 包
└── mypackage-0.1.0.tar.gz # 源码包
发布到 PyPI
# 发布到 PyPI(需要配置 token)
uv publish
# 发布到 TestPyPI
uv publish --repository testpypi
# 指定 token
uv publish --token pypi-xxx...
# 发布特定文件
uv publish dist/mypackage-0.1.0-py3-none-any.whl
配置 PyPI Token
# 使用环境变量
export UV_PUBLISH_TOKEN=pypi-xxx...
# 或在 pyproject.toml 中配置仓库
[tool.uv]
publish-url = "https://upload.pypi.org/legacy/"
完整的发布流程
# 1. 更新版本号
# 编辑 pyproject.toml 中的 version
# 2. 确保测试通过
uv run pytest
# 3. 构建
uv build
# 4. 发布到 TestPyPI 测试
uv publish --repository testpypi
# 5. 从 TestPyPI 安装测试
uv pip install --index-url https://test.pypi.org/simple/ mypackage
# 6. 发布到正式 PyPI
uv publish
# 7. 打 Git 标签
git tag v0.1.0
git push origin v0.1.0
工作流最佳实践
日常开发工作流
# 1. 克隆项目
git clone https://github.com/user/project.git
cd project
# 2. 同步环境
uv sync
# 3. 开发...
# 编辑代码
# 4. 运行测试
uv run pytest
# 5. 代码检查
uv run ruff check .
uv run mypy .
# 6. 提交代码
git add .
git commit -m "feat: add new feature"
添加新依赖工作流
# 1. 添加依赖
uv add new-package
# 2. 锁文件自动更新
# uv.lock 已更新
# 3. 测试功能
uv run python -c "import new_package; print('OK')"
# 4. 提交更改
git add pyproject.toml uv.lock
git commit -m "deps: add new-package"
团队协作工作流
推荐的 .gitignore
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
# 虚拟环境
.venv/
venv/
ENV/
env/
# uv
# 不要忽略 uv.lock - 它应该被提交!
# uv.lock
# 构建产物
build/
dist/
*.egg-info/
*.egg
# IDE
.idea/
.vscode/
*.swp
*.swo
# 测试
.pytest_cache/
.coverage
htmlcov/
.tox/
.nox/
# 类型检查
.mypy_cache/
.dmypy.json
# 其他
*.log
.DS_Store
Thumbs.db
Makefile 示例
创建 Makefile 简化常用操作:
.PHONY: install dev test lint format build clean
# 安装依赖
install:
uv sync
# 安装开发依赖
dev:
uv sync --dev
# 运行测试
test:
uv run pytest -v
# 运行测试并生成覆盖率报告
test-cov:
uv run pytest --cov=src --cov-report=html
# 代码检查
lint:
uv run ruff check .
uv run mypy src
# 代码格式化
format:
uv run ruff format .
uv run ruff check --fix .
# 构建
build:
uv build
# 发布
publish:
uv publish
# 清理
clean:
rm -rf build dist *.egg-info
rm -rf .pytest_cache .mypy_cache .ruff_cache
rm -rf htmlcov .coverage
find . -type d -name __pycache__ -exec rm -rf {} +
# 更新依赖
update:
uv lock --upgrade
uv sync
# 显示依赖树
tree:
uv tree
使用方式:
make dev # 安装开发环境
make test # 运行测试
make lint # 代码检查
make format # 格式化代码
make build # 构建包
多环境管理
使用环境变量区分环境
# config.py
import os
ENV = os.getenv("APP_ENV", "development")
if ENV == "production":
DEBUG = False
DATABASE_URL = os.getenv("DATABASE_URL")
else:
DEBUG = True
DATABASE_URL = "sqlite:///dev.db"
# 开发环境
uv run python app.py
# 生产环境
APP_ENV=production uv run python app.py
使用可选依赖组管理不同环境
# pyproject.toml
[project]
dependencies = [
"flask>=3.0",
"sqlalchemy>=2.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.0",
"ruff>=0.1.0",
]
prod = [
"gunicorn>=21.0",
"psycopg2-binary>=2.9",
]
# 开发环境
uv sync --extra dev
# 生产环境
uv sync --extra prod
# 完整环境
uv sync --all-extras
故障排除
常见问题
依赖冲突
# 查看冲突详情
uv lock --verbose
# 尝试不同的解析策略
uv lock --resolution lowest
uv lock --resolution highest
# 临时排除问题包
uv lock --exclude some-package
同步失败
# 清理并重新同步
rm -rf .venv
uv sync
# 强制重新创建虚拟环境
uv venv --force
uv sync
# 检查锁文件
uv lock --check
构建失败
# 检查构建依赖
uv run pip install build
uv run python -m build
# 验证 pyproject.toml 格式
uv run python -c "import tomllib; tomllib.load(open('pyproject.toml', 'rb'))"
调试技巧
# 启用详细输出
uv sync --verbose
# 查看完整的依赖解析过程
UV_LOG=debug uv lock
# 检查缓存状态
uv cache dir
ls -la $(uv cache dir)
总结
本章涵盖了 uv 项目管理的核心功能:
| 功能 | 命令 |
|---|---|
| 创建项目 | uv init [--lib|--package] |
| 添加依赖 | uv add [--dev|--optional] |
| 移除依赖 | uv remove |
| 同步环境 | uv sync [--frozen] |
| 锁定依赖 | uv lock [--upgrade] |
| 运行命令 | uv run |
| 查看依赖 | uv tree |
| 构建发布 | uv build / uv publish |
关键要点
- 始终提交锁文件 -
uv.lock应该纳入版本控制 - 使用
--frozen保证一致性 - CI/CD 中使用冻结模式 - 善用可选依赖组 - 区分开发、测试、生产依赖
uv run是你的好朋友 - 自动管理环境,无需手动激活
下一步
- 虚拟环境管理 - 深入了解环境隔离
- Python 版本管理 - 管理多个 Python 版本