RareJob Tech Blog

レアジョブテクノロジーズのエンジニア・デザイナーによる技術ブログです

Flake8, autoflake, Black, isort を Ruff へ置き換える際に行ったこと

はじめに

  • EdTech Lab の中島です。 英語スピーキングテスト PROGOS の機械学習モデル開発・改善などを担当しています。
  • Python プロジェクトで利用していた Linter・Formatter ( Flake8, autoflake, Black, isort ) を Ruff に置き換えることで実行時間を約41%~79%短縮することができました。
  • 以下では使用した環境と Ruff の概要について記載し、その後 Flake8, autoflake, Black, isort を Ruff へ置き換える際に行った内容を説明します。

環境

  • Python 3.9.10
  • Poetry 1.8.3
  • Ruff 0.8.2
  • 使用していた Linter, Formatter
    • Flake8 3.9.2 (静的解析のために使用)
    • autoflake 1.7.8 (未使用の import, 変数を削除するために使用)
    • Black 24.8.0 (Formatter として使用)
    • isort 5.13.2 (import をソートするために使用)

Ruff について

  • GitHub には以下のような特徴が挙げられています。
    • Rust で書かれた高速な Linter 兼 Formatter です。
    • 単一の共通インターフェースの下でより多くの機能を統合しながら、他の代替ツールと比べて桁違いに高速であることを目指しています。
    • URL先のように多数のオープンソースプロジェクトで使用されています。

Flake8, autoflake を Ruff へ置き換える際に行ったこと

  • Flake8, autoflake と Ruff Linter について
    • The Ruff Linter には以下の記載があり、Flake8, autoflake を置き換え可能であることが説明されています。

      The Ruff Linter is an extremely fast Python linter designed as a drop-in replacement for Flake8 (plus dozens of plugins), isort, pydocstyle, pyupgrade, autoflake, and more.

設定ファイル変更内容

  • setup.cfg に記載されていた Flake8 の設定を pyproject.toml へ移行しました。
  • Ruff は pyproject.toml 以外にも、.ruff.toml, ruff.toml に設定を記述することができます。より詳細な説明は URL 先 をご参照ください。

    元の setup.cfg 変更前設定内容

# 元の setup.cfg 変更前設定内容

