pip 小吐槽

标题本来是 how pip works, 但是看了 pip 的部分代码,我把它改成了 pip 杂谈。

看代码前自己的两个问题:

  • pip 怎样判断一个包的最新版,或者是 pypi server 做了这件事? pip 做的,解析网页。
  • pip 是怎样一个包有哪些依赖的? 下载包,解压,找到对应文件,解析之。新版 pypi 有 REST API。

循规蹈矩的工作比较消耗人的意志,为了找点乐子,我给自己挖了一个坑,提出这样一个问题: 假设你有一个 Python 包的源代码,也可以从 pypi 上下载这个包的历史版本, 那怎样在不安装一个包前提下,把这个包的依赖给解析出来?

思考两秒钟,我的答案是想办法运行一下 setup.py,获取 install_requires 字段的值,就可以啦?so easy!一个星期之后,准备动手写代码,发现不知道怎样实现。 随后,果断使用 Google 神器:“python get package dependencies without install”, 答案倒是挺多,就是没发现心仪的。于是想研究下 pip…

另外,最近还听说一个似乎非常不错的学习开源软件的方法:从它第一个版本的 源代码开始看(如果文档写的不是特别烂的话)。

(不幸的是,pip 的源代码可能比文档还要烂)不过还是要简单的记录一下, 万一下次还要看呢。

运行 pip install 命令的大致流程

  1. 解析命令行参数。不要小看这一步,pip 的可设置参数多得超乎你想象。 常见的有:-i 指定 index server; -U 升级版本。不那么常见有 –pre 支持安装 pre-release 版本;–timeout 设置超时时间等(貌似也比较常见)。 目测一下,这些可设置的参数个数大概 30 个吧。

以前觉得参数多也没关系啊,反正有默认值。但是如果你要把它当做一个基础 库来用,那就痛苦了。因为不搞懂每个参数的意思,我也不敢贸然使用这个东西。 另外,它的参数命名比较奇怪。

  1. 使用这些参数实例化 PipSession, PackageFinder 这两个类。 其中 PipSession 是对 requests.session 的包装,就做一些网络操作, 下载 wheel 包或者 sdist 包都需要用到它。 PackageFinder 的作用就和它名字一样,它会根据你设置的参数:什么平台、 什么版本去 index server 上找合适的包。

  2. 用实例化出来的 session 和 finder 去构造 RequirementSet。这个类 的构造函数允许传 18 个参数,就问你怕不怕。pip 会用它去帮我们下载、安装包 以及包的依赖。RequirementSet 这个类干的事情太多了,基本上干 每件事情都需要用到它。很奇葩。

写到这里,感觉写不下去了,我觉得自己没有理解 pip 的‘精髓’,只看到了 pip 的冰山一角,今天感触比较多,自己默默消化一会,哈哈哈。

(等哪天 RequirementSet 这个类重构了,我再回来理解一下这东西

2333

吐槽不是目的,见贤思齐,遇不贤自省。自省!虽然代码看得很累,但是毕竟人家 用起来还是舒服。(下次还是不要吐槽了,把心态摆摆正!)

诶,神奇的地球,复杂。

有时间还是去研究一下 wheel/egg/sdist 这些更基础一点东西比较靠谱。

Updated:

Comments