Rye 依赖管理实战指南:从pyproject.toml到rye add的完整解析
【免费下载链接】ryea Hassle-Free Python Experience项目地址: https://gitcode.com/gh_mirrors/ry/rye
导读:本文围绕 Rye 官方指南 deps.md 展开,系统讲解如何在 Rye 管理的 Python 项目中声明与维护依赖:从最基础的
rye add普通依赖、PEP 508 版本约束、extras 特性依赖,到开发依赖、Git/本地路径依赖与 workspace 协作。同时结合本仓库的 Rust 源码(rye/src/cli/add.rs、rye/src/pyproject.rs)与测试用例(rye/tests/test_add.rs),剖析依赖写入pyproject.toml的底层机制与参数语义。读完本文,你将掌握 Rye 中依赖声明、添加、移除与同步的完整工作流,并能根据项目场景选择最合适的依赖类型。
依赖声明的核心:pyproject.toml+rye add
在 Rye 中,所有依赖最终都声明在项目的 pyproject.toml 中。虽然你可以手工编辑该文件,但 Rye 提供了更友好的rye add命令来简化这一过程——它接受 PEP 508 需求字符串作为输入,同时提供一系列辅助参数(如--git、--path),让"声明依赖"这件事不再需要记忆冗长的语法。
Rye 对project.dependencies这一键不做任何私有化改造——它完全符合标准pyproject.toml的语义,只是 Rye 具备通过rye add/rye remove自动修改这些条目的能力。也就是说:用rye add写进去的内容,和手写标准 PEP 508 字符串完全等价。
从源码看,rye add的核心执行流程(rye/src/cli/add.rs)分为三步:
- 解析传入的 PEP 508 需求字符串,并应用
--git、--path、--features等参数改写为最终需求(ReqExtras::apply_to_requirement); - 借助内置的 uv 解析器解析出可用的最新版本,并按照默认或指定的 pin 操作符生成版本约束;
- 调用
PyProject::add_dependency把需求写入对应的 TOML 键(rye/src/pyproject.rs),最后按需触发自动同步(autosync)。
依赖在 TOML 中的归属
根据DependencyKind枚举(rye/src/pyproject.rs),Rye 支持四类依赖写入位置:
| 依赖类型 | 写入位置 | 触发参数 |
|---|---|---|
| 普通依赖(regular) | project.dependencies | 默认 |
| 开发依赖(dev) | tool.rye.dev-dependencies | --dev |
| 排除依赖(excluded) | tool.rye.excluded-dependencies | --excluded |
| 可选分组依赖(optional) | project.optional-dependencies.<分组名> | --optional <名称> |
源码中add_dependency函数(rye/src/pyproject.rs)正是按这个映射将需求写入不同键位,且会自动创建缺失的数组或表。这与 pyproject.md 中project.dependencies、tool.rye.dev-dependencies等键的说明一一对应。
添加基础依赖
添加普通依赖最简单的方式,就是直接用包名调用rye add:
rye add Flask该命令会先初始化/复用项目虚拟环境,随后解析出当前 Python 版本下兼容的最新版本,并以>=操作符写入project.dependencies,最后自动生成requirements.lock与requirements-dev.lock并安装依赖。测试 rye/tests/test_add.rs 中记录的真实输出为:
$ rye add flask colorama Added flask>=3.0.0 as regular dependency Added colorama>=0.4.6 as regular dependency Reusing already existing virtualenv Generating production lockfile: requirements.lock Generating dev lockfile: requirements-dev.lock Installing dependencies Done!对应的pyproject.toml片段:
[project] dependencies = [ "flask>=3.0.0", "colorama>=0.4.6", ]指定版本:使用 PEP 508 需求字符串
如果想控制版本,直接传入 PEP 508 需求字符串即可:
rye add "Flask>=2.0" rye add "werkzeug==3.0.0"注意测试 test_add_explicit_version_or_url 显示:当你显式给出完整版本(如==3.0.0)时,Rye 会保留原样写入,不再解析追加操作符;而只给包名时才会自动补上解析得到的最新版本与默认操作符。
默认版本操作符的定制
Rye 默认使用>=作为自动 pin 操作符,但这一行为可通过全局配置dependency-operator调整(rye/src/config.rs):
# config.toml [default] dependency-operator = "~=" # 可选:">="(默认)、"=="、"~="此外,rye add还提供--pin参数,在单次命令中覆盖该默认值,可选值为equal(==)、tilde-equal(~=)、greater-than-equal(>=),并支持==、~=、>=、exact、compatible等别名(见 rye/src/cli/add.rs):
rye add Flask --pin=tilde-equal # 写入 flask~=<解析版本>从源码看,解析出的版本约束还会做两个细节处理(rye/src/cli/add.rs):对带本地版本号(local version)的版本强制使用==;当~=目标版本只有一位 release 时降级为>=。
extras 特性依赖(feature / extra)
Python 包通常提供可选的 extras(特性),Rye 支持两种等价写法:
rye add "Flask[dotenv]" # 直接在 PEP 508 字符串中声明 rye add Flask --features=dotenv # 使用 --features 参数--features参数在源码中按逗号切分并去重后合并进需求的extras字段(rye/src/cli/add.rs),因此也支持一次传入多个特性:
rye add Flask --features=dotenv,async两种写法最终写入project.dependencies的效果一致,例如"flask[dotenv]>=3.0.0"。测试 test_add_flask_dotenv 证实:添加flask[dotenv]后,解析结果中会额外安装python-dotenv。
关于预发布版本(pre-releases)的重要提示
默认情况下,rye add不会考虑预发布版本。如果你添加的依赖在版本号中带有.dev、rc等预发布标识,将无法解析到匹配项。此时需要显式传入--pre:
rye add "Flask==2.0.0rc2" --pre从源码看,--pre会一路传递给 uv 解析器(uv.resolve(..., pre, ...),见 rye/src/cli/add.rs),控制其是否允许预发布匹配。
开发依赖(Development Dependencies)
只用于开发阶段(如格式化、静态检查工具)的依赖,用--dev添加:
rye add --dev black开发依赖不会被写入标准的project.dependencies,而是存放在 Rye 私有的tool.rye.dev-dependencies键中(pyproject.md):
[tool.rye] dev-dependencies = ["black~=23.3.0"]对应的源码映射见 rye/src/pyproject.rs:--dev时add_dependency会往tool.rye表的dev-dependencies数组追加条目(不存在则自动创建)。测试 test_add_dev 展示了pyproject.toml中tool.rye表的最终形态。
用rye run运行开发工具
开发依赖默认随rye sync安装进虚拟环境,但不需要手动激活虚拟环境即可运行其中的工具——直接用rye run:
rye run blackrye run会优先在虚拟环境中查找并执行对应命令,这一机制同样适用于 tool.rye.scripts 中注册的自定义脚本。若希望sync时不安装开发依赖,可传--no-dev(详见 sync.md)。
排除依赖(Excluded Dependencies)
tool.rye.excluded-dependencies是一个特殊键:其中的依赖永远不会被安装,即使它们作为间接依赖(子依赖)被拉取进来。使用rye add --excluded自动添加:
rye add --excluded cffi[tool.rye] excluded-dependencies = ["cffi"]在源码中,DependencyKind::Excluded与Dev一样写入tool.rye表(rye/src/pyproject.rs),且--excluded与--dev、--optional互斥(rye/src/cli/add.rs)。这一功能在项目与某个传递依赖存在兼容性冲突时非常实用。
可选依赖组(Optional Dependency Groups)
通过--optional可以将依赖加入标准project.optional-dependencies下的命名分组:
rye add --optional=web flask写入后的 TOML:
[project.optional-dependencies] web = ["flask>=3.0.0"]该分组在rye lock/rye sync时可通过--features=web启用(参见 sync.md 的--features说明)。源码中,--optional与--dev、--excluded互斥,且会创建project.optional-dependencies表及对应分组(rye/src/pyproject.rs)。
Git / 本地路径依赖
当依赖来自 Git 仓库或本地目录时,可以传--git、--url、--path参数,无需在需求字符串里手工拼接:
rye add Flask --git=https://github.com/pallets/flask rye add My-Utility --path ./my-utility rye add pip --url=https://example.com/pip-1.3.1.zip注意:使用这些参数时必须同时提供包名(--path/--git/--url与一次传多个需求不兼容,源码中对此有显式校验,见 rye/src/cli/add.rs)。且这些参数会与需求字符串中已有的版本约束冲突——如果需求已经带有版本标记,会直接报错"requirement already has a version marker"(rye/src/cli/add.rs)。
Git 依赖的 tag / rev / branch
Git 依赖支持额外的定位参数:
rye add Flask --git=https://github.com/pallets/flask --tag=3.0.0 rye add Flask --git=https://github.com/pallets/flask --rev=abc1234 rye add Flask --git=https://github.com/pallets/flask --branch=main源码实现中(rye/src/cli/add.rs),--rev、--tag、--branch三选一(互斥)拼接为git+<url>@<ref>形式的 URL;--tag/--rev/--branch均要求同时存在--git。测试输出示例:
$ rye add flask --git https://github.com/pallets/flask Added flask @ git+https://github.com/pallets/flask as regular dependency本地路径依赖与--absolute
--path依赖最终会写成file://URL。默认情况下 Rye 会尝试生成基于${PROJECT_ROOT}的相对路径,以便项目迁移;但当构建后端为 hatchling(其{root:uri}写法不被 uv 支持),或显式传入--absolute时,会强制生成绝对路径(rye/src/cli/add.rs)。--absolute需要同时传入--path:
rye add My-Utility --path ./my-utility --absolute本地依赖强烈建议配合 workspace
当项目依赖本地包时,官方指南强烈建议将其配置为 workspace 成员。workspace 让子目录中的 Python 项目共享同一个虚拟环境与锁文件,从而保证本地依赖与主项目在解析、安装时的一致性。配置方式(详见 workspaces.md):
[tool.rye.workspace] members = ["mylib-*"]移除依赖
与添加对称的是rye remove(命令参考见 remove.md):
rye remove flask rye remove black --dev # 移除开发依赖 rye remove flask --optional=web # 移除可选分组依赖它会从pyproject.toml对应的依赖列表中删除条目(rye/src/pyproject.rs 中的remove_dependency与add_dependency使用相同的键位映射)。与add一样,是否立即同步安装状态取决于 auto-sync 设置。
自动同步(auto-sync)与--sync/--no-sync
rye add/rye remove之后依赖是否立刻被安装,由全局配置behavior.autosync(默认开启)决定(rye/src/config.rs):
- 若 auto-sync 关闭,添加依赖后不会自动安装,需要手动
rye sync,或本次命令显式传--sync; - 若 auto-sync 开启但本次不想同步,可传
--no-sync(--sync与--no-sync互斥,见 rye/src/cli/add.rs)。
rye add flask --sync # 即使 auto-sync 关闭也立即同步 rye add flask --no-sync # 即使 auto-sync 开启也跳过同步从execute主流程看(rye/src/cli/add.rs),同步条件为(autosync && !no_sync) || sync,满足时调用autosync完成锁文件生成与虚拟环境安装。所谓同步,本质是更新两份锁文件(requirements.lock与requirements-dev.lock)并用它们重建虚拟环境,锁定的完整参数说明见 sync.md。
从源码理解rye add的完整调用链
汇总rye add的底层链路,便于读者深入阅读仓库:
- 参数解析:
Args与ReqExtras结构体定义全部命令行参数及互斥/依赖关系(rye/src/cli/add.rs); - 需求构造:
Requirement::from_str解析 PEP 508 字符串,ReqExtras::apply_to_requirement应用--git/--url/--path/--features(rye/src/cli/add.rs); - 版本解析:
resolve_requirements_with_uv通过内置 uv 解析器找到最新兼容版本,并按默认操作符生成版本约束(rye/src/cli/add.rs); - 写入 TOML:
PyProject::add_dependency按DependencyKind写入对应键位(rye/src/pyproject.rs); - 自动同步:按 auto-sync 配置调用
autosync完成 lock + install。
完整的行为快照(含真实输出、最终 TOML 内容)可在测试文件 rye/tests/test_add.rs 中逐一验证,覆盖普通依赖、extras、dev 依赖、显式版本、URL 依赖、自定义 sources 等场景,是学习rye add语义的最佳参考。
小结
- 普通依赖:
rye add <包名>,写入project.dependencies,支持 PEP 508 版本约束与--pin定制操作符; - 特性依赖:PEP 508 的
[extra]写法与--features等价; - 开发依赖:
--dev写入tool.rye.dev-dependencies,用rye run免激活运行; - 排除/可选依赖:
--excluded、--optional <组名>对应tool.rye.excluded-dependencies与project.optional-dependencies; - Git/本地依赖:
--git(配--tag/--rev/--branch)、--url、--path(配--absolute),本地依赖建议纳入 workspace; - 同步控制:受
autosync全局配置影响,可用--sync/--no-sync覆盖单次行为。
完整命令参数清单可参考 add.md,配置文件各键的权威解释见 pyproject.md。
【免费下载链接】ryea Hassle-Free Python Experience项目地址: https://gitcode.com/gh_mirrors/ry/rye
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考