[flake8]
max-line-length = 119
ignore = E121,E123,E126,E133,E226,E241,E242,E704,W503,W504,W505,E127,E266,E402,W605,W391,E701,E731,E203
exclude = ./path/to/exclude/folder/*

pyproject.toml 変更内容

# pyproject.toml

[tool.ruff]
target-version = "py39"
line-length = 119
extend-exclude = ["./path/to/exclude/folder/*"]


[tool.ruff.lint]
# https://docs.astral.sh/ruff/rules/
select = [
"E", # "E" pycodestyle error
"F", # "F" Pyflakes
"W", # "W" pycodestyle warning
]

ignore = ["E203", "E226", "E241", "E242", "E266", "E402", "W391", "W505", "W605", "E701", "E731"]
extend-safe-fixes = ["F841"]

pyproject.toml の設定内容詳細

  • section 毎に記載します。
  • URL 先は関連する Ruff のドキュメントです。
[tool.ruff]
  • target-version
    • プロジェクトで使用していた Python 3.9 を指定しています。
  • line-length
    • 長い行の違反(例: E501)を検出する際や後述する isort や Formatter が行を折り返す際に用いる長さです。プロジェクトで使用していた 119 を指定しています。
  • extend-exclude
    • exclude に加えてフォーマットやリントから除外するファイルパターンのリストです。プロジェクトで使用していた Flake8 の設定に含まれていたフォルダを指定しています。
[tool.ruff.lint]
  • select
    • Flake8 が wrap している中から Pyflakes, pycodestyle error, pycodestyle warning を指定しました。( McCabe はプロジェクトで使用していなかったため指定していません。)
  • ignore
    • setup.cfg の ignore のうち Ruff で実装されているものを指定しました。
  • extend-safe-fixes
    • Ruff が安全でないとみなしている修正を安全なものとして許可するルールを設定可能です。
    • 使用していた autoflake のオプション --remove-unused-variables と同様の挙動にするため F841 (unused-variable) を追加しました。

Makefile 変更内容

check1: 
-    @poetry run flake8 ./path/to/check1/target
+    @poetry run ruff check ./path/to/check1/target

 check2
-    @poetry run autoflake --remove-all-unused-imports --remove-unused-variables --in-place --recursive .path/to/check2/target 
+    @poetry run ruff check --fix .path/to/check2/target
  • Ruff Linter は ruff check command によって実行することができます。
  • flake8ruff check で置き換えました。
  • autoflake を利用している箇所を ruff check --fix で置き換えました。

Black を Ruff へ置き換える際に行ったこと

  • Black と Ruff Formatter について
    • Black compatibility には The formatter is designed to be a drop-in replacement for Black. との記載があり ruff format を実行することで Black 相当の format を実行することが可能です。( 詳細ドキュメント )
    • Black と Ruff Formatter 間の差異については Known Deviations from Black に記載があります。

設定ファイル変更内容

pyproject.toml 変更内容

# pyproject.toml

[tool.ruff]
target-version = "py39"
line-length = 119
extend-exclude = ["./path/to/exclude/folder/*"]


[tool.ruff.lint]
# https://docs.astral.sh/ruff/rules/
select = [
"E", # "E" pycodestyle error
"F", # "F" Pyflakes
"W", # "W" pycodestyle warning
]

ignore = ["E203", "E226", "E241", "E242", "E266", "E402", "W391", "W505", "W605", "E701", "E731"]

+ [tool.ruff.format]
+ quote-style = "double"

pyproject.toml の設定内容詳細

[tool.ruff.format]
  • quote-style に Black で利用している "double" を指定しました。

Makefile 変更内容

 format-check: 
-    @poetry run black --check --diff --line-length 119 .path/to/format/target
+    @poetry run ruff format --check --diff .path/to/format/target

 format:
-    @poetry run black --line-length 119 .path/to/format/target
+    @poetry run ruff format .path/to/format/target

isort を Ruff へ置き換える際に行ったこと

設定ファイル変更内容

  • 変更前の isort の設定には Ruff のドキュメントに置き換え可能と記載があった profile = "black" を使用していました。

    pyproject.toml 変更内容

# pyproject.toml

[tool.ruff]
target-version = "py39"
line-length = 119
extend-exclude = ["./path/to/exclude/folder/*"]


[tool.ruff.lint]
# https://docs.astral.sh/ruff/rules/
select = [
"E", # "E" pycodestyle error
"F", # "F" Pyflakes
+ "I", # "I" isort
"W", # "W" pycodestyle warning
]

ignore = ["E203", "E226", "E241", "E242", "E266", "E402", "W391", "W505", "W605", "E701", "E731"]
extend-safe-fixes = ["F841"]

[tool.ruff.format]
quote-style = "double"

pyproject.toml の設定内容詳細

[tool.ruff.lint]
  • isort を利用するために select へ "I" を追加しました。

Makefile 変更内容

 format2
-    @poetry  run isort .path/to/isort/target
+    @poetry run ruff check --fix .path/to/isort/target && poetry run ruff format .path/to/isort/target
  • ドキュメントの以下の引用箇所のように isort 利用箇所は2つのコマンドruff check --fixruff format で置き換える必要があります。

    Sorting imports Currently, the Ruff formatter does not sort imports. In order to both sort imports and format, call the Ruff linter and then the formatter:

実行時間比較

  • time コマンドを使用して実行時間を比較しました。
ツール 変更前 (秒) 変更後 (秒) 短縮率
Flake8 → Ruff 3.14 0.69 79%
Black → Ruff 1.79 0.67 62%
autoflake → Ruff 1.53 0.55 64%
isort → Ruff 1.78 1.04 41%

最後に

お知らせ

  • 弊社では URL 先の職種を募集しています。ご応募お待ちしております。

rarejob-tech.co.jp