尋找和選擇檔案 (indexPackageFinder)

pip 中的 pip._internal.index 子套件負責決定要從何處以及下載哪個檔案,以滿足專案的要求。套件的功能在很大程度上會透過套件的 PackageFinder 類別公開及協調。

概觀

下面是 pip 用於選擇要為套件下載哪個檔案的過程,以根據於需求而定

  1. 收集包含專案套件檔案的不同網路和檔案系統位置。這些位置是根據 pip 的 --index-url (預設為 https://pypi.org/simple/ ) 設定和任何設定的 --extra-index-url 位置而衍生的。各專案頁面網址都是定義於 PEP 503,亦即「簡單儲存庫 API」中的錨點連結 HTML 頁面。

  2. 對於各專案頁面網址,擷取 HTML 並解析錨點連結,從每一個連結建立 Link 物件。LinkCollector 類別負責前述步驟和透過網路擷取 HTML。

  3. 使用 LinkEvaluator 類別,判斷哪些連結最相關。為這些相關連結建立 InstallationCandidate 物件 (又稱為安裝候選)。

  4. 進一步過濾 InstallationCandidate 物件集合 (使用 CandidateEvaluator 類別),至「適用的」候選集合。

  5. 如果存在適用的候選,透過排序來選擇最佳候選 (再次使用 CandidateEvaluator 類別)。

本節的其餘部分,依下列順序記載 index 套件中部分類別的文件

PackageFinder 類別

PackageFinder 類別是 pip 中的程式碼與 index 套件進行互動的主要方式。它是一個傘狀類別,會封裝並組合各種套件尋找功能。

PackageFinder 類別負責搜尋網路和檔案系統中 pip 可以安裝的套件版本,並會根據使用者的偏好、目標 Python 環境等等來決定哪一個版本是最優先選擇。

使用 PackageFinder 類別的 pip 指令包括

需要使用 PackageFinder 類別的 pip 指令一般會在整個 pip 呼叫中僅實例化 PackageFinder 一次。事實上,pip 會在首次解析指令選項時建立這個 PackageFinder 實例。

除了 pip list,上述每個指令都實作為繼承自 RequirementCommandCommand 類別 (例如 pip download 會由 DownloadCommand 來實作),而 PackageFinder 實例是透過呼叫 RequirementCommand 類別的 _build_package_finder() 方法所建立。另一方面,pip list 則會透過呼叫 ListCommand 類別的 _build_package_finder() 方法來建立其 PackageFinder 實例。(這樣的差異性可能只是源於歷史,實際上並非必要!)

這些命令中的每一個也使用 PackageFinder 類別來進行 pip 的「自我檢查」(也就是說,檢查是否可以使用 pip 升級)。在此範例中, PackageFinder 執行個體是由 self_outdated_check.py 這個模組的 pip_self_version_check() 函數所建立的。

PackageFinder 這個類別負責執行 Overview 區段中所列出的所有事項,例如擷取並分析 PEP 503 簡單儲存庫 HTML 頁面、評估在簡單儲存庫頁面中哪些連結與個別需求相關,並且進一步篩選並根據偏好來排序來自相關連結的安裝候選對象。

PackageFinder 的其中一個主要頂層方法是 find_best_candidate()。此方法會執行以下兩件事

  1. 呼叫它的 find_all_candidates() 方法,這會透過讀取並分析由使用者所提供的索引 URL 和位置(LinkCollector 類別的 collect_sources() 方法),來收集所有可能的套件連結,建構一個 LinkEvaluator 物件來過濾掉其中一些連結,然後傳回一個 InstallationCandidates(亦即安裝候選對象)清單。這對應到上面 Overview 中的步驟 1-3。

  2. 建構一個 CandidateEvaluator 物件,並使用它來決定最佳候選對象。它會在 find_all_candidates() 的傳回值上呼叫 CandidateEvaluator 類別的 compute_best_candidate() 方法來執行這項工作。這對應到 Overview 中的步驟 4-5。

PackageFinder 也有一個 process_project_url() 方法(由 find_best_candidate() 呼叫)用來處理 PEP 503「簡單儲存庫」專案頁面。此方法會擷取並分析 PEP 503 專案頁面 URL 中的 HTML,取出錨定元素並建立 Link 物件,然後評估這些連結。

類別 LinkCollector

類別 LinkCollector 負責從檔案系統位置收集「連結」至套件檔案的原始清單 (表示為 Link 物件),以及 PackageFinder 應該存取的 PEP 503 專案頁面 URL。

類別 LinkCollector 會在決定要從哪個位置收集連結時納入使用者 --find-links--extra-index-url,以及相關選項。該類別的主要方法是 collect_sources() 方法。類別 PackageFinder 會在 find_all_candidates() 方法的第一個步驟中呼叫這個方法。

LinkCollector 也有 fetch_page() 方法,可用來從專案頁面網址擷取 HTML。這個方法之所以「不具智慧」在於,它不會剖析 HTML。

類別 LinkCollectorindex 子套件中唯一一個會進行網路要求,以及唯一一個會直接相依 PipSession 的類別,後者會儲存 Pip 的組態選項和要求狀態。

類別 LinkEvaluator

類別 LinkEvaluator 包含判斷連結 (例如,在簡單的存放庫頁面中) 是否符合安裝候選者的最低條件 (產生 InstallationCandidate 物件) 的商業邏輯。在做出這個判斷時,LinkEvaluator 執行個體會使用目標 Python 解譯器以及使用者喜好設定等資訊,像是是否允許或偏好二進位檔等等。

特別是,類別 LinkEvaluatorevaluate_link() 方法,其會回傳連結是否為安裝候選者的判斷結果。

PackageFinder 類別的 make_link_evaluator(),會在每個需求的基礎上建立此類別的執行個體。

CandidateEvaluator 類別

CandidateEvaluator 類別含有用於評估哪個 InstallationCandidate 物件較佳的商業邏輯。可以將其視為粒度較 LinkEvaluator 類別所執行的作業還要更細緻的判別。

具體而言,與 LinkEvaluator 個別評估每個候選個別不同的是,CandidateEvaluator 類別會在執行判別時使用 InstallationCandidate 物件的全部集合。舉例來說,預先版本是否符合選取條件,或雜湊不符的檔案是否符合條件,取決於整體集合的特性。

CandidateEvaluator 類別會使用下列資訊,例如與目標 Python 詮釋器相容的 平台標籤 清單、使用者提供的雜湊以及其他使用者偏好設定等。

具體來說,此類別有 get_applicable_candidates() 方法。此方法會認可 LinkEvaluator 類別的 evaluate_link() 方法所接受的連結所產生的 InstallationCandidate 物件,對其過濾出「適用的」候選人清單,並依偏好排序。

CandidateEvaluator 類別還有一個 sort_best_candidate() 方法,會傳回最佳(亦即偏好度最高的)候選人。

最後,此類別有一個 compute_best_candidate() 方法,會呼叫 get_applicable_candidates(),緊接著是 sort_best_candidate(),然後傳回 BestCandidateResult 物件,封裝此決策的中間及最終結果。

CandidateEvaluator 的執行個體會由 PackageFinder 類別的 make_candidate_evaluator() 方法在每個需求的基礎上建立。

The CandidatePreferences 類別

The CandidatePreferences 類別是一種簡單的容器類別,它會將 PackageFinder 用於建構 CandidateEvaluator 物件(透過 PackageFinder 類別的 make_candidate_evaluator() 方法)的一些使用者偏好組合在一起。

一個 PackageFinder 實例有一個 _candidate_prefs 屬性,其值是 CandidatePreferences 實例。由於 PackageFinder 具有許多控制行為的職責和選項,因此將與 CandidateEvaluator 相關的偏好組合在一起,可以讓維護者知道哪些屬性僅是 CandidateEvaluator 所需要的。

The BestCandidateResult 類別

The BestCandidateResult 類別是一種便利的「容器」類別,可以封裝找出符合需求的最佳候選者的結果。(「容器」意指一個僅包含資料且沒有業務邏輯或自己的狀態變更方法的物件。)它不只儲存最終結果,還儲存用於判定結果的中間值。

此類別是 CandidateEvaluator 類別的 compute_best_candidate() 方法,以及 PackageFinder 類別的 find_best_candidate() 方法的傳回類型。