VSCodeでのPython開発環境構築：仮想環境、型チェック、リンター、フォーマッター、pre-commitを設定する



## はじめに
この記事では、Pythonの依存関係管理ツールであるPoetryを使ったプロジェクトの構築から、Jupyterの設定、型チェック、リンター及びフォーマッター、pre-commit 設定の流れを紹介します。


## 主な流れ

1. Poetryのインストールと構築
2. Jupyterのインストールと実行
3. Pyrightの型チェックを有効にする
4. Ruffの設定
5. pre-commitの設定


## Poetryとは


Poetryは、Pythonのパッケージ管理,依存関係解決を扱うツールです。
さらにパッケージの公開なども行える高機能なツールです。
Poetryは仮想環境(venv)を作成して各ライブラリをインストールするため、プロジェクトごとに使用するライブラリを分けられます。

pipとvenvでも同じようなことができますが、requirements.txtへの追加忘れなどが発生する可能性があります。

またPoetryと同じようなツールとしてPipenvがあります。
Pipenvも仮想環境と依存関係解決の両方を提供します

主な違い
- 依存関係解決速度がpipenvと比べて早い
- pyproject.tomlが使える
- パッケージの公開を行う機能がある

基本的にPoetryの方が多機能で高速という認識でいいかなと思います。

PoetryとPipenvの比較参考

https://python.land/virtual-environments/python-poetry#:~:text=Poetry%20commands-,Poetry%20vs%20Pipenv,-Although%20I%E2%80%99ve%20written

https://vaaaaaanquish.hatenablog.com/entry/2021/03/29/221715



Poetryのインストール
```sh
brew install poetry
```

任意のディレクトリを作って移動します
```
mkdir 任意名前
cd 任意の名前
```

プロジェクトを作成します。
基本全部enterで大丈夫です。
```sh
poetry init
```

