[初心者向け] Poetry入門!インストール方法から使い方、コマンド、パッケージの管理方法まで徹底解説

## Poetryとは？
公式に記載されている通り、PoetryはPythonのパッケージを管理するツールです
Poetryを使うことでパッケージとその関連性のあるパッケージをPoetry側でバージョンに合わせてアップデートしたりインストールしてくれるのでとても便利です
PoetryでインストールしたパッケージはVirtualenv内にあるのでパッケージ関連のコマンドを実行するときはPoetry経由で実行します(後述)

> Poetry is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. Poetry offers a lockfile to ensure repeatable installs, and can build your project for distribution.

## Poetryのインストール
公式に記載されている下記のコマンドを実行しましょう
```terminal:terminal
curl -sSL https://install.python-poetry.org | python3 -
```
すると以下のように表示されます
```terminal:terminal
curl -sSL https://install.python-poetry.org | python3 -
Retrieving Poetry metadata

# Welcome to Poetry!

This will download and install the latest version of Poetry,
a dependency and package manager for Python.

It will add the `poetry` command to Poetry's bin directory, located at:

/Users/<ユーザ名>/.local/bin

You can uninstall at any time by executing this script with the --uninstall option,
and these changes will be reverted.

Installing Poetry (1.2.0): Done

Poetry (1.2.0) is installed now. Great!

To get started you need Poetry's bin directory (/Users/<ユーザ名>/.local/bin) in your `PATH`
environment variable.

Add `export PATH="/Users/<ユーザ名>/.local/bin:$PATH"` to your shell configuration file.

Alternatively, you can call Poetry explicitly with `/Users/<ユーザ名>/.local/bin/poetry`.

You can test that everything is set up by executing:

`poetry --version`
```

以下のコマンドを実行します
```terminal:terminal
export PATH="/Users/<ユーザ名>/.local/bin:$PATH"
```

実行した後に.zshrcに以下を記載します
```.zshrc
export PATH="$HOME/.local/bin:$PATH"
```
一度exitでターミナルを閉じ、再起動した後に
```terminal:terminal
poetry --version
```
と入力し、バージョンが出ると成功です！
```terminal:terminal
Poetry (version 1.2.1)
```

## oh-my-zsh
oh-my-zshにpoetryのプラグインを入れるとタブによるコマンド補完が充実します
まずは以下のコマンドを入力します
```terminal:terminal
mkdir $ZSH_CUSTOM/plugins/poetry
poetry completions zsh > $ZSH_CUSTOM/plugins/poetry/_poetry
```

.zshrcのpluginsにpoetryを記載します
```zsh:.zshrc
plugins(
	poetry
	...
	)
```

追加した後にpoetryと打った後にタブを押すとコマンドの候補と説明が記載されているのでみやすくなります
![スクリーンショット 2022-10-07 16.59.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/625980/8ebd6cb3-dec9-6045-ce3b-b6b20e0d2f39.png)

## 主なコマンド
ここでは主なコマンドを列挙していきます
### プロジェクトの新規作成
```terminal:terminal
poetry new
```

### 既存プロジェクトにPoetryを導入
```terminal:terminal
poetry init
```
を実行すると既存プロジェクトでPoetryを使用できます
例えばDjangoだと[tool.poetry]のnameにプロジェクト名を指定しないとプログラムが動かないので注意が必要です

```pyproject.toml
[tool.poetry]
name = "<プロジェクト名>"
version = "0.0.1"
description = ""
authors = ["shun198 <メールアドレス>"]
readme = "README.md"
```

## pyproject.tomlとpoetry.lock
Poetryを使ってパッケージをインストールしたりアップデートした際は
- pyproject.toml
- poetry.lock

に記載されます

## Poetryのコマンド一覧
### パッケージを追加
```text:terminal
poetry add　<パッケージ名>
```
パッケージを指定してインストールすると関連パッケージも一緒にインストールされます
```terminal:terminal
poetry add redis
Using version ^4.3.4 for redis

Updating dependencies
Resolving dependencies... (0.9s)

Writing lock file

Package operations: 6 installs, 0 updates, 0 removals

  • Installing pyparsing (3.0.9)
  • Installing wrapt (1.14.1)
  • Installing async-timeout (4.0.2)
  • Installing deprecated (1.2.13)
  • Installing packaging (21.3)
  • Installing redis (4.3.4)
```

