Ruff: Сверхбыстрый линтер и форматтер для Python с примерами

Ruff: Сверхбыстрый линтер и форматтер для Python с примерами


Ruff: Сверхбыстрый линтер и форматтер для Python с примерами

Введение

В мире Python-разработки поддержка чистоты кода критически важна. Традиционно для этого используются:

  • Линтеры (flake8, pylint) — анализ ошибок и стиля
  • Форматтеры (black, autopep8) — автоматическое форматирование
  • Инструменты сортировки импортов (isort)

Проблема: Множество инструментов = сложная настройка + медленная работа.

Решение: Ruff — инструмент на Rust, объединяющий функциональность линтера, форматтера и сортировщика импортов с фокусом на скорости и удобстве.

Ключевые особенности

  1. Невероятная скорость (в 10-100 раз быстрее аналогов)
  2. 700+ встроенных правил (совместимость с flake8, isort, pyupgrade)
  3. Автофикс для 50%+ правил
  4. Форматирование кода (альтернатива black)
  5. Простая установка — один бинарный файл
  6. Современный стандарт — поддержка Python 3.12, Jupyter Notebooks

Установка

pip install ruff
# Или для изолированного окружения:
pipx install ruff

Проверка установки:

ruff --version
# ruff 0.3.4

Базовое использование

Линтинг всех файлов в проекте
ruff check .

Пример вывода:

main.py:5:17: E225 [*] Missing whitespace around operator
utils.py:1:8: F401 [*] `os` imported but unused
...
Found 12 errors.
[*] 8 fixable with the `--fix` option.
Автоматическое исправление ошибок
ruff check --fix .
Форматирование кода
ruff format .

Примеры правил с объяснением

1. Логические ошибки (F-правила)

F601: Повторяющийся ключ в словаре

# До
config = {"port": 8080, "host": "localhost", "port": 8000}

# После автофикса
config = {"host": "localhost", "port": 8000}

F841: Неиспользуемая переменная

# До
def calculate():
    result = 42  # Переменная не используется
    return 100

# После автофикса
def calculate():
    return 100
2. Стиль кода (E, W-правила)

E711: Сравнение с None через is

# До
if value == None:
    pass

# После
if value is None:
    pass

W292: Отсутствие пустой строки в конце файла

# До
print("Hello")
# Файл заканчивается без \n

# После
print("Hello")
# Добавляется \n в конце
3. Сортировка импортов (I-правила)

I001: Несортированные импорты

# До
import sys
import os
from django.conf import settings

# После
import os
import sys

from django.conf import settings
4. Форматирование (RUF-правила)

RUF100: Ненужные noqa

# До
import os  # noqa: F401

# После (комментарий удаляется)
import os

Конфигурация через pyproject.toml

Пример настройки:

[tool.ruff]
line-length = 100
select = [
    "E",   # pycodestyle errors
    "F",   # Pyflakes
    "I",   # isort
    "UP",  # pyupgrade
    "RUF", # ruff-specific
]
ignore = ["E501"]  # Игнорировать длинные строки

# Настройка форматирования
[tool.ruff.format]
quote-style = "single"  # Использовать одинарные кавычки
indent-width = 4

# Настройка isort
[tool.ruff.isort]
known-first-party = ["myapp"]

Интеграция в IDE (VS Code)

  1. Установите расширение Ruff
  2. Добавьте в settings.json:
{
  "python.linting.enabled": true,
  "python.linting.ruffEnabled": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.ruff": true
  },
  "python.formatting.provider": "ruff"
}

Результат: автоматический линтинг и форматирование при сохранении файла.


Работа с Jupyter Notebooks

ruff check --format jupyter notebook.ipynb
ruff format notebook.ipynb

Продвинутые сценарии

1. Локальное подавление правил
def deprecated_function():
    # ruff: noqa: F401, W292
    return 42  # Игнорирует 2 правила
