查找和选择文件 (index
和 PackageFinder
)¶
pip 中的 pip._internal.index
子包负责根据项目的要求来决定要下载哪个文件以及从哪里下载。该包的功能主要通过该包的 PackageFinder
类来公开和协调。
概述¶
以下是对 pip 使用什么过程来选择要为包下载的特定文件(根据给定需求)的粗略描述
收集包含项目包文件的各种网络和文件系统位置。例如,这些位置来自 pip 的 --index-url(默认值为 https://pypi.ac.cn/simple/)设置和任何配置的 --extra-index-url 位置。每个项目页面 URL 都是一个 HTML 页面,其中包含锚链接,如 PEP 503(“简单存储库 API”)中所定义。
对于每个项目页面 URL,获取 HTML 并解析出锚链接,从每个锚链接创建
Link
对象。 LinkCollector 类负责以上步骤以及通过网络获取 HTML。使用 LinkEvaluator 类,确定哪些链接是最相关的。为每个相关链接创建
InstallationCandidate
对象(也称为安装候选对象)。进一步过滤
InstallationCandidate
对象的集合(使用 CandidateEvaluator 类)来获得“适用”的候选对象集合。如果有适用候选对象,则通过排序来选择最佳候选对象(再次使用 CandidateEvaluator 类)。
本节的剩余部分将通过记录 index
包中的一些类来进行组织,按照以下顺序
PackageFinder
类¶
PackageFinder
类是 pip 中的代码与 index
包交互的主要方式。它是一个总括类,封装并组合了各种包查找功能。
PackageFinder
类负责搜索网络和文件系统,以查找 pip 可以安装的包的哪些版本,还负责根据用户的偏好、目标 Python 环境等来决定哪个版本是最优的。
使用 PackageFinder
类的 pip 命令是
需要使用 PackageFinder
类的 pip 命令通常只在整个 pip 调用期间实例化一次 PackageFinder
。实际上,pip 在第一次解析命令选项时创建了此 PackageFinder
实例。
除了 pip list 之外,上述每个命令都实现为从 RequirementCommand
继承的 Command
类(例如 pip download 由 DownloadCommand
实现),并通过调用 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()
。此方法执行以下两个操作
调用其
find_all_candidates()
方法,该方法通过读取和解析用户提供的索引 URL 和位置(LinkCollector 类的collect_sources()
方法)来收集所有可能的包链接,构建一个 LinkEvaluator 对象来过滤掉其中一些链接,然后返回一个InstallationCandidates
列表(也称为安装候选对象)。这对应于上述 概述 的步骤 1-3。构建一个
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()
方法的返回类型。