#### 本番環境用と開発環境用でインストールするバッケージを分ける
Poetryでは以下のようにグループ別でインストールするパッケージを分けることができます
普段私は
- Pytest関連のもの
- formatter
- django-debug-toolbarなどデバッグ用

などのパッケージはdevという開発環境用のグループに配置しています
```pyproject.toml
[tool.poetry.dependencies]
python = "^3.10"
Django = "^4.1.2"
djangorestframework = "^3.14.0"
drf-spectacular = "^0.24.2"
mysqlclient = "^2.1.1"
gunicorn = "^20.1.0"
drf-nested-routers = "^0.93.4"
celery = "^5.2.7"
django-celery-beat = "^2.4.0"
redis = "^4.3.4"
django-cors-headers = "^3.13.0"
Authlib = "^1.1.0"
django-filter = "^22.1"
boto3 = "^1.26.22"
django-ses = "^3.2.2"
django-storages = "^1.13.1"

[tool.poetry.group.dev.dependencies]
pytest = "^7.1.3"
pytest-cov = "^4.0.0"
pytest-django = "^4.5.2"
pytest-sugar = "^0.9.6"
pytest-xdist = "^3.0.2"
django-debug-toolbar = "^3.8.1"
pytest-custom-exit-code = "^0.3.0"
pytest-html = "^3.2.0"
allure-pytest = "^2.12.0"
black = "^22.10.0"
isort = "^5.11.4"
django-extensions = "^3.2.1"
```

#### 特定のグループにパッケージをインストールするとき
```text:terminal
poetry add <パッケージ名> --group <グループ名>
```

今回は`pylint-django`を開発環境用であるdevグループに入れてみます
```terminal:terminal
poetry add pylint-django --group dev
```

すると、以下のように`pylint-django`がdevグループにインストールされます
```pyproject.toml
[tool.poetry.group.dev.dependencies]
pylint-django = "^2.5.3"
```

また、`[tool.poetry.group.dev.dependencies]`の下に直接dev用のパッケージを記載することもできます

### パッケージのインストール
デフォルトでは全てのパッケージをインストールします
```terminal:terminal
poetry install
```

また、グループ別でインストールすることもできます

#### 特定のグループのみインストールするとき
```text:terminal
poetry install --only <グループ名>
```

以下のように複数パッケージを指定することもできます
```text:terminal
poetry install --only test,docs
```

#### 特定のグループを除いてパッケージをインストールするとき
```text:terminal
poetry install --without <グループ名>
```

例えばStg環境、Prd環境では`Pytest`や`django-debug-toolbar`などテストやデバッグ用のパッケージはいらないかと思います
テストやデバッグ用のパッケージを`dev`グループに入れてdev以外のパッケージを入れるといった使い方もできます
```text:terminal
poetry install --without dev
```

### パッケージをアップデート
```text:terminal
poetry update <パッケージ名>
```

### パッケージを削除
```text:terminal
poetry remove <パッケージ名>
```

また、pyproject.tomlからパッケージを直接消しても削除できます

### poetry自身をアップデート
```terminal:terminal
poetry self update
```

## Poetry経由でコマンドを実行
```text:terminal
poetry run <コマンド>
```
DjangoなどのWebフレームワークを使う際はPoetryのPath内のPython経由でコマンドを実行する必要があるので`poetry run`と打ってからコマンドを打つ必要があります
```terminal:terminal
poetry run python manage.py makemigrations
```

## パッケージの一覧・バージョン・詳細を表示
### 一覧表示
```terminal:terminal
poetry show
```
を実行するとインストールされているパッケージの一覧が表示されます
```terminal:terminal
Django              4.1.2  A high-level Python web framework that encourages rapid development and clean, pragmatic design.
djangorestframework 3.14.0 Web APIs for Django, made easy.
drf-nested-routers  0.93.4 Nested resources for the Django Rest Framework
```