2. Per-file игнорирование

В pyproject.toml:

[tool.ruff.per-file-ignores]
"__init__.py" = ["F401"]  # Разрешить неиспользуемые импорты в __init__.py
"tests/*.py" = ["S101"]    # Разрешить assert в тестах
3. Пользовательские правила

Через плагины (требуется сборка из исходников):

// ruff/src/rules/plugin_example.rs
fn rule_impl(context: &mut Context) -> Option<Diagnostic> {
    // Кастомная логика
}
4. Интеграция с pre-commit

.pre-commit-config.yaml:

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: v0.3.4
  hooks:
    - id: ruff
      args: [--fix, --show-fixes]
    - id: ruff-format

Бенчмарки производительности

Тест на кодовой базе Django (20k+ LOC):

ToolTimeRules
flake8 + isort8.2s65
Ruff0.4s188

Причины скорости:

  1. Компиляция в нативный код (Rust)
  2. Параллельная обработка файлов
  3. Оптимизированные алгоритмы

Экосистема Ruff

  1. ruff-lsp — Language Server Protocol
  2. ruff-pre-commit — интеграция с Git hooks
  3. Ruff VS Code Extension — расширение для редактора
  4. Red Hat OpenShift — встроенная поддержка в платформе

Ограничения

  1. Форматирование пока в бета-версии (не 100% совместимость с black)
  2. Меньше кастомизации стиля, чем у pylint
  3. Нет поддержки плагинов из коробки (только через сборку)

Миграция с других инструментов

Пошаговая миграция:

  1. Заменить isort: ruff check --select I --fix
  2. Заменить flake8: ruff check --select E,F,W --fix
  3. Заменить black: ruff format
  4. Настроить конфиг через pyproject.toml

Сравнение команд:

LegacyRuff Equivalent
isort .ruff check --select I --fix
flake8 .ruff check --select E,F,W
black .ruff format
pylint --disable=Cruff check --ignore PLC

Пример полного рабочего процесса

  1. Инициализация проекта:
mkdir myproject && cd myproject
python -m venv .venv
source .venv/bin/activate
  1. Настройка:
echo "[tool.ruff]" > pyproject.toml
echo "line-length = 88" >> pyproject.toml
  1. Пример кода (main.py):
import sys, os  # Ошибки: I001, F401

def calculate():
    x=2+3  # Ошибка: E225
    return {'a':1,'a':2}  # Ошибка: F601
  1. Запуск проверки:
ruff check .
# main.py:1:8: F401 [*] `os` imported but unused
# main.py:1:1: I001 [*] Import block is un-sorted or un-formatted
# main.py:3:16: E225 [*] Missing whitespace around operator
# main.py:4:18: F601 [*] Duplicate key `'a'` in dictionary
  1. Автоматическое исправление:
ruff check --fix .

Исправленный код:

import sys


def calculate():
    x = 2 + 3
    return {"a": 2}

Заключение

Ruff — не просто ещё один инструмент, а качественный скачок в инструментарии Python:

  • Экономия времени — проверка 10k строк за 0.1 сек
  • Упрощение стека — один инструмент вместо 5-7
  • 🔧 Легкая миграция — совместимость с существующими конфигами
  • 🌱 Активное развитие — 20k+ звёзд на GitHub, поддержка PSF

Когда использовать:

  • Новые проекты — сразу начать с Ruff
  • Существующие проекты — постепенная миграция
  • CI/CD пайплайны — ускорение сборок
  • Образовательные проекты — минимум настройки

Рекомендации:

  1. Начните с ruff check --fix
  2. Постепенно настраивайте правила через select/ignore
  3. Включите форматирование в pre-commit
  4. Используйте ruff format вместо black
# Оптимальная стартовая команда
ruff check --fix --show-source --ignore=E501 .

Ruff задаёт новый стандарт инструментов Python, делая поддержку кода не обязанностью, а удовольствием.