uv 包索引配置详解:PyPI 之外的默认索引、索引策略、认证与 Flat 索引
2026/9/5 20:32:27 网站建设 项目流程

uv 包索引配置详解:PyPI 之外的默认索引、索引策略、认证与 Flat 索引

【免费下载链接】uvAn extremely fast Python package and project manager, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/uv/uv

uv 默认使用 PyPI 进行依赖解析和安装,但通过[[tool.uv.index]]配置项(及对应的--index命令行参数)可以接入私有索引、PyTorch 等第三方索引,甚至本地目录构成的 “flat” 索引。读完本文,你可以掌握 uv 的完整索引体系:如何定义与命名索引、把特定包固定到特定索引、按平台选择索引、在多个索引间选择搜索策略(并理解first-index背后的依赖混淆防护)、为私有索引配置认证/缓存/错误码/哈希算法,以及 pip 风格--index-url/--extra-index-url的兼容映射规则。

定义索引:[[tool.uv.index]]与优先级规则

要在依赖解析时加入一个额外索引,在项目的pyproject.toml中增加一个[[tool.uv.index]]条目:

[[tool.uv.index]] # 索引名(可选)。 name = "pytorch" # 索引 URL(必填)。 url = "https://download.pytorch.org/whl/cpu"

优先级规则是这套体系的核心:

  • 索引按定义顺序查询,配置文件中排在最前面的索引最先被查询;
  • 命令行提供的索引(--index/--default-index)优先于配置文件中的索引;
  • uv 默认把 PyPI 作为 “default” 索引,即当某个包在其他索引上找不到时的兜底索引。

要排除 PyPI,需要在其他索引条目上设置default = true(或使用--default-index命令行选项):

[[tool.uv.index]] name = "pytorch" url = "https://download.pytorch.org/whl/cpu" default = true

注意:默认索引无论其在列表中处于什么位置,始终被当作最低优先级。这一点在源码中有明确注释佐证:Index结构体(crates/uv-distribution-types/src/index.rs)对default字段的文档写明 “Marking an index as default will move it to the front of the list of indexes, such that it is given the highest priority when resolving packages”,而在first-index策略语义下该索引实际承担“最后兜底”的角色。

索引名有严格约束:只能包含字母、数字、连字符、下划线和点,且必须是合法 ASCII。这一校验在 crates/uv-distribution-types/src/index_name.rs 中实现,非法字符会返回UnsupportedCharacter/NonAsciiName错误。

命令行与环境变量中的索引引用

在命令行(--index--default-index)或环境变量(UV_INDEXUV_DEFAULT_INDEX)中引用索引时,可以写 URL、已配置的名称,或<name>=<url>语法:

# 命令行方式。 $ uv lock --index pytorch=https://download.pytorch.org/whl/cpu # 环境变量方式。 $ UV_INDEX=pytorch=https://download.pytorch.org/whl/cpu uv lock

如果启用了--preview-features index-by-name,已配置的索引名将优先于匹配的路径。该预览特性在 crates/uv-dev/src/generate_preview_features_reference.rs 中的描述为:允许通过--index--default-index按名称选择已配置的索引;未启用时按名称引用索引会输出 “Referencing an index by name is experimental” 警告(可见于 crates/uv/tests/sync/show_settings.rs 的测试快照)。

将包固定到指定索引:tool.uv.sources

单个包可以通过tool.uv.sources条目固定到某个索引。例如,确保torch永远pytorch索引安装:

[tool.uv.sources] torch = { index = "pytorch" } [[tool.uv.index]] name = "pytorch" url = "https://download.pytorch.org/whl/cpu"

按平台选择索引

sources 支持以环境标记(environment markers)区分的一组列表,从而按平台拉取不同索引。例如在 macOS 上使用 CPU 版 PyTorch、其他平台使用 cu130 版本:

[project] dependencies = ["torch"] [tool.uv.sources] torch = [ { index = "pytorch-cpu", marker = "sys_platform == 'darwin'"}, { index = "pytorch-cu130", marker = "sys_platform != 'darwin'"}, ] [[tool.uv.index]] name = "pytorch-cpu" url = "https://download.pytorch.org/whl/cpu" [[tool.uv.index]] name = "pytorch-cu130" url = "https://download.pytorch.org/whl/cu130"

