技术
2023 年 6 月 27 日
从 Pip 迁移到 Poetry
端午节在家给开发机的系统升级到了到 Ubuntu 23.04,当时只做了一些简单的检查,没有发现问题就安心睡觉去了。
没想到,节后第一天上班,一打开 VSCode 的 Python 项目,就发现一大堆报错,顿感大事不妙。啊,Python,How old are you? (怎么老是你?)
上次升级 macOS 也是遇到了 Python 环境的问题。真让人头疼。这时候不得不祭出这张图了。
![Python 环境](https://img.maymagic.us/assets/2023/202306271600694.png)
Python 环境
这次无论如何,也要把他理清楚,减少以后无休止的莫名其妙的问题,避免持续的流血 DEBUFF。
问题现状
冷静下来,分析了一下。现在的报错主要是依赖缺失,也就是说,之前通过 pip 安装的依赖全部都没有了。
那再安装一遍就是了。当我尝试
pip install langchain
的时候,居然报错了,如下:![pip install error](https://img.maymagic.us/assets/2023/202306271607755.png)
pip install error
关键信息是:This environment is externally managed╰─> To install Python packages system-wide, try apt install python3-xyz, where xyz is the package you are trying to install.
也就是说,系统级别的安装,现在需要通过
apt install python-xyz
来替代原来的 pip install xyz
了。或者就要用 Python 虚拟环境 venv。这是为什么呢?因为默认情况下,pip 是直接安装依赖到当前 pip 对应 Python 的系统目录下的。这在存在多个 Python 版本,或者多个依赖版本时,特别混乱。
经常出现 A 项目有报错,一番操作后,解决了,但 B 项目又出现了问题。或者,明明我昨天安装了 c 依赖,怎么今天又找不到了。。等等。
Python 和 pip 的运作方式
为了从根源上解决问题,我们需要先分析一下 Python 和 pip 的运作方式。下面已 Ubuntu 23.04 为例。
对于 Python,现在一般只有
python3
命令了,python
命令对应的是 Python 2.x 版本,现在已经不维护了。这在一定程度上也简化了问题的复杂度,因此我们也没必要讨论 Python 2.x。通过
which python3
可以查看当前 Shell 使用的 Python 可执行文件路径。对我的 Ubuntu 来说,是 /usr/bin/python3
。在我的 macOS 上,由于是通过 Homebrew 安装的,它的路径是 /usr/local/bin/python3
。/usr/bin/python3
是系统自带的 Python,一般不建议动它。如果要安装其他的版本,一般会安装到别的路径,然后通过修改 PATH
环境变量,优先使用自己安装的版本。(但现在也不推荐这么做了,具体看下文。)对于
pip
,也有 pip
和 pip3
两种。在过去,分别对应 Python 2.x 和 Python 3.x 两个版本,但现在,两者同时指向 Python 3.x。如果系统上同时存在多个 Python 3.x,pip
的指向可能就会乱掉。具体看当前的
pip
指向的是哪个 Python 版本,可以通过 pip show
命令查看。比如 pip show pip
,我的输出是包含了 Location: /usr/lib/python3/dist-packages
这一行,就表明,当前的 pip
对应的 Python 是 /usr/lib/python3
。默认情况下,通过
pip install xyz
安装的软件包,也会安装到 /usr/lib/python3/dist-packages
目录下。当系统升级 Python 时,可能就没了。这也是导致我安装依赖全部丢失的原因。至于
pip3
,现在都没有 python2
了,你也应该忘记它。最佳实践
但现在已经无法通过
pip install xyz
安装了,怎么办呢?通过 apt install python-xyz
不失为一种办法,但这个太不 Pythonic 了。只适合轻量级的使用,比如偶尔用一下某个 Python 编写的命令行工具,比如 httpie 之类,不适合 Python 开发。经过这几天的探索,也算是找到了个人的最佳实践。简而言之就是使用
pipx
和 poetry
这两个工具,其中 pipx
用于系统级别的可执行软件包管理, poetry
用于项目的依赖管理。pipx 的使用
pipx
和 pip
最大的区别就是 pipx
是在一个隔离的环境里安装和运行 Python 程序。可以通过 pipx ensurepath
来确认位置。![pipx ensurepath](https://img.maymagic.us/assets/2023/202306271658160.png)
pipx ensurepath
这个隔离的环境其实也是一个自动创建的 Python 虚拟环境,默认位于
~/.local/pipx/venvs
。由于不对外暴露太多细节,所以不适合用来开发,只适合用来运行命令行程序。安装
pipx
推荐使用系统级别的包管理工具,比如 Ubuntu 上的 apt
或者 macOS 上的 brew
。因为,这真的只是用来进行一些系统级别的包管理,和 Python 开发几乎没有任何关系。唯一的关系就是,Python 开发所需的
poetry
需要通过 pipx
来安装。执行:pipx install poetry
使用
pipx list
可以列出所有安装的 Python 包,并且只会列出直接依赖,所以列表非常简洁。![pipx list](https://img.maymagic.us/assets/2023/202306271710477.png)
pipx list
poetry 的使用
使用 Poetry 很简单,基本只要 3个命令,官方文档也很详细,这里不赘述。
poetry init # 初始化项目
poetry add xyz # 增加依赖
poetry install # 安装所有依赖
Poetry 通过标准的
pyproject.toml
文件描述项目和依赖,通过 poetry.lock
文件记录依赖的版本信息。Poetry 自身的配置信息报错在 ~/.config/pypoetry/config.toml
。默认情况下,Poetry 就很好用了,但我更喜欢通过
poetry config virtualenvs.in-project true
将虚拟环境设置为 in-project
,这样就实现了类似 node_modules
的效果,更好管理,不用担心项目多了之后虚拟环境乱糟糟的无法管理。![poetry venv](https://img.maymagic.us/assets/2023/202306271709875.png)
poetry venv
为什么不用 Pipenv
Pipenv 也是一个优秀的 Python 环境和依赖管理工具,但是相对于 Poetry,有一个缺点难以忍受,就是 locking 比较频繁,且非常慢,尤其在国内网络环境下。为了生活更美好,请用 Poetry。
为什么不用 Conda
我觉得 Conda 是一个非常反程序员的东西,本来想说反人类的,想了想还是改成反程序员。因为它不是一个面向程序的产品,也不符合程序员的工作逻辑。这东西制造出来的麻烦远比它带来的便利多,而且多很多。具体可以看上面的那张图。
Poetry 完全可以解决 Conda 视图解决的问题,并且做得更好。为了生活更美好,请立即停止使用 Conda。
总结
通过以上的步骤,现在我们的系统里只有一种
python3
和 pip
了。你几乎不会直接接触他们,所以直接放养就好,不用管它们的死活。如果你要安装一些 Python 写的命令行工具,请使用
pipx
。如果需要进行 Python 开发,请使用 poetry
。pipx
是用户级别的,poetry
是项目级别的,它们都不会都系统造成什么影响,非常符合 UNIX 哲学。其他什么都不要用。
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
作者: maY 发表日期:2023 年 6 月 27 日