Pyenv+Poetry+VS Codeを使って、Windowsで複数Pythonの開発環境を構築

## はじめに

Windows環境で、同時に複数Djangoアプリを異なるPythonバージョンで開発する必要がありました。
Pyenv+Poetry+VS Codeを使って複数Django開発環境を構築した際の手順を共有します。

## Pyenvとは

- pythonのバージョン管理が可能な仮想環境
    - プロジェクト毎に環境を切り替えることが可能
- [Window版Pyenvのリポジトリ](https://github.com/pyenv-win/pyenv-win)

## Poetryとは

- 複数パッケージを管理するためのツール
    - パッケージ管理に必要なコマンド一式を備えていて、パッケージのビルドや公開を簡単に行える
- [Poetryのリポジトリ](https://github.com/python-poetry/poetry)

## VS Code(Visual Studio Code)とは

- ソースコードエディタで以下の機能を提供
    - デバッグ、埋め込みGitコントロール、シンタックスハイライト
    - インテリジェントなコード補完 、スニペット、コードリファクタリング

## 環境構築手順

### 前提

- 手順では、作業ディレクトリとして`C:\work`を使用します
- コマンドは、VS CodeのPowerShellターミナルで実行します

### Pythonをインストール

- [Pythonインストーラ](https://www.python.org/ftp/python)
    - 必要なPythonバージョンをダウンロード
        - 手順では、[Python 3.9.6](https://www.python.org/ftp/python/3.9.6/python-3.9.6-amd64.exe)をダウンロード

- [インストール手順](https://docs.python.org/ja/3/using/windows.html#installation-steps)
    - インストーラを起動し、画面下部の`Add Python 3.9 to PATH`にチェックを入れる
    - `Install Now`をクリック
    - 最後のステップで、`MAX_PATHの制限を除去`をクリックし実施

- Pythonバージョン確認

```powershell
PS C:\work> python -V
Python 3.9.6
```

### Pyenvをインストール

- [pyenv-winインストール手順](https://github.com/pyenv-win/pyenv-win#power-shell)

```powershell
PS C:\work> Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"
```

- 環境変数`PYENV`,`PYENV_HOME`、`PYENV_ROOT`を追加

```powershell
PS C:\work> [System.Environment]::SetEnvironmentVariable('PYENV',$env:USERPROFILE + "\.pyenv\pyenv-win\","User")
PS C:\work> [System.Environment]::SetEnvironmentVariable('PYENV_ROOT',$env:USERPROFILE + "\.pyenv\pyenv-win\","User")
PS C:\work> [System.Environment]::SetEnvironmentVariable('PYENV_HOME',$env:USERPROFILE + "\.pyenv\pyenv-win\","User")
```

- ユーザーの`PATH`環境変数にpyenvのパスを追加

```powershell
PS C:\work> [System.Environment]::SetEnvironmentVariable('path', $env:USERPROFILE + "\.pyenv\pyenv-win\bin;" + $env:USERPROFILE + "\.pyenv\pyenv-win\shims;" + [System.Environment]::GetEnvironmentVariable('path', "User"),"User")
```

- pyenvのバージョン確認

```powershell
PS C:\work> pyenv --version
pyenv 3.0
```

- VS Code PowerShellを閉じる

### プロジェクトのローカルPythonバージョンをインストール

- VS Code PowerShellを開き、プロジェクトディレクトリに移動

```powershell
PS C:\work> cd project
```

- PyenvがPythonバージョンをサポートしているか確認

```powershell
PS C:\work\project> pyenv install -l | findstr 3.9.6
3.9.6-win32
3.9.6
```

- Pythonをインストール

```powershell
PS C:\work\project> pyenv install 3.9.6
```

- Pythonのローカルバージョンを指定

```powershell
PS C:\work\project> pyenv local 3.9.6
```

- Pyenvで指定されたPythonバージョンを確認
    - Pythonバージョンが二つ存在、指定されたのは3.9.6

```powershell
PS C:\work\project> pyenv versions
  3.10.5
* 3.9.6 (set by C:\work\project\.python-version)
```

- projectディレクトリで使用されるPythonのバージョン確認

```powershell
PS C:\work\project> python -V 
Python 3.9.6
```

### Poetryをインストール

- [Poetryインストール手順](https://python-poetry.org/docs/master/#installing-with-the-official-installer)

```powershell
PS C:\work\project> (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python
```

- PowerShellを再起動し、Poetryバージョン確認

```powershell
PS C:\work\project> poetry --version
Poetry version 1.1.13
```

- プロジェクトの依存関係を統括する`pyproject.toml`を作成

```powershell
PS C:\work\project> poetry init -n
```

- `poetry.lock`に記載されたパッケージをインストール

```
PS C:\work\project> poetry install
```

- 仮想環境のShell起動

```powershell
PS C:\work\project> poetry shell
... ...
C:\work\project> python -V
Python 3.9.6
```

### Djangoをインストール

- Poetry仮想環境にDjangoをインストール

```powershell
C:\work\project> poetry add django
```

- Djangoのバージョン確認

```powershell
C:\work\project> poetry show django
name         : django
version      : 4.0.5
description  : A high-level Python web framework that encourages rapid development and clean,       
            pragmatic design.

dependencies
 - asgiref >=3.4.1,<4
 - sqlparse >=0.2.2
 - tzdata *
```

## おわりに

Windowsで、複数Pythonバージョンで開発可能な環境構築手順でした。
ご参考になればうれしいです。