explicit = true:只对显式固定的包开放

把索引标记为explicit = true后,除非包被显式固定到它,否则不会从该索引安装包。例如让torchpytorch索引、其余所有包走 PyPI:

[tool.uv.sources] torch = { index = "pytorch" } [[tool.uv.index]] name = "pytorch" url = "https://download.pytorch.org/whl/cpu" explicit = true

两条容易踩坑的规则:

  • 通过tool.uv.sources引用的命名索引必须定义在项目自身的pyproject.toml;命令行、环境变量或用户级配置提供的索引不会被识别;
  • 若一个索引同时设置default = trueexplicit = true,它按 explicit 索引处理(只能通过tool.uv.sources使用),同时移除 PyPI 作为默认索引。

跨索引搜索策略:--index-strategy与依赖混淆防护

默认情况下,uv 在第一个包含目标包的索引上就停止搜索,并把候选版本限定在该索引内(first-index)。例如配置了内部索引后,只要包存在于内部索引,就永远从内部索引安装,绝不会从 PyPI 安装。其目的是防止 “依赖混淆(dependency confusion)” 攻击——攻击者在 PyPI 上发布与内部包同名的恶意包,诱导解析器安装恶意版本(2022 年 12 月的torchtriton事件即为例证)。

要切换策略,使用--index-strategy命令行选项或UV_INDEX_STRATEGY环境变量,可选值如下:

策略行为说明
first-index(默认)跨所有索引搜索每个包,但候选版本限定在第一个包含该包的索引最安全,与 pip 行为不同
unsafe-first-match跨所有索引搜索,优先使用第一个有兼容版本的索引,即使其他索引有更新版本旧名unsafe-any-match仍作为别名保留
unsafe-best-match跨所有索引搜索,从合并后的候选版本集中选择最佳版本最接近 pip 行为,但暴露于依赖混淆风险

从源码看,IndexStrategy枚举定义在 crates/uv-configuration/src/build_options.rs,三种变体分别对应FirstIndex(带first-match别名)、UnsafeFirstMatch(带unsafe-any-match别名,并引用 PEP 708)、UnsafeBestMatch。注释明确解释了UnsafeFirstMatch的一个细节:如果某版本在第一个索引中判定不兼容,即使后续索引中该版本存在兼容变体(例如不同 ABI 标签),也不会重新考虑。

unsafe-best-match虽最接近 pip,但会带来依赖混淆风险,因此命名中带有unsafe前缀以作警示。

认证:私有索引的凭证管理

大多数私有包索引要求通过用户名/密码(或访问令牌)认证。针对具体提供商(Azure Artifacts、Google Artifact Registry、AWS CodeArtifact、JFrog Artifactory)的接入指南分别见 Azure Artifacts、Google Artifact Registry、AWS CodeArtifact 和 JFrog Artifactory。

直接提供凭证

凭证可以通过环境变量提供,或直接嵌入 URL。假设有一个名为internal-proxy的索引,需要用户名public、密码koala,先在pyproject.toml中定义不含凭证的索引:

[[tool.uv.index]] name = "internal-proxy" url = "https://example.com/simple"

然后设置UV_INDEX_INTERNAL_PROXY_USERNAMEUV_INDEX_INTERNAL_PROXY_PASSWORD环境变量,其中INTERNAL_PROXY是索引名的大写形式、非字母数字字符替换为下划线:

export UV_INDEX_INTERNAL_PROXY_USERNAME=public export UV_INDEX_INTERNAL_PROXY_PASSWORD=koala

通过环境变量提供凭证可以避免在明文pyproject.toml中存储敏感信息。这个“索引名转环境变量名”的转换规则在源码 crates/uv-distribution-types/src/index_name.rs 的to_env_var方法中实现:字母数字转大写,其余字符一律转下划线。

另一种方式是直接把凭证嵌入索引定义:

[[tool.uv.index]] name = "internal" url = "https://public:koala@pypi-proxy.corp.dev/simple"

