Pipenv有什麼問題

  • 2019 年 11 月 30 日
  • 筆記

這不是我第一次寫Pipenv相關的文章,也相信不是最後一次,前兩篇我用的是英文,(淺陋地)分析了Pipenv和Poetry的優劣,至今仍是我博客訪問量最高的文章。今天是因為在知乎上看到兩位朋友寫的兩篇文章(鏈接我放在文末了),吐槽了一通以後推薦大家不要使用Pipenv。說實話,作為核心維護者之一我是有點心酸的,因為他們說的那些問題的確都存在。在本文中我希望從一個核心維護者的角度,總結一下Pipenv存在的問題,作為一個告解。

從我關注Issues列表以來,我腦中能回想起來的,抱怨頻率最高的,也是最影響用戶體驗的,有幾個問題:

1. Lock時間長

用戶經常抱怨pipenv lock的時間長,特別是涉及到一些科學計算的庫時,如numpy, sklearn, tensorflow,會慢得讓你懷疑人生。pipenv lock其實做的就是依賴解析,而慢的原因是,Pipenv需要下載所有的安裝包來計算它們的哈希值,要命的是,像numpy這種庫,一個版本就有17個包,每個包的大小是10M~20M不等,總共下載的大小就有300多M左右。也有人提PR希望修改這個邏輯,但後來都不了了之。

Issue傳送門:https://github.com/pypa/pipenv/issues/3827

PR傳送門:https://github.com/pypa/pipenv/pull/3830

2. 命令及選項的結果不符合預期

李輝老師的文章裏面列舉了安裝、卸載、更新包的問題,我這裡先回復一下,其實它們都是同一個問題:pipenv update不能保護其他包不被更新。並且--keep-outdated--selective-upgrade這兩個選項意義不明容易讓用戶搞錯。

其實--keep-outdated有一次大修復只是還沒有發佈到新版本,所以用github上的master分支是沒問題的。我在這裡解釋一下--keep-outdated--selective-update這兩個選項的作用:--keep-outdated意思是更新Pipfile.lock時,不會刪除已經不需要的依賴。這對於產生一個跨平台的lock文件非常有用,因為有些僅Windows需要的依賴,你在Windows上生成Pipfile.lock時會有,而換到Linux上再執行pipenv lock時就沒有了。這個選項時針對Pipfile.lock更新的,而--selective-upgrade是針對安裝過程的,它會控制pip安裝包時,只在有必要的時候升級次級依賴的版本。這裡又涉及到一個邏輯的不統一:用pipenv install xxx安裝包的時候會先調用pip install xxx,並用pip的機制去更新依賴,再用Pipenv lock去鎖定依賴。理想情況下,依賴解析器應該唯一,應該通過Pipenv解析完了以後再統一安裝。

除此之外,其他的一些不符合預期的命令和混亂的選項有:

  • pipenv install--skip-lock, --ignore-pipfile, --deploy,此外還有不更新Pipfile.lock的pipenv sync命令,有誰能一眼區分出它們各自的作用?
  • 安裝普通依賴用pipenv install,安裝普通和開發依賴用pipenv install --dev,但pipenv lock永遠一起解析普通和開發依賴,有沒有--dev都一樣。然而pipenv lock -r是生成普通依賴,pipenv lock -r --dev是僅生成開發依賴。
  • 接上一條,pipenv uninstall --all是刪除當前虛擬環境中所有已安裝的包,不更新Pipfile,而pipenv uninstall --all-dev是刪除所有開發的依賴,更新Pipfile

我說的這些問題,都對應着許多Issue,我就(lan)不(de)一一列舉了。

3. 無法解析依賴

這一點也是在Poetry的文檔中作為反面教材抨擊的,其根本原因是,Pipenv不能自動回溯依賴的版本來滿足依賴的限制。比方說A包依賴C<1.0,而B包的1.x版本依賴C<1.0而2.0版本依賴C>=1.0,那麼你在Pipfile中同時包含A, B時就會解析失敗:Pipenv只會選用B的最新版本,在依賴不能滿足時不會嘗試舊版本。

Pipenv解析依賴其實用的是piptools,後者不能解析的Pipenv也不能。好消息是Pipenv維護小組做了一個新的依賴解析器passa,還在試驗階段,它能解決這個問題,未來會替代成為Pipenv的依賴解析器。

4. 怎麼還不release,以及其他的開發流程的問題

董偉明老師說到BDFL,沒錯,Kenneth Reitz曾經設計出了一套PEEP的流程,並把自己放在BDFL的位置上。但是,由於他本人對開源熱情的消退,他已經實際上退出了這個位置。但是PEEP的機制仍然存在:所有Behavior change必須先落地到PEEP文檔上,其實PEEP不難寫,能說清楚就行了,但是從這個機制創立至今,僅有5個PEEP被接受且沒有外部貢獻者的PEEP,這其中,又僅有2個涉及機制變化的PEEP真正落地。

其實Pipenv的問題數量不算多,維護者的人力對比Poetry也不見得少,關鍵問題就是上述的幾個嚴重影響用戶體驗的問題,或者問題修復了卻遲遲不發佈新版。

不止一個人,也不止一次有人抱怨發佈無限延期的問題,就快變成陳永仁那個「說好了三年,三年之後又三年,如今都快十年了!」的梗了,我在這裡也解釋一下。現在核心維護者主要有Dan Ryan(techalchemy), Tsuping Chong(uranusjr)和我,其中只有Dan有PyPI的權限,我其實說白了就是個「比較勤奮的Contributor」的角色。而Dan因為私事纏身無暇顧及開源工作。但好消息是他自稱事情已處理得差不多,會慢慢跟上進度。雖然我知道催促一個維護者在開源社區中不是一個禮貌的做法,但我也理解大家的心情,以及因此而心灰意冷棄用的用戶,所以我懇請大家,寬容一些,靜靜等待吧。

為什麼不開放權限給其他人?比如說我。

Dan是一個嚴謹的人,他希望親自過一遍改動日誌,潤色完了以後再發佈,所以還需要等待一些日子。他也對新特性的態度非常保守,總是害怕影響regression,破壞已有用戶的體驗。具體可以看看這個PR裏面的回復,這一點我不能認同,但也無可指責,畢竟他承擔了Kenneth Reitz以後90%的開發工作,其中有些部分確實非常棘手和麻煩。

作為維護者之一,我的想法是,因為master上已經積壓了太多的改動,先等Dan回來把這次新版本發佈了,回到正軌以後,我會開始針對以上我提到的問題,編寫PEEP,引入Deprecation機制,不去迴避Breaking change。

5. Poetry如何呢

最後還是提一下Poetry吧。Python的工作流工具,其實無非是解決三個方面的問題:虛擬環境管理、依賴管理、打包發佈。Pipenv只包含前兩項,比重是50%:50%,而Poetry同時包括三項,比重是20%:40%:40%。所以當我用慣了Pipenv切換到Poetry時會非常不習慣——它對於虛擬環境的控制太弱了:我無法知道我用的是哪個環境,路徑是什麼,也不能隨心所欲地刪除、清理、指定虛擬環境的位置。Pipenv的依賴解析器確實存在很多問題,但Poetry的也離完美有一段距離。而且Poetry負責的打包發佈部分,也不是最好的。所以我認為Poetry也沒有大家推薦的那麼好。如果Pipenv沒有滿足你的要求,那麼虛擬環境管理方面我推薦virtualenvwrapper+direnv(這兩個的最大問題是不支持Windows),依賴解析方面我推薦piptools,打包發佈還是用setuptools。