标签归档:Poetry

回应《也谈「不要用 Pipenv」》

看了董伟明老师(@董伟明)的《也谈「不要用 Pipenv」》,这篇文章对其中的一些观点做出一些回应和解释。

也看了 Frost Ming 老师(@岂不美哉)的《Pipenv 有什么问题》,很感谢他做出的努力,祝 Pipenv 早日脱离 Kenneth Retiz 的影响,越来越好。

(Kenneth Retiz 下文简称 KR)

KR 有没有借 PyPA 之名来做背书?

所以作者并没有想着用来背书。

我仍然认为 KR 有利用 PyPA 做背书,甚至在误导别人 Pipenv 是 Python 官方(混淆 PyPA 和 Python 官方的概念)推荐的工具。

证据 1

2017 年 8 月 29 号,在 Pipenv 还不够成熟的时候,PyPA 成员 Thea Flowers 创建了一个 PR 要把 Pipenv 添加到 PyPA 的打包教程里,介绍使用 Pipenv 安装和管理依赖(注意这时候 Pipenv 根据教程的内容在 Windows 上是没法正常使用的,具体见 9 月 2 号的这个 issue)。

2017 年 8 月 31 号,Thea Flowers 自己合并了 PR。注意这个教程页面是临时的单独页面,还没有正式放到打包教程的页面里。

