uv 0.4.x 版本演进解析:从非打包项目到命名索引与 PEP 735 依赖组
本文基于 uv 仓库中的 0.4.x 变更日志 系统梳理 0.4.0 至 0.4.30 共 31 个版本的演进脉络。读完本文,你将掌握 uv 0.4 周期的三大主线变化——非打包(virtual)项目的一等支持、[[tool.uv.index]] 命名索引体系、PEP 735 依赖组——以及 uv build、uv publish 两个新命令的引入背景,并能结合仓库源码(如 is_package 判定逻辑与 DependencyGroups 解析器)理解每项特性的实际行为,为升级和排障提供版本能力参照。
0.4 周期的整体定位
0.4.x 是 uv 项目从"通用 Python 包管理器"走向"完整项目生命周期管理"的关键阶段。变更日志开篇(changelogs/0.4.x.md)即点明 0.4.0 的核心目标:为"并非以 Python 包为目标的项目"(Web 应用、数据科学项目等)提供一等支持。随后 31 个补丁版本沿三条主线推进:
- 项目模型重塑(0.4.0、0.4.5):引入 virtual 项目、
uv build; - 索引体系重构(0.4.23、0.4.24、0.4.25):
[[tool.uv.index]]命名索引与tool.uv.sources索引绑定; - 依赖声明标准化(0.4.27、0.4.30):PEP 735
dependency-groups、.env文件与--all-packages。
此外还有若干横向能力:uv publish 与 Trusted Publishing(0.4.16)、托管 Python 3.13 与 free-threaded 构建(0.4.9 / 0.4.21 / 0.4.28)、以及一批环境变量(UV_PROJECT_ENVIRONMENT、UV_FIND_LINKS、UV_NO_SYNC、UV_FROZEN/UV_LOCKED)。
各版本核心亮点速览
| 版本 | 核心变化 |
|---|---|
| 0.4.0 | 非打包项目一等支持;uv init 默认不建 src/ 与 [build-system];--app/--lib 选项 |
| 0.4.1 | uv export --format requirements-txt;版本规约按序规范化;Windows 注册表发现 Python |
| 0.4.2 | uv run 支持 .pyc 文件;uv cache clean 清理悬挂归档 |
| 0.4.3 | uv sync --frozen --package 无需复制成员 pyproject.toml;--verbose 显示构建后端输出 |
| 0.4.4 | UV_PROJECT_ENVIRONMENT 自定义环境路径;uv export --no-hashes;uv init 固定 .python-version |
| 0.4.5 | 实现 uv build(含 --package、--wheel);锁文件剪除不可达包与 wheel |
| 0.4.6 | uv build 支持 --build-constraint、--require-hashes/--verify-hashes;uv tool upgrade 支持多包 |
| 0.4.7 | uv export 增加 --no-emit-project 与 --output-file;uv cache prune 清理未用 sdist |
| 0.4.8 | 动态缓存键(tool.uv.cache-keys);uv init 代码引入类型标注;.tgz 与 .tar.gz 同等对待 |
| 0.4.9 | 托管 Python 3.13;uv self update 支持目标版本;uv run --no-sync |
| 0.4.10 | uv run 支持 Python 包(__main__.py)与 zip 应用;tool.uv.cache-keys 支持 glob |
| 0.4.11 | uv sync/uv export 支持 --no-editable、--only-dev;uvx 生成 shell 补全 |
| 0.4.12 | 支持用户提供预定义解析元数据;Python 解释器不匹配时使工具环境失效 |
| 0.4.13 | SOCKS 代理支持;最低 Rust 版本提升至 1.81 |
| 0.4.14 | 破坏性变更:uvx shell 补全移至 uvx --generate-shell-completion;本地命名冲突解析提示 |
| 0.4.15 | 回退"无效平台比无效 Python 更兼容"的判定 |
| 0.4.16 | 实现 uv publish 与 Trusted Publishing;--project 参数;free-threaded 解释器选择 |
| 0.4.17 | uv build --all 构建整个 workspace;uv init --script;uv init 初始化 Git 仓库 |
| 0.4.18 | tool.uv.sources 允许每个包多条 source 条目;uv run -m foo;UV_NO_SYNC 环境变量 |
| 0.4.19 | uv run --script;UV_FIND_LINKS 环境变量;requires-python 上界参与 wheel 过滤 |
| 0.4.20 | CPython 3.13.0 正式版纳入托管下载并成为 uv python install 默认版本 |
| 0.4.21 | free-threaded Python 托管安装;HTTP/2;远程(https://)脚本运行;UV_INSECURE_HOST 通配符 |
| 0.4.22 | 构建依赖中尊重 [tool.uv.sources];uv publish 交互式输入 |
| 0.4.23 | 命名索引体系:[[tool.uv.index]] + tool.uv.sources 索引绑定 + explicit 索引 |
| 0.4.24 | 修复索引凭证泄露至锁文件;UV_INDEX_ 认证变量按文档生效 |
| 0.4.25 | UV_FROZEN/UV_LOCKED;uv pip show --files;缓存版本化支持向后兼容 |
| 0.4.26 | 系统级 uv.toml 配置支持;direct URL 要求可携带静态元数据 |
| 0.4.27 | PEP 735 dependency-groups:--group/--only-group/--no-group;uv lock --dry-run;强制锁文件 schema 版本 |
| 0.4.28 | +freethreaded 构建请求;禁用进度输出的环境变量 |
| 0.4.29 | riscv64 平台标签;uv tree 循环依赖处理;带版本号的 Python 可执行文件(Preview) |
| 0.4.30 | uv run 支持 .env 与自定义 env 文件;--all-packages;uv publish --check-url |
0.4.0:非打包(virtual)项目的一等支持
这是 0.4 周期最重要的一次语义变更,属于破坏性变更。变更日志说明了动机:此前 uv 要求所有项目都能构建成可分发的 Python 包并装入虚拟环境,uv init 创建的项目总是包含 [build-system] 定义,未定义 [build-system] 的存量项目则默认回退到 legacy setuptools 构建后端。但多数用户开发的是 Web 框架应用或脚本集合,而非需要发布到 PyPI 的库——强制 [build-system] 在这些场景下令人困惑且易错。
0.4.0 的新行为总结为四点(引自变更日志原文):
- 不再打包/安装未定义
[build-system]的项目。项目本身不会进入虚拟环境,但其依赖仍会被解析和安装; - 旧行为可通过
pyproject.toml的[tool.uv]段设置package = true恢复; uv init默认不再创建src/目录、不再定义[build-system];旧行为可通过uv init --lib或uv init --app --package恢复;- 允许(并推荐)虚拟 workspace 根包含
[project]定义(此前要求省略),并允许对定义了[build-system]的项目通过package = false显式禁用打包。
源码印证:is_package 判定逻辑
从源码结构看,该决策的核心入口是 crates/uv-workspace/src/pyproject.rs 中的 is_package 方法,其判定顺序与文档描述完全一致:
/// Returns `true` if the project should be considered a Python package, as opposed to a
/// non-package ("virtual") project.
pub fn is_package(&self, require_build_system: bool) -> bool {
// If `tool.uv.package` is set, defer to that explicit setting.
if let Some(is_package) = self.tool_uv_package() {
return is_package;
}
// Otherwise, a project is assumed to be a package if `build-system` is present.
self.build_system.is_some() || !require_build_system
}
即:tool.uv.package 显式设置时优先采用;否则以是否存在 [build-system] 表推断。这也解释了为什么变更日志中"未定义 [build-system] 的项目默认使用 setuptools 后端"的旧行为在 0.4.0 后被改变——默认路径从"兜底打包"变成了"直接视为 virtual 项目"。
0.4.0 同期其他增强
- 锁文件对非打包依赖使用
virtualsource 标签(PR #6728),便于在uv.lock中识别 virtual 项目来源; uv tool install支持{package}@{version}语法(PR #6762);- 省略
--hashes时从 URL fragment 读取哈希(PR #6731); - 发布不带 patch 版本的额外 Docker 标签。
值得留意的 bug 修复包括:--frozen 下不再要求 workspace 成员同步(PR #6737)、workspace 失效锁文件时比较 virtual 成员(PR #6754)、trusted host 的补全反序列化实现(PR #6716)、以及对 PEP 723 脚本中未闭合 script 标签报错(PR #6704)。
uv build:0.4.5 引入的本地构建命令
0.4.5 实现了 uv build,并在此后四个版本内快速完善,形成完整的本地构建能力:
- 0.4.5:
uv build落地(PR #6895);--package用于指定 workspace 中要构建的包(PR #6990);默认显示构建输出(PR #6912);支持从 sdist 构建 wheel(--wheel,PR #6898); - 0.4.6:
--build-constraint约束构建依赖(PR #7085);--require-hashes与--verify-hashes校验构建环境(PR #7094); - 0.4.14:
uv build输出目录加入.gitignore(0.4.18,PR #7835);workspace 场景改用顶层输出目录(0.4.18,PR #7813); - 0.4.17:
uv build --all一次性构建 workspace 全部包(PR #7724);--quiet生效(PR #7674)。
配套的解析器健壮性改进也在此期间落地:0.4.5 开始锁文件会剪除不可达的包(PR #6959)与 wheel(PR #6961),0.4.7 在 uv cache prune 中清理未使用的 sdist(PR #7112)。
0.4.23:命名索引体系([[tool.uv.index]])
0.4.23 引入了对包索引定义的重构,作为 pip 风格 --index-url/--extra-index-url 的替代方案。变更日志给出了完整配置示例,这里原样保留:
在 pyproject.toml 中定义命名索引:
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
通过 tool.uv.sources 把特定包固定到指定索引,确保 torch 总是从 pytorch 索引安装:
[tool.uv.sources]
torch = { index = "pytorch" }
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
把索引标记为 explicit = true 后,除非显式绑定,否则任何包都不会从该索引安装(torch 从 pytorch 索引、其余包走默认索引):
[tool.uv.sources]
torch = { index = "pytorch" }
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
explicit = true
pyproject.toml 之外的索引通过 --index 命令行参数(或 UV_INDEX 环境变量)定义;替换默认索引(PyPI)则用 --default-index(或 UV_DEFAULT_INDEX)。变更日志明确:这些变更与已弃用的 --index-url/--extra-index-url 完全向后兼容,后者行为不变。
配套增强包括:uv add --index/--default-index 会把索引 URL 写入项目(PR #7746);tool.uv.sources 允许一个包绑定多个索引(PR #7769);命名索引支持环境变量认证(PR #7741);--index 与 --default-index 的命名值可被 tool.uv.sources 引用(PR #7910)。
后续加固(0.4.24–0.4.26)
命名索引上线后立刻经历了一轮安全与健壮性修复:
- 0.4.24(安全相关):从锁文件来源中隐去索引凭证(PR #8307);按文档生效
UV_INDEX_而非UV_HTTP_BASIC_认证变量(PR #8306);改进 sources 反序列化错误信息(PR #8308)。 - 0.4.25:允许自定义索引名包含连字符与下划线(PR #8339);
uv.lock中的索引来源做凭证脱敏(PR #8333);认证缓存的用户名不再被忽略(PR #8345)。 - 0.4.26:提供凭证时不重写
[[tool.uv.index]]条目(PR #8502);索引认证变量名把连字符替换为下划线(PR #8452)。
从源码结构看,索引的认证与配置分别落在 crates/uv-auth/src/index.rs 与 crates/uv-distribution-types/src/index.rs 中的 Index 定义,认证细节可进一步参阅 docs/concepts/authentication 目录。
0.4.27:PEP 735 依赖组(dependency-groups)
0.4.27 实现了对 PEP 735 标准 [dependency-groups] 表的支持。其语义是:声明不会随包元数据发布的可选依赖组(区别于 [project.optional-dependencies],后者是发布到包元数据中的 extras)。uv 在整个接口中引入了 --group、--only-group、--no-group 三个新选项。
变更日志说明了兼容策略,值得逐条理解:
- 此前 uv 用单一的
tool.uv.dev-dependencies列表声明开发依赖;现在可以按标准格式声明,并把开发依赖拆分为多个组; - 对不需要多组的用户,uv 特判名为
dev的组:dev组等价于tool.uv.dev-dependencies,后者的内容会被合并进dev组参与解析; --dev、--only-dev、--no-dev保留为对应--group选项的别名;tool.uv.dev-dependencies在本版本继续支持,未来版本会显示弃用警告;- uv 默认同步
dev组(与旧行为一致),默认组集合可用tool.uv.default-groups设置修改。
源码印证:DependencyGroups 解析器
crates/uv-configuration/src/dependency_groups.rs 中的 DependencyGroups 结构实现了上述语义的收敛逻辑。from_history 方法先把 --dev 系列标志"脱糖"为 dev 组的 include/only/exclude 操作,再合并 --group/--only-group/默认组列表;其中两个关键规则与文档表述一一对应:
- exclude 永远胜过 include(结构体注释:
excludealways wins over include); --only隐含--no-default-groups(let default_groups = !no_default_groups && !only_groups;),即一旦指定--only-group,默认组(含dev)不再自动加入。
同期增强还包括:uv lock --dry-run(PR #7783)与强制锁文件 schema 版本(PR #8509,为后续锁文件演进预留版本约束);0.4.28 又恢复了 dev-dependencies 与 requires-dev 的锁文件兼容读取(PR #8599),并在 uv export 中尊重依赖组标记(0.4.29,PR #8659);0.4.30 则修复了非根 workspace 成员定义 --group 时的误报(PR #8734)与 workspace 锁定时纳入成员组(PR #8736)。
uv publish 与 Trusted Publishing(0.4.16 起)
0.4.16 实现了 uv publish 命令(PR #7475)及 Trusted Publishing 支持(PR #7548),随后持续完善:
- 0.4.21:HTTP/2 请求启用(PR #8049)——发布大文件时受益明显;
- 0.4.22:
uv publish支持交互式输入(PR #8158);缺失用户名时的专用错误(PR #8045);使用原始文件名(PR #8204); - 0.4.26:
uv publish尊重--allow-insecure-host(PR #8440);构建失败帮助页(PR #8286); - 0.4.28:改进 Trusted Publishing 错误信息,并在缺少权限时给出提示(PR #8632、PR #8633);
- 0.4.30:
uv publish --check-url在上传前检查远端是否已存在该发行版(PR #8531),配合--skip-existing使用(PR #8803)。
0.4.18 的文档条目显示官方文档已从 twine 切换到 uv publish 作为发布示例,0.4.17 起 uv build 与 uv publish 也进入了特性总览页——从仓库文档看可参阅 docs/getting-started/features.md。
环境变量配置面:0.4 周期新增项一览
0.4 周期把大量命令行开关镜像为环境变量,便于 CI 与全局配置。按版本归纳:
| 环境变量 | 引入版本 | 作用 |
|---|---|---|
UV_PROJECT_ENVIRONMENT |
0.4.4 | 自定义项目虚拟环境路径(PR #6834);文档见 0.4.4 的 PR #6987 |
UV_NO_SYNC |
0.4.18 | 跳过自动同步(PR #7752) |
UV_FIND_LINKS |
0.4.19 | --find-links 的环境变量形式,值用逗号分隔(0.4.21 修复为 CSV,PR #8061) |
UV_INDEX / UV_DEFAULT_INDEX |
0.4.23 | 命名索引的 CLI 镜像参数 --index/--default-index 的环境变量形式 |
UV_FROZEN / UV_LOCKED |
0.4.25 | --frozen/--locked 的环境变量形式(PR #8340) |
UV_INSECURE_HOST 通配符 |
0.4.21 | 支持通配主机(PR #8052) |
| 禁用进度输出 | 0.4.28 | 无进度条环境(PR #8600) |
UV_PROJECT_ENVIRONMENT 的行为在测试中有明确约束:crates/uv/tests/python/venv.rs 验证了 uv venv 在非项目上下文中忽略该变量,而在项目命令中它会改变环境路径(对应 0.4.4 "提示 VIRTUAL_ENV 已设置但项目命令中不会生效"的警告改进,PR #6864)。系统级 uv.toml 配置的支持则晚到 0.4.26 才落地(PR #7851),使团队可以在机器层面统一索引、镜像等设置,配合 docs/concepts/configuration-files.md 的层级规则使用。
Python 版本管理:3.13 与 free-threaded 构建
0.4 周期完整覆盖了 CPython 3.13 的生命周期:
- 0.4.9:纳入托管 Python 3.13(PR #7263),并升级所有托管 CPython 至最新 patch;
- 0.4.19:新增 CPython 3.13.0rc3 与 3.12.7 托管下载(PR #7880);
- 0.4.20:CPython 3.13.0 正式版纳入托管下载,并成为
uv python install的默认版本(PR #8010); - 0.4.16 / 0.4.21 / 0.4.28:free-threaded(无 GIL)Python 从"允许请求解释器"(PR #7431)发展到"托管安装"(PR #8100)再到"
+freethreaded后缀请求特定构建"(PR #8645),且 0.4.22 起优先选用 free-threaded 的lto优化构建(PR #8515 在 0.4.27 修正)。
同周期的解释器发现与兼容性子改进包括:0.4.1 直接用 Windows 注册表发现 Python(PR #6761);0.4.2 对 Python 与 PEP 723 脚本不兼容时给出警告(PR #6884);0.4.17 不再在解释器发现阶段生成字节码文件(PR #7707);0.4.29 增加 riscv64 平台标签(PR #8660)并修复 ARM 上 managed Python 的 hard/soft float libc 检测(PR #8498)。
uv run 与 PEP 723 脚本能力的持续扩展
uv run 在 0.4 周期吸收了多个"把 Python 跑起来"的长尾场景:
- 0.4.2:支持运行
.pyc文件(PR #6886); - 0.4.9:
--no-sync(PR #7192); - 0.4.10:支持直接运行 Python 包(
__main__.py,PR #7281)与 zip 应用(PR #7289); - 0.4.18:
uv run -m foo运行模块(PR #7754); - 0.4.19:
--script强制按 PEP 723 处理任意扩展名输入(PR #7739); - 0.4.21:PEP 723 元数据支持
uv run -(stdin,PR #8111);远程https://脚本直接运行(PR #6375);--with支持逗号分隔多包(PR #7909); - 0.4.30:
.env与自定义 env 文件支持(PR #8811);--all-packages用于uv run/uv sync/uv export,把 workspace 所有包纳入环境(PR #8742 等);--frozen可与--all-packages联用(PR #8760)。
与运行相关的错误处理也在持续改善:0.4.5 让 uv run 正确透传退出码(PR #6994);0.4.16 在未指定命令时列出可用脚本(0.4.20,PR #7687);0.4.16 新增 --project 参数从指定项目目录运行命令(PR #7603)。
缓存、锁文件与解析器可靠性
变更日志中"Bug fixes"与"Performance"章节密度很高,反映 uv 对缓存与锁正确性的持续投入,摘选具有长期影响的条目:
- 缓存:0.4.4 避免对缓存目录做规范化(PR #6949);0.4.7
uv cache prune清理未用 sdist(PR #7112);0.4.8 动态缓存键支持 glob 匹配并换用globwalk(PR #7337);0.4.13 对损坏 rkyv 条目的uv cache prune健壮性(PR #7561);0.4.13 提升 wheel/sdist 缓存版本并对缺失 sdist 的缓存条目自愈(PR #7560、PR #7559);0.4.25 缓存版本化改为向后兼容模式(PR #8386)。 - 锁文件正确性:0.4.3 下所有 Python 兼容性比较统一为下界语义(PR #6882);0.4.5 剪除不可达包与 wheel(PR #6959、PR #6961);0.4.6 成员版本变化时失效锁文件(PR #7102)、direct URL 来源去除 fragment(PR #7061);0.4.11
--no-sources调用中纳入dev-dependencies(PR #7408);0.4.14 回退了 0.4.13 中"无效平台比无效 Python 更兼容"的判定(0.4.15,PR #7608)——这类回退说明解析器平台兼容策略在该周期内经历了反复校准。 pyproject.toml写入安全:0.4.5 起 Ctrl-C(PR #7024)乃至所有错误(PR #7022)都会回滚pyproject.toml的修改;0.4.9 避免在非添加编辑中更新偏移量(PR #7262);0.4.25 保持注释位置正确(PR #8384)。- 性能:0.4.7
--no-deps与pip sync跳过元数据获取(PR #7127);0.4.8 未优化注册表不做批量预取(PR #7226);0.4.21 锁满足性检查使用共享索引、add与lock共享 resolver 状态避免二次 Git 更新(PR #8147、PR #8146)。 - 并发:0.4.1 修复多个 uv 进程竞争资源锁时的死锁(PR #6790);0.4.13 把"等待获取锁"从用户级警告降级(PR #7502)。
升级路径提示
从变更日志中可以归纳出 0.4 周期需要留意的升级注意点:
- 0.4.0 的打包语义反转:如果你的项目此前依赖"无
[build-system]时默认用 setuptools 打包"的行为,升级后需显式在[tool.uv]中设置package = true;反之,应用类项目可以移除[build-system]获得 virtual 行为。 - 0.4.14 的
uvx补全变更:uvx的 shell 补全入口移动到uvx --generate-shell-completion,这是 0.4.x 中唯一标注为 Breaking 的条目。 - 0.4.27 的依赖组迁移:
tool.uv.dev-dependencies仍可工作,但新代码建议改用[dependency-groups]的dev组,并按需拆分多组;默认组用tool.uv.default-groups调整。 - 0.4.23 的索引迁移:
--index-url/--extra-index-url继续可用但已弃用,新项目建议直接使用[[tool.uv.index]]+tool.uv.sources的显式绑定,尤其是存在多个专用索引(如 PyTorch)的场景。
小结
0.4.x 周期(0.4.0–0.4.30)完成了 uv 项目模型从"一切皆包"到"应用与库分治"的重构,落地了 uv build 与 uv publish 补齐本地构建-发布闭环,并以命名索引和 PEP 735 依赖组两个标准化能力对齐了上游生态。完整的逐版本条目、PR 编号与修复细节可查阅 changelogs/0.4.x.md;周边版本线的演进可对照 changelogs/0.3.x.md 与 changelogs/0.5.x.md。实现层面的深入阅读可从 crates/uv-workspace/src/pyproject.rs(项目/包判定)、crates/uv-configuration/src/dependency_groups.rs(依赖组解析)与 docs/concepts/indexes.md(索引概念)切入。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00