uv 中的依赖声明方式:pyproject.toml 与 requirements.in 完整指南
uv 中的依赖声明方式pyproject.toml 与 requirements.in 完整指南【免费下载链接】uvAn extremely fast Python package and project manager, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/uv/uv声明依赖是 Python 工程化的起点。在 uv 中最佳实践是把依赖声明放在静态文件中而不是对虚拟环境做临时的 ad-hoc 安装一旦依赖被定义就可以通过锁定lock生成一致、可复现的环境。本文围绕 uv 官方文档中 Declaring dependencies 展开讲清pyproject.toml与requirements.in两种声明方式的写法、可选依赖extras的语义差异并结合 uv 仓库源码说明这些声明是如何被解析的。为什么用静态文件声明依赖uv 的 dependencies 文档开篇就给出核心原则依赖应当声明在静态文件中原因是可复现静态声明文件可以随代码库版本化团队成员和 CI 看到的依赖定义完全一致可锁定声明之后可以用uv pip compile将依赖锁定到精确版本生成可复现的安装清单。文档中的链接指向 锁定环境指南$ uv pip compile pyproject.toml -o requirements.txt可审计文件化的依赖便于审查与 diff避免环境里到底装了什么只存在于某个开发者的本地机器上。声明完依赖后后续的完整链路是声明pyproject.toml/requirements.in→ 锁定uv pip compile生成requirements.txt→ 安装/同步uv pip install/uv pip sync。使用 pyproject.toml 声明依赖pyproject.toml是 Python 标准中用于定义项目配置的文件。uv 遵循 PEP 621 来读取其中的project表。声明基础依赖在pyproject.toml中定义项目依赖[project] dependencies [ httpx, ruff0.3.0 ]每个条目都是标准的 PEP 508 需求说明符requirement specifier因此可以带版本约束、环境标记markers等例如ruff0.3.0表示安装不低于 0.3.0 的版本。声明可选依赖extras可选依赖定义在[project.optional-dependencies]表中[project.optional-dependencies] cli [ rich, click, ]这里的每个键key定义一个extra本例中为cli。使用 uv 时有三种安装/锁定这些可选依赖的方式用--extra标志按需启用uv pip install --extra cli或uv pip compile pyproject.toml --extra cli用--all-extras一次性启用所有 extras用 PEP 508 的package[extra]语法在依赖中直接引用例如my-package[cli]。更详细的安装用法见 从文件安装包。源码视角uv 如何解析 pyproject.toml从 uv 的实现看pyproject.toml的解析入口在 uv-pypi-types 的元数据模块/// PEP 621 project metadata. #[derive(Deserialize, Debug, Clone)] #[serde(try_from PyprojectTomlWire)] pub struct Project { /// The name of the project pub name: PackageName, /// The version of the project as supported by PEP 440 pub version: OptionVersion, /// The Python version requirements of the project pub requires_python: OptionString, /// Project dependencies pub dependencies: OptionVecString, /// Optional dependencies pub optional_dependencies: OptionIndexMapExtraName, VecString, /// Specifies which fields listed by PEP 621 were intentionally unspecified pub dynamic: OptionVecString, }来源crates/uv-pypi-types/src/metadata/pyproject_toml.rs几个值得注意的实现细节optional_dependencies是IndexMapExtraName, VecString即extra 名 → 依赖字符串列表的有序映射。文档示例中cli [rich, click]会被解析为键cli映射到两个依赖项。ExtraName来自uv-normalize意味着 extra 名会经过规范化处理大小写不敏感等dynamic字段的特殊含义如果dependencies出现在dynamic列表中说明依赖不是静态可知的需要运行构建后端才能获取。specification.rs 的模块文档解释了 uv 对此的分流逻辑——静态pyproject.toml会直接读取dependencies并丢弃目录本身动态的则把目录加入source_trees通过 PEP 517 调用构建后端获取元数据requires-python也参与解析PyProjectToml::requires_python()会在requires-python被列入dynamic时拒绝提供返回DynamicField错误说明 uv 要求用于版本过滤的requires-python必须是静态可得的。使用 requirements.in 声明依赖除pyproject.toml外Python 生态中常见的另一种做法是用轻量的requirements 文件格式每行一个依赖来声明项目依赖。uv 文档建议将文件命名为requirements.in以便与锁定后生成的requirements.txt区分开。基本写法httpx ruff0.3.0每一行是一个独立的需求条目。关键限制不支持可选依赖分组requirements.in格式不支持可选依赖分组extras groups。这是它与pyproject.toml的重要语义差异特性pyproject.tomlrequirements.in标准项目配置是PEP 621否可选依赖 / extras支持[project.optional-dependencies]不支持--extra/--all-extras锁定支持不适用定位项目元数据 依赖声明轻量依赖清单因此在uv pip compile requirements.in时无法使用--extra来启用额外依赖组而uv pip compile pyproject.toml --extra foo则会把fooextra 下的依赖一并纳入锁定对应测试见 pip_compile 集成测试中 --extra 相关用例。源码视角requirements 行如何被解析requirements 文件的解析实现在 uv-requirements-txt crate 中。其中每一行的需求通过 requirement.rs 中的RequirementsTxtRequirement表示/// A requirement specifier in a requirements.txt file. pub enum RequirementsTxtRequirement { /// The uv-specific superset over PEP 508 requirements specifier /// incorporating tool.uv.sources. Named(uv_pep508::RequirementVerbatimParsedUrl), /// A PEP 508-like, direct URL dependency specifier. Unnamed(UnnamedRequirementVerbatimParsedUrl), }解析流程是先尝试按 PEP 508 语法解析该行即ruff0.3.0这类名称 版本约束形式解析成功则记为Named否则按无名的直接 URL 依赖例如裸 URL 行解析为Unnamed。这与文档示例中httpx纯名称和ruff0.3.0名称 版本约束两类条目对应。所有解析结果最终汇入 uv-requirements 的规格结构RequirementsSpecification该结构统一收集requirements、constraints、overrides、extras、index 配置等字段是uv pip compile/uv pip install -r等命令共享的输入抽象。从该结构的字段定义可以推断extras 是以FxHashSetExtraName集合形式整体收集的这与--extra是一个启用/不启用的集合语义相一致。从声明到锁定完整的操作链路结合 锁定环境文档声明文件与锁定命令的对应关系如下# 锁定 pyproject.toml 中声明的依赖 $ uv pip compile pyproject.toml -o requirements.txt # 锁定 requirements.in 中声明的依赖 $ uv pip compile requirements.in -o requirements.txt # 锁定多个文件 $ uv pip compile pyproject.toml requirements-dev.in -o requirements-dev.txt # 启用指定 extra仅 pyproject.toml 支持 $ uv pip compile pyproject.toml --extra cli $ uv pip compile pyproject.toml --all-extras # 标准输入 $ echo ruff | uv pip compile -注意两点uv pip compile默认只把结果打印到终端需要-o/--output-file才写入文件锁定后用uv pip sync requirements.txt可以让环境精确匹配锁文件uv pip install则不会移除环境中多出来的包可复现性稍弱详见 锁定环境文档。两种声明方式如何选择pyproject.toml适合标准 Python 项目。它既是构建配置[build-system]也是依赖声明[project]支持 extras、requires-python、dynamic等完整语义是与 pip/PEP 621 生态兼容的推荐做法requirements.in适合轻量场景——例如临时实验、数据科学脚本、只需锁定一份依赖清单而不需要打包发布的项目。它的优点是简单直接代价是没有 extras 分组能力。无论选择哪种方式uv 提供的能力是一致的静态声明 → 锁定精确版本 → 跨环境复现安装。掌握这一链路后再配合 约束文件constraints与 覆盖文件overrides 等机制就能覆盖绝大多数 Python 依赖管理的实际需求。【免费下载链接】uvAn extremely fast Python package and project manager, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/uv/uv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考