Ruff для практиков: автозамены (fix), правила E/F и как встроить линтинг в ваш процесс
Покажем, как запускать ruff в режиме проверки и автоисправлений, как управлять выбором правил, исключениями и конфигами по папкам. Отдельно — схема “сначала предупреждения, потом правки”, чтобы не тормозить разработку.
Содержание
Ruff для практиков: автозамены (fix), правила E/F и как встроить линтинг в ваш процесс
Ruff — один из тех инструментов, которые быстро превращаются из “ещё одного линтера” в часть повседневной инженерной дисциплины. Он не просто подсвечивает проблемы, но умеет автоматически исправлять значительную часть замечаний. При грамотной настройке это снижает когнитивную нагрузку и помогает держать кодовую базу в форме, не превращая линтинг в тормоз разработки.
В этой статье разберём практическую схему работы с Ruff: как запускать проверки и автоисправления, как управлять правилами E/F, как организовать конфигурацию по папкам и как встроить линтинг в рабочий процесс так, чтобы не страдать от “вечного статуса pending”.
Что такое fix в Ruff и чем он полезен
Ruff поддерживает режимы:
- Проверка (linting): Ruff анализирует код и сообщает о нарушениях правил.
- Автоисправление: Ruff пытается автоматически применить корректировки там, где это возможно и безопасно.
Ключевой флаг — --fix (или режим, где он подразумевается в документации). На практике полезно различать:
- Правила, которые можно чинить автоматически.
Ruff знает, какие нарушения он может исправить “механически” (например, заменить импорт на более правильный, привести форматирование, убрать неиспользуемые элементы и т. п.). - Правила, которые требуются исправлять вручную.
Это часто вопросы логики, архитектуры, спорного стиля, потенциальных “нестандартных” кейсов. Ruff их подсветит, но автозамена либо невозможна, либо требует участия разработчика.
Типичная ошибка командной работы — запускать --fix “всё подряд” без плана. Иногда это приводит к конфликтам в git или к неожиданным изменениям, которые разработчик не успел осмыслить. Поэтому ниже будет схема “сначала предупреждения, потом правки”.
E/F: что это за правила и как их рационально использовать
В Ruff есть наборы правил, оформленные как категории. Наиболее распространённые в Python-проектах — правила E и F.
E — ошибки стиля/формата (pycodestyle)
Обычно под E попадают нарушения, схожие с классическим pycodestyle (включая PEP 8-подобные требования). Типовые примеры: лишние пробелы, неправильные переносы, некорректные отступы, длины строк и т. п.
Важно: некоторые ошибки E можно исправлять автоматически, но даже если можно — иногда это “шум” в диффе. Например, изменения форматирования могут захватить большую часть файлов.
F — ошибки, связанные с флагами (pyflakes)
F чаще всего отражает класс задач “это реально ошибка/проблема в коде”: неиспользуемые импорты, не определённые имена, неиспользуемые переменные и т. п. Эти нарушения обычно важнее для качества и часто исправляются быстро.
Как выбирать E/F осознанно
Есть хорошая практическая логика:
- Для команды и стабильности: начинайте с
Fкак “минимального здоровья”. Это уменьшает риск деградации. - Для единообразия стиля: добавляйте
E, но вводите аккуратно. Иначе вы получаете массовые изменения форматирования и эффект “линтер сделал всё, но никто не знает зачем”.
Компромисс — включить E/F на проверку и отдельно управлять тем, что Ruff будет чинить автоматически.
Базовые команды: проверка и автозамена
Проверка без изменений
Минимальный “диагностический” запуск:
ruff check .
Если вы хотите чтобы это использовалось в CI, полезно понимать: Ruff возвращает ненулевой код при наличии проблем (и тем самым может провалить пайплайн).
Автоисправления
Автоисправление делается командой:
ruff check . --fix
Чаще всего это применяют аккуратно локально (перед коммитом), а в CI используют проверку без правок, чтобы изменение окружения было предсказуемым.
“Сначала предупреждения, потом правки”: рабочая схема
Для команды этот порядок обычно лучший:
- Запускаем проверку и смотрим список проблем:
ruff check .
- Затем применяем исправления:
ruff check . --fix
- Снова проверяем, что всё чисто:
ruff check .
Почему так? Потому что --fix может повлиять на дифф, а значит первая проверка нужна, чтобы:
- понять “объём” работ,
- согласовать изменения в команде,
- отделить быстро исправляемое от того, что требует ручного решения.
Управление выбором правил: что именно Ruff проверяет
Ruff позволяет включать/исключать правила. Обычно управление делают через конфиг (TOML), но для понимания логики полезно знать, что на уровне CLI можно передавать выбор.
Например, часто делают так:
- в конфиге включают определённые классы (E и F),
- а часть правил отключают, если они не соответствуют реальности проекта.
Практическая установка: вы не обязаны включать “все подряд”. На зрелом проекте обычно складывается набор:
- “обязательные” правила (F, ключевые E),
- “опциональные” (стилистические ограничения, которые команда пока не хочет enforced),
- “отключённые” (правила, которые конфликтуют с текущей архитектурой или удобствами разработки).
Пример конфигурации (базовый)
Допустим, у вас pyproject.toml. Пример:
[tool.ruff]
line-length = 100
[tool.ruff.lint]
select = ["E", "F"]
ignore = []
Этот конфиг делает Ruff строгим по E/F, но не объясняет, что именно нельзя или не нужно чинить автоматически. Следующий шаг — управлять “fix-стратегией”.
Управление автоисправлениями: когда --fix действительно безопасен
Ruff автозаменяет только то, что он умеет чинить корректно. Но даже “умение” не отменяет инженерную реальность: после --fix вы можете получить неожиданные изменения в форматировании, перестановках импортов или структуре кода.
Поэтому практикуют две линии:
- Локально применять
--fix.
До коммита, на своей ветке. - В CI прогонять проверку без
--fix.
Чтобы пайплайн был детерминированным и быстро обнаруживал отклонения.
Если же вы хотите, чтобы Ruff ещё и “точно” не правил нежелательные типы проблем, можно ограничивать правила, которые разрешены к исправлениям. Конкретные детали зависят от версии Ruff, но общий принцип: контролируйте, что вы доверяете автоправкам, и не делайте “всесильный автопатч” без политики.
Исключения и “островки” в кодовой базе: где линтинг должен и не должен работать
В реальных репозиториях почти всегда есть вещи, которые линтить не хочется или не получается:
- сгенерированный код,
- миграции,
- файлы с автоформатами,
- примеры, которые сознательно нарушают стиль,
- vendor-папки,
- папки с тестовыми фикстурами, если там специфические конструкции.
Ruff поддерживает исключения через конфиг. Типовой подход — использовать .gitignore-подобную логику: “не трогай то, что не должно влиять”.
Пример:
[tool.ruff]
exclude = [
".venv",
".git",
"build",
"dist",
"migrations",
"generated",
"vendor",
]
Подводный камень: слишком широкие исключения создают “дыры” в качестве. Если исключаете папку — убедитесь, что там нет критичного кода, который потом придётся разбирать при инцидентах.
Конфигурация по папкам: разные правила для разных частей проекта
Один из сильных практических паттернов — разная политика правил в разных директориях. Например:
src/— строгое соблюдение E/F и минимум исключений;tests/— возможно, допускаются некоторые стилистические вещи (например, длинные имена для читабельности);scripts/— более свободный стиль, но без ошибок (F обязателен).
Ruff умеет поддерживать конфигурацию, где локальные настройки могут переопределять глобальные (через структуру конфигурационных файлов и наследование настроек). Общий практический подход:
- Делайте общий базовый конфиг в корне репозитория.
- Если нужен локальный override — создайте конфиг, который применится к конкретной поддиректории.
Ниже иллюстративный пример структуры:
pyproject.toml
src/
tests/
scripts/
В корне — базовое:
[tool.ruff.lint]
select = ["E", "F"]
exclude = ["migrations", "generated"]
А в tests/ — локальные изменения, если Ruff позволяет подключить конфиг в папке (в зависимости от способа конфигурации в вашей версии и выбранной стратегии). Типично это делается через локальный pyproject.toml или через поддерживаемый Ruff механизм, который позволяет переопределять настройки. На практике важно сверить вашу версию Ruff и формат локальных конфигов. Самое главное — помнить цель: локальная настройка должна снижать шум и не обнулять контроль качества.
Схема “сначала предупреждения, потом правки” — как встроить это в процесс разработки
Теперь — то, что действительно влияет на скорость команды: пайплайн действий.
Предкоммитная проверка (и почему не всегда нужен --fix)
В идеале перед коммитом запускают ruff check и (опционально) ruff check --fix. Но если делать это всегда, можно получить ситуацию, когда коммит “переезжает” из-за автозамен, а разработчик перестаёт понимать, что именно он фиксировал.
Стабильный вариант:
ruff check— показать список.- Затем
ruff check --fix— применить только исправляемое. - Повторить
ruff check, чтобы подтвердить чистоту.
В командах это можно оформить в виде make/скрипта:
ruff check .
ruff check . --fix
ruff check .
CI: “проверка без правок”
В CI лучше использовать только проверку:
ruff check .
Преимущества:
- детерминизм;
- быстрый фидбек;
- если автоисправления не были применены локально — CI покажет, что именно требуется обновить.
Как не превратить линтинг в постоянные конфликты
Если у команды уже есть большой “технический долг” по линтеру, есть опасность: вы включите новые правила — и каждый PR будет тонуть в сотнях замечаний. Практически это делается так:
- Ввести Ruff постепенно.
- Сначала включить минимум (часто F + несколько ключевых E).
- Затем расширять набор правил.
- Для существующего долга использовать план “санации” частями: по папкам, по модулям или по темам.
Эта стратегия не “красивая”, но она рабочая.
Типичные ошибки при настройке Ruff
Ошибка 1: включить всё сразу (E/F и дополнительные правила)
Это создаёт:
- огромный шум в репозитории;
- долгие диффы;
- раздражение команды (и, как следствие, игнорирование линтера).
Решение: стартовать с ядра E/F и добавлять остальное постепенно.
Ошибка 2: слепо применять --fix в CI или на каждый коммит
Проблема не в Ruff, а в инженерной практике: автоправки меняют состояние кода, а CI должен быть проверкой, а не “редактором”.
Решение: CI только check, автоисправления — локально.
Ошибка 3: исключить слишком много папок
Это превращает линтер в “для красоты”. В итоге проблемы копятся в местах, которые не проверяются.
Решение: исключать только то, что действительно не подлежит качественному контролю (генерация, vendor и т. п.).
Ошибка 4: отсутствие повторной проверки после --fix
Даже если Ruff исправляет много, важно подтвердить состояние.
Решение: после --fix делать ещё один ruff check.
Пример “боевого” workflow для разработчика
Ниже пример последовательности действий, которая хорошо ложится в повседневную работу:
- Проверить текущее состояние:
ruff check .
- Применить автоправки:
ruff check . --fix
- Убедиться, что стало лучше/чисто:
ruff check .
-
Если есть ошибки, которые Ruff не исправляет автоматически — чините вручную и снова прогоняйте check.
-
Коммитить изменения.
Такой поток минимизирует время простоя и оставляет линтинг прозрачным: сначала вы видите, что именно происходит, потом вы доверяете машине исправить то, что она реально умеет чинить.
Встроенный линтинг в редакторы и pre-commit: стоит ли
Инструменты редактора (например, подсветки и автопроверка) полезны, но они не заменяют дисциплину проверки в CI. А pre-commit (или аналогичные хуки) хороши как мост между локальным удобством и репозиторием.
Практический совет: используйте хуки, которые запускают ruff check, а автоправки делайте либо отдельной командой, либо аккуратно внутри hook’а, если команда договорилась о правилах диффов и конфликтов.
Если вы только начинаете и хотите привести процесс к воспроизводимому виду — начните с “check в pre-commit”, а --fix оставьте на осознанный запуск перед коммитом.
Как начать: минимальный набор настроек и действий
Если ваша цель — внедрить Ruff без боли, можно стартовать так:
- Включить базовую проверку E/F.
- Добавить исключения для очевидно неподконтрольных папок.
- В CI использовать только
ruff check. - Локально применять
--fixв понятном порядке “сначала предупреждения”.
В качестве точки входа для команды полезно взять структурированный материал, например руководство «ruff – для начинающих!» (ссылка: /course/ruff-free ). Оно помогает быстро разобраться в базовых командах и логике конфигурации — а дальше вы уже сможете уточнять правила под конкретную архитектуру своего проекта.
Выводы
Ruff хорошо работает, когда его воспринимают не как “проверку ради галочки”, а как инструмент инженерной дисциплины. Практическая суть подхода такая:
- Разделяйте проверку и автоисправления: сначала
ruff check, затемruff check --fix, потом повторная проверка. - Используйте E/F рационально:
F— фундамент,E— единообразие, но вводите аккуратно, чтобы не утонуть в диффах. - Управляйте тем, что линтится, через exclude, и по необходимости — через локальные переопределения по папкам, чтобы снизить шум и сохранить контроль качества.
- В CI держите детерминированную проверку без
--fix, а правки доверяйте локальному процессу. - Делайте внедрение постепенным: линтер должен ускорять, а не ломать разработку.
Если вы построите процесс по этой схеме, Ruff станет не источником конфликтов, а одним из самых быстрых способов поддерживать качество Python-кода на уровне команды.
Комментарии
Пока нет комментариев