相比 Pipenv,Poetry 是一個更好的選擇
前情提要
Pipenv 描繪了一個美夢,讓我們以為 Python 也有了其他語言那樣完善的包管理器,不過這一切卻在後來者 Poetry 這裡得到了更好的實現。
這幾年 Pipenv 收穫了很多使用者,但是也暴露了很多問題。雖然 Lock 太慢、Windows 支援不好和 bug 太多的問題都已經改進了很多,但對我來說,仍然不能接受隨時更新鎖定依賴的設定,在上一篇文章《不要用 Pipenv》裡也吐槽了很多相關的問題。
在這篇文章裡,我會介紹一個看起來和事實上都更靠譜的 Python 虛擬環境和依賴管理工具 Poetry,作者是 Sébastien Eustace。這是一個新的坑嗎?我想並不是,儘管這是一個更年輕的工具,1.0 還沒有釋出,也存在各種各樣的 bug,但至少基本使用流程沒有問題,用法設計也符合直覺。
Poetry 是什麼
Poetry 和 Pipenv 類似,是一個 Python 虛擬環境和依賴管理工具,另外它還提供了包管理功能,比如打包和釋出。你可以把它看做是 Pipenv 和 Flit 這些工具的超集。它可以讓你用 Poetry 來同時管理 Python 庫和 Python 程式。
- 主頁:https://poetry.eustace.io/
- 原始碼:https://github.com/sdispater/poetry
- 檔案:https://poetry.eustace.io/docs
安裝 Poetry
官方推薦的安裝命令是使用自帶的 get-poetry.py 指令碼,使用 curl:
$ curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python複製程式碼
或者直接下載這個安裝指令碼 get-poetry.py,然後在本地執行。
因為這個命令在安裝時會從 GitHub 下載一個 7M 的壓縮包,如果不用代理某些地區可能會很慢。實際測試使用代理安裝耗時約 30 秒,不用代理等了 5 分鐘,然後連線被重置。
如果沒有用代理,可以用 pip 安裝(不過 Poetry 官方檔案不建議這麼做,因為有可能會造成依賴衝突,可以考慮用 pipx 或 pipsi):
$ pip install --user poetry複製程式碼
安裝後可以使用下面的命令確認安裝成功:
$ poetry --version
Poetry 0.12.17複製程式碼
如果報錯,可以試試重新建立一個命令列會話。
附註 在 Mac 上安裝報錯 ~/.bash_profile 許可權錯誤,臨時沒管,也能正常執行。後續可以考慮手動把 ~/.poetry/bin 加進去。
Poetry 的基本用法
Poetry 的用法很簡單,大部分命令和 Pipenv 接近。我們需要先了解一些基本概念和 Tips:
- 使用 PEP 518 引入的新標準 pyproject.toml 檔案管理依賴列表和專案的各種 meta 資訊,用來替代 Pipfile、requirements.txt、setup.py、setup.cfg、MANIFEST.in 等等各種配置檔案。
- 依賴分為兩種,普通依賴(生產環境)和開發依賴。
- 安裝某個包,會在 pyproject.toml 檔案中預設使用 upper bound(中文翻譯?)版本限定,比如 Flask^1.1。這被叫做 Caret requirements(中文翻譯?),比如某個依賴的版本限定是 ^2.9.0,當你執行 poetry update 的時候,它或許會更新到 2.14.0,但不會更新到 3.0.0;假如固定的版本是 ^0.1.11,它可能會更新到 0.1.19,但不會更新到 0.2.0。總之,在更新依賴的時候不會修改最左邊非零的數字號版本(對於 SemVer 版本號而言),這樣的預設設定可以確保你在更新依賴的時候不會更新到具有不相容變動的版本。另外也支援更多依賴版本限定符號。
- 不會像 Pipenv 那樣隨時更新你的鎖定依賴版本,鎖定依賴儲存在 poetry.lock 檔案裡(這個檔案會自動生成)。所以,記得把你的 poetry.lock 檔案納入版本控制。
- 執行 poetry 或 poetry list 命令檢視所有可用的命令。
如果你想了解更多進階的內容,比如設定命令列補全、打包和釋出等等,請閱讀 Poetry 檔案。
準備工作
如果你是在一個已有的專案裡使用 Poetry,你只需要執行 poetry init 命令來建立一個 pyproject.toml 檔案:
$ poetry init複製程式碼
根據它的提示輸入你的專案資訊,不確定的內容就按下 Enter 使用預設值,後續也可以手動更新。指定依賴的環節可以跳過,手動安裝會更高效一點。
如果你想建立一個新的 Python 專案,使用 poetry new <資料夾名稱> 命令可以建立一個專案模板:
$ poetry new foo複製程式碼
這會建立一個這樣的專案結構:
foo
├── pyproject.toml
├── README.rst
├── foo
│ └── __init__.py
└── tests
├── __init__.py
└── test_foo.py複製程式碼
如果你想使用 src 資料夾,可以新增 --src 選項,這會把程式包巢狀在 src 資料夾裡。
建立虛擬環境
使用 poetry install 命令建立虛擬環境(確保當前目錄有 pyproject.toml 檔案):
$ poetry install複製程式碼
這個命令會讀取 pyproject.toml 中的所有依賴(包括開發依賴)並安裝,如果不想安裝開發依賴,可以附加 --no-dev 選項。如果專案根目錄有 poetry.lock 檔案,會安裝這個檔案中列出的鎖定版本的依賴。如果執行 add/remove 命令的時候沒有檢測到虛擬環境,也會為當前目錄自動建立虛擬環境。
啟用虛擬環境
執行 poetry 開頭的命令並不需要啟用虛擬環境,因為它會自動檢測到當前虛擬環境。如果你想快速在當前目錄對應的虛擬環境中執行命令,可以使用 poetry run <你的命令> 命令,比如:
$ poetry run python app.py複製程式碼
如果你想顯式的啟用虛擬環境,使用 poetry shell 命令:
$ poetry shell複製程式碼
安裝包
使用 poetry add 命令來安裝一個包:
$ poetry add flask複製程式碼
新增 --dev 引數可以指定為開發依賴:
$ poetry add pytest --dev複製程式碼
追蹤 & 更新包
使用 poetry show 命令可以檢視所有安裝的依賴(可以傳遞包名稱作為引數檢視具體某個包的資訊):
$ poetry show複製程式碼
新增 --tree 選項可以檢視依賴關係:
$ poetry show --tree複製程式碼
新增 --outdated 可以檢視可以更新的依賴:
$ poetry show --outdated複製程式碼
執行 poetry update 命令可以更新所有鎖定版本的依賴:
$ poetry update複製程式碼
如果你想更新某個指定的依賴,傳遞包名作為引數:
$ poetry update foo複製程式碼
解除安裝包
使用 poetry remove <包名稱> 解除安裝一個包:
$ poetry remove foo複製程式碼
常用配置
Poetry 的配置儲存在單獨的檔案中,比 Pipenv 設定環境變數的方式要方便一點。配置通過 poetry config 命令設定,比如下面的命令可以寫入 PyPI 的賬號密碼資訊:
$ poetry config http-basic.pypi username password複製程式碼
下面的命令設定在專案內建立虛擬環境資料夾:
$ poetry config settings.virtualenvs.in-project true複製程式碼
另一個常用的配置是設定 PyPI 映象源,以使用豆瓣提供的 PyPI 映象源為例,你需要在 pyproject.toml 檔案里加入這部分內容:
[[tool.poetry.source]]
name = "douban"
url = "https://pypi.doubanio.com/simple/"複製程式碼
不過經過測試 Poetry 會使用 pip.ini 設定的 PyPI 映象,而且豆瓣的源好像很久沒更新了(建立虛擬環境安裝的預設依賴裡 importlib-metadata==0.20 找不到),這篇文章列出了一些其他國內的 PyPI 源。
總結
總的來說,我願意深入嘗試和使用 Poetry。當然,經過使用 Pipenv 的痛苦經歷,我對推薦工具這種事情變得更保守了。所以我不推薦 Python 初學者使用,不推薦直接在生產環境使用,不推薦沒法正常訪問國際網際網路的人使用。
列一些我瞭解到的優缺點:
優點
- 使用標準的 pyproject.toml 標準,不用寫多個配置檔案
- 同時支援管理 Python 程式和 Python 庫
- 更符合直覺的預設設計,比如不會隨便更新鎖定版本的依賴
- 乾淨簡潔的命令列輸出,沒有星星和蛋糕
- 安裝包的時候,使用 upper bound 版本限定,而不是 Pipenv 預設的萬用字元
- 解除安裝包的時候,直接解除安裝孤立的子依賴,不需要像 Pipenv 那樣需要再執行 pipenv clean
缺點
- 「poetry」這個單詞有一點難打……
- 引入新的 pyproject.toml 標準,舊專案需要一點遷移成本和學習成本
- 會有一些潛在的 bug
- 解析依賴的過程偶爾會久一點
- 對虛擬環境的管理控制有些弱,沒有 Pipenv 那樣的刪除虛擬環境和清空依賴的操作
- 缺少一個穩定的維護團隊,有大量 issue 和 PR 等待處理,但情況在逐漸好轉
當然,你還是可以選擇繼續使用 virtualenv 和 pip 這些基礎工具,直到有一個完美的解決方案出現。或者,也可以選擇試試新東西,然後嘗試改進它,讓完美的解決方案早一點出現。
(2)
原標題是「相比 Pipenv,Poetry 是一個更好的選擇嗎?」