为什么不能在代码中使用 pip

pip 是命令行程序。尽管它是用 Python 实现的,并且可以通过 import pip 在 Python 代码中使用,但您不得以这种方式使用 pip 的内部 API。有许多的原因:

  1. pip 代码假定该代码完全由程序的全局状态控制。 pip 管理诸如日志系统配置或标准IO流的值之类的事情,无需考虑用户代码可能受到影响的可能性。
  2. pip 的代码不是线程安全的。如果您要在线程中运行 pip,则无法保证您的代码或 pip 都能按预期运行。
  3. pip 一旦完成工作,将会退出。此后,无需处理其他代码将继续运行的过程,因此在同一过程中两次调用 pip 可能会出现问题。

这并不意味着 pip 开发人员原则上反对将 pip 用作库的想法:『只是这不是它的编写方式,作为一个库,重新设计内部结构以进行使用将需要大量工作。处理上述所有问题,并设计一个可用的,可靠的和稳定的 API,我们可以保证该 API 在多个 pip 版本中仍然可用。而且,我们目前根本没有资源来考虑这项任务。』。

实际上,这意味着将 pip 内部的所有内容都视为实现细节。甚至导入名称是 pip 的事实也会随时更改,恕不另行通知。尽管我们尽量不破坏事物,但所有内部 API 均可随时出于任何原因而更改。这也意味着我们通常不会解决由于不支持使用 pip 而导致的问题。

还应该注意的是,在运行的 Python 进程中将软件包安装到 sys.path 中是必须谨慎进行的事情。导入系统缓存中的某些数据,并且在程序运行时安装新软件包可能并不会按预期方式进行。实际上,很少有问题,但这是需要注意的问题。

综上所述,如果您决定确实要从程序中运行 pip,则值得介绍所有可用选项。最可靠且完全受支持的方法是在子流程中运行 pip。使用 subprocess 可以轻松完成此操作:

subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'my_package'])

如果要进一步处理输出,请使用模块中的其他API:

reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])

如果您不想使用 pip 的命令行功能,而是想实现适用于 Python 软件包,其元数据或 PyPI 的代码,那么您应该考虑提供这种功能的其他受支持软件包。您可以考虑的一些示例包括:

  • packaging: 用于处理标准打包元数据(版本,要求等)的实用程序
  • setuptools(特别是pkg_resources): 用于查询用户在系统上安装了哪些软件包的函数。
  • distlib: 包装和分发实用程序(包括用于与 PyPI 交互的功能)。

尝试使用 pip 的一些内部实现细节的方式是不支持被 pip 支持的。 pip 曾经多次要求禁止使用这种危险的方式,最终在 pip 10通过将几乎所有代码都移到pip._internal命名空间中使之明确。

当然的确有某种方式来支持这种操作。

参考链接:
pypa/pip#5246
Using pip from your program

本文链接:

https://jamchoi.me/archives/21.html
1 + 6 =
快来做第一个评论的人吧~