VSCode + rye + Ruff で雑に整えるPython開発環境

# 導入
Pythonは導入だけで言えば非常に簡単な言語です。公式のインストーラを入れるもよし、`brew install python`などするもよしでしょう。パッケージを入れたくなったら`pip install ...`だけで済みますし、そしてコンパイルの必要もありません。

が、いざチームで開発したり、リポジトリをcloneすると吸収しきれないOSの違い・Pythonバージョンの差異・依存パッケージのバージョンの差異などなどで困らされることも少なくありません。

というわけで私は書き捨てのコードを書く以上の目的で使いづらいという印象が拭えずにいたのですが、いつの間にかすごいツールが現れてPythonの開発環境は以前より格段に整えやすくなっていました。

# 想定読者
* MacOSのプリインストールPythonや、Pythonの仮想環境を大量に作りすぎて困ったことがある人[^1]
* 複数のプロジェクトでPythonを使う時Pythonやパッケージのバージョンで困ったことがある人
* `venv`, `poetry`, `pyenv`, `Anaconda`などなどに遭遇して頭がパンクしたことがある人
* 久々にPython触ってツールを選択しようとしている人
* Curious Cat

# TL;DR
* ryeはPython周りで面倒なことを全部やってくれます
	* Pythonのバージョン管理
	* Python仮想環境の生成
	* 依存ライブラリの管理
* Ruffは高速なPython用Linter/Formatter