出于安全考虑,凭证永远不会被写入uv.lock文件;相应地,uv 在安装时必须能访问经过认证的 URL。

使用凭证提供者(netrc / keyring)

除直接提供凭证外,uv 还支持从 netrc 和系统 keyring 中发现凭证,具体各凭证提供者的配置见 HTTP 认证 文档。

默认行为是:uv 先尝试无认证请求,若失败再去查找凭证;找到凭证后发起认证请求。若已显式设置了用户名,uv 会在无认证请求之前就查找凭证。

有些索引(如 GitLab)会把无认证请求转发到公共索引(如 PyPI),这会导致 uv 认为无需凭证而不再搜索。可用authenticate设置按索引改变这一行为。例如,始终查找凭证:

[[tool.uv.index]] name = "example" url = "https://example.com/simple" authenticate = "always"

authenticate的取值在源码中对应AuthPolicy枚举(crates/uv-auth/src/index.rs):

  • auto(默认):提供凭证则使用;否则先无认证请求,失败后再查找凭证;
  • always:立即查找凭证,找不到凭证直接报错,而不尝试无认证请求;
  • never:绝不查找凭证;若直接提供了凭证也会报错——可用于禁用某索引的认证以防止凭证泄漏
[[tool.uv.index]] name = "example" url = "https://example.com/simple" authenticate = "never"

从源码结构看,uv 按 URL 前缀(scheme + host + port + 完整路径段前缀)把请求 URL 匹配到具体索引,从而应用该索引的AuthPolicy(见 crates/uv-auth/src/index.rs 中Indexes::find_prefix_index),并且前缀匹配要求完整路径段边界——/simple能匹配/simple/anyio,但不会误匹配/simpleevil

忽略特定错误码:ignore-error-codes

使用first-index策略时,若遇到 HTTP 401 Unauthorized 或 403 Forbidden,uv 会停止跨索引搜索(唯一的例外是pytorch索引——该索引在包不存在时返回 403,uv 对其忽略 403)。此外,获取发行版元数据或归档时若遇到 HTTP 错误,uv 默认也会停止解析;而忽略某个错误码的效果是把受影响的包版本标记为不可用,让解析器尝试其他版本。

要为某索引配置需要忽略的错误码,使用ignore-error-codes设置,例如私有索引忽略 403 但不忽略 401:

[[tool.uv.index]] name = "private-index" url = "https://private-index.com/simple" authenticate = "always" ignore-error-codes = [403]

无论配置如何,遇到404 Not Found时 uv始终会继续搜索下一个索引,这一点无法被覆盖。

自定义缓存控制头:cache-control

默认情况下 uv 尊重索引提供的 Cache-Control 头。例如 PyPI 以max-age=600提供包元数据(uv 可缓存 10 分钟),以max-age=365000000, immutable提供 wheel 和源码分发(可无限期缓存制品)。

要覆盖某索引的缓存控制头,使用cache-control设置:

[[tool.uv.index]] name = "example" url = "https://example.com/simple" cache-control = { api = "max-age=600", files = "max-age=365000000, immutable" }

该设置接受一个对象,包含两个可选键:

  • api:控制 Simple API 请求(包元数据)的缓存;
  • files:控制制品下载(wheel 和源码分发)的缓存。

两个键的取值是遵循 HTTP Cache-Control 语法的字符串。例如,强制每次重新验证包元数据,可设api = "no-cache"

[[tool.uv.index]] name = "example" url = "https://example.com/simple" cache-control = { api = "no-cache" }

这个设置最常见的用途,是覆盖那些(往往是无意识地)禁用了缓存的私有索引的默认缓存头。官方建议遵循 PyPI 的做法:api = "max-age=600"files = "max-age=365000000, immutable"

从源码看,IndexCacheControl(crates/uv-distribution-types/src/index.rs)在反序列化时会把两个字符串解析为 HTTPHeaderValue,非法值会报 “cache-control.apimust be a valid HTTP header value” 之类的错误。另外源码中还内置了一个例外:对download.pytorch.orgpypi.nvidia.com的制品下载,uv 会强制覆盖为max-age=365000000, immutable, public,因为 PyTorch 仓库的部分 wheel 曾被误带上no-cache,no-store,must-revalidate头(见 crates/uv-distribution-types/src/index.rs 中的注释)。

