Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

從零開始使用 Poetry

出處: https://blog.kyomind.tw/python-poetry/

本文所有的參考資料會放在文末的「參考」一欄中,不過在此還是要特別提及主要的參考對象,總共有二:

如果在本文找不到你需要的內容,以上二處可能會有,所以主動列出。

另外本文主要以 macOS 和 Linux(Ubuntu)環境來進行安裝及教學,Windows 用戶如果有無法順利安裝的情況,建議參考官方文件內容修正。不過,即使有問題,應該也是集中在安裝與設定階段,本文其餘部分仍可適用。

安裝 Poetry

Poetry 和 pip、git、pyenv 等工具一樣,都是典型的命令列工具,需要先安裝才能下達指令——poetry。

安裝方式選擇

Poetry 主要提供了兩種安裝方式:

  1. 全域安裝至使用者的家目錄。
  2. pip 安裝至專案使用的 Python(虛擬)環境,即pip install poetry。

個人推薦使用全域安裝,官方文件也表示不推薦使用 pip 安裝。

因為 pip 安裝是直接安裝到「專案所屬的 Python 虛擬環境」裡,而 Poetry 所依賴的套件非常多,總計超過 30 個,會嚴重影響專案虛擬環境的整潔度。文件中也警告這些依賴套件可能和專案本身的套件發生衝突:

Be aware that it will also install Poetry’s dependencies which might cause conflicts with other packages.

全域安裝 Poetry 至家目錄

所以我們就使用全域安裝吧!

macOS / Linux / WSL(Windows Subsystem for Linux)

curl -sSL https://install.python-poetry.org | python3 -

或

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -

Windows