### 詳細表示
パッケージ名を指定すると詳細表示されます
```text:terminal
poetry show <パッケージ名>
```
```terminal:terminal
poetry show gunicorn
 name         : gunicorn                  
 version      : 20.1.0                    
 description  : WSGI HTTP Server for UNIX 

dependencies
 - setuptools >=3.0
```

## poetry.lockとpyproject.tomlの同期
poetry.lockとpyproject.tomlが対応するよう更新
```terminal:terminal
poetry lock
```

## PoetryのPATHの確認
```terminal:terminal
poetry env info
```
を実行するとローカルとVirtualenv内のPythonのPATHが確認できます
コンテナ内にリモートデバッグする際はPythonのインタプリンタをPoetryのパスに指定しないと動かないので私はこのコマンドをよく使います

```terminal:terminal
Virtualenv
Python:         3.10.5
Implementation: CPython
Path:           /Users/shun/Library/Caches/pypoetry/virtualenvs/api-vJJX1F0w-py3.10
Executable:     /Users/shun/Library/Caches/pypoetry/virtualenvs/api-vJJX1F0w-py3.10/bin/python
Valid:          True

System
Platform:   darwin
OS:         posix
Python:     3.10.5
Path:       /Users/shun/.pyenv/versions/3.10.5
Executable: /Users/shun/.pyenv/versions/3.10.5/bin/python3.10
```
リモートデバッグについて興味のある方は以下の記事も読んでくださると幸いです

https://qiita.com/shun198/items/9e4fcb4479385217c323

## 各パッケージに必要な設定を全てpyproject.tomlに集約させよう！
例えばPytestのオプションはpytest.iniに記載していましたが、pyproject.tomlにも記載できます
いろんなパッケージをインストールするたびに専用のファイルを作成してオプションを記載するより
pyproject.tomlに集約すると管理が楽で便利です

### Black
```pyproject.toml
[tool.black]
line-length = 79
include = '\.py$'
exclude = '''
(
  /(
      \.eggs         # exclude a few common directories in the
    | \.git          # root of the project
    | \.hg
    | \.mypy_cache
    | \.tox
    | \.venv
    | _build
    | buck-out
    | build
    | dist
  )/
)
'''
```

### Isort
Blackと一緒に使うと競合してしまうため、ImportのフォーマットはBlackを優先するよう設定します
また、Blackを実行してからIsortを実行してしまうとBlackで1行79文字以下で設定していてもimportをソートする際に79文字を超えてソートしてしまうため、isortにも設定を適用します

```pyproject.toml
[tool.isort]
line_length = 79
profile = "black"
```

https://pycqa.github.io/isort/docs/configuration/options.html

### Pytest
```pyproject.toml
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "project.settings"
addopts = "-v -s --durations=0"
```
addoptsを使う際はオプションをダブルクォーテーションを囲ってください
また、`pytest-django`を使う際は`DJANGO_SETTINGS_MODULE`という環境変数を使う必要があるのでこちらに記載することもできます

## その他設定
### package-mode
プロジェクトをsdistやwheelにパッケージ化し、公開するかどうかの設定です
package-modeはデフォルトでtrueなのでPoetryをパッケージ管理でのみ使用したい場合は下記のようにpackage-modeをfalseにできます

```
[tool.poetry]
package-mode = false
```

https://python-poetry.org/docs/basic-usage/#operating-modes

Poetryのバージョン2.0.0からは以下のエラーが表示され、poetry installコマンド自体が失敗してしまうので注意が必要です
下記のエラーを解消させるには先ほど説明したpackage-modeをfalseにする必要があります

```
Warning: The current project could not be installed: No file/folder found for package XXXXXXXXXX
```

詳細はエムスリーさんのテックブログに記載されています

https://www.m3tech.blog/entry/2025/01/09/110000

## まとめ
思ってた以上にPoetryは使うと便利ですし実際の現場でも使ってる会社は多いので使い方や原理をある程度知る必要があります
(Dockerはrequirements.txt推しですが。)
その他コマンドは公式ドキュメントを参照してください

## 参考
https://github.com/python-poetry/poetry

https://python-poetry.org/docs/#installing-with-the-official-installer