前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Debian 系统上捉摸不定的 Python

Debian 系统上捉摸不定的 Python

作者头像
岂不美哉Frost
发布2023-10-19 09:39:28
2100
发布2023-10-19 09:39:28
举报
文章被收录于专栏:Frost's BlogFrost's Blog

在上周的周记中我记了一句:

  • pdm 提了几个 issue,都和 debian 系统的 python 有关,i hate it

本文是对这句话的一个扩展。作为一个 Python 打包工具的开发者,非常痛恨 Debian 系统,所以我在回复 laixintao 时说道: Python 打包系统的混乱,Debian 系统是要居大功的。其实不止 Debian 是如此,下面开始吐槽,非常不严谨,吐槽完我就跑。

Python 中的 Install Scheme

Install Scheme 的概念,中文大概是翻译成「安装蓝图」?意思就是提供了一个路径的集合,告诉 Python 包的安装器(如 pip),什么文件应该放到哪个路径下。 本文只打算讨论 purelibplatlib,也就是 Python 库应该放到哪里。Install Scheme 可以通过以下函数获得:

代码语言:javascript
复制
import sysconfig
install_paths = sysconfig.get_paths()
print(install_paths['purelib'])

正常情况下,比如我之前的文章提到的一样,Python 库是放到:

  • Posix: $path_prefix/lib/pythonX.Y/site-packages
  • Windows: $path_prefix/Lib/site-packages

$path_prefix 是 Python 解释器所在的路径前缀。在这里我们先请优秀学生 Windows 回到座位上,来说说 Posix 的问题,比如 Python 路径是 /usr/bin/python3.9,那么 /usr 是路径前缀,上述路径则变为 /usr/lib/python3.9/site-packages

Debian:事实并非如此

基本所有的 Linux 发行版都会自己打包 Python 库,他们不信任 PyPI,所有用到的 Python 库都拿源码下来,自己打包。那问题来了,那么多 Python 包,那么多 Python 版本,怎么打,怎么安装?他们发现了一点:纯 Python 库是比较兼容的,不需要每个 Python 版本都打一个包,只需要整个 Python 3 打一个包就可以了,所以有 python3-pip, python3-requests 这种命名方式的包。安装的时候,也把它们放在一个地方,所有 Python 3 版本都可以用。其他不是纯 Python 的包,再分版本存放。(这段是我臆想,不严谨)

所以,在 Debian 上,就有了下面三个路径存放 Python 库:

  1. /usr/lib/python3/dist-packagesapt 安装的纯 Python 库
  2. /usr/lib/python3.9/dist-packages/apt 安装的带扩展的 Python 库
  3. /usr/local/lib/python3.9/dist-packages/pip3 安装的 Python 库

这属于自己的设计了,那么就需要改安装库和导入库的逻辑。Debian 维护了一系列的补丁 来干这件事,改完之后,sys.path 会包含上面三个路径,site-packages 的路径从中去除了,而 pip3 也会安装包到第三个路径。所以要记住,发行版上自带的 Python 和 pip 都是特制的,你用从官网和 PyPI 上下载的去替换是会出问题的。

OK,这没问题,也能接受,反正你自己魔改自己发布到 apt,只要闭环了用户是感知不到变化的。但问题是,这些补丁是不完备的!。为了改默认的 sys.path,Debian 只修改了 site 模块,以及 distutils1 模块,而没有修改上面的 sysconfig 模块,而 distutils 模块已经在 PEP 632 里被 Deprecated 了,官方推荐的替代就是 sysconfig。这个问题随着 Python 3.10 的发布而暴露了出来,Debian 的维护者也意识到这个问题,最新的补丁里已经修改了 sysconfig,但不是很小心,造成了一些回归问题。这样的后果就是,如果用户切换发行版的不同版本,以及 Python 3.10 或 3.10 以下,这个 Install Scheme 安装到哪里完全捉摸不定,不可预测,那么包管理器就很难做了(还能怎样,当然是原谅(兼容)啊,难道威胁用户,不许用 apt 的版本吗?)

到底有多捉摸不定?

做了一个测试,分别测试 Python 3.9 和 3.10,以及 pip 使用 apt 的版本和 get-pip.py 安装的版本,在旧版本 Debian2debian:testing 中获取 Install Scheme 的值。

Image

Python 3.9

Python 3.10

ubuntu:focal

sysconfig: 未修改site: 已修改distutils: 已修改get-pip.py 安装的 pip 把库安装到 site-packages下

sysconfig: 已修改3site: 已修改distutils: api 已移除get-pip.py 安装 pip 失败

debian:testing

sysconfig: 未修改site: 已修改distutils: 已修改get-pip.py 安装的 pip 把库安装到 site-packages下

sysconfig: 已修改site: 已修改distutils: 已修改get-pip.py 安装的 pip 把库安装到 dist-packages下

这里已修改是指返回 dist-packages 的路径,而未修改是指返回 site-packages 的路径。测试脚本见仓库。

可以看到在 Python < 3.10 上虽然补丁不完备,行为倒还是统一的,但在 Python 3.10 上就出幺蛾子了,简直就是一团乱麻,Python 环境太难了。

Bonus: MacOS 上的 Python,取决于它是不是 framework,安装路径也有区别,但这已经在 CPython 的标准库中得到支持,不是用补丁方式解决的。 所以大家对下面这个主张没有异议了吧:

Windows 上的 Python 环境是最清爽干净的。

如何避坑?

两条建议:

  1. 如果要在容器中使用 Python,用 python 系列的镜像。那里面的 Python 是标准化的,不是特制的。
  2. 如果用户系统是 Debian 系,不要在系统路径中安装包,对,--user 都不行,甚至 python3-pip 都不要装以绝后患。而应该使用虚拟环境(python3-venv 包)和 pipx。或者用 PDM 或 Poetry 这种包管理工具。因为只有在虚拟环境中,Python 库的安装路径永远是 site-packages,无论在哪个系统上。

一些 GitHub issues

Footnotes

  1. distutils.sysconfig 中也包含一些和 sysconfig 模块中作用类似的函数。
  2. 因为 deadsnakes ppa 只支持 ubuntu,我在这里用的其实是 ubuntu:focal 镜像。
  3. 在 focal 上没有 Python 3.10 的系统包,所以这里是从 deadsnakes ppa 安装的。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-3-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Python 中的 Install Scheme
  • Debian:事实并非如此
  • 到底有多捉摸不定?
  • 如何避坑?
  • 一些 GitHub issues
  • Footnotes
相关产品与服务
腾讯云服务器利旧
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档