# rye
## ryeとは
[rye](https://github.com/mitsuhiko/rye) とは、[Flask](https://github.com/pallets/flask)などの開発者として知られるArmin Ronacher氏が開発した`one-stop-shop`ツールです。
これまでPythonでは複数のツールを組み合わせて管理していた以下の管理をまとめてやってくれます(これが`one-stop-shop`と呼ばれている理由です)
* Pythonのインストール管理
* `pyproject.toml`の管理
* 依存のインストール／アンインストール
* 仮想環境の管理

:::note info
プロジェクトが公開されるに至った経緯は
[Should rye Exist?](https://github.com/mitsuhiko/rye/discussions/6)に**熱く**記されています。暇な時に読んでみてください。
:::


## インストール

shが動く環境では
```sh
curl -sSf https://rye-up.com/get | bash
```

Windowsにはバイナリが用意されています。
また、homebrewからもインストール出来ました。
```sh
brew install rye
```

## 基本的な操作
### プロジェクトの新規作成
新規のプロジェクトを作る場合は`init`コマンドを呼び出します。
以下、プロジェクト名は`hello_rye_ruff`で進めていきます。

```sh
~ % rye init hello_rye_ruff
```

`pyproject.toml`などなど、↓のようなフォルダが出来上がります。
```
hello_rye_ruff % git ls-files --exclude-standard -o | tree --fromfile
.
├── .gitignore
├── .python-version
├── README.md
├── pyproject.toml
└── src
    └── hello_rye_ruff
        └── __init__.py
```

:::note info
`requirements.txt`が既存のプロジェクトを取り込みたい場合、`-r`オプションで指定してあげると、`pyproject.toml`に取り込んでくれます。他にもオプションが数多くあります。
```sh
rye init -r requirements.txt
```
:::

### 仮想環境の作成
`init`が済んだら、次は`sync`を実行しましょう。
プロジェクトフォルダ内に`.venv`が生成され、仮想環境が生成されます。
作成した仮想環境には`rye shell`で入ることができます。
```sh
hello_rye_ruff % rye shell 
Spawning virtualenv shell from /<path>/hello_rye_ruff/.venv
Leave shell with 'exit'
```

:::note info
カレントディレクトリが`pyproject.toml`を含むディレクトリの配下でない場合は仮想環境に入れません。
```sh
~ % rye shell
error: did not find pyproject.toml
```
:::

### 依存パッケージの管理
プロジェクトで使用したい依存パッケージは`pyproject.toml`で管理します。
ryeでは、`pyproject.toml`を下のコマンドで操作することができます。
```sh
rye add # パッケージの追加
rye remove # パッケージの削除
```
`rye sync`することで、依存を解決した`requirements.lock`・`requirements-dev.lock`を自動生成します。

### Pythonバージョンの固定
もしプロジェクトでPythonのバージョンを固定したい場合は`rye pin`を使います。

:::note warn
デフォルトの場合、OSプリインストールのPythonになっている場合があります（特にMacOSでは注意が必要です）。これを回避したい場合、pinしておく方が良いでしょう。
:::

```sh
rye pin 3.12
```
のようにバージョンを引数に設定すると、バージョンファイルが書き換えられます。
```text:.python-version
3.12.0
```
`rye sync`をした後に仮想環境に入るとpythonのバージョンは指定したバージョンになっています。
```sh
hello_rye_ruff % rye shell
Spawning virtualenv shell from /<path>/hello_rye_ruff/.venv
Leave shell with 'exit'
hello_rye_ruff % python --version
Python 3.12.0
```

# Ruff
## Ruffとは
Ruffは、Rust製Linter/Formatterです。
LintとFormatの両方を持っており、超高速を謳っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210706/3604f788-ccee-926b-91a2-be717c28e75c.png)
[GitHub](https://github.com/astral-sh/ruff)のreadmeより。

Linterに`Flake8`、Formatterに`Black`を、といった構成などは少なからず見てきましたが、こちらもRuffで将来的にまとめられそうです。
GitHub Starsは既に21kStarsに達しています。

## インストール
RuffはCLI/各種エディターのプラグイン/GitHub Actionsに対応しています。
が、ここでは開発環境向けにCLI/VSCode拡張に絞って紹介します。

### CLI インストール
`homebrew`、`pacman`などからインストールが可能です。
```sh
brew install ruff
```
`pip`からもインストール可能なので、当然`rye`経由でもインストールできます。
```sh
rye install ruff
```

### VSCode　拡張機能
Ruffには[VSCode用の拡張機能](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff)が用意されています。
これを入れるだけです。簡単ですね。

## Lintルールの設定
設定は`pyproject.toml`もしくは`ruff.toml`に記載していきます。
デフォルトでも設定値があるので、あまり多くを設定する必要はないかもしれません。
全ては記述しきれないので頻繁に使うものだけ下に紹介します。

```toml:pyproject.toml
# Lint/Formatter非依存のルール
[tool.ruff]
# 除外したいファイル
# excludeを設定するとデフォルトで設定されている.venv配下などの設定が上書きされるため要注意
extend-exclude = ["src/something.py"]
# 行文字数
line-length = 88
# インデント幅
indent-width = 4

# Linterのルール
[tool.ruff.lint]
# Lintルール
# https://docs.astral.sh/ruff/rules/　に記載されているルールのうち、Codeが前方一致するルールが適用されます
select = ["E", "F", "I", "PLR"]
# 除外するLintルール
# selectで選択したルールから除外したいものを指定できます
ignore = ["PLR2004"]
# auto fixの対象にするルール
fixable = ["ALL"]
# auto fixから除外するルール
# editor.formatOnSaveを使う際に自動でFixされると困るものを指定できます
unfixable = ["F401"]

# Formatterのルール
[tool.ruff.format]
# 文字列をダブルクォートに統一
quote-style = "double"
# インデントをタブ文字(\t)からスペースに変換
indent-style = "space"
```

Ruffは豊富な設定と`pycodestyle`/`pyflakes`/`isort`など**700以上**のルールに対応しています。
設定する際は[Settings](https://docs.astral.sh/ruff/settings/)と[Rules](https://docs.astral.sh/ruff/rules/)を見るようにしましょう。

## VSCodeの設定
後は保存時にRuffを実行するようにすれば、設定された内容でLint/Formatが自動で実行されます。
```json
{
    "[python]": {
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.formatOnSave": true,
    }
}
```

# あとがき

以前は開発環境整える作業でカロリーを消費しがちだったPython開発ですが、ryeとRuffの登場によって非常に快適な構築ができました。同じような経験をしてきた人が少しでも楽な開発環境を組む一助になれば幸いです。

[^1]: 筆者がこの記事を書いた理由は先日MacOSのプリインストールPythonに痛い目に遭わされたからです。