【Python】Poetryのpyproject.tomlについて

業務でPoetryを使っています。
Poetryを使うにあたり色々調べたのでメモとして整理しておきます。

## Poetryとは
PoetryとはPythonの依存関係やパッケージの管理ツール。
- [python-poetry.org](https://python-poetry.org/)

`pyproject.toml`に依存関係を記述することで簡単にパッケージ管理ができます。

## pyproject.tomlとは
`pyproject.toml`はTOML形式で記載されており、`poetry new`や`poetry init`した際に自動で出力されます。

```python:pyproject.toml
[tool.poetry]
name = "poetry-demo"
version = "0.1.0"
description = ""
authors = ["Sébastien Eustace <sebastien@eustace.io>"]
readme = "README.md"
packages = [{include = "poetry_demo"}]

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

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
```
- [参考：TOML(Tom's Obvious Minimal Language)](https://toml.io/en/)

依存関係は`tool.poetry.dependencies`セクションで定義し、`パッケージ名 = バージョン制約`で記載します。

```python:pyproject.toml
[tool.poetry.dependencies]
python = "^3.11"
```
依存関係は`pyproject.toml`に直接もしくはコマンドで追加することができます。
（コマンドでの追加は下記のように実行）

```
$ poetry add パッケージ名
```

- [参考：The pyproject.toml file](https://python-poetry.org/docs/pyproject/#dependencies-and-dependency-groups)

## バージョン制約について
`pyproject.toml`に記載する`バージョン制約`は「セマンティックバージョニング」を前提とした指定を行います。

:::note info
セマンティックバージョニングとは、ソフトウェアのバージョンをどう管理するかのルールで、バージョン番号を`major:minor:patch`形式で表す仕様のことです。
- major：互換性のない変更を行った場合にインクリメント
- minor：下位互換性のある方法で機能を追加した場合にインクリメント
- patch：下位互換性のあるバグ修正を行った場合にインクリメント
- [参考：Semantic Versioning 2.0.0](https://semver.org/)
:::

例えば、`pyproject.toml`の`バージョン制約`として下記のようにいろいろな指定が可能となります。
| バージョン制約 | 許可されるバージョン | 説明 |
|:-:|:-:|:-|
| ^1.2.3  | >=1.2.3 <2.0.0  | minorレベルの変更のみ許可  |
| ～1.2.3  | >=1.2.3 <1.3.0  | patchレベルの変更のみ許可  |
| 1.2.*  | >=1.2.0 <1.3.0  | `*`が配置される最新のバージョンを許可  |
| >= 1.2.0  | >= 1.2.0  | 指定したバージョン範囲を許可  |
| ==1.2.3  | 1.2.3  | 一意のバージョンを許可  |

例えば、`バージョン制約`に`^1.2.3`を指定した場合、ビルド時に`1.2.3 =< バージョン <2.0.0`の範囲内でその時の最新バージョンをダウンロードおよびインストールします。

上記のような指定が可能なため、新しいバージョンが出るたびに`python:pyproject.toml`を変更しなくても良いとういメリットがあります。

- [参考：Dependency specification](https://python-poetry.org/docs/dependency-specification/)


## poetry.lockとは
Poetryには`pyproject.toml`以外にも`poetry.lock`というファイルもあります。

2つのファイルの違いは、以下となります。
- `pyproject.toml`：適用したいライブラリおよびバージョンが記載されたファイル
- `poetry.lock`：現環境に適用されているライブラリおよびバージョンが記載されたファイル

また、ビルド時に参照するファイルについては、下記の条件で判断されます。
1. `poetry.lock`が存在しない場合、`python:pyproject.toml`にリストされている依存関係を解決し、許可されるバージョンをダウンロードします。
1. ダウンロードおよびインストールが完了すると、ダウンロードしたすべてのパッケージとその正確なバージョンが`poetry.lock`に書き込まれます。

そのため、`pyproject.toml`に`^3.11`と書いた場合、その時にインストールされたバージョンが何なのかは`poetry.lock`を見ればわかるようになっています。

また、使用しているパッケージの最新バージョンが公開されるなど、ビルドするタイミングによってはメンバーによっては使っているバージョンが異なってしまう可能性もでてきます。

それだと困るので、`poetry.lock`ファイルを出力し、`poetry.lock`がある場合は`poetry.lock`を先に見にいくようになっています。

このような仕様となっているので`poetry.lock`をバージョン管理下にすることで、メンバー全員が同じバージョンのパッケージを使って開発ができるようにすることが推奨されています。

## 依存関係グループについて
最後に、Poetryでは依存関係をグループ別に整理することができる。
依存関係のグループを宣言するには`tool.poetry.group.<group>`セクションを使用します。

このグループはあくまでラベル的な扱いで論理的に依存関係を整理するためのものとなります。

```
[tool.poetry.dependencies]
python = "^3.11"
pydantic = "^1.10.7"
spectree = "^1.1.2"

[tool.poetry.group.dev.dependencies]
pytest = "^7.3.1"
ruff = "^0.0.261"
black = "^23.3.0"
```
- [参考：dependencies and dependency groups](https://python-poetry.org/docs/pyproject/#dependencies-and-dependency-groups)


以上です。