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。