强制指定哈希算法:hash-algorithm

当索引为某个发行版公布多个哈希时,uv 会选择其中一个记录到 lockfile。通过hash-algorithm设置可以为某索引的解析结果强制要求特定算法:

[tool.uv] preview-features = ["index-hash-algorithm"] [[tool.uv.index]] name = "private-index" url = "https://private-index.com/simple" hash-algorithm = "sha256"

若被锁定的发行版没有公布所要求的算法,uv 会直接失败,而不是回退到另一种哈希算法。该选项处于 preview 状态,可能在未来版本中变化。

为索引单独配置exclude-newer

如果正在使用exclude-newer(见 reproducible resolutions),可以为特定索引配置不同的截止点:

[[tool.uv.index]] name = "internal" url = "https://internal.example.com/simple" exclude-newer = "7 days"

索引级取值只影响从该索引提供的包;包级的exclude-newer-package覆盖仍然优先。若某索引不提供upload-time元数据,可以彻底禁用该索引的截止点:

[[tool.uv.index]] name = "internal" url = "https://internal.example.com/simple" exclude-newer = false

该字段在源码中为Option<ExcludeNewerOverride>(crates/uv-distribution-types/src/index.rs),文档注释同样标注其处于 preview。

“Flat” 索引:本地目录与--find-links等价物

默认情况下,[[tool.uv.index]]条目被视为实现 PEP 503 Simple Repository API 的 PyPI 风格注册表。但 uv 还支持 “flat” 索引——包含 wheel 和源码分发扁平列表的本地目录或 HTML 页面,对应 pip 中的--find-links选项(解析实现见 crates/uv-client/src/flat_index.rs)。

pyproject.toml中定义 flat 索引使用format = "flat"

[[tool.uv.index]] name = "example" url = "/path/to/directory" format = "flat"

Flat 索引支持 Simple Repository API 索引的完整特性集(例如explicit = true),也可以通过tool.uv.sources把包固定到 flat 索引。

pip 兼容:--index-url--extra-index-url

[[tool.uv.index]]外,uv 为兼容性支持 pip 风格的--index-url--extra-index-url命令行选项,其中--index-url定义默认索引,--extra-index-url定义额外索引。

这两个选项可以与[[tool.uv.index]]联用,并遵循相同的优先级规则:

  • 无论通过旧式--index-url、推荐的--default-index,还是default = true[[tool.uv.index]]条目定义,默认索引始终被当作最低优先级;
  • 索引按定义顺序查询,无论是旧式--extra-index-url、推荐的--index,还是[[tool.uv.index]]条目。

可以把--index-url--extra-index-url理解为未命名的[[tool.uv.index]]条目,前者隐含default = true。在这个视角下,--index-url映射到--default-index--extra-index-url映射到--index——从 pip 迁移时按此对应关系转换即可。

小结:索引配置速查

配置/选项作用
name/url索引身份;名称仅允许 ASCII 字母、数字、-_.
default = true该索引成为默认索引(最低优先级),并排除 PyPI 兜底
explicit = true仅当包通过tool.uv.sources显式固定时才使用该索引
format = "flat"索引为本地目录/HTML 扁平列表(等价--find-links
authenticateauto/always/never,控制凭证查找时机与禁用认证
ignore-error-codes解析时忽略的 HTTP 状态码(404 永远继续搜索)
cache-control覆盖api(元数据)与files(制品)的 Cache-Control 头
hash-algorithm强制 lockfile 使用指定哈希算法(preview)
exclude-newer索引级时间截止点,false表示禁用(preview)
--index-strategy/UV_INDEX_STRATEGYfirst-index(默认)、unsafe-first-matchunsafe-best-match
--index-url/--extra-index-urlpip 兼容选项,分别等价于--default-index/--index

【免费下载链接】uvAn extremely fast Python package and project manager, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/uv/uv

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询