Poetryを使ったPython環境のセットアップ手順（2023年2月時点）

※以下の日本語ドキュメントはしばらく更新されていないようで公式ドキュメントとズレが生じているので注意してください

日本語ドキュメント：https://cocoatomo.github.io/poetry-ja/
公式ドキュメント：https://python-poetry.org/

# 概要
Python環境を新たにセットアップする機会があったので備忘として方法をまとめる。

Pythonはバージョンの使い分けやパッケージ管理などでいろんな方法が出回っているが、最近のトレンドはPyenv+Poetryで管理するになっているらしい。

# Pyenv
Pythonを複数バージョン使いわけたい場合に使用する。

他の言語にもrbenvやnodenv、goenvなどがあり、それらをメタ的に管理してくれるanyenvというものがある。
homebrewで直接pyenvをインストールしても良いが、いろんな**envがあるとその都度PATHへの追記管理が手間になってくるので、何も考えなくて良いanyenv経由でインストールすると便利。

```bash
$ brew install anyenv
$ anyenv install --init
$ anyenv install pyenv
```
インストール可能なpythonバージョンを確認する。今回は3.10.4をインストール。

```bash
$ pyenv install -l

Available versions:
  2.1.3
  2.2.3
  2.3.7
  2.4.0
  2.4.1
  2.4.2
  2.4.3
  2.4.4
...
  3.10.4
  3.11.0a6
  3.11-dev
  activepython-2.7.14
  activepython-3.5.4
  activepython-3.6.0
```
```bash
$ pyenv install 3.10.4
```
ローカルで使用するバージョンを3.10.4に指定（.python-versionというテキストファイルが生成される）
```bash
$ pyenv local 3.10.4
$ pyenv versions
  system
* 3.10.4 (set by /Users/xxx/.anyenv/envs/pyenv/version)
```

# Poetry
Poetryは2022年4月現在一番ナウいと思われるPythonのパッケージ管理ツール。
https://python-poetry.org/
pip + virtualenvのような動きをしてくれるので、**プロジェクトごとの閉じた環境内でライブラリを管理することができる。**（pipを単独で使うとグローバルにインストールされてしまうのでローカル環境が汚染されてしまう）
pipと同じくpypiで公開されているライブラリをインストールすることができる。

## インストール（Linux, macOS, Windows (WSL)）
```bash
$ curl -sSL https://install.python-poetry.org | python3 -
$ poetry --version
Poetry version 1.1.13
$ poetry self update
```

PowerShellでのインストール手順は以下を参照
https://python-poetry.org/docs/master/#installing-with-the-official-installer


## 環境構築手順
### プロジェクトを新規に作成する場合
```bash
$ poetry new hello-project
```

### すでにあるプロジェクトをpoetry配下に入れる
いろいろ聞かれるがEnter連打でおk。実行後project.tomlというファイルが生成される。
```
$ poetry init
```

### 仮想環境の作成
poetryで作られる仮想環境も実態はvirtualenvになっている。
デフォルトだと仮想環境は `~/Library/Caches/pypoetry/virtualenvs/` に作られるが、
プロジェクト配下に`.venv`ファイルを作った方が管理しやすい（jupyterを動かす場合は特に）なので以下を実行する。

```bash
$ poetry config --list
cache-dir = "/Users/xxx/Library/Caches/pypoetry"
experimental.new-installer = true
installer.parallel = true
virtualenvs.create = true
virtualenvs.in-project = false
virtualenvs.path = "{cache-dir}/virtualenvs"  # /Users/xxx/Library/Caches/pypoetry/virtualenvs

$ poetry config virtualenvs.in-project true 

$ poetry config --list
cache-dir = "/Users/xxx/Library/Caches/pypoetry"
experimental.new-installer = true
installer.parallel = true
virtualenvs.create = true
virtualenvs.in-project = true
virtualenvs.path = "{cache-dir}/virtualenvs"  # /Users/xxx/Library/Caches/pypoetry/virtualenvs
```
`virtualenvs.in-project = false`が`true`に変わった。

上記を行う前に仮想環境を作ってしまっていた場合、その環境を削除する必要がある。

仮想環境の削除手順
```bash
$ poetry env list
poetry-xx-py3.6

$ poetry env remove poetry-xx-py3.6
```

以下を実行すればプロジェクトでpoetryが使えるようになる。
```bash
$ poetry env use 3.10.4
$ poetry install
```
実行後`poetry.lock`というファイルと`.venv`というフォルダが生成される。
`poetry.lock`は実際にインストールされたライブラリごとのバージョンが記載されたファイル。
`.venv`は仮想環境の実態となるフォルダ。

### ライブラリの追加（インストールとpyproject.tomlへの追記）
`pyproject.toml`はライブラリごとのバージョンを指定するファイル。

```bash
# ライブラリの追加
$ poetry add pandas

# ライブラリの削除
$ poetry remove pandas

# ライブラリのアップデート
# pyproject.tomlに記載されているバージョン指定条件に応じて各ライブラリをアップデートし、その後poetry.lockを更新する
$ poetry update
```

## poetry環境下でのpythonの実行
```bash
$ poetry run python ./main.py
```
都度上記を叩くのが面倒な人はaliasを設定しておくのがおすすめ

```bash
## .zshrc
alias po='poetry run'
alias pp='poetry run python'
```

## poetry環境下でjupyter notebookを動かす
poetryにjupyterを追加する。

```bash
$ poetry add jupyter
```

ノートブックの実行時に求められるカーネル選択で先ほど作成した`.venv`を選択すると上記の手順でpoetryに追加したライブラリたちが入った仮想環境でノートブックを動かすことができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77606/7b372257-c157-b3f1-5fa0-f5569d635891.png)

## requirements.txtに記載されたパッケージを一括でpoetry管理に追加したい場合

```bash
$ cat requirements.txt | xargs poetry add
```


## poetry add がいつまでたっても終わらない場合
2022年4月現在、IPv6がONになっているといつまでも依存関係の解決が終わらない状態になることがあるようです。
https://github.com/python-poetry/poetry/issues/2094
Macではなぜか初期状態ではシステム環境設定からIPv6をオフにすることができないため、以下の手順でオフにします（一度この操作をした後はシステム環境設定からIPv6をオフに切り替えられるようになります）
元に戻す際は
システム環境設定 > Network > Wi-Fi > Advanced > TCP/IP > Configure IPv6 > Automaticallyを選択します。

```bash
# ネットワークの一覧を確認
$ networksetup -listallnetworkservices
An asterisk (*) denotes that a network service is disabled.
USB 10/100/1000 LAN
Wi-Fi
Thunderbolt Bridge
Thunderbolt Bridge 2

# 特定のネットワークのIPv6通信をオフにする
$ networksetup -setv6off Wi-Fi
```


## 参考にさせて頂いた記事
https://qiita.com/sk217/items/43c994640f4843a18dbe
https://qiita.com/ksato9700/items/b893cf1db83605898d8a
https://gumfum.hatenablog.com/entry/2021/01/02/183000