Skip to content

How to migrate to Ruff

The stack migrated from isort + black + flake8 to Ruff as a unified tool for linting, formatting, and import sorting. This guide shows the configuration and how to run the checks.

Why Ruff

Aspect Before (isort + black + flake8) Ruff
Speed ~10-30 s 10-100× faster (Rust)
Tools 3 + plugins 1 single binary
Configuration 3 sections 1 single [tool.ruff]
Active rules Limited 700+ ported and unified
Auto-fix Partial Mostly automatic

The trigger was a blocking bug in the ms-python.isort extension with Python 3.12 on Windows (PackageNotFoundError, LSP crash -32097).

Applied configuration

In pyproject.toml:

[tool.ruff]
line-length = 100
target-version = "py312"

[tool.ruff.lint]
select = ["E", "W", "F", "I", "UP", "B"]
ignore = []

[tool.ruff.lint.isort]
known-first-party = ["domains", "tools", "core", "src"]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
Rule Origin What it detects
E/W pycodestyle Style errors/warnings
F pyflakes Unused imports/names/variables
I isort Import sorting
UP pyupgrade PEP 585/604 modernization
B flake8-bugbear Subtle bugs (mutable defaults, zip without strict=)

Local workflow

ruff check .                      # lint (daily use)
ruff check . --fix                # safe auto-fixes
ruff check . --select I001 --fix  # imports only
ruff format .                     # format (drop-in for black)
ruff format --check .             # CI mode (fails if formatting needed)
ruff check . --statistics         # per-rule stats

CI (GitHub Actions)

ruff:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-python@v5
      with:
        python-version: "3.12"
    - run: pip install -r requirements-dev.txt
    - run: ruff check . --output-format=github
    - run: ruff format --check .

--output-format=github produces native PR annotations.

Migrate VSCode from isort to Ruff

code --uninstall-extension ms-python.isort
code --install-extension charliermarsh.ruff

.vscode/settings.json:

{
  "[python]": {
    "editor.defaultFormatter": "charliermarsh.ruff",
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.fixAll": "explicit",
      "source.organizeImports": "explicit"
    }
  }
}

Single provider per category

Stack policy: a single provider for lint/format/imports (charliermarsh.ruff). Forbidden (redundant) extensions: ms-python.black-formatter, ms-python.flake8, ms-python.pylint, ms-python.autopep8.

Apply fixes in phases

Applying all auto-fixes in one commit creates too much noise. Recommended plan:

  1. Imports (low risk): ruff check . --select I001 --fix
  2. Types (low-medium risk): ruff check . --select UP --fix
  3. F + B (manual review): ruff check . --select F,B → review → --fix --unsafe-fixes
  4. Format (last): ruff format .

See also

Canonical source

Derives from docs/shared/RUFF_MIGRATION.md.