Open13

Python Rye+Black+Ruff+pytestによるVS Codeの開発環境構築

3w36zj63w36zj6

Black (Formatter)

https://github.com/psf/black

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

rye add --dev black

Blackのフォーマットの設定をpyproject.tomlに追加する。以下はデフォルトの行の長さが短いので120に変更している。

pyproject.toml
[tool.black]
line-length = 120

実行は以下のコマンド。

black ./src/

VS Codeでは.vscode/settings.jsonに以下を追加することで保存時にフォーマットされる。

.vscode/settings.json
{
  "editor.formatOnSave": true,
  "[python]": {
    "editor.defaultFormatter": "ms-python.black-formatter"
  },
  "black-formatter.importStrategy": "fromEnvironment"
}
3w36zj63w36zj6

Ruff (Linter)

https://github.com/astral-sh/ruff

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

Installation

rye add --dev ruff

Usage

checkは省略可。--fixで修正が入る。

ruff check .                        # Lint all files in the current directory (and any subdirectories)
ruff check path/to/code/            # Lint all files in `/path/to/code` (and any subdirectories)
ruff check path/to/code/*.py        # Lint all `.py` files in `/path/to/code`
ruff check path/to/code/to/file.py  # Lint `file.py`

Configuration

pyproject.tomlに対応しているのでそこに書く。

pyproject.toml
[tool.ruff]
line-length = 120
select = ["ALL"]
ignore = ["EXE", "T20", "E501", "D203", "D212"]

[tool.ruff.pydocstyle]
convention = "google"

ルールは以下から確認。

https://beta.ruff.rs/docs/rules/

厳しくしたいのであればselect = ["ALL"]としておいて不要なものだけignoreで指定するとよい。

VS Codeでは.vscode/settings.jsonに以下を追加することで保存時にフォーマットされる。

.vscode/settings.json
{
  "[python]": {
    "editor.codeActionsOnSave": {
      "source.fixAll.ruff": true,
      "source.organizeImports.ruff": true
    }
  }
}
3w36zj63w36zj6

pytest (Testing Framework)

テスト用。

https://github.com/pytest-dev/pytest

rye add --dev pytest

実行は以下のコマンド。

pytest ./tests/

VS Codeでは.vscode/settings.jsonに以下を追加することでテストを実行できる。

.vscode/settings.json
{
  "python.testing.pytestArgs": ["tests"], // ./tests/にテストファイルを入れる
  "python.testing.unittestEnabled": false,
  "python.testing.pytestEnabled": true,
}
3w36zj63w36zj6

Mypy (Type Checker)

型チェック用。Pylanceで使われているPyrightはこれだけnpmから入れる必要があり管理が煩わしいので、CLIではPyPIで入るこちらを使う。

https://github.com/python/mypy

RuffではMypyを完全に置き換えることはできない。詳細は以下を参照。

https://beta.ruff.rs/docs/faq/#how-does-ruff-compare-to-mypy-or-pyright-or-pyre

rye add --dev mypy
pyproject.toml
[tool.mypy]
strict = true # 好みで

実行は以下のコマンド。

mypy ./src/
3w36zj63w36zj6

VS Code Extension

以下の拡張機能を入れる。

.vscode/extensions.json
{
  "recommendations": [
    "ms-python.python",
    "ms-python.black-formatter",
    "ms-python.mypy-type-checker",
    "ms-python.vscode-pylance",
    "charliermarsh.ruff",
    "njpwerner.autodocstring"
  ]
}

Python

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

Pylance

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

Black

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

Mypy

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

Ruff

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

autoDocstring - Python Docstring Generator

Docstringの生成用。

https://marketplace.visualstudio.com/items?itemName=njpwerner.autodocstring

3w36zj63w36zj6

Python Project

フォーマットやリントやテストを簡単に行えるようにpyproject.tomlにスクリプトを追加する。

testpython -m pytestなのはimport src.xxxをできるようにするため。

pyproject.toml
[tool.rye.scripts]
format = { chain = ["black src", "ruff check --fix src"] }
lint = { chain = ["black --check src", "ruff check src", "mypy src"] }
test = { chain = ["python -m pytest tests"] }

実行にはrye runを使用する。

3w36zj63w36zj6

GitHub Actions (CI/CD)

Pull Requestを開いた際にLintとTestを行うため、以下の.github/workflows/check-pull-request.ymlを作成する。

初回のみcargo installに時間がかかるが2回目からは高速に動く。

.github/workflows/check-pull-request.yml
name: Check Pull Request

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  check-pull-request:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          ref: ${{ github.head_ref }}
      - name: Install Rye
        uses: baptiste0928/cargo-install@v2
        with:
          crate: rye
          git: https://github.com/mitsuhiko/rye
          branch: main
      - name: Install Dependencies
        run: rye sync
      - name: Lint
        run: rye run lint
      - name: Test
        run: rye run test
3w36zj63w36zj6

EditorConfig

https://editorconfig.org

.editorconfig
root = true

[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8

[*.py]
indent_style = space
indent_size = 4