LWN:讓Python的各種軟件安裝方式不再?zèng)_突!
關(guān)注了就能看到更多這么棒的文章哦~
Cooperative package management for Python
By Jake Edge
August 31, 2021
DeepL assisted translation
https://lwn.net/Articles/867657/
系統(tǒng)中使用的軟件包管理器同 Python 自己的安裝機(jī)制 (主要是 pip,但也有其他一些方案) 之間一直都有一些沖突,現(xiàn)在看來終于要被解決了,或者至少可以規(guī)范化下來。PEP 668 ("外部軟件包管理器和 Python 軟件包管理器之間的優(yōu)雅合作方案") 提案的目的就是要提出能讓兩種類型的軟件包安裝方式能配合工作,而不是時(shí)不時(shí)地相互破壞。由于許多操作系統(tǒng)都依賴 Python 工具,其中使用的軟件包版本可能與用戶的 Python 應(yīng)用程序的版本可能是不同的。因此,人們非常希望能讓它們可以很好地配合工作,從而使系統(tǒng)更加穩(wěn)定。
這個(gè)問題的根本原因在于,發(fā)行版中的軟件包管理器和 Python 軟件包管理器 (本文后續(xù)部分用 "pip" 來代稱) 往往公用同一個(gè) "site-packages" 目錄,來存儲(chǔ)已安裝的軟件包。如果更新了某一個(gè)軟件包,或者更糟糕的情況是刪除了某個(gè)軟件包,那么在其中一個(gè)包管理器中可能是可以正常執(zhí)行的,但在另一個(gè)包管理器中卻導(dǎo)致了破壞。正如 PEP 中所指出的,這一切都可能會(huì)造成真實(shí)的麻煩:
這可能會(huì)給發(fā)行版的完整性(integrity)帶來嚴(yán)重問題,因?yàn)榘l(fā)行版的軟件包管理工具本身就是用 Python 編寫的。例如可能無意中用 pip install 命令破壞了 Fedora 的 dnf 命令,難以恢復(fù)回去。
sys.path 這個(gè)系統(tǒng)參數(shù)用來管理 Python 在遇到 import 語句時(shí)在哪里尋找 module。它會(huì)根據(jù) PYTHONPATH 環(huán)境變量來初始化,然后添加了一些安裝時(shí)和調(diào)用時(shí)相關(guān)的目錄。sys.path 是一系列的目錄,會(huì)按順序查找,行為上很像它所模仿的 shell 中的 PATH 環(huán)境變量。Python 程序可以修改 sys.path 來指定要搜索的位置,這個(gè)功能被 virtual environment 利用來實(shí)現(xiàn)其功能。
挺長時(shí)間以來,為了避免與操作系統(tǒng)安裝的軟件包沖突,更推薦的做法是在 virtual environment 中使用 pip,而不是直接安裝到當(dāng)前系統(tǒng)中去。但這一般來說不是強(qiáng)制性的要求,所以用戶有時(shí)候還是會(huì)遇到問題。PEP 668 的一個(gè)目標(biāo)就是允許發(fā)行版來聲明他們提供了另一種管理 Python 軟件包的機(jī)制,這樣一來 pip 的默認(rèn)行為就會(huì)相應(yīng)地改變。用戶仍然可以覆蓋修改該默認(rèn)行為,但希望這已經(jīng)足夠能提醒他們要注意到可能出現(xiàn)的問題。
如果發(fā)行版希望選擇這個(gè)新的行為,那么就會(huì)通過在 Python 標(biāo)準(zhǔn)庫所在的目錄中放置一個(gè)名為 EXTERNALLY-MANAGED 的配置文件來告知 pip 發(fā)行版在用自己的工具管理 Python 包。如果 pip 在那里發(fā)現(xiàn)了 EXTERNALLY-MANAGED 文件,并且當(dāng)前 pip 沒有在 virtual environment 中運(yùn)行,那么它就應(yīng)該報(bào)錯(cuò)退出,除非用戶明確用命令行參數(shù)來修改默認(rèn)行為。PEP 中推薦用 –break-system-packages 這個(gè)參數(shù)名稱。EXTERNALLY-MANAGED 文件可以包含錯(cuò)誤信息,當(dāng) pip 因?yàn)榇嗽蚨顺鰰r(shí),就會(huì)返回這些錯(cuò)誤信息。這些錯(cuò)誤信息也可以在文件中根據(jù)本地化信息進(jìn)行翻譯。其目的都是讓這個(gè)錯(cuò)誤信息能夠提供出這個(gè)發(fā)行版特有的一些指導(dǎo)信息,來指導(dǎo)用戶以正確的方式創(chuàng)建一個(gè) virtual environment 虛擬環(huán)境。
另一個(gè)可能出現(xiàn)問題是在軟件包被 pip 從系統(tǒng)范圍內(nèi)安裝的版本中移除時(shí)。例如,如果用戶在全系統(tǒng)范圍內(nèi)安裝了一個(gè)軟件包,并遇到了問題,那么此時(shí)最 "明顯的" 解決方案可能會(huì)導(dǎo)致更大的問題:
在系統(tǒng)位置進(jìn)行安裝還有一個(gè)更糟糕的問題:如果你試圖用 sudo pip uninstall 來解決這種問題,那你可能最終會(huì)刪除掉系統(tǒng)包管理器所提供的軟件包。事實(shí)上,哪怕你只是簡單地進(jìn)行一個(gè)軟件包的升級(jí)操作,這種情況也會(huì)發(fā)生,因?yàn)?pip 會(huì)試圖刪除操作系統(tǒng)所提供的舊版本軟件包。此時(shí)僅僅使用系統(tǒng)上剩余的軟件都可能無法將系統(tǒng)恢復(fù)到之前的正常狀態(tài)了。
PEP 中提出的第二個(gè)改動(dòng)就是限制 pip 只在指定的目錄中運(yùn)行。這里的設(shè)計(jì)思路是讓發(fā)行版將這兩種軟件包分別放置到它們自己的目錄中來管理,這其實(shí)是一些 Linux 發(fā)行版已經(jīng)在做的事情了:
例如,F(xiàn)edora 和 Debian(以及它們的衍生版本)都使用了隔離方式,也就是將 /usr/local 路徑用來在 pip 等方式安裝的軟件包,而 /usr 用在發(fā)行版所安裝的軟件包。Fedora 的相應(yīng)目錄就是/usr/local/lib/python3.x/site-packages 與/usr/lib/python3.x/site-packages。(Debian 使用了 /usr/local/lib/python3/dist-packages 和 /usr/lib/python3/dist-packages,前者是作為與本地編譯生成的 Python 解釋器的額外隔離用途的,也就是說如果在/usr/local/bin 中編譯和安裝了 upstream 的 CPython,那么它就會(huì)查找 /usr/local/lib/python3/site-packages 目錄,而 Debian 希望確保那些本地構(gòu)建出來的 python 解釋器所安裝的軟件包不會(huì)出現(xiàn)在發(fā)行版提供的 python 解釋器的 sys.path 中)。
所以這個(gè)提議中就要求 pip 需要查詢它將會(huì)放置軟件包的位置,并且只修改該目錄下的文件。由于本地安裝的軟件包通常在 sys.path 中會(huì)位于系統(tǒng)級(jí)別軟件包目錄之前,因此這可能會(huì)導(dǎo)致 pip 安裝的版本好像覆蓋了(shadow)發(fā)行版所提供的相應(yīng)軟件包。當(dāng)然,這種 "shadow" 方式安裝的軟件包也會(huì)導(dǎo)致之前提到的一些問題,所以建議 pip 在碰到這種情況的時(shí)候也要發(fā)出 warning。
PEP 中對(duì)使用場景以及這些改動(dòng)將產(chǎn)生的影響進(jìn)行了深入分析。"本 PEP 中改變的行為旨在讓盡可能多的使用場景能 '做正確的事'"。尤其是允許發(fā)行版可以針對(duì)系統(tǒng)軟件包以及 pip 安裝的軟件包指定兩組不同位置互不干擾,這種做法基本上是對(duì)當(dāng)前一些發(fā)行版的現(xiàn)行做法進(jìn)行了標(biāo)準(zhǔn)化。PEP 的 "對(duì)發(fā)行版的建議" 這一小節(jié)專門指出這種隔離方式應(yīng)該是未來的最應(yīng)該使用的做法。
然而,在某些情況下,發(fā)行版并不希望默認(rèn)采用這種新行為。那些用來運(yùn)行單個(gè)應(yīng)用程序的 container 容器就可能無法從這個(gè)規(guī)定中得到任何好處,所以 PEP 建議發(fā)行版針對(duì)這些 container image 可以改變默認(rèn)行為:
為這些單一應(yīng)用的 container 制作官方鏡像的發(fā)行版(例如,Docker container images)就應(yīng)該刪除 EXTERNALLY-MANAGED 文件,最好確保該鏡像內(nèi)用戶在安裝軟件包更新時(shí)也不會(huì)導(dǎo)致這個(gè)文件再次出現(xiàn)(比如 RUN apt-get dist-upgrade 這種情況)。在基于 dpkg 的系統(tǒng)上,只要使用 dpkg-divert –local 來永久性地改變這個(gè)文件的名字就可以了。在其他系統(tǒng)上可能需要有一些配置 flag 供 post-install 腳本調(diào)用來重新刪除 EXTERNALLY-MANAGED 這個(gè)文件。
總的來說,這個(gè) PEP 似乎沒有很大爭議。PEP 的相關(guān)討論中大部分都是積極的回應(yīng),盡管 Paul Moore(他可能是最終會(huì)批準(zhǔn)該提案的 PEP-Delegate)有些擔(dān)心那些被影響的人可能完全不知道這個(gè)信息:
我還是希望能有更多的討論。人們提到的 linux-sig 討論自從 5 月份以來,總共只有 6 條信息,而這里也只有幾條 message。我不認(rèn)為這里我們可以有充足理由判定 "沉默意味著贊同",目前很難確定可能會(huì)感興趣的那些人員主要活躍在什么地方,所以在這種情況下,沉默似乎更可能意味著 "他們完全不知道這個(gè)提議"。具體來說,我建議在 PEP 中加入一小節(jié)來列出已經(jīng)確認(rèn)支持該提案的發(fā)行版,列明發(fā)行版的名稱,并提供一個(gè)鏈接來指向他們當(dāng)時(shí)做出承諾的那個(gè)信息。
假如上述這個(gè)確認(rèn)信息會(huì)很快搜集完整,或者人們采納并解決了那些反對(duì)意見和建議,那么 PEP 668 應(yīng)該會(huì)成為 Python 一個(gè)很重要的進(jìn)步。像 DNF 和 apt 這樣的工具同 pip 之間的沖突,顯然在過去確實(shí)造成了一些問題,而且今后還會(huì)再次造成問題。因此要是能找到一種既能合作又不會(huì)造成重大向后兼容問題的方法就非常重要了。我們要確保其他發(fā)行版加入這個(gè)改動(dòng),并且所有這些改動(dòng)最終都是可選的,那么應(yīng)該會(huì)給我們帶來更穩(wěn)定的發(fā)行版,最終會(huì)讓用戶對(duì) Python 和發(fā)行版的滿意度都會(huì)更高。
全文完
LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。
長按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開源社區(qū)的各種新近言論~
