@@ -210,7 +210,7 @@ build-backend = "uv_build"
210210uv run exmaple-pkg
211211```
212212
213- ### Libraries
213+ #### Libraries
214214一个库提供函数和对象为其他项目使用.
215215库需要构建和分发, 例如上传到 PyPI.
216216使用 ` --lib ` flag 来创建库结构.
@@ -292,8 +292,8 @@ uv init example --bare
292292```
293293
294294
295- ## Managing dependencies
296- ### Dependency fields
295+ ### Managing dependencies
296+ #### Dependency fields
297297项目依赖由以下几个字段定义
298298- ` project.dependencies ` : 发布的依赖
299299- ` project.optional-dependencies ` : 发布的可选依赖
@@ -307,7 +307,7 @@ uv init example --bare
307307uv 支持使用 ` uv add ` 和 ` uv remove ` 来定义项目依赖, 但也可以直接修改 ` pyproject.toml ` .
308308
309309
310- ### Adding dependencies
310+ #### Adding dependencies
311311例如这样
312312``` bash
313313uv add httpx
@@ -434,7 +434,7 @@ uv 支持下面几种依赖源:
434434- [ Path] ( https://docs.astral.sh/uv/concepts/projects/dependencies/#path ) : 一个本地 wheel, 源码包或项目目录
435435- [ Workspace] ( https://docs.astral.sh/uv/concepts/projects/dependencies/#workspace-member ) : 当前工作空间的成员
436436
437- ### Optional dependencies
437+ #### Optional dependencies
438438项目作为库发布时, 使一些功能称为可选的, 从而降低默认依赖树的大小, 这种做法很常见.
439439例如, Pandas 有额外的 excel extra 和 plot extra 包, 来避免安装 Excel 解析器和 matplotlib.
440440除非明确说明安装, Extras 使用 ` package[<extra>] ` 语法指明, 例如 ` pandas[plot, excel] ` .
@@ -491,7 +491,7 @@ name = "torch-gpu"
491491url = " https://download.pytorch.org/whl/cu124"
492492```
493493
494- ### Development dependencies
494+ #### Development dependencies
495495不同于可选依赖, 开发依赖只会在本地安装, 不会在发布到 PyPI 这样的项目依赖中生效.
496496因此, 开发依赖不包含在 ` [project] ` 表中.
497497同样地, 开发依赖也可以使用 ` tool.uv.sources ` 来指定源.
@@ -509,7 +509,7 @@ dev = [
509509```
510510` dev ` 组是一个特例, 可以使用 ` --dev ` , ` --only-dev ` 和 ` --no-dev ` flags 来设置包含或排除依赖.
511511
512- #### Dependency groups
512+ ##### Dependency groups
513513开发环境可以被拆分成多个组, 使用 ` --group ` flag.
514514例如, 想要为开发依赖 ` ruff ` 加入 lint 组:
515515``` bash
@@ -531,7 +531,7 @@ uv 要求所有的依赖组之间是相互兼容的, 并且会在创建 lockfile
531531
532532如果一组的依赖和其他组的依赖不兼容, uv 会无法解析依赖并报错.
533533
534- #### Nesting groups
534+ ##### Nesting groups
535535一个依赖组可以包含其他依赖组, 例如:
536536``` toml
537537[dependency-groups ]
@@ -547,7 +547,7 @@ test = [
547547]
548548```
549549
550- #### Default groups
550+ ##### Default groups
551551默认情况下, uv 在环境中包含一个 ` dev ` 依赖组.
552552默认的组可以使用 ` tool.uv.default-groups ` 来设置:
553553``` toml
@@ -560,7 +560,7 @@ default-groups = ["dev", "foo"]
560560default-groups = " all"
561561```
562562
563- #### ` requires-python ` 组
563+ ##### ` requires-python ` 组
564564默认情况下, 依赖组必须和项目 ` requires-python ` 兼容.
565565如果一个依赖组需要不同的 Python 版本, 可以在 ` [tool.uv.dependency-groups] ` 里面指定 Python 版本.
566566``` toml
@@ -576,7 +576,7 @@ dev = ["pytest"]
576576dev = {requires-python = " >=3.12" }
577577```
578578
579- #### Legacy ` dev-dependencies `
579+ ##### Legacy ` dev-dependencies `
580580在 ` [dependency-groups] ` 成为标准之前, uv 使用 ` tool.uv.dev-dependencies ` 字段来指定开发依赖
581581``` toml
582582[tool .uv ]
@@ -585,8 +585,136 @@ dev-dependencies = [
585585]
586586```
587587
588+ #### Build dependencies
589+ 如果一个项目使用 [ Python package] ( https://docs.astral.sh/uv/concepts/projects/config/#build-systems ) 的结构, 它可能需要构建项目的依赖, 但无需运行. 这类依赖是 ` [build-system] ` , 在 ` build-system.requires ` 下面, 详见 [ PEP 518] ( https://peps.python.org/pep-0518/ ) .
588590
589- ## Using workspace
591+ 例如, 如果一个项目使用 ` setuptools ` 作为后端构建, 它应该声明 ` setuptools ` 作为一个构建依赖:
592+ ``` toml
593+ [project ]
594+ name = " pandas"
595+ version = " 0.1.0"
596+
597+ [build-system ]
598+ requires = [" setuptools>=42" ]
599+ build-backend = " setuptools.build_meta"
600+ ```
601+ 默认情况下, uv 构建依赖的时候会检查 ` tool.uv.sources ` .
602+ 例如, 使用本地版本的 ` setuptools ` 进行构建, 将源添加进 ` tool.uv.sources `
603+ ``` toml
604+ [project ]
605+ name = pandas
606+ version = " 0.1.0"
607+
608+ [build-system ]
609+ requires = [" setuptools>=42" ]
610+ build-backend = " setuptools.build_meta"
611+
612+ [tool .uv .sources ]
613+ setuptools = { path = " ./packages/setuptools" }
614+ ```
615+ 当发布一个包的时候, 建议当 ` tool.uv.sources ` 被禁用时, 运行 ` uv build --no-source ` 来确保正确构建.
616+ 使用其他构建工具也是一样的, 例如 ` pypa/build ` .
617+
618+
619+ #### Editable dependencies
620+ 常规的目录安装会先构建 wheel 包, 然后将该 wheel 包安装到虚拟环境中, 这回复制所有的源文件.
621+ 当包源文件被编译时, 虚拟环境中的版本将保持旧版本.
622+
623+ 可编辑安装通过向虚拟环境内添加项目连接 (.pth 文件) 解决了这个问题, 该链接指示解释器直接包含源文件.
624+ 可编辑安装存在一些限制, 但对于开发常见非常实用, 因为虚拟环境会始终使用包的最新修改.
625+
626+ uv 默认对工作区包采用可编辑安装模式.
627+
628+ #### Virtual dependencies
629+ uv 运行依赖项设置为"虚拟"模式, 在此模式下, 依赖项本身不会作为软件包被安装, 但其依赖关系会被正常处理.
630+
631+ 默认情况下, 依赖项永远不会被视作虚拟依赖.
632+
633+ 对于路径源的依赖项, 若显示设置 ` tool.uv.package = false ` 则可成为虚拟依赖.
634+ 与在依赖项目中使用 ` uv ` 工作不同, 即使未声明构建系统, 该软件包仍会被构建.
635+
636+ 若要将某个依赖项视位虚拟依赖, 需要在其源配置中设置 ` package = false ` :
637+ ``` toml
638+ [project ]
639+ dependencies = [" bar" ]
640+
641+ [tool .uv .sources ]
642+ bar = { path = " ../projects/bar" , package = false }
643+ ```
644+ 如果依赖设置 ` tool.uv.package = false ` , 则可以在 source 通过声明 ` package = true ` 来覆盖.
645+ ``` toml
646+ [project ]
647+ dependencies = [" bar" ]
648+
649+ [tool .uv .source ]
650+ bar = { path = " ../projects/bar" , package = true }
651+ ```
652+ 同样地, 对于工作区源的依赖项, 若显式设置 ` tool.uv.package = false ` 也可成为虚拟依赖.
653+ 即使未声明构建系统, 该工作区成员仍会被构建.
654+
655+ 对于非依赖项的工作区成员, 默认情况下可设置为虚拟模式, 例如, 若父级 ` pyproject.toml ` 文件配置如下:
656+ ``` toml
657+ [project ]
658+ name = " parent"
659+ version = " 1.0.0"
660+ dependencies = []
661+
662+ [tool .uv .workspace ]
663+ members = [" child" ]
664+ ```
665+ 并且 child 的 ` pyproject.toml ` 不含有构建系统.
666+ ``` toml
667+ [project ]
668+ name = " child"
669+ version = " 1.0.0"
670+ dependencies = [" anyio" ]
671+ ```
672+ 那么 ` child ` workspace 成员将不会被安装, 但是依赖 ` anyio ` 会被传递.
673+
674+ 相对的, 如果父级声明了对 ` child ` 的依赖:
675+ ``` toml
676+ [project ]
677+ name = " parent"
678+ version = " 1.0.0"
679+ dependencies = [" child" ]
680+
681+ [tool .uv .sources ]
682+ child = { workspace = true }
683+
684+ [tool .uv .workspace ]
685+ members = [" child" ]
686+ ```
687+ 那么 ` child ` 将会被构建和安装.
688+
689+
690+ #### Dependency specifiers
691+ uv 采用最初由 [ PEP 508] ( https://peps.python.org/pep-0508/ ) 定义的依赖项限定符, 依赖项限定符按顺序包括以下组件:
692+ - 依赖项名称
693+ - 所需额外功能
694+ - 版本限定符
695+ - 环境标记
696+
697+ 版本限定符通过逗号分割进行组合, 例如 ` foo >=1.2.3,<2,!=1.4.0 ` 表示 "` foo ` 的版本需不低于 1.2.3, 小于 2, 且不能是 1.4.0".
698+ 限定符会自动补零, 因此 ` foo ==2 ` 也会匹配 foo 2.0.0.
699+
700+ 星号可以用于等号匹配的最后一位数字, 例如 ` foo ==2.1.* ` 将接受 2.1 系列的所有版本.
701+ 类似地, ` ~= ` 匹配最后一位数字相等或更高的版本, 例如 ` foo ~=1.2 ` 等价于 ` foo >=1.2,<2 ` , 而 ` foo ~=1.2.3 ` 等价于 ` foo >=1.2.3,<1.3 ` .
702+
703+ 额外功能在名称和版本直接的方括号内用逗号分隔, 例如 ` pandas[excel, plot] ==2.2 ` .
704+ 额外功能名称之间的空格会被忽略.
705+
706+ 某些依赖项仅在特定环境中需要, 例如特定的 Python 版本或系统.
707+ 比如要为 ` importlib.metadata ` 模块安装 importlib-metadata 回溯包, 可使用 ` importlib-metadata >=7.1.0,<8; python_version < '3.10' ` .
708+ 要在 Windows 上安装 colorama 则可使用 ` colorama >=0.4.6,<5; platform_systemm == "Windows ` .
709+
710+ 环境标记通过 and, or 和括号进行组合, 例如
711+ ```
712+ aiohttp >=3.7.4,<4; (sys_paltform != 'win32' or implementation_name != 'pypy') and python_version >= '3.10'
713+ ```
714+ 注意标记内的版本需要加引号, 而标记外的版本不加引号.
715+
716+
717+ ### Using workspace
590718工作空间受到 Cargo 的同名概念启发, 即将一个或多个包一起管理, 叫做 workspace.
591719
592720Workspace 通过将项目拆分多个包和相同的依赖, 从而组织大型代码库.
@@ -618,7 +746,7 @@ exclude = ["packages/seeds"]
618746例如上例中, ` uv run ` 与 ` uv run --package albatross ` 是等效的, 而 ` uv run --package bird-feeder ` 则会在 ` bird-feeder ` 包中执行命令.
619747
620748
621- ### Workspace sources
749+ #### Workspace sources
622750在一个 workspace 内, 对工作区成员的依赖通过 ` tool.uv.sources ` 实现, 例如:
623751```
624752[project]
@@ -642,3 +770,64 @@ requires = ["uv_build>=0.8.20,<0.9.0"]
642770工作区根目录中的任何 ` tool.uv.sources ` 定义将适用于所有成员, 除非在特定成员的 ` tool.uv.sources ` 中被覆盖.
643771
644772
773+ #### Workspace layouts
774+ 最常见的工作区布局可以是一个根目录和一系列的库组成.
775+ 例如, 接着上面的例子, 工作区间有一个根目录 ` albatross ` , 以及 ` packages ` 目录下面的两个库 ` bird-feeder ` 和 ` seed ` .
776+ ```
777+ albatross
778+ ├── packages
779+ │ ├── bird-feeder
780+ │ │ ├── pyproject.toml
781+ │ │ └── src
782+ │ │ └── bird_feeder
783+ │ │ ├── __init__.py
784+ │ │ └── foo.py
785+ │ └── seeds
786+ │ ├── pyproject.toml
787+ │ └── src
788+ │ └── seeds
789+ │ ├── __init__.py
790+ │ └── bar.py
791+ ├── pyproject.toml
792+ ├── README.md
793+ ├── uv.lock
794+ └── src
795+ └── albatross
796+ └── main.py
797+ ```
798+ 由于 ` seeds ` 被 ` pyproject.toml ` 排除在外, 故该工作区一共有两个成员: ` albatross ` 和 ` bird-feeder ` .
799+
800+
801+ #### When (not) to use workspaces
802+ Workspaces 是为了促进同一仓库下的多个包之间内部连接的开发.
803+ 当代码库逐渐变复杂, 将其切分成更小的可组合的包将十分有用.
804+ 每个包都有自己的依赖和版本限制.
805+
806+ 工作区有助于执行隔离和分离问题.
807+ 例如, 在 uv 中, 有分离的 core 包和命令行界面, 这使得我们可以分开测试 core 包和 CLI, 反之亦然.
808+
809+ 其他常见工作区间使用包括:
810+ - 在模块中实现了性能关键的扩展库
811+ - 插件系统库, 每个插件是一个分离的 workspace 包和一个根目录下的依赖
812+
813+ 工作区模式不适用于成员之间存在需求冲突, 或需要为每个成员创建独立虚拟环境的场景.
814+ 此类情况下, 路径依赖通常是更优选择.
815+ 例如, 无需将 albatross 及其相关组件强制归入同一工作区, 可以将每个软件包定义为独立项目, 并通过在 ` tool.uv.sources ` 中配置路径依赖来定义包间依赖关系.
816+ ``` toml
817+ [project ]
818+ name = " albatross"
819+ version = " 0.1.0"
820+ requires-python = " >=3.12"
821+ dependencies = [" bird-feeder" , " tqdm>=4,<5" ]
822+
823+ [tool .uv .sources ]
824+ bird-feeder = { path = " packages/bird-feeder" }
825+
826+ [build-system ]
827+ requires = [" uv_build>=0.8.20,<0.9.0" ]
828+ build-backend = " uv_build"
829+ ```
830+ 这种方法能带来许多相同优势, 同时运行依赖解析和虚拟环境管理进行更精细的控制 (但无法使用 ` uv run --package ` 命令, 需要从对应软件目录运行命令).
831+
832+ 最后, uv 的工作区强制要求整个工作区间采用统一的 ` requires-python ` 配置, 该配置取所有 ` requires-python ` 值的交集.
833+ 如果需要给某个成员测试工作区其他成员不支持的 Python 版本, 可能需要使用 ` uv pip ` 将该成员安装到独立的虚拟环境中.
0 commit comments