pylock.toml
规范¶
pylock.toml
文件格式用于指定依赖项,以实现 Python 环境中可复现的安装。
注意
此规范最初在 PEP 751 中定义。
文件名¶
锁定文件必须命名为 pylock.toml
,或者如果需要命名锁定文件或存在多个锁定文件,则必须匹配正则表达式 r"^pylock\.([^.]+)\.toml$"
(对于任何文件名,正则表达式为 r"^pylock\.([^.]+\.)?toml$"
)。命名文件的前缀和后缀在可能的情况下必须是小写,以便于检测和删除,例如:
if len(filename) > 11 and filename.startswith("pylock.") and filename.endswith(".toml"):
name = filename.removeprefix("pylock.").removesuffix(".toml")
服务将自动从锁定文件中安装,并会搜索
带有服务名称的锁定文件,并进行默认安装
一个具有服务名称的依赖组的
pylock.toml
多用途文件pylock.toml
的默认安装
例如,一个名为“spam”的云主机服务将首先查找 pylock.spam.toml
进行安装,如果该文件不存在,则从 pylock.toml
进行安装,并查找名为“spam”的依赖组(如果存在)。
锁定文件应位于适合该锁定文件作用域的目录中。例如,锁定单个 pyproject.toml
会将 pylock.toml
放在同一目录中。如果锁定文件涵盖了单体仓库中的多个项目,那么 pylock.toml
文件应位于包含所有被锁定项目的目录中。
文件格式¶
该文件格式为 TOML。
工具应以一致的方式写入其锁定文件,以最大程度地减少 diff 输出中的噪音。表中的键(包括顶级表)应以一致的顺序记录(如果需要灵感,本规范已尝试按逻辑顺序记录键)。同样,工具应以一致的顺序对数组进行排序。内联表的用法也应保持一致。
lock-version
¶
类型:字符串;值为
"1.0"
必需?:是
记录文件所遵循的文件格式版本。
此 PEP 指定了初始版本——也是唯一有效值,直到标准的未来更新更改它——为
"1.0"
。如果工具支持主版本但不支持次版本,则在看到未知键时应发出警告。
如果工具不支持主版本,则必须引发错误。
environments
¶
requires-python
¶
类型:字符串
必需?:否
指定锁定文件所支持的任何环境的最低 Python 版本兼容的 Requires-Python(即锁定文件的最低可用 Python 版本)。
extras
¶
类型:字符串数组
必需?:否;默认为
[]
此锁定文件支持的 extras 列表。
锁定器可以选择不支持写入支持 extras 和依赖项组的锁定文件(即,工具可能只支持导出单用途锁定文件)。
支持 extras 的工具也必须支持依赖项组。
工具应显式将此键设置为空数组,以表明用于生成锁定文件的输入没有 extras(例如,pyproject.toml 文件没有 [project.optional-dependencies] 表),表明该锁定文件实际上是多用途的,即使它看起来是单用途的。
dependency-groups
¶
类型:字符串数组
必需?:否;默认为
[]
此锁定文件公开支持的 依赖项组 列表(即用户期望可以通过工具 UI 指定的依赖项组)。
锁定器可以选择不支持写入支持 extras 和依赖项组的锁定文件(即,工具可能只支持导出单用途锁定文件)。
支持依赖项组的工具也必须支持 extras。
工具应显式将此键设置为空数组,以表明用于生成锁定文件的输入没有依赖项组(例如,pyproject.toml 文件没有 [dependency-groups] 表),表明该锁定文件实际上是多用途的,即使它看起来是单用途的。
default-groups
¶
类型:字符串数组
必需?:否;默认为
[]
表示默认应安装的合成依赖项组的名称(例如,[project.dependencies] 隐式表示的)。
用于 packages.marker 需要存在此类组的情况。
此键列出的组不应列在 dependency-groups 中,因为这些组不打算通过名称直接暴露给用户,而是通过安装程序的 UI。
created-by
¶
类型:字符串
必需?:是
灵感:在锁定文件名中包含其名称的工具
记录用于创建锁定文件的工具名称。
工具可以(MAY)使用 [tool] 表来记录足够详细的信息,以便推断出用于创建锁定文件的输入。
工具应记录工具的规范化名称(如果它是一个 Python 包),以方便查找该工具。
[[packages]]
¶
packages.name
¶
类型:字符串
必需?:是
灵感:Name
包的*规范化*名称。
packages.version
¶
packages.marker
¶
类型:字符串
必需?:否
灵感:PDM
指定应在何时安装包的*环境标记*。
packages.requires-python
¶
类型:字符串
必需?:否
包含包的 Python 版本兼容性的*版本说明符*。
[[packages.dependencies]]
¶
类型:表数组
必需?:否
记录 [[packages]] 中是此包直接依赖项的其他条目。
每个条目都是一个表,其中包含使查找相应包的条目没有歧义所需的最小信息(例如,如果存在两个
spam
包的条目,则可以包含版本号,如{name = "spam", version = "1.0.0"}
,或按来源,如{name = "spam", vcs = { url = "..."}
)。工具在安装时不得使用此信息;它仅用于审计目的。
[packages.vcs]
¶
类型:表
必需?:否;与 [packages.directory]、[packages.archive]、[packages.sdist] 和 [[packages.wheels]] 互斥。
记录其中包含的*源树*的版本控制系统详细信息。
工具可以(MAY)选择不支持版本控制系统,无论是在锁定还是安装角度。
工具可以(MAY)选择仅支持可用 VCS 类型的一个子集。
工具应(SHOULD)提供一种方式让用户选择启用/禁用版本控制系统。
从版本控制系统安装被认为是源自*直接 URL 引用*。
packages.vcs.type
¶
类型:字符串;支持的值在 Registered VCS 中指定。
必需?:是
灵感:VCS URLs
使用的版本控制系统的类型。
packages.vcs.url
¶
类型:字符串
必需?:如果未指定 packages.vcs.path。
灵感:VCS URLs
源树的*URL*。
packages.vcs.path
¶
类型:字符串
必需?:如果未指定 packages.vcs.url。
灵感:VCS URLs
源树本地目录的*路径*。
如果使用相对路径,则它必须相对于此文件的位置。
如果路径是相对的,则可以(MAY)显式使用 POSIX 风格的路径分隔符以提高可移植性。
packages.vcs.requested-revision
¶
类型:字符串
必需?:否
灵感:VCS URLs
用户请求的分支/标签/引用/提交/修订版等。
这纯粹是信息性的,用于帮助编写 Direct URL Data Structure;不得(MUST NOT)用于检出存储库。
packages.vcs.commit-id
¶
类型:字符串
必需?:是
灵感:VCS URLs
要安装的确切提交/修订版号。
如果 VCS 支持基于提交哈希的修订标识符,则必须(MUST)使用该提交哈希作为 commit ID,以引用代码的不可变版本。
packages.vcs.subdirectory
¶
类型:字符串
必需?:否
灵感:子目录中的项目
源树中项目根目录所在的子目录(例如,pyproject.toml 文件的位置)。
路径必须(MUST)相对于源树结构的根目录。
[packages.directory]
¶
类型:表
必需?:否;与 [packages.vcs]、[packages.archive]、[packages.sdist] 和 [[packages.wheels]] 互斥。
灵感:本地目录
记录其中包含的*源树*的本地目录详细信息。
工具可以(MAY)选择不支持本地目录,无论是在锁定还是安装角度。
工具应(SHOULD)提供一种方式让用户选择启用/禁用本地目录。
从目录安装被认为是源自*直接 URL 引用*。
packages.directory.path
¶
类型:字符串
必需?:是
灵感:本地目录
源树所在的本地目录。
如果路径是相对的,则它必须相对于锁定文件的位置。
如果路径是相对的,则可以(MAY)使用 POSIX 风格的路径分隔符以提高可移植性。
packages.directory.editable
¶
类型:布尔值
必需?:否;默认为
false
灵感:本地目录
一个表示在锁定时间源树是否为可编辑安装的标志。
安装程序可以(MAY)选择忽略此标志,如果用户操作或上下文使得可编辑安装不必要或不受欢迎(例如,一个容器镜像,它不会被挂载用于开发目的,而是部署到生产环境,在那里它将被视为只读)。
packages.directory.subdirectory
¶
[packages.archive]
¶
类型:表
必需?:否
灵感:Archive URLs
一个直接引用要安装的归档文件(这可以包括 wheels 和 sdists,以及包含源树的其他归档格式)。
工具可以(MAY)选择不支持归档文件,无论是在锁定还是安装角度。
工具应(SHOULD)提供一种方式让用户选择启用/禁用归档文件。
从归档文件安装被认为是源自*直接 URL 引用*。
packages.archive.url
¶
参见 packages.vcs.url。
packages.archive.path
¶
packages.archive.size
¶
类型:整数
必需?:否
归档文件的大小。
工具在合理可能的情况下应(SHOULD)提供文件大小(例如,文件大小可通过 Content-Length 标头从 HEAD HTTP 请求获得)。
packages.archive.upload-time
¶
类型:datetime
必需?:否
文件上传的时间。
日期和时间必须(MUST)以 UTC 记录。
[packages.archive.hashes]
¶
类型:字符串表
必需?:是
一个列出文件已知哈希值的表,其中键是哈希算法,值是哈希值。
该表必须(MUST)包含至少一个条目。
哈希算法键应(SHOULD)为小写。
应(SHOULD)始终包含至少一个来自
hashlib.algorithms_guaranteed
的安全算法(在撰写本文时,特别推荐 sha256。
packages.archive.subdirectory
¶
packages.index
¶
类型:字符串
必需?:否
灵感:uv
来自 Simple repository API 的包索引的基本 URL,在此找到 sdist 和/或 wheels(例如,
https://pypi.ac.cn/simple/
)。如果可能,应(SHOULD)指定此项,以帮助生成*软件物料清单*(SBOM)或辅助查找文件(如果 URL 不再有效)。
工具可以(MAY)支持从索引安装,如果特定文件的 URL 不再有效(例如,返回 404 HTTP 错误代码)。
[packages.sdist]
¶
类型:表
必需?:否;与 [packages.vcs]、[packages.directory] 和 [packages.archive] 互斥。
灵感:uv
包的*源分发文件名*的详细信息。
工具可以(MAY)选择不支持 sdist 文件,无论是在锁定还是安装角度。
工具应(SHOULD)提供一种方式让用户选择启用/禁用 sdist 文件。
packages.sdist.name
¶
类型:字符串
必需?:否,当 packages.sdist.path/ packages.sdist.url 的最后一部分是相同值时,则不需要。
源分发文件的*文件名*。
packages.sdist.upload-time
¶
packages.sdist.url
¶
packages.sdist.path
¶
packages.sdist.size
¶
packages.sdist.hashes
¶
[[packages.wheels]]
¶
类型:表数组
必需?:否;与 [packages.vcs]、[packages.directory] 和 [packages.archive] 互斥。
用于记录包的*二进制分发格式*指定的 wheel 文件。
工具必须(MUST)支持 wheel 文件,无论是在锁定还是安装角度。
packages.wheels.name
¶
类型:字符串
必需?:否,当 packages.wheels.path/ packages.wheels.url 的最后一部分是相同值时,则不需要。
二进制分发文件的*文件名*。
packages.wheels.upload-time
¶
packages.wheels.url
¶
packages.wheels.path
¶
packages.wheels.size
¶
packages.wheels.hashes
¶
[[packages.attestation-identities]]
¶
类型:表数组
必需?:否
对*此包所有*已记录文件的证明的记录。
如果可用,工具应(SHOULD)包含找到的证明标识符。
发布者特定的键将按原样包含在此表中(即,顶级),遵循 Index hosted attestations 的规范。
packages.attestation-identities.kind
¶
类型:字符串
必需?:是
受信任发布者的唯一标识符。
[packages.tool]
¶
类型:表
必需?:否
用法与 pyproject.toml 规范 中的 [tool] 表类似,但位于包版本级别而不是锁定文件级别(后者也可通过 [tool] 访问)。
表中记录的数据必须(MUST)是可丢弃的(即,它不得(MUST NOT)影响安装)。
[tool]
¶
类型:表
必需?:否
参见 [packages.tool]。
示例¶
lock-version = '1.0'
environments = ["sys_platform == 'win32'", "sys_platform == 'linux'"]
requires-python = '== 3.12'
created-by = 'mousebender'
[[packages]]
name = 'attrs'
version = '25.1.0'
requires-python = '>= 3.8'
[[packages.wheels]]
name = 'attrs-25.1.0-py3-none-any.whl'
upload-time = 2025-01-25T11:30:10.164985+00:00
url = 'https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl'
size = 63152
hashes = {sha256 = 'c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a'}
[[packages.attestation-identities]]
environment = 'release-pypi'
kind = 'GitHub'
repository = 'python-attrs/attrs'
workflow = 'pypi-package.yml'
[[packages]]
name = 'cattrs'
version = '24.1.2'
requires-python = '>= 3.8'
dependencies = [
{name = 'attrs'},
]
[[packages.wheels]]
name = 'cattrs-24.1.2-py3-none-any.whl'
upload-time = 2024-09-22T14:58:34.812643+00:00
url = 'https://files.pythonhosted.org/packages/c8/d5/867e75361fc45f6de75fe277dd085627a9db5ebb511a87f27dc1396b5351/cattrs-24.1.2-py3-none-any.whl'
size = 66446
hashes = {sha256 = '67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0'}
[[packages]]
name = 'numpy'
version = '2.2.3'
requires-python = '>= 3.10'
[[packages.wheels]]
name = 'numpy-2.2.3-cp312-cp312-win_amd64.whl'
upload-time = 2025-02-13T16:51:21.821880+00:00
url = 'https://files.pythonhosted.org/packages/42/6e/55580a538116d16ae7c9aa17d4edd56e83f42126cb1dfe7a684da7925d2c/numpy-2.2.3-cp312-cp312-win_amd64.whl'
size = 12626357
hashes = {sha256 = '83807d445817326b4bcdaaaf8e8e9f1753da04341eceec705c001ff342002e5d'}
[[packages.wheels]]
name = 'numpy-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl'
upload-time = 2025-02-13T16:50:00.079662+00:00
url = 'https://files.pythonhosted.org/packages/39/04/78d2e7402fb479d893953fb78fa7045f7deb635ec095b6b4f0260223091a/numpy-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl'
size = 16116679
hashes = {sha256 = '3b787adbf04b0db1967798dba8da1af07e387908ed1553a0d6e74c084d1ceafe'}
[tool.mousebender]
command = ['.', 'lock', '--platform', 'cpython3.12-windows-x64', '--platform', 'cpython3.12-manylinux2014-x64', 'cattrs', 'numpy']
run-on = 2025-03-06T12:28:57.760769
安装¶
以下概述了从锁定文件安装的步骤(虽然要求是规定性的,但一般步骤和顺序是建议性的)。
收集要安装的 extras 和依赖项组,并分别设置
extras
和dependency_groups
以进行标记评估。extras
默认应(SHOULD)设置为空集。dependency_groups
默认应(SHOULD)是根据 default-groups 创建的集合。
检查 lock-version 指定的元数据版本是否受支持;必须(MUST)酌情引发错误或警告。
如果指定了 requires-python,请检查正在安装的环境是否满足要求;如果不满足,则必须(MUST)引发错误。
如果指定了 environments,请检查是否至少有一个环境标记表达式得到满足;如果不满足任何表达式,则必须(MUST)引发错误。
对于 [[packages]] 中列出的每个包:
如果指定了 packages.marker,请检查它是否得到满足;如果未满足,则跳到下一个包。
如果指定了 packages.requires-python,请检查它是否得到满足;如果不满足,则必须(MUST)引发错误。
检查是否没有其他冲突的包实例已被计划安装;否则,必须(MUST)引发关于歧义的错误。
检查包的来源是否已适当地指定(即,在包条目中没有冲突的来源);如果发现任何问题,则必须(MUST)引发错误。
将包添加到要安装的包集合中。
对于每个要安装的包:
如果设置了 [packages.vcs]:
将存储库克隆到 packages.vcs.commit-id 中指定的提交 ID。
构建(Build)包,并遵守 packages.vcs.subdirectory。
安装。.
否则,如果设置了 [packages.directory]:
构建(Build)包,并遵守 packages.directory.subdirectory。
安装。.
否则,如果设置了 [packages.archive]:
获取文件。
使用 packages.archive.size 和 [packages.archive.hashes] 进行验证。
构建(Build)包,并遵守 packages.archive.subdirectory。
安装。.
否则,如果存在 [[packages.wheels]] 的条目:
根据 packages.wheels.name 查找合适的 wheel 文件;如果没有找到,则继续到 [packages.sdist],否则必须(MUST)引发关于项目缺乏来源的错误。
获取文件。
如果设置了 packages.wheels.path,则使用它。
否则,如果设置了 packages.wheels.url,则尝试使用它;工具可以(MAY)选择使用 packages.index 或一些工具特定的机制来下载选定的 wheel 文件(工具不得(MUST NOT)尝试根据可用内容更改要下载的 wheel 文件;要安装的文件应以离线方式确定,以保证可复现性)。
使用 packages.wheels.size 和 packages.wheels.hashes 进行验证。
安装。.
否则,如果没有找到 [[packages.wheels]] 文件或仅设置了 [packages.sdist]:
获取文件。
如果设置了 packages.sdist.path,则使用它。
否则,如果设置了 packages.sdist.url,则尝试使用它;工具可以(MAY)使用 packages.index 或一些工具特定的机制来下载文件。
使用 packages.sdist.size 和 packages.sdist.hashes 进行验证。
构建(Build)包。
安装。.
历史¶
2025 年 4 月:初始版本,通过 PEP 751 批准。