Course Builder个人学习工作台 · 本地模式
Modern Python:面向有经验开发者的回归路线

pyproject.toml、uv 与可复现环境

目标:能够解释项目声明、依赖锁定、环境同步和命令执行的区别,并用 uv 建立可删除重建的实验环境。

旧式 Python 项目常把 setup.py、requirements.txt、virtualenv 命令和各工具配置分散在多处。现代项目通常以 pyproject.toml 作为声明入口,用 lockfile 保存一次解析的确定结果,再把 .venv 当作可删除的本地物化结果。

四者职责不同:

  • pyproject.toml:项目名、Python 兼容范围、直接依赖和工具配置。
  • uv.lock:包含传递依赖和版本解析结果,应与项目一起提交。
  • .venv:当前机器安装结果,不提交,坏了可重建。
  • uv run:在项目环境中执行命令;无需手动 source activation。

实验:从声明到锁定

在第 1 课创建的 textlab 项目中运行:

uv add pydantic
uv tree
uv run python -c 'import pydantic; print(pydantic.__version__)'

打开 pyproject.toml,确认 pydantic 出现在 [project].dependencies;再打开 uv.lock,会看到 Pydantic 和传递依赖。不要手工编辑 lockfile。

一个适合本课程的基础配置形如:

[project]
name = "textlab"
version = "0.1.0"
description = "Runnable Modern Python course project"
requires-python = ">=3.12,<3.15"
dependencies = [
    "pydantic>=2",
]

这里的范围表达课程实验支持 3.12–3.14;具体解析版本仍由 lockfile 决定。若只写 >=3.12,未来不兼容的大版本也可能被认为满足声明。

同步不是解析的同义词

  • uv lock 更新解析结果;
  • uv sync 让环境与 lockfile 对齐;
  • uv sync --locked 在 lockfile 与声明不一致时失败,而不是悄悄重写;
  • uv run --locked ... 适合 CI 或需要确认不发生重锁的命令。

删除环境并重建:

rm -rf .venv
uv sync --locked
uv run --locked python main.py

预期观察:.venv 会重新出现,程序仍能运行。真正的复现证据是“删除后能按声明与锁重建”,不是“我的旧 .venv 一直没坏”。Windows PowerShell 可用 Remove-Item -Recurse -Force .venv 替代第一条。

引导实验:运行依赖与开发依赖

测试、格式化和类型检查工具只在开发与 CI 中使用:

uv add --dev pytest ruff pyright

检查 pyproject.toml,这些工具应进入 dependency-groups.dev,而不是应用运行依赖。随后:

uv sync --locked
uv run ruff --version
uv run pyright --version
uv run pytest --version

如果 --locked 在刚 uv add 后失败,说明 lock 更新未完成或文件被手改;查看 Git diff,不要删除保护参数。

独立练习

新增可选依赖组 api,包含 FastAPI,但暂时不要安装到默认环境。然后用 uv 明确安装该 extra/group,并证明 import fastapi 的前后差异。由于 uv 对 dependency group 与 project extra 的命令语义不同,先选择一种并在 README 中写清。

一种参考做法

使用 project optional dependency:

[project.optional-dependencies]
api = ["fastapi>=0.115"]

更新锁并安装:

uv lock
uv sync --extra api
uv run python -c 'import fastapi; print(fastapi.__version__)'

若应用最终始终需要 FastAPI,就不应继续把它当 optional;第 16 课会把它加入正常依赖。

排错路线

  • uv run 使用了意外 Python:运行 uv run python -VV 和 uv run python -c 'import sys; print(sys.executable)'。
  • 声明改了但环境没变:运行 uv lock/uv sync,检查命令是否用了 --locked。
  • lockfile 在不同机器变化:比较 uv 版本、Python 范围、index 配置和平台 marker,不要只比较最终包名。

参考资料