(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | python -

Poetry 實際安裝路徑如下:

The installer installs the poetry tool to Poetry’s bin directory. This location depends on your system:

  • $HOME/.local/bin for Unix
  • %APPDATA%\Python\Scripts on Windows

以 macOS 為例,如果要下poetry指令,就需要打完整路徑$HOME/.local/bin/poetry,顯然不太方便,所以我們需要設定 PATH。

設定 PATH

新增poetry指令執行檔所在的路徑至 PATH。

在.zshrc或.bashrc或.bash_profile新增:

export PATH=$PATH:$HOME/.local/bin

存檔後重啟 shell 即可使用。直接在命令列打上poetry指令測試:

❯ poetry
Poetry version 1.1.13

USAGE
  poetry [-h] [-q] [-v [<...>]] [-V] [--ansi] [--no-ansi] [-n] <command> [<arg1>] ... [<argN>]

...

設定 alias

比起pip,poetry這個指令實在太冗長了!我們還是給它一個 alias 吧!

基於它是我極為常用的指令,我願意賦與它**「單字母」的 alias 特權**,我使用p:

alias p='poetry'

測試結果:

❯ p
Poetry version 1.1.13

USAGE
  poetry [-h] [-q] [-v [<...>]] [-V] [--ansi] [--no-ansi] [-n] <command> [<arg1>] ... [<argN>]

alias 是方便自己使用,但本文基於表達清晰考量,下面的解說除了圖片外,原則上並不會使用 alias 表示。


初始化 Poetry 專案

為了方便解說,我們先建立一個全新的專案,名為poetry-demo。

指令都很簡單,但還是建議可以一步一步跟著操作。

就像 git 專案需要初始化,Poetry 也需要,因為每一個使用了 Poetry 的專案中一定要有一個pyproject.toml作為它的設定檔。否則直接使用poetry相關指令就會出現下列錯誤訊息:

Poetry could not find a pyproject.toml file in {cwd} or its parents

所以一定先初始化,使用poetry init:

mkdir poetry-demo
cd poetry-demo
poetry init

此時會跳出一連串的互動對話,協助你建立專案的資料,大部分可以直接enter跳過:

This command will guide you through creating your pyproject.toml config.

Package name [poetry-demo]:
Version [0.1.0]:
Description []:
Author [kyo <odinxp@gmail.com>, n to skip]:
License []:
Compatible Python versions [^3.8]:

Would you like to define your main dependencies interactively? (yes/no) [yes]

直到出現「Would you like to define your main dependencies interactively? (yes/no) [yes]」,我們先選擇「no」後,會讓你確認本次產生的toml檔內容:

Would you like to define your development dependencies interactively? (yes/no) [yes] no
Generated file

[tool.poetry]
name = "poetry-demo"
version = "0.1.0"
description = ""
authors = ["kyo <odinxp@gmail.com>"]

[tool.poetry.dependencies]
python = "^3.8"

[tool.poetry.dev-dependencies]

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

並詢問你「Do you confirm generation? (yes/no) [yes]」,按enter使用預設選項「yes」或直接回答「yes」,則pyproject.toml建立完成。

此時專案目錄結構如下:

poetry-demo
└── pyproject.toml

0 directories, 1 file

管理 Poetry 虛擬環境

我覺得學習 Poetry 的第一道關卡,就是它對於虛擬環境的管理。

「強制」虛擬環境

Poetry 預設上(可透過poetry config修改)會強制套件都要安裝在虛擬環境中,以免汙染全域,所以它整合了virtualenv。

所以在執行poetry add、install等指令時,Poetry 都會自動檢查當下是否正在使用虛擬環境:

  • 如果是,則會直接安裝套件至當前的虛擬環境。
  • 如果否,則會自動幫你建立一個新的虛擬環境,再進行套件安裝。

容易混淆的虛擬環境

Poetry 主動納入虛擬環境管理算是立意良善,相當於把pip+venv兩者的功能直接整合在一起,但也帶來一定的複雜度,尤其在你已經自行使用了venv、virtualenv或 pyenv-virtualenv或conda等工具來管理虛擬環境的情況下!

沒錯,Python 的虛擬環境管理就是這麼麻煩!

個人建議,對新手而言,於 Poetry 的專案中,一律使用 Poetry 來管理虛擬環境即可。我目前也是這樣,省得麻煩。

以指令建立虛擬環境

使用指令poetry env use python:

❯ poetry env use python
Creating virtualenv poetry-demo-IEWSZKSE-py3.8 in /Users/kyo/Library/Caches/pypoetry/virtualenvs
Using virtualenv: /Users/kyo/Library/Caches/pypoetry/virtualenvs/poetry-demo-IEWSZKSE-py3.8

可以看出 Poetry 為我們建立了名為poetry-demo-IEWSZKSE-py3.8的虛擬環境。

重點說明

  • poetry env use python建立虛擬環境所使用的 Python 版本,取決於python指令在你的 PATH 是連結到哪個版本。同理,你也可以將指令明示為use python3或use python3.8,只要這些指令確實存在 PATH 中。
  • 預設上,Poetry 會統一將虛擬環境建立在「特定目錄」裡,比如本例中存放的路徑是/Users/kyo/Library/Caches/pypoetry/virtualenvs。
  • 虛擬環境的命名模式為專案名稱-亂數-Python版本。

老實說我個人不是很喜歡這樣的做法,因為這意味著單一專案允許建立複數個虛擬環境(比如 Python 3.7、3.8、3.9 可以各來一個),彈性之餘也增加了混亂的可能,而且這命名模式我也不太欣賞,顯得過於僵化且冗長。

既然 Python 的虛擬環境理論上都是高度綁定專案本身的,我更偏好venv式的做法,也就是把虛擬環境放到專案目錄內,而非統一放在獨立的目錄,讓虛擬環境與專案呈現直觀的一對一關係。

所幸,Poetry 具備這樣的選項。


修改config,建立專案內的.venv虛擬環境

我們先使用poetry config指令來查看 Poetry 目前幾個主要的設定,需要--list這個參數:

❯ poetry config --list
cache-dir = "/Users/kyo/Library/Caches/pypoetry"
experimental.new-installer = true
installer.parallel = true
virtualenvs.create = true
virtualenvs.in-project = false
virtualenvs.path = "{cache-dir}/virtualenvs"

其中virtualenvs.create = true若改成false,則可以停止 Poetry 在「偵測不到虛擬環境時會自行建立」的行為模式,但建議還是不要更動。

而virtualenvs.in-project = false就是我們要修改的目標,使用指令:

poetry config virtualenvs.in-project true

好,我們先把之前建立的虛擬環境刪除:

❯ poetry env remove python
Deleted virtualenv: /Users/kyo/Library/Caches/pypoetry/virtualenvs/poetry-demo-IEWSZKSE-py3.8

重新建立,看看行為有何差異:

❯ poetry env use python
Creating virtualenv poetry-demo in /Users/kyo/Documents/code/poetry-demo/.venv
Using virtualenv: /Users/kyo/Documents/code/poetry-demo/.venv

可以看出:

  • 虛擬環境的路徑改為「專案的根目錄」。
  • 名稱固定為.venv。

我覺得這樣的設定更加簡潔。

啟動與退出虛擬環境

啟動虛擬環境,需移至專案目錄底下,使用指令poetry shell:

❯ poetry shell
Spawning shell within /Users/kyo/Documents/code/poetry-demo/.venv
❯ . /Users/kyo/Documents/code/poetry-demo/.venv/bin/activate

poetry shell指令會偵測當前目錄或所屬上層目錄是否存在pyproject.toml來確定所要啟動的虛擬環境,所以如果不移至專案目錄,則會出現下列錯誤:

❯ poetry shell

  RuntimeError

  Poetry could not find a pyproject.toml file in /Users/kyo/Documents/code or its parents

  at ~/Library/Application Support/pypoetry/venv/lib/python3.8/site-packages/poetry/core/factory.py:369 in locate
      365│             if poetry_file.exists():
      366│                 return poetry_file
      367│
      368│         else:
    → 369│             raise RuntimeError(
      370│                 "Poetry could not find a pyproject.toml file in {} or its parents".format(
      371│                     cwd
      372│                 )
      373│             )

可以看到,Poetry 的錯誤訊息非常清楚,讓你很容易知曉修正的方向,這是作為一個優秀命令列工具的必要條件。

退出就簡單多了,只需要exit即可。


Poetry 常用指令

Poetry 是一個獨立的命令列工具,就像 pyenv,它有自己的指令,需要花費額外的心力學習,且較 pip 更加複雜,這可能是使用 Poetry 的第二道關卡。好在常用的指令,其實也不超過 10 個,下面就來一一介紹。

在此我們繼續使用前面提過的 Flask 和 Black 套件,來示範並說明 Poetry 的優勢以及它和 pip 的不同之處。

Poetry 新增套件

使用指令:

poetry add

相當於pip install,我們來試著安裝 Flask 看看會有什麼變化:

img

圖中可以看出 Poetry 漂亮的命令列資訊呈現,會清楚告知總共新增了幾個套件。

此時專案中的pyproject.toml也會發生變化:

...
[tool.poetry.dependencies]
python = "^3.8"
Flask = "^2.1.1"  # 新增部分

[tool.poetry.dev-dependencies]

[build-system]
...

這裡要說明,安裝 Flask,則pyproject.toml就只會新增記載Flask = "^2.1.1"這個 top-level 的 package 項目,其餘的依賴套件不會直接記錄在toml檔中。

我覺得這是一大優點,方便區分哪些是你主動安裝的主要套件,而哪些又是基於套件的依賴關係而一併安裝的依賴套件。

poetry.lock 與更新順序

除了更新pyproject.toml,此時專案中還會新增一個檔案,名為poetry.lock,它實際上就相當於 pip 的requirements.txt,詳細記載了所有安裝的套件與版本。

當你使用poetry add指令時,Poetry 會自動依序幫你做完這三件事:

  1. 更新pyproject.toml。
  2. 依照pyproject.toml的內容,更新poetry.lock。
  3. 依照poetry.lock的內容,更新虛擬環境。

由此可見,poetry.lock的內容是取決於pyproject.toml,但兩者並不會自己連動,一定要基於特定指令才會進行同步與更新,poetry add就是一個典型案例。

此時專案目錄結構如下:

poetry-demo
├── poetry.lock
└── pyproject.toml

0 directories, 2 files

更新 poetry.lock

當你自行修改了pyproject.toml內容,比如變更特定套件的版本(這是有可能的,尤其在手動處理版本衝突的時候),此時poetry.lock的內容與pyproject.toml出現了「脫鉤」,必須讓它依照新的pyproject.toml內容更新、同步,使用指令:

poetry lock

如此一來,才能確保手動修改的內容,也更新到poetry.lock中,畢竟虛擬環境如果要重新建立,是基於poetry.lock的內容來安裝套件,而非pyproject.toml。

還是那句話:poetry.lock相當於 Poetry 的requirements.txt。


安裝套件至 dev-dependencies

有些套件,比如pytest、flake8等等,只會在開發環境中使用,產品的部署環境並不需要。

Poetry 允許你區分這兩者,將上述的套件安裝至dev-dependencies區塊,方便讓你輕鬆建立一份「不包含」dev-dependencies開發套件的安裝清單。

在此以 Black 為例,安裝方式如下:

poetry add black -D

或

poetry add black --dev

結果的區別顯示在pyproject.toml裡:

...
[tool.poetry.dependencies]
python = "^3.8"
Flask = "^2.1.1"

[tool.poetry.dev-dependencies]
black = "^22.3.0"
...

可以看到black被列在不同區塊:tool.poetry.dev-dependencies。

強烈建議:善用 dev-dependencies

善用-D參數,明確區分開發環境專用的套件,我認為非常必要。

首先,這些套件常常屬於「檢測型」工具,相關的依賴套件著實不少!比如flake8,它依賴了pycodestyle、pyflakes、mccabe等等,還有black、pre-commit,依賴套件數量也都很可觀。

其次,既然它們都只在開發階段才需要,則完全可以從部署環境中缺席。如果不分青紅皂白一律安裝到dependencies區塊,部署環境容易顯得過於臃腫。

常見的dev-dependencies區塊項目,例示如下:

[tool.poetry.dev-dependencies]
flake8 = "4.0.1"
yapf = "0.32.0"
pytest = "7.1.2"
pytest-django = "4.5.2"
pytest-cov = "3.0.0"
pytest-env = "0.6.2"
pytest-sugar = "0.9.4"
pre-commit = "2.20.0"

列出全部套件清單

類似pip list,這裡要使用poetry show:

❯ poetry show
black              22.3.0 The uncompromising code formatter.
click              8.1.3  Composable command line interface toolkit
flask              2.1.2  A simple framework for building complex web applications.
importlib-metadata 4.11.4 Read metadata from Python packages
itsdangerous       2.1.2  Safely pass data to untrusted environments and back.
jinja2             3.1.2  A very fast and expressive template engine.
markupsafe         2.1.1  Safely add untrusted strings to HTML/XML markup.
mypy-extensions    0.4.3  Experimental type system extensions for programs checked...
pathspec           0.9.0  Utility library for gitignore style pattern matching of ...
platformdirs       2.5.2  A small Python module for determining appropriate platfo...
...

特別提醒的是,這裡的清單內容並不是來自於虛擬環境,這點和 pip 不同,而是來自於poetry.lock的內容。

你可能會想,來自於poetry.lock或虛擬環境,有差嗎?兩者不是應該要一致?

沒錯,理論上是,但也有不一致的時候,比如你使用了pip install指令安裝套件,就不會記載在poetry.lock中,那poetry show自然也不會顯示。

「樹狀」顯示套件依賴層級

Poetry 最為人津津樂道的就是它的樹狀顯示——poetry show --tree。

❯ poetry show --tree
flask 2.1.1 A simple framework for building complex web applications.
├── click >=8.0
│   └── colorama *
├── importlib-metadata >=3.6.0
│   └── zipp >=0.5
├── itsdangerous >=2.0
├── jinja2 >=3.0
│   └── markupsafe >=2.0
└── werkzeug >=2.0
black 22.3.0 The uncompromising code formatter.
├── click >=8.0.0
│   └── colorama *
├── mypy-extensions >=0.4.3
├── pathspec >=0.9.0
├── platformdirs >=2
├── tomli >=1.1.0
└── typing-extensions >=3.10.0.0

讓主要套件與其依賴套件的關係與層次,一目瞭然。

而且很貼心的是,它也可以**只顯示「指定套件」**的依賴層級,以celery為例:

❯ poetry show celery --tree
celery 4.4.0 Distributed Task Queue.
├── billiard >=3.6.1,<4.0
├── kombu >=4.6.7,<4.7
│   ├── amqp >=2.6.0,<2.7
│   │   └── vine >=1.1.3,<5.0.0a1
│   └── importlib-metadata >=0.18
│       ├── typing-extensions >=3.6.4
│       └── zipp >=0.5
├── pytz >0.0-dev
└── vine 1.3.0

Poetry 移除套件

使用poetry remove指令。和poetry add一樣,可以加上-D參數來移除置於開發區的套件。

而移除套件時的「依賴解析(相依性管理)」能力,正是 Poetry 遠優於 pip 的主要環節,因為 pip 沒有嘛!也是我提議改用 Poetry 的關鍵理由——為了順利移除套件。

前面已經提過,pip 的pip uninstall只會移除你所指定的套件,而不會連同依賴套件一起移除。

這是基於安全考量,因為 pip 沒有「依賴解析」功能。如果貿然移除所有「安裝時一併安裝」的依賴套件,可能會造成巨大災難,讓別的套件失去效用。

前面也舉了 Flask 和 Black 都共同依賴click這個套件的例子,在手動移除套件的情況下,你可能未曾注意 Black 也依賴了click,結果為了「徹底移除」Flask 的所有相關套件,不小心把click也移除掉了。

所以,使用 pip 時,我們鮮少會去移除已經不再使用的套件。畢竟依賴關係錯綜複雜,移除套件可能造成許多「副作用」,實在是太麻煩了。

poetry remove的依賴解析

好,解釋了很多,接下來就是 Poetry 的表演了,它會幫你處理這些棘手的「套件相依性」難題,讓你輕鬆移除 Flask 而不影響 Black:

poetry remove flaskpoetry remove flask

可以對比上面安裝 Flask 時的截圖,那時總共安裝了 8 個套件,但現在移除的卻只有 7 個——沒錯,因為有依賴解析,Poetry 知道 Black 還需要click!所以不能移除:

❯ poetry show --tree
black 22.3.0 The uncompromising code formatter.
├── click >=8.0.0
│   └── colorama *
├── mypy-extensions >=0.4.3
├── pathspec >=0.9.0
├── platformdirs >=2
├── tomli >=1.1.0
└── typing-extensions >=3.10.0.0

一個套件直到環境中的其餘套件都不再依賴它,Poetry 才會安心讓它被移除。


輸出 Poetry 虛擬環境的 requirements.txt

理論上,全面改用 Poetry 後,專案中是不需要存在requirements.txt,因為它的角色已經完全被poetry.lock所取代。

但事實是,你可能還是需要它,甚至希望它隨著poetry.lock的內容更新!至少對我而言就是如此,我在 Docker 部署環境中並不使用 Poetry,所以我需要一份完全等價於poetry.lock的requirements.txt,用於 Docker 部署。

你可能想說,那我就在 Poetry 的虛擬環境下,使用以往熟悉的指令pip freeze > requirements.txt來產生一份就可以了吧?我本來也是這麼想,但實際的產出卻是如此:(提醒:目前 poetry-demo 專案中僅剩下 Black 和它的依賴套件)

black @ file:///Users/kyo/Library/Caches/pypoetry/artifacts/11/4c/fc/cd6d885e9f5be135b161e365b11312cff5920d7574c8446833d7a9b1a3/black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl
click @ file:///Users/kyo/Library/Caches/pypoetry/artifacts/f0/23/09/b13d61d1fa8b3cd7c26f67505638d55002e7105849de4c4432c28e1c0d/click-8.1.2-py3-none-any.whl
mypy-extensions @ file:///Users/kyo/Library/Caches/pypoetry/artifacts/b6/a0/b0/a5dc9acd6fd12aba308634f21bb7cf0571448f20848797d7ecb327aa12/mypy_extensions-0.4.3-py2.py3-none-any.whl
...

這呈現好像不是我們以前熟悉的那樣:

black==22.3.0
click==8.1.2
mypy_extensions==0.4.3
...

沒錯,只要是使用poetry add安裝的套件,在pip freeze就會變成這樣。此時想輸出類似requirements.txt的格式,需要使用poetry export。

預設的輸出結果會有 hash 值,很乾擾閱讀。不想納入 hash 則要加上參數去除。以下就是我固定用來輸出requirements.txt的指令與參數:

poetry export -f requirements.txt -o requirements.txt --without-hashes

2022/08/24補充:網友提醒,hash 有其價值,並建議保留,詳見留言區。

我們再看一下輸出結果,雖然不盡相同,但也相去不遠了……嗎?等等,怎麼是空白?

輸出 dev-dependencies

因為poetry export預設只會輸出toml中的[tool.poetry.dependencies]區塊的套件!還記得上面我們把 Black 安裝到[tool.poetry.dev-dependencies]了嗎?

顯然 Poetry 認為你 export 基本上就為了部署,並不需要開發區的套件。

這倒是沒錯,不過基於演示需求,我們必須輸出[tool.poetry.dev-dependencies]的套件,才能看到 Black。

加上--dev參數即可:

poetry export -f requirements.txt -o requirements.txt --without-hashes --dev

輸出的requirements.txt內容:

black==22.3.0; python_full_version >= "3.6.2"
click==8.1.2; python_version >= "3.7" and python_full_version >= "3.6.2"
colorama==0.4.4; python_version >= "3.7" and python_full_version >= "3.6.2" and platform_system == "Windows"
...

雖然長得有點不一樣,但這個檔案確實是可以pip install的。

從這裡也可以看出先前一再提及「區分開發、部署套件」的價值——大部分時候我們並不需要輸出開發用套件。

poetry export所有參數用法與說明,請參考文件。

此時專案目錄結構如下:

poetry-demo
├── poetry.lock
├── pyproject.toml
└── requirements.txt

0 directories, 3 files

Poetry 常用指令清單

算來算去,Poetry 的常用指令主要有下面幾個:

  • poetry add
  • poetry remove
  • poetry export
  • poetry env use
  • poetry shell
  • poetry show
  • poetry init
  • poetry install

其中一半,單一專案可能只會用個一兩次而已,比如init、install和env use,實際上需要學習的指令並不多。

那麼,只要知曉這些指令,就可以順利運用 Poetry 了嗎?可能是,也可能否,所以我下面還會再補充 Poetry 的常見使用情境與操作方式,讓你接納 Poetry 的阻力可以進一步下降!


Poetry 常見使用情境與操作 QA

這部分會以「使用場景」的角度切入,介紹 Poetry 應用情境與操作說明,還包括一些自問自答:

  1. 新增專案並使用 Poetry
  2. 現有專案改用 Poetry
  3. 在別臺主機回復專案狀態
  4. 我想要重建虛擬環境
  5. 為什麼我不在 Docker 環境中使用 Poetry?
  6. 我可以使用自己習慣的 virtualenv 嗎?

一、新增專案並使用 Poetry

這是最理想的狀態,沒有過去的「包袱」,可謂是最能輕鬆採用 Poetry 的情境。

使用順序不外乎是:

  1. poetry init:初始化,建立pyproject.toml。
  2. poetry env use python:建立專案虛擬環境並使用。
  3. poetry shell:進入專案但虛擬環境還未啟動,以這個指令啟動。如果使用本指令時虛擬環境尚未建立或已移除,則會直接自動幫你建立虛擬環境並使用。
  4. poetry add:新增套件並寫入虛擬環境。必要時使用-D參數新增至 dev 區塊。
  5. poetry remove:移除套件,若是移除 dev 區塊的套件,需要加上-D參數。

這部分和前面內容沒有差別,因為前面內容就是以全新專案作為基礎。

二、現有專案改用 Poetry

極為常見的需求,但並沒有很正式的做法,因為不存在poetry import之類的指令。

首先要考量的就是:要怎麼把requirements.txt的所有項目加到pyproject.toml中呢?經過一番 Google,基本上只能土法煉鋼:

cat requirements.txt | xargs poetry add

然而這樣做是有可能遇到一些問題的,因為 Poetry 對套件的版本衝突比較敏感,所以即便用pip install -r requirements.txt都能正常安裝,透過上述指令的遷移過程卻仍有機會出現錯誤。

那怎麼辦?只能照著錯誤訊息手動修正requirements.txt中的套件版本。

只能說這個「手動 import」做法實在是不得已,因為我們最早介紹pyproject.toml時有提到,poetry add只會在pyproject.toml中寫入「主套件」,但這樣的 import 方式相當於把requirements.txt中的所有套件,都當作主套件來add了!

畢竟在requirements.txt中無從區分主套件與依賴套件,都是「一視同仁」地列出。

但如此做法也讓專案的套件失去主從之分,這樣會有什麼壞處?日後要移除主套件時,需要花額外的心力去區分主從(因為僅僅移除依賴套件並不會有移除效果),比如使用poetry show --tree去一個一個檢視,終究是件麻煩事。

完成轉換後,為保險起見,建議透過新的pyproject.toml來重建一個虛擬環境。

三、在別臺主機上重現專案的 Poetry 虛擬環境

這也是非常常見的需求。

第一步當然是git clone專案,此時專案中已經有 Poetry 所需的必要資訊了——也就是pyproject.toml和poetry.lock。

你還缺少的僅僅是虛擬環境。如果是全新的主機,則還得先安裝、設定好 Poetry。

確定 Poetry 可正常使用後,移至專案目錄底下,依序執行指令:

  1. poetry env use python:建立專案虛擬環境並使用。如果你懶得打這麼長的指令,直接poetry shell也是可以。此時我們會有一個「空的」虛擬環境。
  2. poetry install:因為是舊專案,不需要init,會直接依poetry.lock記載的套件版本安裝到虛擬環境中!類似npm install。

四、我想要重建虛擬環境

在使用專案內虛擬環境方案,也就是.venv的前提下,想要刪除這個虛擬環境並加以重建,也不需要使用poetry env remove python指令了,因為會出錯。

還有更簡單暴力的方式,是什麼呢?——直接刪除.venv資料夾即可。

然後再poetry env use python或poetry shell建一個新的就好。

五、為什麼我不在 Docker 環境中使用 Poetry?

因為啟動容器後需要先安裝 Poetry 到全域,或打包一個帶有 Poetry 的 image,兩者都會增加新的耦合與依賴,我覺得並不妥當。

所幸 Poetry 依舊可以輸出requirements.txt,Docker 部署環境就繼續使用這個舊方案即可,而且 Poetry 本來主要就是用於「開發」時的套件管理,對部署差別不大。

六、我可以使用自己習慣的 virtualenv 嗎?

當然可以。

不過我本來也繼續使用pyenv的virtualenv,但兩者有時候也是會小小打架,後來還是索性用 Poetry 的虛擬環境就好。

一個專案對應一個虛擬環境,應該還是比較簡潔的做法,我的觀察啦!😎


結語:井然有序的複雜

總的來說,Poetry 是一款優秀的套件管理工具,但並不像 pip 那般簡單、好上手。

使用 Poetry 來管理專案的套件與虛擬環境,需要一定的學習成本,但帶來的效益還是相當可觀的,尤其在你希望能夠乾淨且安心地移除套件之際,可謂莫它莫屬。

所以,別再猶豫,從今天起,加入 Poetry 的行列吧!