Please enable Javascript to view the contents

Python - Poetry

 ·  ☕ 4 min read

前言

最近瀏覽網頁時看到有文章在介紹 Poetry,其中的 pyproject.toml 似乎是未來的趨勢 (PEP 518, PEP 621),就來研究一下。

什麼是 Poetry

根據 Poetry GitHub 說明

Poetry helps you declare, manage and install dependencies of Python projects, ensuring you have the right stack everywhere.

僅支援 Python 3.7+

類似於 pip,能輔助我們進行套件管理,提供了比 pip 強大的功能

  • 套件的追蹤/建置/發布 (Track/Build/Publish)
  • 相依套件解析 (DEPENDENCY RESOLVER)
  • 虛擬環境 (ISOLATION)
  • 直觀的 Poetry 命令 (INTUITIVE CLI)

過往作法與缺陷

我之前是使用 pipenv 作為 Python 的虛擬環境管理工具,但是其對於套件依賴解析上並不是很好

如果需要移除某套件的話,pipenv uninstall 只會移除指定的套件,而與其一同安裝的套件並不會被移除,需要手動移除,但是自己又無法確定是不是有被其他套件依賴,若隨便移除可能會導致其他套件無法正常工作

如同 kyo 在這篇文章所述的情境,如果同時使用到 flaskblack,移除 flask 後再手動移除 click 就會導致 black 無法正常運作

開始使用 Poetry

安裝 Poetry

Linux

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

Windows powershell

1
(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python -
Poetry Installation

Windows 的話會安裝在 %APPDATA%\Python\Scripts,安裝時也會一同設置這個路徑到環境變數 PATH

PPoetry Env:Path

檢查 poetry 版本

1
poetry --version

更新 poetry 版本

1
poetry self update

查看 poetryconfig

1
poetry config --list

其中的 cache-dir 就是透過 poetry 建立虛擬環境時會存放的目錄

如果 virtualenvs.in-project 設置成 true,則會將虛擬環境建立於當前 project 的資料夾內

可以依據個人喜好去設置

1
poetry config virtualenvs.in-project true

然而,目前如果將 in-project 設成 true 的話,在使用命令移除虛擬環境時似乎有 BUG 而無法正常移除,但我們仍然能透過手動刪除資料夾的方式移除虛擬環境

建立 Poetry 專案

建立一個全新的 poetry 專案

1
2
poetry new poetry-demo
cd poetry-demo

此時資料夾內會是

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
poetry-demo
  pyproject.toml
  README.rst

├─poetry_demo
      __init__.py

└─tests
        test_poetry_demo.py
        __init__.py

其中的 pyproject.toml 就是最重要的檔案

此外,如果有已存在的專案,你也可以透過 init 來建立 pyproject.toml

1
2
cd pre-existing-project
poetry init

再來就可以建立虛擬環境

1
2
3
4
5
poetry env use python

# There is a new .venv folder
Creating virtualenv poetry-demo in D:\Projects\Test\Python\poetry-demo\.venv
Using virtualenv: D:\Projects\Test\Python\poetry-demo\.venv

接著啟用虛擬環境 (資料夾內需有 pyproject.toml,否則會報錯)

1
poetry shell

Terminal 有些主題會顯示是否處於虛擬環境

Poetry Shell

也可以使用使用 poetry env info 來取得目前虛擬環境資訊

1
2
3
poetry env info
poetry env info --path  # Get the path to the virtual environment
poetry env list # List all the virtual environments associated with the current project

離開虛擬環境

1
exit

新增套件

使用指令 poetry add 新增套件

1
2
poetry add requests
poetry add flake8 --dev # Install to dev-dependencies
poetry add requests

此時 pyproject.toml 會一併更新

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[tool.poetry]
name = "poetry-demo"
version = "0.1.0"
description = ""
authors = ["JIHONGO <jihongoidv@gmail.com>"]

[tool.poetry.dependencies]
python = "^3.9"
requests = "^2.27.1"    # requests we added just now

[tool.poetry.dev-dependencies]
pytest = "^5.2"

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

從上面可以觀察到,安裝 requests 時也安裝了其他套件,例如 certifi, urllib3 等等,這些都是 requests 的依賴,且不會記錄在 pyproject.toml

這時可以使用 poetry show 命令來觀察套件依賴關係,而這些關係來源自 poetry.lock

1
poetry show --tree
poetry tree

如果要移除套件的話,需要使用 poetry remove 命令

1
poetry remove LIBRARY_NAME

這邊就不演示移除的部分了,可以試試看同時安裝上述提到的 flaskblack 再移除其中一個看看會怎樣

執行

我們可以透過 run 來執行虛擬環境中的命令

例如以下可以列出正在執行的 Python 版本

1
poetry run python -V

再來我們建立一個簡單的程式碼 (main.py)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
poetry-demo
  pyproject.toml
  README.rst

├─poetry_demo
      __init__.py
      main.py  # new script

└─tests
        test_poetry_demo.py
        __init__.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# main.py
import sys


def start(args=sys.argv[1:]):
    print(f"Rinning main.py: start (args: {args})")


def main():
    print("Running main.py: main")


if __name__ == "__main__":
    main()

可以透過 poetry run python 執行

1
2
3
4
poetry run python .\poetry_demo\main.py

# Result
Running main.py: main

也可以透過新增 Script 的方式來執行命令

修改 pyproject.toml,新增 tool.poetry.scripts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
[tool.poetry]
name = "poetry-demo"
version = "0.1.0"
description = ""
authors = ["JIHONGO <jihongoidv@gmail.com>"]

[tool.poetry.dependencies]
python = "^3.9"
requests = "^2.27.1"

[tool.poetry.dev-dependencies]
pytest = "^5.2"
flake8 = "^4.0.1"

# add tool.poetry.scripts
[tool.poetry.scripts]
main = "poetry_demo.main:main"
start = "poetry_demo.main:start"

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

接著就能夠執行這些命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
poetry run main

# Result
Running main.py: main

# Run with args
poetry run start arg1 arg2

# Result
Rinning main.py: start (args: ['arg1', 'arg2'])

輸出 requirements.txt

如果有需求需要把套件輸出成 requirements.txt,可以藉由下面的命令生成

1
poetry export -f requirements.txt --output requirements.txt --without-hashes

常用命令

  • poetry new PROJECT_NAME
  • poetry init
  • poetry env use python
  • poetry shell
  • poetry add LIBRARY_NAME
  • poetry install
  • poetry remove LIBRARY_NAME
  • poetry show --tree
  • poetry export -f requirements.txt --output requirements.txt --without-hashes

結論

poetry 目前版本約 1.1.13,看起來還在陸續優化中,可能還存在潛在 BUG,例如先前提到的 env 無法 remove 的問題,希望之後能夠越來越好。

對我目前來說,可能之後會從 pipenv 轉成使用 poetry,雖然還需要熟悉一下,但是從各方面看來 poetry 似乎是目前的最佳解以及趨勢,當然要來嘗試一下

Reference

分享
您的鼓勵是我最大的動力

JIHONGO
作者
JIHONGO
A Person