Pipenv是一個Python打包工具,它可以很好地完成一件事-應用程序依賴管理。然而,它也受到各種問題、局限性和發展進程的影響。過去,Pipenv的宣傳材料在其目的和支持者方面具有很高的誤導性。
在這篇文章中,我將探討Pipenv的問題。它真的是Python.org所推薦的嗎?每個人——或者至少是絕大多數人——都能從中受益嗎?
內容
應用差異
運行腳本(差勁)
一切都做完了
-
pipenv不能做什麼
Setup.py,資源分配,還有wheels文件
在項目駐點之外運作
Nikola
-
我試著測時間的那一部分
-
替代工具和新工具
Hatch工具
Poetry工具
Pip要留在這裡了!
-
Pipenv的夭折速度
-
結論
「官方推薦工具」,或者說我們怎麼做到的
「Pipenv——是Python官方網站Python.org推薦的Python打包工具,免費(自由版)。」
在好幾個月期間Pipenv的README文檔中常常有上面那句口號:這句口號是2017-08-31加進去README文檔里的,最終在2018-05-19被刪除。有那麼一陣子(在2018-05-16),有說明(管理應用程序依賴,還有Pypa而非Python.org),而在約15分鐘的時間裡,這句口號變成了「Pipenv是世界上最爛的」或其他大概是這個意思的話(這是維護者的吐槽)。
README這句口號聲稱Pipenv是Python打包工具的關鍵。問題是:不是這樣的。Pipenv可能有時會有點用,但是對於其他許多人來說,試用這個工具只會讓人沮喪。我們稍後會探討這個問題。
這個口號值得吐槽的地方還有「Python.org」和「官方」這兩點。讓它變得「官方」的是有關Packaging.python.org的一個簡短教程[1],這是Pypa的打包用戶指南。還值得注意的是它引用了Python.org這個詞,這聽起來好像Pipenv得到了Python核心團隊的認可。Pypa(Python Packaging Authority)是一個獨立的組織——它們負責Python的打包文件(包括pypi.org、setuptools、pip、wheel、virtualenv等),所以這認可具有誤導性。當然,Pypa是Python的一個很有價值的部分;核心團隊的認可-比如,包含在官方Python發行版中-要重要得多。
這條標語引發了許多激烈的討論,可能是自5月在Reddit網貼出來後最受熱議最重大的帖子了。這種改變是由Reddit網的這個帖子引發的。我建議全文閱讀這個帖子。
Pipenv能做什麼
我們已經了解到Pipenv用於管理應用程序依賴。讓我們來了解一下這個詞的真正含義。
應用程序依賴
以下是Pipenv的一個示例:我正在開發一個基於Django的網站。我創建了~/git/website,並在該目錄中運行pipenv install Django。Pipenv:
-
自動在我的主目錄中的某個位置創建一個虛擬環境。
-
編寫一個Pip文件,它將Django列為我的依賴
-
使用pip安裝Django
-
繼續編寫Pipfile.lock文件,它存儲每個已安裝包(包括pytz,即Django的依賴)的確切版本和源文件碎片[2] 。
這個過程的最後一部分是最耗時的。在鎖定依賴版本的同時,Pipenv暫停了46秒鐘,這是Pipenv值得注意的問題之一:速度慢。當然,這不是唯一的一個,但它絕對沒有幫助。損失46秒並不多,但是當我們在計時測試部分中進行更長的等待時,會知道這個小問題會讓用戶覺得使用這個工具包很麻煩。
運行腳本(差勁)
但我們還是繼續吧。pipenv run django-admin startproject foobanizer 是我現在必須要用到的,它不便輸入,並且芝麻綠豆的小事都要運行pipenv。(manage.py腳本框有/usr/bin/env python。) 我可以運行pipenv shell來獲得一個新的殼,這個殼默認運行activate腳本,讓您在虛擬激活中體驗兩者中最糟糕的一個:新殼的笨拙,和造殼支持者不喜歡的激活腳本。
使用pipenv shell意味著生成一個新的子殼,執行殼啟動腳本(例如bashrc),並要求您使用Exit或^D退出,如果您鍵入 「 deactivate」,則在虛擬程序之外使用一個額外的殼。或者你可以使用—fancy模式在啟動子shell之前操縱$PATH,但是它需要一個特定的殼配置,其中$PATH在非登錄殼中不被覆蓋-還經常更改終端模擬器的配置以運行登錄殼,因為許多Linux終端不這樣做。
為什麼會發生這種事?因為一個命令不能操作它生成的殼的環境。這意味著Pipenv必須假裝它所做的是一件合理的事情,而不是一個解決辦法。這可以通過使用source$(pipenv-venv)/bin/activate(可以變成一個整潔的別名)或殼包裝器(類似於虛擬包裝器)來手動激活解決。
都完成了
不管怎樣,我想在我的網站上有個博客。我想用Markdown語法編寫它們,所以我運行pipenv install markdown,幾秒鐘後,它被添加到兩個Pipfile中。我可以做的另一件事是pipenv install-dev IPython,並獲得一個方便的殼進行修改,但它將被標記為開發依賴——因此,不會安裝在生產中。最後一部分是使用Pipenv的一個重要優勢。
當我完成我的網站工作後,我將兩個Pip文件提交到我的git存儲庫中,並將其推送到遠程伺服器。然後我可以克隆到,比如說, /srv/website。現在,我只需運行pipenv install就可以安裝所有的生產包(但不安裝開發包-Django、pytz、Markdown將被安裝,但IPython及其所有的所以依賴項都不會安裝)。只有一個警告:默認情況下,仍將在當前用戶的主目錄中創建虛擬伺服器。在本例中,這是一個問題,因為它需要由nginx和uWSGi訪問,它們無法訪問我的(或根目錄)主目錄,也沒有自己的主目錄。這可以通過導出PIPENV_VENV_IN_project=1來解決。但是請注意,每當我通過Pipenv使用/srv中的應用程序時,我都需要導出這個環境變數。該工具支持載入.env文件,但只有當運行pipenv shell和pipenv run時。你不能用它來配置Pipenv。要使用nginx或uWSGI運行我的應用程序,我需要知道精確的虛擬路徑,因為我不能將pipenv run作為uWSGI配置的一部分。
Pipenv不能做什麼
上面提到的工作流程看起來很合理,對吧?有一些不足,但除此之外,它似乎工作得很好。Pipenv的主要問題是:它在一個工作環境下運行,並且只能在一個工作環境下運行。嘗試做任何其他事情,會有很多麻煩。
Setup.py,資源分配,還有wheels文件
Pipenv只關心管理依賴關係。這不是一個包裝工具。如果你想把你的東西放在PyPI上,Pipenv派不上什麼用場。您仍然需要使用install_Requires編寫setup.py,因為Pipfile格式只指定依賴和運行時需求(Python版本),因此包名沒有位置,Pipenv不強制/期望您安裝項目。管理開發環境(作為Requiments.txt替換,或用於編寫上述文件的東西)時比較方便,但是如果您的項目有setup.py文件,則仍然需要手動管理install_Requires。Pipenv也不能自己創造wheels文件,而pip freeze 將會比Pipenv更快。
在項目駐點之外運作
Pipenv的另一個問題是使用工作目錄來選擇虛擬環境。[3]假設我是圖書館的作者。我的foobar庫的一個用戶剛剛報告了一個bug,並附上了一個repro.py文件讓我重現這個問題。我將該文件下載到我的文件系統上的~/Download目錄。用普通的舊虛擬器可以很容易地用以下語句在備用外殼中重現:
然後我可以啟動我的高級IDE來修復這個bug。我不需要在這個項目中cd。但對於Pipenv,我真的不能這麼做。如果我用命令行選項在.venv中加上虛擬,就可以鍵入~/git/foobar/.venv/bin/python~/Download/Replei.py。如果我使用集中式目錄+碎片,且還沒有儲存碎片,那麼Tab實現就變得強制性了。
如果我有兩個.py文件,或者reple.py文件,否則就依賴於在當前的工作目錄中,該怎麼辦?
這樣相當不好看。而且,使用虛擬包裝器,我可以這樣做:
別忘了Pipenv幫不了我編寫setup.py文件、分發代碼或管理釋放。它只是管理依賴,而且做得很糟糕。
Nikola
我是一個靜態站點生成器的副維護者:Nikola。作為其中的一部分,我需要在以下地方運行Nikola:
列表很長。Nikola的最終用戶可能沒有那麼長的列表,但他們可能有不止一個Nikola站點。對我和上述用戶來說,Pipenv不起作用。要使用Pipenv,所有這些存儲庫都需要在一個目錄中。我還需要為Nikola用戶創建一個獨立的Pipenv環境,因為這需要Django。此外,如果我們要利用項目中的文件,則Pip文件必須與~/git/Nikola連接。所以,為了讓Pipenv變得巧妙,在SSD上進行測試/bug複製(並且更快地磨損它)等…我想有一個~/Nikola目錄。我也可以直接使用虛擬環境。但是在這種情況下,Pipenv失去了它的用處,使我的工作流程更加複雜。我不能使用虛擬包裝器,因為我需要黑掉一個模糊匹配系統到它上,或者記住附加在我的虛擬名稱上的隨機字元串。這都是因為Pipenv過於依賴當前目錄。
希望使用Pipenv的Nikola最終用戶也將強制使用特定的目錄結構。如果該站點充當項目的文檔,並且在另一個項目中複製怎麼辦?兩個虛擬環境,浪費掉100兆位元組。或者更糟的是,Nikola最終進入了另一個項目的Pipfile,這在技術上對我們的下載統計數據是好的,但對其他項目的貢獻者卻不是很好。
我試著測時間的那一部分
Pipenv以速度慢而聞名。但它到底有多慢?我對它進行了測試。我使用了兩個測試環境:
遠程:DigitalMarine VPS,這是最低廉的(1 VCPU),Python 3.6/Fedora 28,在法蘭克福
本地:我的2015年買的13英寸蘋果筆記本電腦上(基本模型)Python 3.7,在一個相當慢的互聯網連接上(好的時候網速達1000萬bps,但一個測試都沒執行到)
兩者都是在2018年7月1日運行由pip安裝的Pipenv。
同時也安裝了以下cache:
-
移除的: ~/.cache/pipenv 被移除
-
部分: rm -rf ~/.cache/pipenv/depcache-py*.json ~/.cache/pipenv/hash-cache/
-
不變的: 跟上一次運行沒什麼變化
事實證明Pipenv喜歡用緩存和鎖定來做一些奇怪的事情。查看活動顯示器發現,當Pipenv顯示其鎖定[包]依賴項時,網路活動正在進行…線程掛起來。沒有文件會告訴你。最糟糕的例子是在兩次運行中完成的本地Nikola安裝:第一次運行Pipenv InstallNikola在安裝軟體包後立即中斷[4],因此緩存中有所有必要的wheels文件。安裝花費了10分7秒,其中9分50秒是由鎖定依賴項和安裝鎖定的依賴項完成的-因此,大約有9分鐘半時間盯著靜態屏幕,工具在後台做一些事情-Pipenv不會告訴您這個階段會發生什麼。
(更新於2018-07-22:在Pipenv測量中:第一項是Pipenv可執行的總時間。第二項是等待Pipenv完成其「主要」任務:鎖定依賴項並安裝它們。計時在Pipenv開始鎖定依賴項時開始,在提示符出現時結束。第三項是Pipenv報告的安裝時間。因此,Pipenv安裝時間?鎖定/安裝時間?Pipfile.lock安裝時間。)
替代工具和新工具
Python打包似乎沒人會滿意。因此,有許多新的競爭者作為「最好的新包裝工具」的角色。除了Pipenv之外,還有Hatch工具(由Ofek Lev創作)和Poetry工具(由Sébastien Eustace創作)。兩者都被列為「正式」教程中的備胎選項。
Hatch?工具
Hatch工具試圖管理整個打包過程。它可以說是一種資產,因為它有助於替代其他工具。然而,也可以說,它增加了一個單一的失敗點。Hatch工具根據標準的文件例如requments.txt和setup.py來工作,因此很容易被其他文件替換。它不像Pipenv那樣搞那麼多花樣,而是更容易配置。Hatch工具所做的一些選擇是可疑的(例如手動解析pkg/_init_.py以獲取版本號,將測試套件安裝到Site-Package(相當常見的疏忽),或者它的殼特性與Pipenv一樣難看),而且它不做任何管理依賴的工作。它不一定適用於我前面提到的Django用例,也不一定適用於軟體的最終用戶。
Poetry?工具
Poetry工具介於兩者之間。它的主要目標是接近Pipenv,但也可能分配工作給PyPI。它極力隱藏它在幕後使用Pip的事實。它的自述文件附帶了一個「關於Pipenv」的延伸閱讀部分,我建議閱讀——它有更多Pipenv的不好的特性。Poetry工具聲稱使用標準化的(PEP 518)pyproject.toml文件來代替通常的大量文件。不幸的是,唯一標準化的是文件名和語法。Poetry工具使用自定義[tool.poetry]部分,這意味著人們需要Poetry工具充分使用它創建的包,這樣就離不開供應商了。(上述Hatch工具還生成一個pyproject.tmpl,其中包含元數據部分…)這裡有一個build特性來生成一個帶有setup.py以及關聯文件的sdist。