查找和选择文件 (indexPackageFinder)

pip 中的 pip._internal.index 子包负责根据项目的要求来决定要下载哪个文件以及从哪里下载。该包的功能主要通过该包的 PackageFinder 类来公开和协调。

概述

以下是对 pip 使用什么过程来选择要为包下载的特定文件(根据给定需求)的粗略描述

  1. 收集包含项目包文件的各种网络和文件系统位置。例如,这些位置来自 pip 的 --index-url(默认值为 https://pypi.ac.cn/simple/)设置和任何配置的 --extra-index-url 位置。每个项目页面 URL 都是一个 HTML 页面,其中包含锚链接,如 PEP 503(“简单存储库 API”)中所定义。

  2. 对于每个项目页面 URL,获取 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 之外,上述每个命令都实现为从 RequirementCommand 继承的 Command 类(例如 pip downloadDownloadCommand 实现),并通过调用 RequirementCommand 类的 _build_package_finder() 方法创建 PackageFinder 实例。另一方面,pip list 通过调用 ListCommand 类的 _build_package_finder() 来构建其 PackageFinder 实例。(这种差异可能仅仅是历史性的,实际上可能不是必需的。)

这些命令中的每一个还使用 PackageFinder 类进行 pip 的“自检”(即检查是否有可用的 pip 升级)。在这种情况下,PackageFinder 实例由 self_outdated_check.py 模块的 pip_self_version_check() 函数创建。

PackageFinder 类负责执行 概述 部分中列出的所有操作,例如获取和解析 PEP 503 简单存储库 HTML 页面,评估简单存储库页面中哪些链接与每个需求相关,以及进一步过滤和按优先级排序来自相关链接的安装候选对象。

PackageFinder 的主要顶层方法之一是 find_best_candidate()。此方法执行以下两个操作

  1. 调用其 find_all_candidates() 方法,该方法通过读取和解析用户提供的索引 URL 和位置(LinkCollector 类的 collect_sources() 方法)来收集所有可能的包链接,构建一个 LinkEvaluator 对象来过滤掉其中一些链接,然后返回一个 InstallationCandidates 列表(也称为安装候选对象)。这对应于上述 概述 的步骤 1-3。

  2. 构建一个 CandidateEvaluator 对象,并使用它来确定最佳候选对象。它通过对 find_all_candidates() 的返回值调用 CandidateEvaluator 类的 compute_best_candidate() 方法来实现这一点。这对应于概述的步骤 4-5。

PackageFinder 还有一个 process_project_url() 方法(由 find_best_candidate() 调用)来处理 PEP 503 “简单存储库”项目页面。此方法从 PEP 503 项目页面 URL 获取并解析 HTML,提取锚元素并从它们创建 Link 对象,然后评估这些链接。

LinkCollector

LinkCollector 类负责从文件系统位置收集“链接”到包文件的原始列表(表示为 Link 对象),以及 PEP 503 项目页面 URL,PackageFinder 应该访问这些 URL。

The LinkCollector 类在决定从哪些位置收集链接时,会考虑用户的 --find-links--extra-index-url 和相关选项。该类主要方法是 collect_sources() 方法。 PackageFinder 类在 find_all_candidates() 方法的第一步调用此方法。

LinkCollector 还有一个 fetch_page() 方法,用于从项目页面 URL 获取 HTML。此方法是“不智能的”,因为它不解析 HTML。

The LinkCollector 类是 index 子包中唯一进行网络请求的类,也是子包中唯一直接依赖于 PipSession 的类,它存储 pip 的配置选项和用于发出请求的状态。

The LinkEvaluator

The LinkEvaluator 类包含用于确定链接(例如,在简单存储库页面中)是否满足成为安装候选者的最低条件(生成 InstallationCandidate 对象)的业务逻辑。在进行此确定时,LinkEvaluator 实例使用目标 Python 解释器等信息以及用户偏好,例如是否允许或首选二进制文件等。

具体而言,LinkEvaluator 类有一个 evaluate_link() 方法,它返回链接是否为安装候选者。

此类的实例由 PackageFinder 类的 make_link_evaluator() 在每个需求的基础上创建。

The CandidateEvaluator

The CandidateEvaluator 类包含用于评估哪些 InstallationCandidate 对象应该优先的业务逻辑。这可以看作是比 LinkEvaluator 类执行的更细粒度的确定。

特别是,CandidateEvaluator 类在进行确定时会使用 InstallationCandidate 对象的整个集合,而不是像 LinkEvaluator 一样单独评估每个候选者。例如,预发布是否符合选择资格或哈希不匹配的文件是否符合资格取决于集合的整体属性。

The CandidateEvaluator 类使用目标 Python 解释器兼容的 平台标签 列表、用户提供的哈希和其他用户偏好等信息。

具体而言,该类有一个 get_applicable_candidates() 方法。它接受 LinkEvaluator 类的 evaluate_link() 方法接受的链接所生成的 InstallationCandidate 对象,将它们筛选为一个“适用”候选者的列表,并按偏好排序。

The CandidateEvaluator 类还有一个 sort_best_candidate() 方法,它返回最佳(即最优选)候选者。

最后,该类有一个 compute_best_candidate() 方法,它调用 get_applicable_candidates(),然后调用 sort_best_candidate(),然后返回一个 BestCandidateResult 对象,封装了决策的中间结果和最终结果。

The 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() 方法的返回类型。