2017 年 9 月 1 号,KR 在 Pipenv 的 README 里加了这样一行介绍语:「Pipenv — the officially recommended Python packaging tool from Python.org, free (as in freedom).」(commit

其中的关键内容翻译过来大概是「官方推荐的 Python 打包工具,来自 Python.org」。

仅仅因为在 PyPA 的打包文档里加入了一个短教程(其中介绍了使用 Pipenv 安装和管理依赖),然后 KR 就在 Pipenv 的介绍里宣传这是「官方推荐」,而注明的官方来源则是「Python.org」,这两个关键词背后的超链接都是 PyPA 打包文档的 Pipenv 介绍。packaging.python.org(PyPA) 和 python.org(Python 官方) 的区别很大,很明显,他清楚两者的区别,但又故意没有表达清楚。
退一步讲,不管他的意图是什么,这样的措辞都会让人以为是 Python 官方推荐的打包工具,尤其是对 PyPA 这个组织不了解的人,看到 Python.org 都会认为是 Python 官方。

证据 2

在 PyCon 2018(五月),KR 在演讲《Pipenv: The Future of Python Dependency Management》里介绍 Pipenv 的卖点的时候,列在第一条的仍然是上面那一句「Officially recommended tool from python.org」:

和在 README 里不同的是,这次在演讲上别人没法去点那个 python.org 的链接去甄别究竟是 python.org(Python 官方) 还是 packaging.python.org(PyPA)。而 KR 在介绍这里的时候没有任何说明,直接说是「来自 Python.org 的官方推荐」。

至于 KR 和 PyPA 或者说和 Thea Flowers 有什么关系?把 Pipenv 的介绍加到打包文档是 Thea Flowers 的个人意愿?还是 PyPA 的 35 个成员全部同意的结果?是什么促使 PyPA 在 Pipenv 还不成熟、甚至教程里的内容没法在 Windows 上正常操作的情况下添加到打包教程里?这些问题我暂时找不到答案。

(注:PyPA 指的是 Python Packaging Authority,一个负责维护 Python 打包相关的库(比如 pip、virtualenv 等)和文档的组织。)

从 0 升到 18 的措辞问题

而所谓的18.X.X是 calver versioning(基于日历的版本)

在上一篇文章里,我引用了一段 HN 上的评论来概括 Pipenv 在推广方式上的问题:

Kenneth Retiz 滥用他在 PyPA 的位置(而且快速把一个实际上是 beta 状态的产品的版本号从 0 升到 18)来暗示 Pipenv 已经非常稳定,受到大力支持并且非常官方,但事实却并不是这样。

这句话的英文原文是:

However, Kenneth abused his position with PyPA (and quickly bumped a what is a beta product to version 18) to imply Pipenv was more stable, more supported and more official than it really was.

其中关于版本的部分是「and quickly bumped a what is a beta product to version 18」,可能是我乱翻译造成了误解……我认为原文里的 18 就是一个夸张的表达方式,把这里的数字换成 100 也可以表达同样的意思(也可能是指 0.3.0 跳到 3.0.1 那次)。换用日期版本号(CalVer)那次看起来没什么问题(11.10.4 -> 2018.05.12),所以我认为这里的 18 和日期版本号没关系。

Lockfile 只要过期就重新生成是合理的吗?

Kenneth Reitz 先是说 lockfile 只要是过期了就总是会被重新生成

这是对的,Pipfile和Pipfile.lock是对应的,当执行pipenv install后改了Pipfile,对应的Pipfile.lock就定会改。错误的是,不应该改那些不相关包的版本: 既然已经是==的了,就表明确定了具体版本呀。

这些问题,其实源于 Pipfile对应依赖在一开始没指定具体版本,也就是Pipfile对标requirements.txt,而Pipfile.lock只是当前环境的一个「快照」,如果Pipfile没有明确版本就用Pipfile.lock里面指定的。

我的主要想法是这样的功能实现是不合理的。Pipenv 在安装一个包的时候默认就使用通配符(*)版本写到 Pipfile 是不合理的设计。这样的设计不符合正常的开发流程和使用习惯。如果我在安装一个包的时候就要明确自己要安装哪个版本,以便在 Pipfile 里固定版本,这样会很不方便,而且让 Pipfile.lock 的存在意义变得很弱。

按照 KR 自己的解释,Pipfile 对标的是 requirements.in,Pipfile.lock 对标的是 requirements.txt:

blank
按照大部分人的理解,Pipfile 是所有不固定版本的高层依赖的列表(unpinned),而 Pipfile.lock 是固定安装时采用版本的详细依赖列表(pinned),用来复现程序具体的依赖环境;除非我主动执行 update 命令更新某个依赖,否则 Pipfile.lock 不应该被改动。但实际的 Pipenv 并不是这样,更新 Pipfile.lock 变成了频繁发生(install/uninstall/update)的默认行为。

Poetry 分析依赖慢

Resolving dependencies… (422.9s)

安装个包7分钟,这… 谁能忍?你们试试把bluelog项目的依赖用poetry add加一遍需要多久?我反正体验不下去了

实际测试安装 Flask-SQLAlchemy,解析依赖花了 42 秒(Windows+代理),没有 7 分钟那么夸张。因为解析依赖的结果会被缓存,我就在另一台 Mac(代理)上也试了一遍,结果只花了 8.3 秒。可能是网络状况的问题?

另外我试了把 Bluelog 的所有依赖一次性安装(Windows+代理),其中解析依赖只花了 16.8 秒(因为解析结果缓存的原因,实际也许会稍久一点):

$ poetry add flask flask-ckeditor flask-mail flask-sqlalchemy flask-wtf flask-moment python-dotenv bootstrap-flask flask-login flask-debu gtoolbar gunicorn psycopg2 flask-migrate
Using version ^1.1 for flask
Using version ^0.4.3 for flask-ckeditor
Using version ^0.9.1 for flask-mail
Using version ^2.4 for flask-sqlalchemy
Using version ^0.14.2 for flask-wtf
Using version ^0.9.0 for flask-moment
Using version ^0.10.3 for python-dotenv
Using version ^1.0 for bootstrap-flask
Using version ^0.4.1 for flask-login
Using version ^0.10.1 for flask-debugtoolbar
Using version ^19.9 for gunicorn
Using version ^2.8 for psycopg2
Using version ^2.5 for flask-migrate

Updating dependencies
Resolving dependencies... (16.8s)

所以 Poetry 或许没那么糟糕(当然我还没深入使用过)。

星星

虽然不是决定性的,但是对于这Star不到6K的项目来说我是不敢用的

Pipenv 的 Star 的确很多(而且 README、文档甚至代码里到处都是星星✨),KR 可是个营销专家,但项目质量却并没有那么好。反正我现在一看见星星和蛋糕就有点头疼。

✨🍰✨

另外,顺便说一句,pip(5627)、virtualenv(3189)和 setuptools(883) 的 Star 数量都没到六千……

好吧,我承认最后这两段是在抬杠 :D

从国内的 PyPI 镜像(源)安装 Python 包

不论是使用 pip,还是 Pipenv、Poetry等工具,安装 Python 包的时候会默认从官方的 PyPI 源下载文件,速度比较慢。国内的一些公司和机构提供了 PyPI 镜像源(mirror source),你可以设置让这些工具从国内的镜像源安装 Python 包,以便提高下载速度。

官方 PyPI 源的 URL 为 https://pypi.org/simple (旧的 URL 为 https://pypi.python.org/simple ),下面我们将以豆瓣提供的镜像源为例(URL 为 https://pypi.doubanio.com/simple/),介绍不同工具更改 PyPI 镜像源的方法:

pip

临时设置可以通过 -i 选项:

$ pip install -i https://pypi.doubanio.com/simple/ flask

全局设置有不同的层级和文件位置,以用户全局(per-user)为例,在 Linux & macOS 中,配置需要写到 ~/.pip/pip.conf 文件中;Windows 中,配置文件位置为 %HOMEPATH%\pip\pip.ini,%HOMEPATH% 即你的用户文件夹,一般为“\Users\<你的用户名>”,具体值可以使用 echo %HOMEPATH% 命令查看。

通常你需要手动创建对应的目录和文件,然后写入下面的内容:

[global]
index-url = https://pypi.doubanio.com/simple
[install]
trusted-host = pypi.doubanio.com

附注:按照 pip 文档,上面的配置文件位置是旧(legacy)的配置方式,但是因为比较方便设置,这里沿用了。新的建议是 Linux & macOS 放到 $HOME/.config/pip/pip.conf,Windows 则放到 %APPDATA%\pip\pip.ini。具体可以访问 pip 文档配置部分查看。

Pipenv

类似 pip 的 -i (–index-url)选项,你可以使用 –pypi-mirror 临时设置镜像源地址:

$ pipenv install --pypi-mirror https://pypi.doubanio.com/simple flask

如果想对项目全局(per-project)设置,可以修改 Pipfile 中 [[source]] 小节:

[[source]]

url = "https://pypi.doubanio.com/simple"
verify_ssl = true
name = "douban"

另外一种方式是使用环境变量 PIPENV_PYPI_MIRROR 设置(Windows 系统使用 set 命令):

$ export PIPENV_PYPI_MIRROR=https://pypi.doubanio.com/simple

你可以通过把这个环境变量的设置语句写入到终端的配置文件里实现“永久”设置,Linux & macOS 可参考这里,Windows 可参考这里

Poetry / Flit

因为 Poetry,Flit 这些工具遵循 PEP 518 创建了一个 pyproject.toml 文件来替代 setup.py、Pipfile 等配置文件,所以我们可以在这个文件里更改 PyPI 源。

使用 Poetry 时,在 pyproject.toml 末尾添加下面的内容来设置自定义镜像源:

[[tool.poetry.source]]
name = "douban"
url = "https://pypi.doubanio.com/simple/"

目前暂时没有其他方式,未来或许会为 poetry add 命令添加一个相关的设置选项。

同样的,Flit 大概要添加下面这些内容(未测试):

[[tool.flit.source]]
name = "douban"
url = "https://pypi.doubanio.com/simple/"

常用的国内 PyPI 镜像列表

  • 豆瓣 https://pypi.doubanio.com/simple/
  • 网易 https://mirrors.163.com/pypi/simple/
  • 阿里云 https://mirrors.aliyun.com/pypi/simple/
  • 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/

顺便提一下,使用镜像源需要注意一个问题:包的版本可能不会及时更新,遇到这种情况可以通过临时换回官方源解决。