Modernise the dev toolchain with Ruff

Same rules, fewer moving parts

Geschrieben von Timo Rieber am 22. Dezember 2023

For years I used a combination of isort, brunette (a wrapper around black) and Flake8 to lint and format my code with only little changes to their default configuration, held together within setup.cfg:

[flake8]
max-line-length = 79
max-complexity = 6
per-file-ignores =
  src/application/migrations/*.py: C901

[isort]
force_alphabetical_sort_within_sections = true
line_length = 79
lines_after_imports = 2
multi_line_output = 3
no_lines_before = LOCALFOLDER
profile = black

[tool:brunette]
line-length = 79
single-quotes = true
Ini

Then Ruff appeared. It promised to replace all three.

I tried it on a small project first. One session was enough. Configuration took a few iterations, but the result was straightforward. The main advantages:

* much faster than my current tools (saves me and the CI pipeline minutes) * single, integrated tool and a drop-in replacement for Flake8, isort and brunette * highly configurable within a single file

Ruff can also fix common findings automatically:

* removes unused imports * trims empty lines and spaces, even in multiline strings * removes unused f-string syntax

With the prepared configuration in the pyproject.toml I was then able to replace the same toolchain in cloudapps, a course-management platform with over 30,000 lines of Python, within a few minutes:

[tool.ruff]
fix = true
line-length = 79
select = [
  "C90", # lint.mccabe
  "E",  # lint.pycodestyle
  "F", # lint.pyflakes
  "I", # lint.isort
  "W", # lint.pycodestyle
]
src = ["src", "tests"]
target-version = "py311"

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

[tool.ruff.lint.isort]
known-first-party = ["tests"]
lines-after-imports = 2

[tool.ruff.lint.mccabe]
max-complexity = 6
Toml

The transition was very smooth. And the promise of being a drop-in replacement was kept: the task to lint and format the whole project with 623 files and 30,468 lines of Python code resulted in only 143 lines added and 127 lines removed. Most of it automatically and most of it because of some whitespace changes in multiline strings.

The commands could not be simpler:

# Format "src" recursively
ruff format src

# Lint and automatically fix "src" recursively
ruff check src
Bash