注意

此部分文档目前正在编写中。pip 开发人员欢迎您帮助完成此文档。如果您有兴趣帮忙,请在 跟踪问题 中告诉我们。

概述功能

pip 是一个包安装器。

pip 不仅仅是安装工具,它还有缓存、配置和命令行界面,这些界面本身也有一些特性。但主要来说

pip 所做的事情

  1. 管理包的构建 (将包构建卸载到后端),当需要时 (源代码分发包 - 如果包是 wheel,则不需要此操作)。
    1. 默认情况下,出于向后兼容性原因,pip 将包构建委托给 setuptools。但 setuptools 的问题在于:它有一个 setup.py 文件,它会调用该文件以 …… 获取信息?
  2. 决定将东西安装在哪里。一旦包构建完成,生成的工件就会被安装到系统中,放置在适当的位置。 PEP 517 定义了构建后端和安装器之间的接口。

流程概述

按照顺序,pip 做了什么?

  1. 获取用户输入 (用户提供的字符串,说明他们想要安装哪个包)

  2. 弄清楚这意味着什么:用户准确请求了什么 - 将其转换为 pip 可以操作的东西 (用户输入到需求)

  3. 整个过程的核心?一旦从步骤 2 获取了一组需求,您必须将其扩展为具体的“要安装的东西” - 根据用户给出的需求,弄清楚要安装哪些其他需求,以及从哪里获取它们。

    1. 此步骤很复杂 - 也是探索性的,涉及依赖关系

      解析 - 我们需要访问索引,查看哪些版本可用

    2. 有时您需要构建包本身才能获取

      依赖关系信息,这意味着从包索引中获取包,这意味着需要知道它是否存在。对于单个包,

  4. 安装要安装的实际项目。

为什么?pip 从 PyPI 以外的地方安装!但同样,我们以前从未对 PyPI 的 JSON API 进行过保证,因此没有人从 PyPI 获取元数据,而与下载包本身分开。

从安装过程的流程角度来看

  1. 对于 1 个包:获取该包的抽象需求,并尝试查看这意味着什么 (此抽象需求可以采用多种形式)。定义抽象依赖关系。

  2. 一旦我们有一组“此包,从这里获取,这是该包的该版本”,

  3. 修改环境以安装这些东西 (这意味着:将文件放在正确的位置)。例如:如果您已经拥有版本 6.0 的需求,而您正在安装 7.2,则卸载 6.0 并安装 7.2。

下载过程

安装中会发生什么?嗯,install 的一个子集,pip 通常在 pip install 期间执行的操作是 download (也作为 pip download 命令提供给用户)。我们下载并检查包以获取清单。对于任何给定的包名称,我们需要知道哪些文件可用以及它们的文件名是什么。

pip 可以从 Python 包库中下载,包在库中以结构化格式存储,这样像 pip 这样的安装器就可以找到它们。

PEP 503 定义了我们与 Python 包库通信时使用的 API。

PyPI

如果我们运行 pip download somepackage 而不带其他参数会发生什么?默认情况下,我们查看 PyPI,这是 pip 知道在哪里寻找更多信息的地方,以了解包索引关于 somepackage 的信息。

pip 然后知道:哪些文件可用,以及它们的文件名是什么。

换句话说

在所有依赖关系都未解决之前,请执行以下操作

  1. 按照 PEP 503 中定义的 API,从 http://{pypi_index}/simple/{package_name}

  2. 解析页面中的所有文件链接。

  3. 从链接列表中选择一个要下载的文件。

  4. 从下载的包中提取元数据。

  5. 根据元数据更新依赖关系树。

包索引通过 (现有的 PyPI API) 为 pip 提供了该包的文件列表。这些文件包含版本和其他一些信息,可以帮助 pip 决定是否应该下载这些文件。

pip 从列表中选择一个文件下载。

它可能会返回并选择另一个文件下载。

当 pip 查看包索引时,它查看的地方基本上有一个链接。链接的文本是文件名。

这是 PyPI Simple API (PyPI 拥有多个 API,一些 API 正在被弃用)。pip 查看 Simple API,最初在 PEP 503 中进行了记录 - packaging.python.org 拥有 PyPA 规范,其中包含有关 Simple Repository API 的更多详细信息。

对于这个包名称 - 这是可用文件的列表。

在那里寻找

  • 文件名列表

  • 其他信息

一旦有了这些,它就会选择一个文件并下载。

(问题:如果我想要 pip install flask,我认为整个文件名列表不能……不应该……?我只要 Flask……为什么我会得到整个列表?

答案:它不是每个文件,只是 Flask 的文件。没有 API 用于获取 PyPI 上的所有文件。它是用于获取所有 Flask 文件的。)