完了するとpyproject.tomlが作成されます。
pyproject.tomlは、Pythonプロジェクトの依存関係、ビルドシステム、ツール設定を一元管理するための設定ファイルです。
```toml:pyproject.toml
[tool.poetry]
name = "python-env"
version = "0.1.0"
description = ""
authors = ["beyond-toyama"]
readme = "README.md"

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


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



次に仮想環境が作られる場所を変更します。
デフォルトだと`~/.cache/pypoetry/virtualenvs`に仮想環境が構築されてしまうのでプロジェクト直下に作成されるように設定します。
```sh
poetry config --local virtualenvs.in-project true
```

例としてnumpyとmatplotlibをプロジェクトの依存関係として追加します。
```
poetry add numpy matplotlib 
```

するとpyproject.tomlが更新されます。
```toml:pyproject.toml
[tool.poetry.dependencies]
python = "^3.12"
numpy = "^1.26.4"
matplotlib = "^3.8.4"
```



仮想環境のシェルに切り替わります。
```
poetry shell
```

numpyとmatplotlibが存在するか確認できます。
```
pip3 list
```

コマンド結果
```
❯ pip3 list                                                                                                                                                      ─╯
Package         Version
--------------- -----------
contourpy       1.2.1
cycler          0.12.1
fonttools       4.51.0
kiwisolver      1.4.5
matplotlib      3.9.0
numpy           1.26.4
packaging       24.0
pillow          10.3.0
pip             24.0
pyparsing       3.1.2
python-dateutil 2.9.0.post0
six             1.16.0
```

仮想環境から抜けます。
```
exit
```

## VSCodeの設定と実行
VSCodeにPython拡張機能をインストールします。
これを入れるとPylance,Pythonデバッガーの二つの拡張機能がインストールされます。

https://marketplace.visualstudio.com/items?itemName=ms-python.python

インタープリターの選択をします。
Cmd+Shift+Pでコマンドパレットを開き、Python: Select Interpreterを選択。
![スクリーンショット 2024-05-16 21.41.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662481/ec37f4c6-1f2d-9204-41b4-bfb63a52cbd7.png)

その後.venv:poetryを選ぶ。これで、VSCodeが仮想環境からインポートを探すようになります。
![スクリーンショット 2024-05-16 21.42.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662481/e3370fdd-b23d-72d9-2aa9-6fbaf9de2d88.png)



main.pyを作成
```py:main.py
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y)
plt.show()
```

poetry runを使うと仮想環境内で直接スクリプトを実行できます(便利)。
```
poetry run python3 main.py   
```

実行結果
![](https://storage.googleapis.com/zenn-user-upload/9ed1e373570b-20240505.png)

### Code Runnerと組み合わせる
コードの言語に応じて特定のコマンドを実行できるプラグインです
これを使うと毎回コマンドを打つ手間が減ります

https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner

.vscodeディレクトリにsettings.jsonを作成し以下のようにします。

```json:.vscode/settings.json
{
  "code-runner.executorMap": {
    "python": "poetry run python3 -u",
  }
}
```

コマンドパレットを開き`Run Code`でPythonのコードを実行できます。
ショートカットを当てるともっと便利になります。(自分の環境ではCmd+R)
![スクリーンショット 2024-05-19 10.44.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662481/e59e664c-5945-7270-2634-89ef2ecae7d1.png)



## Jupyterの拡張機能の設定

VSCodeにJupyterの拡張機能を入れます。

https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter

Jupyter Notebookを実行するために開発環境の依存関係にipykernelを追加します。
```
poetry add -D ipykernel
```

pyproject.tomlが更新されます。
```toml:pyproject.toml
[tool.poetry.group.dev.dependencies]
ipykernel = "^6.29.4"
```



main.ipynbを作成
``` py:main.ipynb
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y)
plt.show()
```

コマンドパレットからJupyterのInterpreterを選択します。
![スクリーンショット 2024-05-17 3.10.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662481/c78296b2-f184-e8b2-dd24-4836a95e6a0c.png)

Poetry環境を選択します。
![スクリーンショット 2024-05-17 3.12.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662481/eb52c3aa-6f1b-5f95-8cb7-b253bdad37ad.png)


実行して表示
![](https://storage.googleapis.com/zenn-user-upload/48758575030d-20240505.png)

## Pyrightで型をチェックする
PyrightはMicrosoft製のPythonコード向け静的型チェッカーです。 
実行時にエラーが出ないコードだったとしても、型ヒントに合致しない値が代入される可能性がある場合は警告やエラーを出してくれます。

コードの型チェックの厳密さを設定するtypeCheckingModeにはoff、basic、standard、strictの4種類があります。

違いについては以下を見るといいです。

https://github.com/microsoft/pyright/blob/main/docs/configuration.md#:~:text=src%22%20%7D%0A%5D-,%E8%A8%BA%E6%96%AD%E8%A8%AD%E5%AE%9A%E3%81%AE%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88,-%E5%90%84%E8%A8%BA%E6%96%AD%E8%A8%AD%E5%AE%9A

strictでもいいですが、少し厳しすぎるので個人的にはstandardでもいいと思います。

pyproject.tomlに追記
```toml:pyproject.toml
[tool.pyright]
# settings.jsonにも設定できるがこちらが優先される模様
typeCheckingMode = "standard"
# basePath
venvPath = "."
# basePathから指定する
venv = ".venv"
```

コードを少し変更。
エラーが出ればOK。
Pylanceからエラーが出ていますが、これは拡張機能Pylanceの内部でPyrightが使われている関係でそうなってます。
![](https://storage.googleapis.com/zenn-user-upload/0ce90659d4ae-20240505.png)




## Ruff(リンター、フォーマッター)を設定
2022年8月にリリースされた比較的新しい、Pythonのリンター兼フォーマッターです。
他のツールと比較して高速に動作するのが公式ページで示されています。

![スクリーンショット 2024-05-16 21.50.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662481/8d7e230a-f39f-9490-9871-6edb7bbea701.png)
参照(https://docs.astral.sh/ruff/)





インストール
```
brew install ruff
```

拡張機能を入れます。

https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff

pyproject.tomlに追記
```toml:pyproject.toml
[tool.ruff]
extend-include = ["*.ipynb"]
[tool.ruff.lint]
select = ["ALL"]
# 無視したいルールを書く
ignore = ["D100"]
```

settings.jsonに追記
```json:.vscode/settings.json
  "[python]": {
    "editor.defaultFormatter": "charliermarsh.ruff",
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.fixAll": "explicit",
      "source.organizeImports": "explicit"
    } 
  },
  "notebook.formatOnSave.enabled": true,
  "notebook.codeActionsOnSave": {
    "notebook.source.fixAll": "explicit",
    "notebook.source.organizeImports": "explicit"
  },
```

保存した時にフォーマットとリンターのコードアクションが実行されます。


## pre-commit

コミット前にコードに対してチェックやタスクを実行できるフレームワークです。
今回はコミット前にruffのリントとフォーマット,pyrightを走らせ問題がないかチェックします。

インストール
```
brew install pre-commit
```

git initします

```
git init
```

pre-commit-config.yamlを作成する。
```yaml:.pre-commit-config.yaml
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.4.3
    hooks:
      # Run the linter.
      - id: ruff
        files: '\.(py|ipynb)$'
      # Run the formatter.
      - id: ruff-format
        files: '\.(py|ipynb)$'
  - repo: local
    hooks:
      - id: pyright
        name: pyright
        entry: poetry run pyright
        language: system
        files: '\.(py|ipynb)$'
```


Gitリポジトリにコミットフックをインストールします。
```
pre-commit install
```

仮想環境でPyrightを実行する必要があるので依存関係に追加します。
```
poetry add -D pyright
```

ソースコードにprintを入れます。
```py:main.py
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.sin(x)
print(x)
print(y)
plt.plot(x, y)
plt.show()
```

コミットしようとすると失敗します。
![スクリーンショット 2024-05-16 21.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662481/017ad69e-4aa5-cc00-9379-8cc1e41f3d7a.png)


printを消して再びコミットすると成功します。
![スクリーンショット 2024-05-16 21.37.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662481/71ca7e17-1be1-8c53-0c5e-19ec4e0cdba0.png)


## 終わりに

この記事では、Poetry、Jupyter、Pyright、Ruff、pre-commitを使ったPythonプロジェクトのセットアップ方法を説明しました。これらのツールを活用することで、より効率的にPythonの開発を行えるようになると思います。