PEP 440 – 版本識別與依賴規格
- 作者:
- Alyssa Coghlan <ncoghlan at gmail.com>, Donald Stufft <donald at stufft.io>
- BDFL-Delegate:
- Alyssa Coghlan <ncoghlan at gmail.com>
- 討論於:
- Distutils-SIG 郵件列表
- 狀態:
- 最終 (Final)
- 類型:
- 標準軌跡 (Standards Track)
- 主題:
- 套件封裝 (Packaging)
- 建立日期:
- 2013年3月18日
- 公告歷史:
- 2013年3月30日, 2013年5月27日, 2013年6月20日, 2013年12月21日, 2014年1月28日, 2014年8月8日, 2014年8月22日
- 取代:
- 386
- 決議:
- Distutils-SIG 訊息
摘要
本 PEP 描述了一種用於識別 Python 軟體發行版版本以及宣告特定版本依賴關係的方案。
定義
本文件中的關鍵字「MUST」(必須)、「MUST NOT」(絕不)、「REQUIRED」(強制)、「SHALL」(應)、「SHALL NOT」(不應)、「SHOULD」(建議)、「SHOULD NOT」(不建議)、「RECOMMENDED」(推薦)、「MAY」(可以)以及「OPTIONAL」(選用)應依照 RFC 2119 所述進行詮釋。
「專案」是指為整合而提供的軟體元件。專案包括 Python 函式庫、框架、指令稿、外掛程式、應用程式、資料集或其他資源,以及上述各種組合。公開的 Python 專案通常註冊於 Python 套件索引 (Python Package Index)。
「發行版 (Releases)」是指專案中被唯一識別的快照。
「發行檔案 (Distributions)」是指用於發布和分發發行版的封裝檔案。
「建置工具」是指旨在開發系統上執行,並產生原始碼和二進位發行檔案的自動化工具。建置工具也可能由整合工具呼叫,以建置以原始碼發行檔案 (sdist) 而非預先建置的二進位封存檔形式散布的軟體。
「索引伺服器」是指發布版本和依賴關係元資料,並對允許的元資料施加限制的活動分發註冊中心。
「發布工具」是指旨在開發系統上執行,並將原始碼和二進位發行檔案上傳到索引伺服器的自動化工具。
「安裝工具」是指專門設計在部署目標上執行,從索引伺服器或其他指定位置消費原始碼和二進位發行檔案,並將其部署到目標系統的整合工具。
「自動化工具」是一個集體術語,涵蓋建置工具、索引伺服器、發布工具、整合工具以及任何其他產生或消費發行版版本和依賴關係元資料的軟體。
版本方案
發行檔案由一個支援所有已定義版本比較運算的公開版本識別碼來標識。
版本方案既用於描述特定發行檔案所提供的發行版版本,也用於對建置或執行軟體所需的依賴關係版本施加限制。
公開版本識別碼
規範的公開版本識別碼必須符合以下方案:
[N!]N(.N)*[{a|b|rc}N][.postN][.devN]
公開版本識別碼不得包含前導或尾隨空白字元。
公開版本識別碼在給定的發行檔案內必須是唯一的。
安裝工具應忽略任何不符合此方案的公開版本,但必須包含以下指定的正規化處理。當偵測到不符合規範或歧義的版本時,安裝工具可以警告使用者。
另請參閱 附錄 B:使用正規表示式解析版本字串,該附錄提供了用於檢查是否嚴格符合規範格式的正規表示式,以及一個更寬鬆的、接受可能需要後續正規化輸入的正規表示式。
公開版本識別碼分為最多五個部分:
- 紀元部分 (Epoch segment):
N! - 發行版部分 (Release segment):
N(.N)* - 預發布版本部分 (Pre-release segment):
{a|b|rc}N - 後發布版本部分 (Post-release segment):
.postN - 開發版本部分 (Development release segment):
.devN
任何給定的發行版都將是下列章節中所定義的「最終版本」、「預發布版本」、「後發布版本」或「開發版本」。
所有數值元件必須是非負整數,以 ASCII 數字序列表示。
所有數值元件必須根據其數值而非文字字串進行解釋和排序。
所有數值元件可以為零。除了下述的發行版部分外,數值為零的元件除始終為版本排序中可能的最低值外,沒有特殊含義。
附註
此方案允許一些難以閱讀的版本識別碼,以便更好地適應現有公開和私有 Python 專案中廣泛存在的版本控制做法。
因此,對於新專案,強烈建議不要使用本 PEP 技術上允許的某些版本控制做法。若屬此類情況,相關細節將在後續章節中說明。
本地版本識別碼
本地版本識別碼必須符合以下方案:
<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、release candidate」預發布週期,以支援使用者在最終版本發布前進行測試。
若作為專案開發週期的一部分使用,這些預發布版本透過在版本識別碼中包含預發布版本部分來標示。
X.YaN # Alpha release
X.YbN # Beta release
X.YrcN # Release Candidate
X.Y # Final release
僅由發行版部分和預發布版本部分組成的版本識別碼被稱為「預發布版本」。
預發布版本部分由預發布階段的字母識別碼以及一個非負整數值組成。給定發行版的預發布版本首先按階段(alpha、beta、release candidate)排序,然後按該階段內的數值元件排序。
安裝工具可以接受同一個發行版部分的 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
附註
雖然它們對於持續整合目的很有用,但強烈建議不要向通用公開索引伺服器發布預發布版本的開發版本,因為這會使人類讀者難以解析版本識別碼。如果需要發布此類版本,建議透過遞增數值元件來建立新的預發布版本,這樣會清楚得多。
後發布版本的開發版本同樣受到強烈反對,但對於使用後發布註記來表示可能包含程式碼更改的完整維護版本的專案來說,這可能是合適的。
版本紀元 (Epochs)
若包含在版本識別碼中,紀元出現在所有其他組件之前,並以驚嘆號與發行版部分分隔。
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 和 release candidate 預發布版本的「主版本.次版本」版本控制
0.9
1.0a1
1.0a2
1.0b1
1.0rc1
1.0
1.1a1
...
帶有開發版本、release candidate 和用於修正微小錯誤的後發布版本的「主版本.次版本」版本控制
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 的方式排序。工具可以將在同一個發行版部分中同時存在 c 和 rc 的情況視為歧義而拒絕,並仍符合 PEP 規範。
在 alpha (1.0a1)、beta (1.0b1) 或 release candidate (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 必須用於所有元資料版本,並取代 PEP 386,即使對於元資料 v1.2 也是如此。工具應忽略任何無法被本 PEP 規則解析的版本,但若無符合本 PEP 的版本可用,可以回退到由實作定義的版本解析和排序方案。
發行版使用者可能希望從他們控制的任何私有套件索引中明確移除不符合規範的版本。
與其他版本方案的相容性
有些專案可能選擇使用需要轉換才能符合本 PEP 定義的公開版本方案的版本方案。在此類情況下,專案特定的版本可以儲存在元資料中,而轉換後的公開版本則發布在版本欄位中。
這允許自動化分發工具提供一致且正確的已發布發行版本排序,同時仍然允許開發人員在其專案中使用他們偏好的內部版本控制方案。
語意化版本控制 (Semantic versioning)
語意化版本控制 (Semantic versioning) 是一種流行的版本識別方案,相較於本 PEP,它對發行版本號不同元素的意義有更具規範性的規定。即使專案選擇不遵守語意化版本控制的細節,理解該方案也很有價值,因為它涵蓋了依賴其他發行版,以及發布他人所依賴的發行版時可能出現的許多問題。
語意化版本控制的「主版本.次版本.修補版本」(本 PEP 中描述為「主版本.次版本.微版本」)面向(2.0.0 規格中的條款 1-8)與本 PEP 中定義的版本方案完全相容,並鼓勵遵守這些面向。
包含連字號(預發布版本 - 條款 10)或加號(建置 - 條款 11)的語意版本與本 PEP 不相容,且不允許在公開版本欄位中使用。
將此類基於語意版本控制的來源標籤轉換為相容公開版本的一種可能機制是使用 .devN 後綴來指定適當的版本順序。
具體的建置資訊也可以包含在本地版本標籤中。
基於 DVCS 的版本標籤
許多建置工具與 Git 和 Mercurial 等分散式版本控制系統整合,以便將識別雜湊加入版本識別碼。由於雜湊無法可靠地排序,因此版本識別碼中不允許出現此類版本。
與語意化版本控制一樣,公開的 .devN 後綴可用於唯一識別此類用於發布的版本,而原始的基於 DVCS 的標籤可以儲存在專案元資料中。
識別雜湊資訊也可以包含在本地版本標籤中。
Olson 資料庫版本控制
pytz 專案繼承了其對應的 Olson 時區資料庫版本控制方案:年份後接一個表示該年度資料庫版本的小寫字元。
這可以轉換為相容的公開版本識別碼 <年份>.<序號>,其中序號從 0 或 1 開始(對於 '<年份>a' 發布),並在該年度內每次後續資料庫更新時遞增。
與其他轉換後的版本識別碼一樣,相應的 Olson 資料庫版本可以記錄在專案元資料中。
版本指定符 (Version specifiers)
版本指定符由一系列以逗號分隔的版本條款組成。例如:
~= 0.9, >= 1.0, != 1.3.4.*, < 2.0
比較運算子決定了版本條款的類型:
逗號(「,」)等同於邏輯 **AND** 運算子:候選版本必須匹配所有給定的版本條款,才能使版本指定符整體匹配。
條件運算子與隨後版本識別碼之間的空白字元是可選的,逗號周圍的空白字元也是如此。
當多個候選版本匹配版本指定符時,建議的首選版本應為根據標準 版本方案 定義的一致排序所確定的最新版本。預發布版本是否被視為候選版本應依據 預發布版本的處理 中所述的方式進行處理。
除以下特別註明外,版本指定符中不得包含本地版本識別碼,且在檢查候選版本是否匹配給定版本指定符時,必須完全忽略本地版本標籤。
相容版本 (Compatible release)
相容版本條款由相容版本運算子 ~= 和版本識別碼組成。它匹配任何預期與指定版本相容的候選版本。
指定的版本識別碼必須採用 版本方案 中描述的標準格式。此版本指定符中不允許使用本地版本識別碼。
對於給定的發行版識別碼 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 或類似用法來達成。
與版本匹配一樣,發行版部分在必要時進行零填充,以確保發行版部分在相同的長度下進行比較。
此版本指定符中不允許使用本地版本識別碼。
任意相等性
任意相等性比較是簡單的字串相等運算,不考慮任何語意資訊,例如零填充或本地版本。此運算子也不支援 == 運算子所支援的前綴匹配。
任意相等性的主要使用場景是允許指定一個無法以其他方式由本 PEP 表示的版本。此運算子很特殊,作為一個緊急出口,允許使用實作本 PEP 工具的使用者仍能安裝與本 PEP 不相容的遺留版本。
一個範例是 ===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 或更新版本。
直接參照 (Direct references)
有些自動化工具可能允許使用直接參照作為正常版本指定符的替代方案。直接參照由指定符 @ 和一個明確的 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 [4]。
更新版本控制規格
版本控制規格可以在不需要新 PEP 或更改元資料版本的情況下進行澄清更新。
任何影響版本識別和比較語法與語意的技術變更,都需要在新的 PEP 中定義更新後的版本控制方案。
與 pkg_resources.parse_version 的差異總結
- 注意:此比較是針對該 PEP 撰寫時的
pkg_resourses.parse_version。在 PEP 被採納後,setuptools 6.0 及更高版本採用了本 PEP 中描述的行為。 - 本地版本的排序方式不同,本 PEP 要求它們在排序時大於沒有本地版本的相同版本,而
pkg_resources.parse_version將其視為預發布版本標記。 - 本 PEP 有意限制了構成有效版本的語法,而
pkg_resources.parse_version試圖從任何任意字串中提供一些含義。 pkg_resources.parse_version允許任意深層巢狀的版本識別符,如1.0.dev1.post1.dev5。然而,本 PEP 僅允許每種類型使用一次,且它們必須以特定的順序存在。
與 PEP 386 的差異總結
- 將版本指定符的描述移入版本控制 PEP
- 加入「直接參照」概念作為直接參照資源的標準標記法(而不是讓每個工具都需要發明自己的參照方式)
- 加入「本地版本識別碼」和「本地版本標籤」概念,允許系統整合商以受到上游工具支援的方式指示已修補的建置,並允許將建置標籤納入二進位發行版的版本控制中。
- 加入「相容版本」條款
- 為基於前綴的版本匹配和排除加入尾隨萬用字元語法
- 更改了
.devN後綴的頂層排序位置 - 允許單數值版本號
- 明確排除前導或尾隨空白字元
- 明確支援基於日期的版本
- 明確的正規化規則以提高與 PyPI 上現有版本元資料的相容性(在不引入歧義的情況下)
- 隱含排除預發布版本,除非它們已經存在或需要滿足依賴關係
- 將後發布版本視同無條件發行版本
- 討論跨元資料版本的排序和依賴關係
- 從偏好
c轉向偏好rc。
主要變更的理由在以下章節中給出。
更改版本方案
本 PEP 中版本方案相較於 PEP 386 的一項關鍵變更是將頂層開發版本(如 X.Y.devN)排在 alpha 發布版本(如 X.Ya1)之前。這是一個更合乎邏輯的排序順序,因為已經同時使用開發版本和 alpha/beta/release candidate 的專案,不希望它們的開發版本被排在 release candidate 和最終版本之間。在該位置使用 dev 版本,而不是僅僅建立額外的 release candidate,沒有任何理由。
更新後的排序順序也意味著 dev 版本的排序現在在元資料標準和 pkg_resources 的既有行為(以及當前安裝工具的行為)之間保持一致。
進行此更改應使受影響的現有專案更容易遷移到最新版本的元資料標準。
版本方案的另一個變更允許單一數字版本,類似於 Mozilla Firefox、Google Chrome 和 Fedora Linux 發行版等非 Python 專案使用的版本。這實際上被預期對版本指定符更有用,但允許其同時用於版本指定符和發行版本號要比分開定義兩者更簡單。
在 PyPI 上發現幾個僅因尾隨 \n 字元而不同的版本識別碼的專案後,對前導和尾隨空白字元的排除被明確化。
如下方關於版本正規化的獨立章節所述,還加入了各種其他正規化規則。
附錄 A 展示了 2014 年 8 月 8 日收集的 PyPI 發行版版本資訊分析的詳細結果。此分析比較了本 PEP 定義的明確排序版本方案與 setuptools 行為所定義的事實標準之間的行為。這些指標很有用,因為本 PEP 的意圖是在盡可能貼近現有 setuptools 行為的同時,仍為不可排序的版本拋出異常(而不是像 setuptools 那樣試圖猜測適當的順序)。
對版本控制方案更具觀點的描述
正如 PEP 386 中一樣,主要重點是將現有實務編纂成文,使其更適合自動化,而不是要求現有專案對其工作流程進行非必要的更改。然而,標準方案允許的靈活性遠超過絕大多數簡單 Python 套件所需(通常它們甚至不需要維護版本 - 許多使用者樂於需要升級到新的功能發布版本來獲得錯誤修正)。
為了新手開發人員的利益,以及為了希望更好地理解各種使用場景的經驗豐富的開發人員,該規範現在更詳細地介紹了定義版本方案的組件,包括每個組件如何在實務中使用的範例。
該 PEP 還明確引導開發人員朝向語意化版本控制(不強制要求),並勸阻使用完整版本控制方案中的某些面向,這些面向在很大程度上被納入是為了涵蓋現有專案做法和 Linux 發行版軟體重新封裝中的深奧邊角情況。
在版本控制方案旁描述版本指定符
首先擁有標準化版本方案的主要原因,是為了使其更容易進行可靠的自動化依賴關係分析。在定義版本識別碼的同時描述其主要使用場景更有意義。
更改版本指定符的解釋
先前對版本指定符的解釋使得意外下載依賴關係的預發布版本變得非常容易。這反過來使得開發人員難以向 Python 套件索引發布軟體的預發布版本,因為即使將套件標記為隱藏,也不足以阻止自動化工具下載它,也使得使用者更難透過主要的 PyPI Web 介面手動取得測試發布版本。
先前的解釋還因為沒有充分證明的理由而將後發布版本從一些版本指定符中排除。
更新後的解釋旨在使意外接受預發布版本作為滿足依賴關係變得困難,同時在預發布版本是滿足依賴關係的唯一方式時,仍然允許自動檢索。
「假設有一定的前向相容性」版本約束源自 Ruby 社群的「悲觀版本約束」運算子 [2],旨在允許專案對前向相容性承諾採取謹慎態度,同時仍然可以輕鬆地為其依賴關係設定最低要求版本。相容版本條款的拼寫(~=)受到 Ruby (~>) 和 PHP (~) 等價物的啟發。
還計劃對處理同一函式庫多個版本的並行安裝進行進一步改進,但這將取決於對安裝資料庫定義的更新,以及用於動態路徑操作的改進工具。
加入了請求基於前綴的版本匹配的尾隨萬用字元語法,以使定義相容版本條款變得可行。
支援基於日期的版本識別碼
排除基於日期的版本在將 pytz 遷移到新元資料標準時造成了重大問題。這也引起了 OpenStack 開發人員的擔憂,因為他們使用基於日期的版本控制方案,並希望在不更改方案的情況下遷移到新元資料標準。
加入版本紀元
加入版本紀元的原因與它們成為其他版本控制方案(如 Fedora 和 Debian Linux 發行版)一部分的原因相同:允許專案優雅地更改其發布編號方法,而不必讓新發布版本看起來比以前的版本號更低,也不必更改專案名稱。
特別是,支援版本紀元允許先前使用基於日期的版本控制的專案,透過指定新的版本紀元來切換到語意化版本控制。
選擇 ! 字元來分隔紀元版本,而不是其他系統中常用的 : 字元,是因為 : 在 Windows 目錄名稱中不是有效字元。
加入直接參照
加入直接參照作為處理無法整齊對應到標準分發模型的混亂現實情況的「逃生條款」。這包括內部使用未發布軟體的依賴關係,以及在將第三方函式庫包裝為 C 擴充時可能出現的更複雜相容性問題的處理(科學界對此尤為關注)。
索引伺服器被特意賦予了很大的自由度來拒絕直接參考,因為它們主要是作為整合者的工具,而非發布者的工具。特別是 PyPI 目前正致力於「消除」對外部參考的依賴,因為不可靠的外部服務會拖慢安裝操作,並降低 PyPI 自身的可靠性。
加入任意相等性
引入「任意相等性」(Arbitrary equality)作為一個「脫身條款」,旨在處理有人需要安裝使用不相容版本專案的情況。雖然本 PEP 能夠達到與 PyPI 上現有版本約 97% 的相容性,但仍有約 3% 的版本無法被解析。此運算子提供了一種簡單且有效的方法來依賴這些版本,而無需對其語義進行「猜測」(如果支援除嚴格字串相等以外的任何方式,則必須進行此類猜測)。
加入本地版本識別碼
下游整合者經常需要將上游的錯誤修復向後移植(backport)到舊版本,這是一個客觀事實。這是 Linux 發行版廠商獲取報酬的服務項目之一,應用程式開發者也可能會對捆綁的依賴項應用他們所需的修補程式。
從歷史上看,這種做法對跨平台的語言特定發布工具來說是不可見的——上游元數據(metadata)中報告的「版本」與未經修改的程式碼相同。當嘗試同時處理整合者提供的程式碼和未經修改的上游程式碼,或者僅僅是嘗試精確識別安裝了哪個版本的軟體時,這種不精確性可能會導致問題。
在版本編號方案中引入「本地版本識別碼」和「本地版本標籤」,並配合對應的 python.integrator 元數據擴充,使得這類操作可以被精確地呈現,這應該能改善上游工具與各種整合平台之間的互通性。
所選擇的確切方案主要參考了 pkg_resources.parse_version 和 pkg_resources.parse_requirements 的現有行為,主要區別在於:pkg_resources 目前在比較版本以進行精確匹配時總是會考慮後綴,而本 PEP 要求當版本指定子(version specifier)條款中不存在本地版本標籤時,應忽略候選版本的本地版本標籤。此外,本 PEP 不嘗試對本地版本標籤施加任何結構(除了限制允許的字元集並定義其排序順序外)。
此更改旨在確保整合者提供的版本(如 pip 1.5+1 或 pip 1.5+1.git.abc123de)仍然能夠滿足像 pip>=1.5 這樣的版本指定子。
選擇加號(+)主要是為了提高本地版本識別碼的可讀性。之所以選擇它而非連字號(-),是為了防止 pkg_resources.parse_version 將其解析為預發布版本,這對於成功遷移到新的、結構更完善的版本編號方案非常重要。選擇加號而非波浪號(~),則是因為波浪號在 Debian 的版本排序演算法中具有特殊意義。
提供明確的版本正規化規則
從歷史上看,Python 中解析版本的事實標準一直是 setuptools 專案中的 pkg_resources.parse_version 指令。它不會嘗試拒絕「任何」版本,而是試圖從給定的內容中解析出一些有意義的東西,儘管成功程度各異。它有一些簡單的規則,但除此之外,它或多或少主要依賴於字串比較。
本 PEP 提供的正規化規則主要是為了增加與 pkg_resources.parse_version 的相容性,特別是在已記錄的用例(如 rev、r、pre 等)中,或者對 PyPI 上已經存在的版本進行更合理的處理。
所有可能的正規化規則都經過權衡,以判斷它們是否「可能」導致任何歧義(例如,雖然有人可能會設計一套方案,將 v1.0 和 1.0 視為不同的發布版本,但有人真的這樣做的可能性,更不用說達到顯著規模的可能性,是相當低的)。它們也經過了權衡,考量 pkg_resources.parse_version 如何處理特定版本字串,特別是在排序方面。最後,每條規則都根據它所允許的額外版本類型、這些版本看起來有多「醜」、解析難度(無論是心智上還是機械上)以及它帶來的額外相容性進行了權衡。
正規化的範圍被限制在可以輕易作為版本解析過程的一部分來實作的內容,而非應用於版本的預解析轉換。這樣做是為了限制每次轉換的副作用,因為簡單的搜尋與取代風格的轉換會增加產生歧義或「垃圾」版本的可能性。
在正規化中允許底線
PyPI 上使用 _ 字串作為版本的專案並不多。然而,本 PEP 允許在任何可以使用 - 的地方使用它。原因是 Wheel 正規化方案指定將 - 正規化為 _,以利於檔名的解析。
PEP 440 的變更總結
根據最初的參考實作在 setuptools 8.0 和 pip 6.0 中發布後收到的回饋,本 PEP 進行了以下更改:
- 排除性有序比較(Exclusive ordered comparisons)已更新,不再隱含
!=V.*,因為這被認為是令人驚訝且極難精確描述的行為。相反地,排除性有序比較將僅僅禁止匹配指定版本的預發布、後發布和本地版本(除非指定版本本身就是預發布、後發布或本地版本)。如需詳盡討論,請參見 distutils-sig 上的執行緒 [6] [7]。 - 發布候選版本(release candidates)的正規化形式已從 ‘c’ 更新為 ‘rc’。此更改是基於當 setuptools 8.0 開始對準備發布到 PyPI 的軟體包元數據進行正規化處理時所收到的使用者回饋 [8]。
- PEP 內文和
is_canonical正規表示式已更新,明確指出數值組件必須由 ASCII 數字序列表示,而非任意 Unicode [Nd] 碼位。這在附錄 B 的版本解析正規表示式中先前是隱含的,但未明確說明 [10]。
參考文獻
最初嘗試制定的標準化版本方案,以及對需要此類標準的理由,可以在 PEP 386 中找到。
附錄 A
Metadata v2.0 指南與 setuptools 的對比
$ invoke check.pep440
Total Version Compatibility: 245806/250521 (98.12%)
Total Sorting Compatibility (Unfiltered): 45441/47114 (96.45%)
Total Sorting Compatibility (Filtered): 47057/47114 (99.88%)
Projects with No Compatible Versions: 498/47114 (1.06%)
Projects with Differing Latest Version: 688/47114 (1.46%)
附錄 B:使用正規表示式解析版本字串
正如先前在 Public version identifiers(公開版本識別碼)一節中所述,已發布的版本識別碼「應當」(SHOULD)使用規範格式。本節提供了可用於測試版本是否已為該形式的正規表示式,如果不是,則提取各個組件以進行後續的正規化。
要測試版本識別碼是否為規範格式,您可以使用以下函式:
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>alpha|a|beta|b|preview|pre|c|rc)
[-_\.]?
(?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,
)
版權
此文件已歸入公有領域 (public domain)。
來源:https://github.com/python/peps/blob/main/peps/pep-0440.rst