uv 构建分发深入指南uv build 的打包流程、构建依赖约束与 PyPI 发布防护【免费下载链接】uvAn extremely fast Python package and project manager, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/uv/uv本文基于 uv 官方文档 Building distributions 展开系统讲解如何用uv build将 Python 项目打包为 source distributionsdist与 wheel如何结合--build-constraint与--require-hashes实现可复现的构建依赖锁定以及如何通过Private :: Do Not Upload分类器防止内部包误发布到 PyPI。读完之后你可以独立完成项目分发构建并在 CI 中建立一套可审计、可复现的打包流水线。一、为什么要构建分发sdist 与 wheel要把项目分发给他人例如上传到 PyPI 等索引首先需要将其构建为可分发的格式。Python 项目通常同时分发两种产物Source distributionsdist源分发通常是.tar.gz或.zip文件包含项目源码以及额外的打包元数据安装时需要重新执行构建过程Binary distributionwheel二进制分发.whl文件包含预先构建好的产物模块、元数据等可以跳过构建步骤直接安装因此安装速度更快。官方文档对uv build的边界有明确界定这一点在理解整个打包链路时非常关键使用uv build时uv 充当build frontend构建前端它只负责确定使用哪个 Python 版本、以及调用构建后端build backend。构建的细节——包含哪些文件、分发文件的命名——都由构建后端决定构建后端定义在pyproject.toml的[build-system]表中。构建配置的具体信息需要查阅相应工具setuptools、hatchling、maturin 等的文档。从源码可以印证这一“前端/后端”职责划分。在 uv-build-frontend 中uv 解析pyproject.toml的[build-system]表得到Pep517Backend后端名、requires依赖、可选的backend-path。当pyproject.toml中没有[build-system]表时uv 会回退到默认后端/// The default backend to use when PEP 517 is used without a build-system section. static DEFAULT_BACKEND: LazyLockPep517Backend LazyLock::new(|| Pep517Backend { backend: setuptools.build_meta:__legacy__.to_string(), requirements: vec![Requirement::from( uv_pep508::Requirement::from_str(setuptools 40.8.0).unwrap(), )], });这与 构建系统配置文档 中的说明一致uv 依据[build-system]表的存在与否判断项目是否包含需要安装的包对依赖的第三方包而言即使没有声明构建系统也会因历史兼容原因以setuptools.build_meta:__legacy__方式构建。二、使用uv build构建分发uv build可以为项目同时构建 sdist 与 wheel。默认情况下它对当前目录的项目进行构建并把产物放在dist/子目录中$ uv build $ ls dist/ example-0.1.0-py3-none-any.whl example-0.1.0.tar.gz构建其他目录与选择构建目标传入路径即可构建其他目录的项目uv build path/to/projectuv build的执行顺序是先构建 source distribution再从该 sdist 构建 binary distributionwheel。这一顺序保证了 wheel 的内容与 sdist 的内容一致可以用标志限定构建范围uv build --sdist只构建源分发uv build --wheel只构建 wheeluv build --sdist --wheel显式同时构建两者从 sdist 构建 wheel。uv build的完整参数视图除了文档提到的选项CLI 定义 中BuildArgs还暴露了以下常用选项可按需组合使用参数说明src位置参数构建来源目录默认当前目录也支持传入一个 sdist 归档将其构建为 wheel--package name在工作区内构建指定包与--all-packages互斥--all-packages别名--all构建工作区内的所有包--out-dir/-o指定产物输出目录默认为来源目录下的dist/--sdist/--wheel限定只构建 sdist 或只构建 wheel--build-constraint/-b用约束文件约束构建依赖的版本见下一节--require-hashes启用哈希校验模式要求构建依赖匹配已知哈希--python/-p指定构建环境使用的 Python 解释器构建默认在隔离的虚拟环境中执行--clear构建前清空输出目录删除过期产物--no-build-logs隐藏构建后端输出的日志--force-pep517对使用 uv 构建后端的项目强制走完整 PEP 517 流程默认存在直连后端的快速路径--no-create-gitignore不在输出目录生成.gitignore默认会在dist/中生成一份将构建产物排除出版本控制例如只构建某个工作区成员并输出到指定目录$ uv build --package my-lib -o /tmp/artifacts三、构建依赖约束--build-constraint与--require-hashesuv build接受--build-constraint选项用于约束构建过程中安装的构建依赖即[build-system].requires声明的包如setuptools、hatchling的版本。与--require-hashes组合使用时uv 会强制要求用于构建的依赖匹配特定的、已知的哈希值从而实现可复现构建——这在 CI/CD 中锁定打包工具链版本时非常有用。完整示例假设你有如下constraints.txtsetuptools68.2.2 --hashsha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a运行以下命令uv 会用指定版本的setuptools构建项目并校验下载到的setuptools分发包与给定哈希一致$ uv build --build-constraint constraints.txt --require-hashes约束文件是类requirements.txt格式的文件注意其语义是只控制版本在约束文件中列出某个包并不会“触发”该包的额外安装它只会在构建依赖恰好包含该包时限制其版本。参数细节与错误行为从 CLI 参数定义 可以看到--build-constraint是长选项名同时带有短选项-bshort和别名--build-constraint的兼容写法并支持环境变量UV_BUILD_CONSTRAINT通过空格分隔value_delimiter 可一次传入多个约束文件。当约束与项目的build-system.requires冲突时构建会直接失败且不会产出任何分发文件。集成测试 build_constraints 验证了这一行为// 项目声明 requires [hatchling1.0]约束文件写 hatchling0.1.0 // 期望失败输出 // error: Failed to resolve requirements from build-system.requires // Caused by: No solution found when resolving: hatchling1.0 // Caused by: Because you require hatchling1.0 and hatchling0.1.0, // we can conclude that your requirements are unsatisfiable.测试还断言了dist/project-0.1.0.tar.gz与dist/project-0.1.0-py3-none-any.whl均不存在即构建失败时不留下部分产物。此外从测试用例可以推断工作区场景还支持在pyproject.toml中以[tool.uv] build-constraint-dependencies [hatchling0.1.0]声明成员包可继承的构建约束见 crates/uv/tests/build/build.rs。底层原理构建隔离环境如何生效在 uv-build-frontend/src/lib.rs 的SourceBuild::setup中可以看到约束生效的完整链路uv 解析pyproject.toml得到Pep517Backend后端名与requires依赖在缓存目录下创建一个隔离的临时虚拟环境uv_virtualenv::create_venv构建在独立环境中进行不污染项目环境通过get_resolved_requirements对build-system.requires执行依赖解析——--build-constraint提供的约束文件正是在此解析阶段参与版本选择--require-hashes则在下载安装时校验哈希将解析出的构建依赖安装进隔离环境后才真正调用后端钩子执行构建。四、PEP 517 构建流程源码解析uv build实际执行的构建由SourceBuild结构体uv-build-frontend/src/lib.rs驱动它维护了构建过程中的关键状态临时目录、来源树路径、后端信息、隔离 venv、构建类型sdist / wheel / editable等。核心流程如下1后端导入与 backend-path 处理。Pep517Backend::backend_import生成导入代码若后端形如module:object例如setuptools.build_meta:__legacy__生成from {path} import {object} as backend若声明了backend-path还会先把这些目录插入sys.path头部以便支持 in-tree代码库内嵌构建后端。uv 对backend-path有安全校验路径必须是源树内的相对目录绝对路径或逃逸出源树的路径会直接报错见extract_pep517_backend中的BackendPathOutsideSourceTree检查。2可选的元数据预构建。get_metadata_without_build会先调用prepare_metadata_for_build_wheel钩子提前获取元数据供后续build_wheel复用PEP 517 契约要求两者的元数据一致。对hatchling.build后端且dependencies/optional-dependencies声明为dynamic的项目uv 会跳过这一步因为 Hatch 的动态钩子可能无法保证两次调用结果一致。3执行构建钩子。pep517_build根据构建类型生成 Python 脚本调用backend.build_sdist(output_dir, config_settings)或backend.build_wheel(output_dir, config_settings, metadata_directory)并让后端把产物的文件名写回临时文件供 uv 读取。脚本在隔离 venv 中执行工作目录为来源树。4并发安全。由于 setuptools 会在来源树中写入*.egg-info、build/、dist/等文件并发构建可能相互踩踏。acquire_lock会在检测到后端为 setuptools 时对一个位于系统临时目录的代理锁文件按来源树规范化路径的摘要命名加独占锁避免在用户源目录中留下需要.gitignore的.lock文件。5Python 版本的选择。uv build作为前端通过--python默认发现机制选定解释器该解释器用于创建隔离构建环境在不同平台以符号链接或拷贝方式接入。构建产物如 wheel 的 tag仍由构建后端根据运行时环境决定。五、防止误发布到 PyPI对于不希望公开的内部包官方文档推荐在pyproject.toml中标记为私有[project] classifiers [Private :: Do Not Upload]该分类器的效果与边界PyPI 会拒绝带有Private :: Do Not Upload分类器的上传请求相当于在索引侧增加了一道保险它不影响其他替代注册表内部索引等的安全或隐私设置——那些系统是否拦截取决于其自身配置文档同时建议只生成 per-project 的 PyPI API token。若 token 与项目名不匹配则该项目根本无法被上传从凭证层面杜绝误发布。将两者结合使用——分类器 细粒度 token——可以覆盖“工具误传”和“凭证滥用”两类风险。六、小结与延伸阅读uv build是 PEP 517 构建前端只负责选 Python 版本、隔离构建环境、调用后端文件清单与命名由[build-system]指定的后端决定详见 构建系统说明默认先构建 sdist、再基于 sdist 构建 wheel产物落在dist/可用--sdist/--wheel/--out-dir/--package/--all-packages精细控制--build-constraint--require-hashes是构建链可复现性的关键手段约束只限版本、不触发额外安装冲突时构建失败且不留产物内部包用Private :: Do Not Upload分类器配合 per-project API token 双重防护避免误传 PyPI。更多上下文可参考构建系统配置、CLI 参数定义、构建前端实现 以及 uv build 集成测试。【免费下载链接】uvAn extremely fast Python package and project manager, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/uv/uv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考