版本说明符¶
本规范描述了一种用于标识 Python 软件发行版版本以及声明对特定版本依赖关系的方案。
定义¶
本文档中的关键词“必须”、“不得”、“必需”、“应”、“不应”、“建议”、“不建议”、“推荐”、“可”和“可选”应根据RFC 2119进行解释。
“构建工具”是指旨在开发系统上运行的自动化工具,用于生成源和二进制发行版归档。构建工具也可以由集成工具调用,以构建以 sdist 而非预构建二进制归档形式分发的软件。
“索引服务器”是活跃的发行版注册表,发布版本和依赖元数据,并对允许的元数据施加限制。
“发布工具”是旨在开发系统上运行并向索引服务器上传源和二进制发行版归档的自动化工具。
“安装工具”是专门旨在部署目标上运行的集成工具,从索引服务器或其他指定位置获取源和二进制发行版归档并将其部署到目标系统。
“自动化工具”是涵盖构建工具、索引服务器、发布工具、集成工具以及任何其他生产或消费发行版版本和依赖元数据的软件的统称。
版本方案¶
发行版通过支持所有已定义版本比较操作的公共版本标识符进行标识
版本方案既用于描述特定发行版归档提供的发行版版本,也用于对构建或运行软件所需的依赖版本施加限制。
公共版本标识符¶
规范的公共版本标识符必须符合以下方案
[N!]N(.N)*[{a|b|rc}N][.postN][.devN]
公共版本标识符不得包含前导或尾随空格。
公共版本标识符在给定发行版中必须是唯一的。
安装工具应忽略不符合此方案的任何公共版本,但必须包含以下指定的规范化。安装工具在检测到不合规或模糊版本时可向用户发出警告。
另请参阅附录:使用正则表达式解析版本字符串,其中提供了用于检查与规范格式严格一致性的正则表达式,以及接受可能需要后续规范化的输入的更宽松的正则表达式。
公共版本标识符最多分为五个部分
纪元部分:
N!发布部分:
N(.N)*预发布部分:
{a|b|rc}N后期发布部分:
.postN开发发布部分:
.devN
任何给定的发布都将是以下部分定义的“最终发布”、“预发布”、“后期发布”或“开发发布”。
所有数字组件必须是非负整数,表示为 ASCII 数字序列。
所有数字组件必须根据其数值而不是文本字符串进行解释和排序。
所有数字组件都可以为零。除了下面针对发布部分描述的情况外,零的数字组件没有特殊意义,只是在版本排序中始终是可能的最低值。
注意
为了更好地适应现有公共和私有 Python 项目的广泛版本控制实践,本方案允许一些难以阅读的版本标识符。
因此,本规范技术上允许的一些版本控制实践强烈不鼓励用于新项目。在这种情况下,相关细节将在以下部分中注明。
本地版本标识符¶
本地版本标识符必须符合以下方案
<public version identifier>[+<local version label>]
它们由一个普通的公共版本标识符(如上一节所述)和一个任意的“本地版本标签”组成,两者之间用加号分隔。本地版本标签没有分配特定的语义,但施加了一些语法限制。
本地版本标识符用于表示上游项目的完全 API(如果适用,还有 ABI)兼容的修补版本。例如,这些可能由应用程序开发人员和系统集成商通过应用特定的回溯错误修复程序来创建,当升级到新的上游版本对应用程序或其他集成系统(如 Linux 发行版)造成太大干扰时。
本地版本标签的包含使得区分上游版本和下游集成商可能更改的重建版本成为可能。使用本地版本标识符不影响发布的类型,但当应用于源发行版时,确实表示它可能不包含与相应的上游版本完全相同的代码。
为确保本地版本标识符可以轻松地作为文件名和 URL 的一部分,并避免十六进制哈希表示中的格式不一致,本地版本标签必须限于以下允许的字符集
ASCII 字母 (
[a-zA-Z])ASCII 数字 (
[0-9])句点 (
.)
本地版本标签必须以 ASCII 字母或数字开头和结尾。
本地版本的比较和排序分别考虑本地版本的每个部分(由.分隔)。如果一个部分完全由 ASCII 数字组成,则该部分应视为整数进行比较;如果一个部分包含任何 ASCII 字母,则该部分按词典顺序(不区分大小写)进行比较。当比较数字部分和词典部分时,数字部分始终大于词典部分。此外,具有更多部分的本地版本始终大于具有较少部分的本地版本,只要较短本地版本的部分与较长本地版本的部分完全匹配。
“上游项目”是指定义自己的公共版本的项目。“下游项目”是指跟踪和重新分发上游项目,并可能从上游项目的后续版本回溯安全和错误修复的项目。
将上游项目发布到公共索引服务器时,不应使用本地版本标识符,但可用于标识直接从项目源创建的私有构建。下游项目在发布与公共版本标识符标识的上游项目版本 API 兼容但包含额外更改(例如错误修复)的版本时,应使用本地版本标识符。由于 Python 包索引仅用于索引和托管上游项目,因此它不得允许使用本地版本标识符。
使用本地版本标识符的源发行版应提供python.integrator扩展元数据(如PEP 459中定义)。
最终发布¶
仅由发布部分和可选的纪元标识符组成的版本标识符称为“最终发布”。
发布部分由一个或多个非负整数值组成,用点分隔
N(.N)*
项目中的最终发布必须以一致递增的方式编号,否则自动化工具将无法正确升级它们。
发布部分的比较和排序依次考虑发布部分每个组件的数值。当比较不同组件数量的发布部分时,较短的部分根据需要用额外的零填充。
虽然在此方案下允许在第一个组件之后添加任意数量的额外组件,但最常见的变体是使用两个组件(“主版本.次版本”)或三个组件(“主版本.次版本.微版本”)。
例如
0.9
0.9.1
0.9.2
...
0.9.10
0.9.11
1.0
1.0.1
1.1
2.0
2.0.1
...
发布系列是任何以公共前缀开头的最终发布数字集。例如,3.3.1、3.3.5和3.3.9.45都是3.3发布系列的一部分。
注意
X.Y和X.Y.0不被视为不同的发布数字,因为发布部分比较规则在将其与任何包含三个组件的发布部分进行比较时,隐式地将两组件形式扩展为X.Y.0。
还允许基于日期的发布部分。例如,使用发布年份和月份的基于日期的发布方案
2012.4
2012.7
2012.10
2013.1
2013.6
...
预发布¶
一些项目使用“alpha、beta、候选发布版”预发布周期,以支持用户在最终发布之前进行测试。
如果作为项目开发周期的一部分使用,这些预发布通过在版本标识符中包含预发布部分来指示
X.YaN # Alpha release
X.YbN # Beta release
X.YrcN # Release Candidate
X.Y # Final release
仅由发布部分和预发布部分组成的版本标识符称为“预发布”。
预发布部分由预发布阶段的字母标识符以及非负整数值组成。给定发布版本的预发布首先按阶段(alpha、beta、候选发布版)排序,然后按该阶段内的数字组件排序。
安装工具可接受相同发布部分的c和rc发布,以处理一些现有的旧版发行版。
安装工具应将c版本解释为等同于rc版本(即c1表示与rc1相同的版本)。
构建工具、发布工具和索引服务器不应允许为同一发布部分创建rc和c发布。
后期发布¶
一些项目使用后期发布来解决最终发布中不影响分发软件的次要错误(例如,纠正发行说明中的错误)。
如果作为项目开发周期的一部分使用,这些后期发布通过在版本标识符中包含后期发布部分来指示
X.Y.postN # Post-release
包含后期发布部分但没有开发发布部分的版本标识符称为“后期发布”。
后期发布部分由字符串.post组成,后跟一个非负整数值。后期发布按其数字组件排序,紧随相应的发布之后,并位于任何后续发布之前。
注意
强烈不鼓励使用后期发布来发布包含实际错误修复的维护发布。通常,最好使用较长的发布号并递增每个维护发布的最后一个组件。
预发布也允许后期发布
X.YaN.postM # Post-release of an alpha release
X.YbN.postM # Post-release of a beta release
X.YrcN.postM # Post-release of a release candidate
注意
强烈不鼓励创建预发布版本的后期发布,因为它使版本标识符对人类读者难以解析。通常,只需递增数字组件即可创建一个新的预发布,这样会更清晰。
开发发布¶
有些项目会定期进行开发版本发布,系统打包商(尤其是 Linux 发行版)可能希望直接从源代码控制创建早期版本,这些版本不与后来的项目版本冲突。
如果作为项目开发周期的一部分使用,这些开发版本通过在版本标识符中包含开发版本部分来指示
X.Y.devN # Developmental release
包含开发发布部分的版本标识符称为“开发发布”。
开发版本部分由字符串.dev组成,后跟一个非负整数值。开发版本按其数字组件排序,紧随相应的发布(以及与同一发布部分相关的任何预发布)之前,并紧随任何以前的发布(包括任何后期发布)之后。
预发布和后期发布也允许开发发布
X.YaN.devM # Developmental release of an alpha release
X.YbN.devM # Developmental release of a beta release
X.YrcN.devM # Developmental release of a release candidate
X.Y.postN.devM # Developmental release of a post-release
请注意,处理开发版本时,它们被视为预发布的一种类型。
注意
虽然它们可能对持续集成目的有用,但强烈不鼓励将预发布的开发版本发布到通用公共索引服务器,因为它使版本标识符对人类读者难以解析。如果需要发布此类版本,则通过递增数字组件来创建新的预发布会更清晰。
强烈不鼓励后期发布的开发版本,但对于使用后期发布表示法进行可能包含代码更改的完整维护发布的项目,它们可能适用。
版本纪元¶
如果包含在版本标识符中,纪元出现在所有其他组件之前,与发布部分用感叹号分隔
E!X.Y # Version identifier with epoch
如果没有给出明确的纪元,则隐式纪元为0。
大多数版本标识符不会包含纪元,因为只有当项目_改变_其版本编号处理方式,导致正常版本排序规则给出错误结果时,才需要显式纪元。例如,如果项目使用2014.04等基于日期的版本,并希望切换到1.0等语义版本,那么在使用正常排序方案时,新版本将被标识为比基于日期的版本_更旧_
1.0
1.1
2.0
2013.10
2014.04
然而,通过指定一个明确的纪元,排序顺序可以适当地改变,因为来自后期纪元的所有版本都排在早期纪元的版本之后
2013.10
2014.04
1!1.0
1!1.1
1!2.0
规范化¶
为了更好地兼容现有版本,解析版本时必须考虑许多“替代”语法。解析版本时必须考虑这些语法,但是它们应该“规范化”为上面定义的标准语法。
大小写敏感性¶
所有 ASCII 字母在版本中应不区分大小写地解释,且正常形式为小写。这允许诸如1.1RC1的版本,它将被规范化为1.1rc1。
整数规范化¶
所有整数通过内置的int()函数进行解释,并规范化为输出的字符串形式。这意味着整数版本00将规范化为0,而09000将规范化为9000。这不适用于本地版本字母数字段内的整数,例如1.0+foo0100,它已经处于规范化形式。
预发布分隔符¶
预发布应允许在发布段和预发布段之间使用.、-或_作为分隔符。其正常形式是不带分隔符。这允许诸如1.1.a1或1.1-a1的版本被规范化为1.1a1。它还应允许在预发布标识符和数字之间使用分隔符。这允许诸如1.0a.1的版本被规范化为1.0a1。
预发布拼写¶
预发布允许alpha、beta、c、pre和preview的额外拼写,分别对应a、b、rc、rc和rc。这允许诸如1.1alpha1、1.1beta2或1.1c3的版本,它们分别规范化为1.1a1、1.1b2和1.1rc3。在每种情况下,额外的拼写应被视为等同于其正常形式。
隐式预发布号¶
预发布允许省略数字,在这种情况下,它隐式假定为0。其正常形式是明确包含0。这允许诸如1.2a的版本被规范化为1.2a0。
后期发布分隔符¶
后期发布允许使用.、-或_作为分隔符,也可以完全省略分隔符。其正常形式是带.分隔符。这允许诸如1.2-post2或1.2post2的版本被规范化为1.2.post2。与预发布分隔符一样,这也允许在后期发布标识符和数字之间使用可选的分隔符。这允许诸如1.2.post-2的版本被规范化为1.2.post2。
后期发布拼写¶
后期发布允许使用额外的拼写rev和r。这允许诸如1.0-r4的版本被规范化为1.0.post4。与预发布一样,额外的拼写应被视为等同于其正常形式。
隐式后期发布号¶
后期发布允许省略数字,在这种情况下,它隐式假定为0。其正常形式是明确包含0。这允许诸如1.2.post的版本被规范化为1.2.post0。
隐式后期发布¶
后期发布允许完全省略post标识符。当使用此形式时,分隔符必须是-,不允许其他形式。这允许诸如1.0-1的版本被规范化为1.0.post1。此特定的规范化不得与隐式后期发布号规则结合使用。换句话说,1.0- 不是 有效版本,并且它 不会 规范化为1.0.post0。
开发发布分隔符¶
开发发布允许使用.、-或_作为分隔符,也可以完全省略分隔符。其正常形式是带.分隔符。这允许诸如1.2-dev2或1.2dev2的版本被规范化为1.2.dev2。
隐式开发发布号¶
开发发布允许省略数字,在这种情况下,它隐式假定为0。其正常形式是明确包含0。这允许诸如1.2.dev的版本被规范化为1.2.dev0。
本地版本段¶
在本地版本中,除了使用.作为段分隔符之外,-和_的使用也是可接受的。正常形式是使用.字符。这允许诸如1.0+ubuntu-1的版本被规范化为1.0+ubuntu.1。
前导字符v¶
为了支持常见的版本表示法v1.0,版本前面可以有一个单独的字面量v字符。此字符必须出于所有目的而被忽略,并且应从版本的所有规范化形式中省略。带有和不带有v的同一版本被认为是等效的。
前导和尾随空格¶
前导和尾随空格必须被静默忽略,并从版本的所有规范化形式中删除。这包括" "、\t、\n、\r、\f和\v。这允许合理地处理意外的空格,例如1.0\n之类的版本,它规范化为1.0。
符合版本方案的示例¶
标准版本方案旨在涵盖公共和私有 Python 项目中广泛的标识实践。实际上,一个项目如果试图充分利用该方案提供的所有灵活性,将导致人类用户难以确定版本的相对顺序,尽管上述规则确保所有合规工具都能一致地对其进行排序。
以下示例展示了项目可以选择的不同发布标识方法的一小部分,同时仍确保人类用户和自动化工具都能轻松确定“最新发布”和“最新稳定发布”。
简单的“主版本.次版本”版本控制
0.1
0.2
0.3
1.0
1.1
...
简单的“主版本.次版本.微版本”版本控制
1.1.0
1.1.1
1.1.2
1.2.0
...
带有 alpha、beta 和候选预发布版本的“主版本.次版本”版本控制
0.9
1.0a1
1.0a2
1.0b1
1.0rc1
1.0
1.1a1
...
带有开发版本、候选发布版本和用于次要更正的后期发布版本的“主版本.次版本”版本控制
0.9
1.0.dev1
1.0.dev2
1.0.dev3
1.0.dev4
1.0c1
1.0c2
1.0
1.0.post1
1.1.dev1
...
基于日期的发布,每年内部序列递增,跳过零
2012.1
2012.2
2012.3
...
2012.15
2013.1
2013.2
...
允许的后缀和相对顺序摘要¶
注意
本节主要面向自动处理分发元数据的工具作者,而不是决定版本控制方案的 Python 分发开发者。
版本标识符的纪元部分必须按照给定纪元的数值进行排序。如果不存在纪元部分,则隐式数值为0。
版本标识符的发布部分必须按照 Python 元组排序的相同顺序排序,当规范化后的发布部分解析如下时
tuple(map(int, release_segment.split(".")))
参与比较的所有发布段都必须通过根据需要用零填充较短段来转换为一致的长度。
在数字发布(1.0、2.7.3)中,允许使用以下后缀,并且必须按所示顺序排序
.devN, aN, bN, rcN, <no suffix>, .postN
请注意,c在语义上被认为是等同于rc,并且必须像rc一样排序。工具可以拒绝在同一发布部分中同时出现具有相同N的c和rc的情况,因为这被认为是模糊的,并且仍符合规范。
在 alpha (1.0a1)、beta (1.0b1) 或发布候选版 (1.0rc1、1.0c1) 中,允许使用以下后缀,并且必须按所示顺序排序
.devN, <no suffix>, .postN
在后期发布(1.0.post1)中,允许使用以下后缀,并且必须按所示顺序排序
.devN, <no suffix>
请注意,devN和postN必须始终以点号开头,即使紧随数字版本之后使用(例如1.0.dev456、1.0.post1)。
在具有共同前缀的预发布、后期发布或开发发布段中,排序必须按数字组件的值进行。
以下示例涵盖了许多可能的组合
1.dev0
1.0.dev456
1.0a1
1.0a2.dev456
1.0a12.dev456
1.0a12
1.0b1.dev456
1.0b2
1.0b2.post345.dev456
1.0b2.post345
1.0rc1.dev456
1.0rc1
1.0
1.0+abc.5
1.0+abc.7
1.0+5
1.0.post456.dev34
1.0.post456
1.0.15
1.1.dev1
跨不同元数据版本的版本排序¶
元数据 v1.0 (PEP 241) 和元数据 v1.1 (PEP 314) 未指定标准版本标识或排序方案。然而,元数据 v1.2 (PEP 345) 确实指定了一个在PEP 386中定义的方案。
由于简单安装程序 API 的性质,安装程序无法知道特定发行版使用的是哪个元数据版本。此外,安装程序需要能够创建一个合理的优先列表,其中包含项目的所有或尽可能多的版本,以确定应安装哪些版本。这些要求需要对所有项目版本使用一个解析机制进行标准化。
由于上述原因,本规范必须用于所有元数据版本,并取代PEP 386,即使是元数据 v1.2。工具应忽略任何无法根据本规范规则解析的版本,但如果没有符合本规范的版本可用,则可回退到实现定义的版本解析和排序方案。
分发用户可能希望从他们控制的任何私有包索引中明确删除不合规版本。
与其他版本方案的兼容性¶
有些项目可能选择使用需要转换才能符合本规范中定义的公共版本方案的版本方案。在这种情况下,项目特定版本可以存储在元数据中,而转换后的公共版本则发布在版本字段中。
这使得自动化分发工具能够提供一致正确的已发布版本排序,同时仍允许开发人员为其项目使用他们偏好的内部版本控制方案。
语义版本控制¶
语义版本控制是一种流行的版本标识方案,它比本规范对发布号不同元素的意义规定更严格。即使项目选择不遵守语义版本控制的细节,该方案也值得理解,因为它涵盖了在依赖其他发行版以及发布他人依赖的发行版时可能出现的许多问题。
语义版本控制的“主版本.次版本.补丁版本”(本规范中描述为“主版本.次版本.微版本”)方面(2.0.0 规范中的条款 1-8)与本规范中定义的版本方案完全兼容,并鼓励遵守这些方面。
包含连字符(预发布 - 条款 10)或加号(构建 - 条款 11)的语义版本与本规范 不兼容,并且不允许出现在公共版本字段中。
将此类基于语义版本控制的源标签转换为兼容的公共版本的一种可能机制是使用.devN后缀来指定适当的版本顺序。
具体的构建信息也可以包含在本地版本标签中。
基于 DVCS 的版本标签¶
许多构建工具与 Git 和 Mercurial 等分布式版本控制系统集成,以将标识哈希添加到版本标识符。由于哈希无法可靠地排序,因此此类版本不允许出现在公共版本字段中。
与语义版本控制一样,公共的.devN后缀可用于唯一标识此类发布以进行发布,而原始的基于 DVCS 的标签可存储在项目元数据中。
标识哈希信息也可以包含在本地版本标签中。
奥尔森数据库版本控制¶
pytz项目继承了相应的奥尔森时区数据库版本控制方案:年份后跟一个指示该年份数据库版本的两位小写字符。
这可以转换为符合要求的公共版本标识符,如<year>.<serial>,其中序列从零或一(对于“
与其他翻译版本标识符一样,相应的奥尔森数据库版本可以记录在项目元数据中。
版本说明符¶
版本说明符由一系列版本子句组成,用逗号分隔。例如
~= 0.9, >= 1.0, != 1.3.4.*, < 2.0
比较运算符决定了版本子句的类型
逗号(“,”)等同于逻辑 and 运算符:候选版本必须匹配所有给定的版本子句才能匹配整个说明符。
条件运算符和后面的版本标识符之间的空格是可选的,逗号周围的空格也是可选的。
当多个候选版本匹配版本说明符时,首选版本应为由标准版本方案定义的一致排序所确定的最新版本。是否将预发布版本视为候选版本应按预发布版本处理中的描述处理。
除非下面特别注明,否则版本说明符中不得允许使用本地版本标识符,并且在检查候选版本是否与给定版本说明符匹配时,必须完全忽略本地版本标签。
兼容发布¶
兼容发布子句由兼容发布运算符~=和一个版本标识符组成。它匹配任何预期与指定版本兼容的候选版本。
指定的版本标识符必须符合版本方案中描述的标准格式。此版本说明符中不允许使用本地版本标识符。
对于给定的发布标识符V.N,兼容发布子句大约等同于以下比较子句对
>= V.N, == V.*
此运算符不得用于单段版本号,例如~=1。
例如,以下几组版本子句是等效的
~= 2.2
>= 2.2, == 2.*
~= 1.4.5
>= 1.4.5, == 1.4.*
如果在兼容发布子句中将预发布、后期发布或开发发布命名为V.N.suffix,则在确定所需的匹配前缀时会忽略后缀
~= 2.2.post3
>= 2.2.post3, == 2.*
~= 1.4.5a4
>= 1.4.5a4, == 1.4.*
发布段比较的填充规则意味着,兼容发布子句中假定的向前兼容程度可以通过向版本说明符添加额外的零来控制
~= 2.2.0
>= 2.2.0, == 2.2.*
~= 1.4.5.0
>= 1.4.5.0, == 1.4.5.*
版本匹配¶
版本匹配子句包含版本匹配运算符==和一个版本标识符。
指定的版本标识符必须符合版本方案中描述的标准格式,但公共版本标识符上允许使用尾随的.*,如下所述。
默认情况下,版本匹配运算符基于严格相等比较:指定版本必须与请求版本完全相同。执行的 唯一 替换是对发布部分进行零填充,以确保发布部分以相同的长度进行比较。
严格版本匹配是否适用取决于版本说明符的具体用例。自动化工具至少应发出警告,并且当严格版本匹配使用不当时可完全拒绝它们。
可以通过在版本匹配子句的版本标识符后附加.*来请求前缀匹配而非严格比较。这意味着在确定版本标识符是否匹配子句时,将忽略额外的尾随段。如果指定版本仅包含发布段,则发布段中的尾随组件(或缺少尾随组件)也将被忽略。
例如,给定版本1.1.post1,以下子句将匹配或不匹配,如下所示
== 1.1 # Not equal, so 1.1.post1 does not match clause
== 1.1.post1 # Equal, so 1.1.post1 matches clause
== 1.1.* # Same prefix, so 1.1.post1 matches clause
为了进行前缀匹配,预发布段被认为有一个隐含的前导.,因此给定版本1.1a1,以下子句将匹配或不匹配,如下所示
== 1.1 # Not equal, so 1.1a1 does not match clause
== 1.1a1 # Equal, so 1.1a1 matches clause
== 1.1.* # Same prefix, so 1.1a1 matches clause if pre-releases are requested
精确匹配也被视为前缀匹配(此解释由版本标识符发布段的通常零填充规则暗示)。给定版本1.1,以下子句将匹配或不匹配,如下所示
== 1.1 # Equal, so 1.1 matches clause
== 1.1.0 # Zero padding expands 1.1 to 1.1.0, so it matches clause
== 1.1.dev1 # Not equal (dev-release), so 1.1 does not match clause
== 1.1a1 # Not equal (pre-release), so 1.1 does not match clause
== 1.1.post1 # Not equal (post-release), so 1.1 does not match clause
== 1.1.* # Same prefix, so 1.1 matches clause
包含开发版本或本地版本(例如1.0.dev1.*或1.0+foo1.*)的前缀匹配是无效的。如果存在,开发版本段始终是公共版本中的最后一个段,并且本地版本在比较时被忽略,因此在前缀匹配中使用两者都没有意义。
在为已发布发行版定义依赖项时,强烈不鼓励使用==(至少不带通配符后缀),因为它极大地复杂化了安全补丁的部署。严格版本比较运算符主要用于在使用共享发行版索引时,为可重复的 应用程序部署 定义依赖项。
如果指定的版本标识符是公共版本标识符(没有本地版本标签),则在匹配版本时必须忽略任何候选版本的本地版本标签。
如果指定的版本标识符是本地版本标识符,则在匹配版本时必须考虑候选版本的本地版本标签,其中公共版本标识符按上述方式匹配,本地版本标签通过严格字符串相等比较进行检查。
版本排除¶
版本排除子句包括版本排除运算符!=和一个版本标识符。
允许的版本标识符和比较语义与版本匹配运算符相同,只是任何匹配的意义都相反。
例如,给定版本1.1.post1,以下子句将匹配或不匹配,如下所示
!= 1.1 # Not equal, so 1.1.post1 matches clause
!= 1.1.post1 # Equal, so 1.1.post1 does not match clause
!= 1.1.* # Same prefix, so 1.1.post1 does not match clause
包含式有序比较¶
包含式有序比较子句包含一个比较运算符和一个版本标识符,并且将匹配任何版本,其中根据标准版本方案定义的一致排序,候选版本和指定版本的相对位置比较正确。
包含式有序比较运算符是<=和>=。
与版本匹配一样,发布段根据需要进行零填充,以确保发布段以相同的长度进行比较。
此版本说明符中不允许使用本地版本标识符。
排他式有序比较¶
排他式有序比较>和<与包含式有序比较相似,它们都依赖于在标准版本方案定义的一致排序下,候选版本和指定版本的相对位置。然而,它们明确排除了指定版本的预发布、后期发布和本地版本。
排他式有序比较>V 不得 允许给定版本的后期发布,除非V本身是后期发布。您可以通过使用>V.postN来强制要求版本晚于特定的后期发布,包括额外的后期发布。例如,>1.7将允许1.7.1但不允许1.7.0.post1,而>1.7.post2将允许1.7.1和1.7.0.post3但不允许1.7.0。
排他式有序比较>V 不得 匹配指定版本的本地版本。
排他式有序比较<V 不得 允许指定版本的预发布版本,除非指定版本本身就是预发布版本。允许早于但不等于特定预发布版本的预发布版本可以通过使用<V.rc1或类似方式来实现。
与版本匹配一样,发布段根据需要进行零填充,以确保发布段以相同的长度进行比较。
此版本说明符中不允许使用本地版本标识符。
任意相等¶
任意相等比较是简单的字符串相等操作,不考虑任何语义信息,例如零填充或本地版本。此运算符也不支持==运算符那样的前缀匹配。
任意相等的主要用例是允许指定无法通过本规范表示的版本。此运算符是特殊的,充当一个逃生舱口,允许使用实现本规范的工具的用户仍然安装一个与本规范不兼容的旧版本。
一个例子是===foobar,它将匹配foobar版本。
此运算符也可用于明确要求项目的未修补版本,例如===1.0,它将不匹配版本1.0+downstream1。
强烈不鼓励使用此运算符,并且工具在使用时 可 显示警告。
预发布版本的处理¶
任何类型的预发布版本,包括开发版本,都隐含地排除在所有版本说明符之外, 除非 它们已存在于系统上,由用户明确请求,或者满足版本说明符的唯一可用版本是预发布版本。
默认情况下,依赖解析工具应
接受所有版本说明符的已安装预发布版本
接受没有最终发布或后期发布版本满足版本说明符的远程可用预发布版本
排除所有其他预发布版本
如果需要预发布版本才能满足版本说明符,依赖解析工具可以发出警告。
依赖解析工具还应允许用户请求以下替代行为
接受所有版本说明符的预发布版本
排除所有版本说明符的预发布版本(如果预发布版本已本地安装,或者预发布版本是满足特定说明符的唯一方式,则报告错误或警告)
依赖解析工具还可以允许对上述行为进行每个发行版的基础控制。
后期发布和最终发布在版本说明符中没有特殊处理——它们总是包含在内,除非明确排除。
示例¶
~=3.1:版本 3.1 或更高版本,但不包括版本 4.0 或更高版本。~=3.1.2:版本 3.1.2 或更高版本,但不包括版本 3.2.0 或更高版本。~=3.1a1:版本 3.1a1 或更高版本,但不包括版本 4.0 或更高版本。== 3.1:特指版本 3.1(或 3.1.0),排除所有预发布版本、后期发布版本、开发版本以及任何 3.1.x 维护版本。== 3.1.*:任何以 3.1 开头的版本。等同于~=3.1.0兼容发布子句。~=3.1.0, != 3.1.3:版本 3.1.0 或更高,但不包括版本 3.1.3,也不包括版本 3.2.0 或更高。
直接引用¶
一些自动化工具可能允许使用直接引用作为正常版本说明符的替代。直接引用由说明符@和一个显式 URL 组成。
是否适合使用直接引用取决于版本说明符的具体用例。自动化工具至少应发出警告,并且在不当使用直接引用时可完全拒绝它们。
公共索引服务器不应允许在上传的发行版中使用直接引用。直接引用旨在作为软件集成商而非发布者的工具。
根据用例,直接 URL 引用的某些适当目标可以是 sdist 或 wheel 二进制归档。具体支持的 URL 和目标将取决于工具。
例如,可以直接引用本地源归档
pip @ file:///localbuilds/pip-1.3.1.zip
另外,也可以引用预构建的归档文件
pip @ file:///localbuilds/pip-1.3.1-py33-none-any.whl
所有不引用本地文件 URL 的直接引用应指定安全的传输机制(例如https)并包含 URL 中的预期哈希值以进行验证。如果直接引用在没有哈希信息、哈希信息工具无法理解或选择的哈希算法工具认为太弱而不可信的情况下指定,自动化工具应至少发出警告,并可拒绝依赖该 URL。如果此类直接引用还使用不安全的传输,自动化工具不应依赖该 URL。
建议仅使用标准库hashlib模块最新版本无条件提供的哈希值作为源存档哈希。撰写本文时,该列表包括'md5'、'sha1'、'sha224'、'sha256'、'sha384'和'sha512'。
对于源存档和 wheel 引用,可以通过在 URL 片段中包含<hash-algorithm>=<expected-hash>条目来指定预期的哈希值。
对于版本控制引用,应使用VCS+protocol方案来同时标识版本控制系统和安全传输,并且应使用具有基于哈希的提交标识符的版本控制系统。对于不提供基于哈希的提交标识符的版本控制系统,自动化工具可省略关于缺少哈希的警告。
为了处理不支持直接在 URL 中包含提交或标签引用的版本控制系统,这些信息可以使用@<commit-hash>或@<tag>#<commit-hash>表示法附加到 URL 的末尾。
注意
这与 pip 支持的现有 VCS 引用表示法 不完全 相同。首先,发行版名称移到前面,而不是嵌入到 URL 中。其次,即使基于标签检索,也包含提交哈希,以满足上述要求,即 每个 链接都应包含哈希,以使其更难伪造(创建带有特定标签的恶意仓库很容易,创建带有特定 哈希 的仓库则不然)。
远程 URL 示例
pip @ https://github.com/pypa/pip/archive/1.3.1.zip#sha1=da9234ee9982d4bbb3c72346a6de940a148ea686
pip @ git+https://github.com/pypa/pip.git@7921be1537eac1e97bc40179a57f0349c2aee67d
pip @ git+https://github.com/pypa/pip.git@1.3.1#7921be1537eac1e97bc40179a57f0349c2aee67d
文件 URL¶
文件 URL 的形式为file://<host>/<path>。如果省略<host>,则假定为localhost,即使省略<host>,第三个斜杠也必须存在。<path>定义要访问的文件系统上的文件路径。
在各种 *nix 操作系统上,<host>唯一允许的值是省略它、localhost或当前机器认为与其自己的主机匹配的另一个 FQDN。换句话说,在 *nix 上,file://方案只能用于访问本地机器上的路径。
在 Windows 上,文件格式应包含驱动器号(如果适用)作为<path>的一部分(例如file:///c:/path/to/a/file)。与 *nix 不同,在 Windows 上,<host>参数可用于指定位于网络共享上的文件。换句话说,为了将\\machine\volume\file转换为file://URL,它将变为file://machine/volume/file。有关 Windows 上file://URL 的更多信息,请参阅MSDN。
与 pkg_resources.parse_version 的差异摘要¶
注意:此比较是针对PEP 440编写时存在的
pkg_resources.parse_version。在 PEP 被接受后,setuptools 6.0 及更高版本采用了此处描述的行为。本地版本排序方式不同,本规范要求它们排序时大于不带本地版本的相同版本,而
pkg_resources.parse_version将其视为预发布标记。本规范特意限制了构成有效版本的语法,而
pkg_resources.parse_version试图从 任何 任意字符串中提供一些意义。pkg_resources.parse_version允许任意深度嵌套的版本标识符,例如1.0.dev1.post1.dev5。然而,本规范只允许每种类型使用一次,并且它们必须以特定顺序存在。
附录:使用正则表达式解析版本字符串¶
如公共版本标识符部分早前所述,发布的版本标识符应使用规范格式。本节提供了可用于测试版本是否已采用该格式的正则表达式,如果不是,则提取各个组件以进行后续规范化。
要测试版本标识符是否为规范格式,可以使用以下函数
import re
def is_canonical(version):
return re.match(r'^([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))?(\.dev(0|[1-9][0-9]*))?$', version) is not None
要提取版本标识符的组件,请使用以下正则表达式(由packaging项目定义)
VERSION_PATTERN = r"""
v?
(?:
(?:(?P<epoch>[0-9]+)!)? # epoch
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
(?P<pre> # pre-release
[-_\.]?
(?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
[-_\.]?
(?P<pre_n>[0-9]+)?
)?
(?P<post> # post release
(?:-(?P<post_n1>[0-9]+))
|
(?:
[-_\.]?
(?P<post_l>post|rev|r)
[-_\.]?
(?P<post_n2>[0-9]+)?
)
)?
(?P<dev> # dev release
[-_\.]?
(?P<dev_l>dev)
[-_\.]?
(?P<dev_n>[0-9]+)?
)?
)
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
"""
_regex = re.compile(
r"^\s*" + VERSION_PATTERN + r"\s*$",
re.VERBOSE | re.IGNORECASE,
)
历史¶
2014 年 8 月:本规范通过PEP 440获得批准。
2025 年 5 月:澄清开发版本在处理时是一种预发布版本。