Выбор правил: select и ignore
Тонкая настройка того, что проверяет Ruff.
select — какие правила включить
Параметр select определяет, какие категории или конкретные правил будет применять Ruff при проверке. Это главный рычаг управления тем, что проверяет линтер. Без указания select Ruff использует значение по умолчанию — категории E (pycodestyle errors) и F (Pyflakes).
select или extend-select.
Минимальная конфигурация, которая включает стиль, логику и сортировку импортов:
[tool.ruff.lint]
select = ["E", "F", "I"]
Более строгий набор для серьёзных проектов:
[tool.ruff.lint]
select = ["E", "F", "I", "N", "UP", "B", "S", "C90"]
А если нужно включить абсолютно все правила:
[tool.ruff.lint]
select = ["ALL"]
Как указывать правила в select
Правила можно указывать на трёх уровнях детализации:
| Уровень | Пример | Описание |
|---|---|---|
| Категория | "F" |
Все правила категории (Pyflakes) |
| Подкатегория | "F4" |
Все правила, начинающиеся на F4 |
| Конкретное правило | "F401" |
Только одно конкретное правило |
Пример использования разных уровней:
[tool.ruff.lint]
select = [
"E", # вся категория pycodestyle errors
"F4", # только подкатегория F4 (логические ошибки Pyflakes)
"N801", # только конкретное правило — классы должны быть CamelCase
"B", # вся категория flake8-bugbear
"I001", # только конкретное правило — сортировка импортов (избыточно если есть вся I)
]
"I", то указывать "I001" отдельно уже не нужно — правило уже входит в категорию. Но это не ошибка, просто избыточно.
ignore — исключить правила
Параметр ignore позволяет исключить определённые правила из проверки. Он применяется поверх того, что было выбрано через select. Это удобно, когда вы включаете целую категорию, но хотите отключить несколько конкретных правил из неё.
[tool.ruff.lint]
select = ["E", "F", "I", "N", "UP", "B"]
ignore = [
"E501", # line too long — часто отключают в Django/FastAPI проектах
"E711", # comparison to None — иногда мешает при работе с SQLAlchemy
"B008", # function call in default argument — нужен в FastAPI для зависимостей
"N818", # exception class name — некоторые проекты используют свой нейминг
]
Правила, которые часто отключают
| Правило | Причина отключения | Типичный сценарий |
|---|---|---|
E501 |
Слишком длинные строки | Django модели, SQL запросы, строки документации |
B008 |
Вызов функции в аргументе по умолчанию | FastAPI зависимости, Pydantic поля |
B009 |
getattr/setattr с константами | Магические методы, ORM маппинг |
S101 |
Использование assert | Тесты (pytest использует assert) |
N818 |
Имя исключения без суффикса Error | Кастомные исключения в бизнес-логике |
ANN101 |
Пропущен self в аннотации | Крупные codebase где не хотят везде писать self: Self |
Как работает ignore: приоритет и конфликты
Механизм работы ignore при совместном использовании с select подчиняется следующим правилам:
selectопределяет, какие правила вообще рассматриваются.ignoreвычитается из набора, полученного на шаге 1.- Если правило указано и в
select, и вignore—ignoreимеет приоритет (правило будет отключено). - Правила, не входящие ни в одну из выбранных категорий, не могут быть включены через
ignore.
[tool.ruff.lint]
select = ["E", "F", "ARG"] # включили категории
ignore = ["E501", "ARG002"] # исключили два правила
# Итоговый набор:
# Все E, кроме E501
# Все F
# Все ARG, кроме ARG002
extend-select и extend-ignore
Параметры extend-select и extend-ignore работают так же, как select и ignore, но добавляются к значениям по умолчанию, а не заменяют их. Это особенно полезно, когда вы хотите сохранить дефолтные правила E и F и добавить к ним новые категории, не перечисляя всё вручную.
[tool.ruff.lint]
# добавить к дефолтным правилам (E + F), не заменяя их
extend-select = ["I", "N", "UP"]
# добавить правило в ignore поверх дефолтного
extend-ignore = ["E501"]
Сравнение select vs extend-select
| Подход | Конфигурация | Результат |
|---|---|---|
| Только дефолт | ничего не указано | E + F |
| select | select = ["I", "N"] |
I + N (E и F потеряны!) |
| extend-select | extend-select = ["I", "N"] |
E + F + I + N (сохранены) |
select, то полностью заменяете набор правил по умолчанию. Категории E и F не будут включены, если не указать их явно. extend-select этого недостатка лишён.
Практические сценарии использования
Сценарий 1: Вы начинаете проект и хотите постепенно ужесточать проверки.
# Этап 1: базовые проверки
[tool.ruff.lint]
extend-select = ["I"] # E + F + I
# Этап 2: добавляем именование и типы
[tool.ruff.lint]
extend-select = ["I", "N", "UP", "ANN"]
# Этап 3: полный набор
[tool.ruff.lint]
extend-select = ["I", "N", "UP", "B", "S", "C90", "ANN", "ARG"]
Сценарий 2: В вашей компании есть базовый стандарт кодирования, но некоторые проекты добавляют свои правила.
# Базовый конфиг компании (в общем pyproject.toml)
[tool.ruff.lint]
select = ["E", "F", "I", "N", "UP", "B"]
# Проект может расширить
# (в локальном pyproject.toml, который мержится с базовым)
extend-select = ["S", "C90"] # добавляем безопасность и сложность
extend-ignore = ["B008"] # отключаем B008 для FastAPI
Специальное значение ALL
Значение "ALL" в select включает все правила, известные Ruff. Это удобно для максимально строгой проверки, но может быть слишком шумным для больших проектов.
[tool.ruff.lint]
select = ["ALL"]
ignore = [
"E501", # отключаем длину строки
"B008", # отключаем вызовы в дефолтах
"S101", # отключаем assert для тестов
"ANN001", # отключаем обязательные аннотации для аргументов
"D", # отключаем docstrings (если их нет в проекте)
]
select = ["ALL"] в новых проектах с нуля, чтобы сразу привить лучшие практики. Для существующих проектов лучше добавлять категории постепенно, иначе вы получите тысячи ошибок.
Когда вы используете "ALL", Ruff включает правила из всех категорий:
| Префикс | Категория | Кол-во правил |
|---|---|---|
E | pycodestyle errors | ~50 |
W | pycodestyle warnings | ~20 |
F | Pyflakes | ~40 |
I | isort | ~5 |
N | pep8-naming | ~30 |
UP | pyupgrade | ~50 |
B | flake8-bugbear | ~60 |
S | flake8-bandit | ~60 |
C90 | mccabe | ~5 |
ANN | flake8-annotations | ~20 |
ARG | flake8-unused-arguments | ~5 |
D | pydocstyle | ~50 |
RUF | Ruff-specific | ~30 |
PL | Pylint | ~200 |
SIM | flake8-simplify | ~50 |
T20 | flake8-print | ~3 |
PT | flake8-pytest-style | ~20 |
RET | flake8-return | ~10 |
SLF | flake8-self | ~5 |
ERA | eradicate (комментарии-код) | ~1 |
PD | pandas-vet | ~20 |
NPY | NumPy-specific | ~10 |
FA | flake8-future-annotations | ~3 |
ISC | flake8-implicit-str-concat | ~3 |
IC | flake8-import-conventions | ~3 |
PTH | flake8-use-pathlib | ~20 |
TD | flake8-todos | ~5 |
DJ | flake8-django | ~15 |
ASYNC | flake8-async | ~10 |
TCH | flake8-type-checking | ~10 |
PYI | flake8-pyi (stub files) | ~20 |
EXE | flake8-executable | ~5 |
RSE | flake8-raise | ~5 |
FURB | refurb | ~30 |
COM | flake8-commas | ~10 |
FLY | flynt (f-strings) | ~3 |
PERF | perflint | ~15 |
DOC | pydoclint | ~20 |
DTZ | flake8-datetimez | ~5 |
EM | flake8-errmsg | ~5 |
G | flake8-logging-format | ~10 |
LOG | flake8-logging | ~10 |
INP | flake8-ini | ~3 |
PIE | flake8-pie | ~20 |
Q | flake8-quotes | ~3 |
R | ruff-format | ~3 |
"ALL" с select заменяет все дефолтные настройки. Это означает, что если вы укажете select = ["ALL"], а потом extend-select = ["S"], то extend-select не добавит ничего нового, так как ALL уже включает S. Однако extend-select всё ещё работает, если базовый select не включает нужную категорию.
fixable и unfixable — управление автоисправлением
Не все правила Ruff могут автоматически исправлять код. Некоторые правки считаются безопасными (safe), другие — только предварительными (unsafe). Параметры fixable и unfixable управляют тем, какие правила могут применять автоисправления.
fixable — разрешить исправление
По умолчанию Ruff может исправлять все безопасные правила. Параметр fixable ограничивает этот набор:
[tool.ruff.lint]
# разрешить автоисправление только для импортов и pyupgrade
fixable = ["I", "UP"]
# все остальные правила (E, F, B, S и т.д.) будут только предупреждать,
# но не исправлять код автоматически
Также можно использовать "ALL":
[tool.ruff.lint]
# разрешить автоисправление для всех правил
fixable = ["ALL"]
unfixable — запретить исправление
Противоположность fixable. Позволяет отключить автоисправление для конкретных правил, не отключая проверку целиком:
[tool.ruff.lint]
# не удалять неиспользуемые импорты автоматически
unfixable = ["F401"]
# не исправлять мутируемые дефолты
unfixable = ["B006"]
Safe vs Unsafe исправления
| Тип | Флаг | Описание | Пример |
|---|---|---|---|
| Safe | --fix |
Исправления, которые точно не меняют смысл кода | Удаление неиспользуемого импорта |
| Unsafe | --unsafe-fixes |
Исправления, которые могут изменить поведение программы | Замена типа, удаление assert |
# только безопасные исправления
ruff check --fix
# включая небезопасные (нужно подтверждение)
ruff check --fix --unsafe-fixes
fixable и unfixable определяют максимально возможный набор исправлений. Даже если правило разрешено в fixable, Ruff применит только безопасные исправления без флага --unsafe-fixes.
Комбинирование fixable и unfixable
Два параметра работают в связке: сначала fixable определяет белый список, затем unfixable вычитает из него правила:
[tool.ruff.lint]
fixable = ["ALL"] # разрешить всё
unfixable = ["F401", "B006"] # но не исправлять F401 и B006
# Итог: все безопасные исправления, кроме F401 и B006
CLI vs Конфигурация: приоритет
Ruff поддерживает настройку правил как через конфигурационные файлы (pyproject.toml, ruff.toml), так и через аргументы командной строки. Важно понимать, как эти два источника взаимодействуют.
Приоритет настроек (от высшего к низшему)
- Аргументы CLI — имеют наивысший приоритет.
- CONFIG в CLI — параметр
--config path/to/configуказывает на конкретный файл. - Локальный конфиг — ruff.toml или pyproject.toml в корне проекта.
- Пользовательский конфиг — ~/.config/ruff/ruff.toml (или ~/.ruff.toml).
- Значения по умолчанию — встроенные в Ruff.
Примеры CLI-переопределений
# Временно добавить категорию (не меняя конфиг)
ruff check --select I
# Отключить правило при запуске
ruff check --ignore E501
# Включить все правила
ruff check --select ALL
# Применить исправления
ruff check --fix
# Использовать конкретный конфиг
ruff check --config /path/to/ruff.toml
# Посмотреть, какие правила активны
ruff check --show-settings
Как CLI переопределяет конфиг
| Параметр в CLI | Поведение |
|---|---|
--select |
Заменяет select из конфига полностью |
--ignore |
Добавляется к ignore из конфига |
--fix |
Включает режим исправления, независимо от конфига |
--show-settings |
Показывает итоговую конфигурацию (полезно для отладки) |
Пример отладки:
# Посмотреть какие правила будут применены
ruff check --show-settings
# Вывод покажет:
# - Какой конфиг был найден
# - select / ignore / fixable / unfixable
# - per-file-ignores
# - Все остальные настройки
ruff check --show-settings для отладки, когда не уверены, какие правила активны. Это особенно полезно при работе с несколькими конфигурационными файлами или наследованием настроек.
extend-fixable
Аналогично extend-select, параметр extend-fixable добавляет правила к списку исправляемых, не заменяя его полностью. Это полезно, когда вы используете чей-то базовый конфиг и хотите добавить свои правила в автоисправление:
[tool.ruff.lint]
# Базовый конфиг: fixable = ["I"]
# Добавляем UP к исправляемым
extend-fixable = ["UP"]
# Итог: fixable = ["I", "UP"] (если базовый конфиг не переопределён)
Практические примеры конфигураций
Пример 1: Минимальная конфигурация для нового проекта
[tool.ruff]
line-length = 88
[tool.ruff.lint]
extend-select = ["I", "N", "UP", "B"]
ignore = ["E501"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
Пример 2: Строгая конфигурация для open-source библиотеки
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["ALL"]
ignore = [
"D203", "D212", "D213", "D214", "D215",
"PLR0913", # too-many-arguments
"ANN101", # missing-type-self
"ANN102", # missing-type-cls
"S101", # assert used
]
fixable = ["ALL"]
unfixable = ["F401"]
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["S101", "ANN", "D"]
"__init__.py" = ["F401", "D"]
[tool.ruff.format]
quote-style = "double"
Пример 3: Конфигурация для Django проекта
[tool.ruff]
line-length = 120
[tool.ruff.lint]
extend-select = [
"I", "N", "UP", "B", "S", "C90",
"DJ", # Django-specific rules
"ARG", # unused arguments
]
ignore = [
"E501", # строки в Django бывают длинными
"B008", # FastAPI-like patterns в Django тоже
"S105", # hardcoded passwords — часто ложно
"S106", # hardcoded passwords
"DJ008", # model meta
]
[tool.ruff.lint.per-file-ignores]
"*/migrations/*.py" = ["ALL"]
"*/tests/**/*.py" = ["S101", "ANN", "D", "DJ"]
"*/settings.py" = ["S105", "S106"]
"*/admin.py" = ["D"]
"*/models.py" = ["D"]
[tool.ruff.format]
quote-style = "double"
Пример 4: Постепенное внедрение в legacy проекте
Если у вас большой существующий проект, не стоит включать сразу все правила. Лучше внедрять Ruff постепенно:
# Этап 1: только самые важные проблемы
[tool.ruff.lint]
extend-select = ["F", "I"] # логика + импорты
# F404: undefined name — помогает находить реальные баги
# F401: unused import — очищает код
# Этап 2: добавляем стиль и именование
[tool.ruff.lint]
extend-select = ["F", "I", "E", "N"]
ignore = ["E501"] # слишком много нарушений в старом коде
# Этап 3: добавляем баги и безопасность
[tool.ruff.lint]
extend-select = ["F", "I", "E", "N", "B", "S", "UP"]
ignore = ["E501", "B008"]
# Этап 4: полный набор
[tool.ruff.lint]
extend-select = ["F", "I", "E", "N", "B", "S", "UP", "C90", "ANN", "ARG"]
ignore = ["E501", "B008", "ANN001", "ANN201"]
Проверка и отладка конфигурации
Ruff предоставляет несколько инструментов для проверки текущей конфигурации:
ruff check --show-settings
Показывает полную конфигурацию, которую Ruff использует для текущего проекта:
ruff check --show-settings
# Пример вывода (сокращён):
# Resolved settings:
# - config: /path/to/project/pyproject.toml
# - select: ["E", "F", "I", "N", "UP"]
# - ignore: ["E501"]
# - fixable: ["I", "N", "UP"]
# - unfixable: []
# - per-file-ignores: {"__init__.py": ["F401"]}
# - line-length: 88
# - target-version: py311
ruff check --only
Позволяет запустить только одно правило (игнорируя все остальные). Полезно для отладки конкретного правила:
# Проверить только F401 во всём проекте
ruff check --only F401
# Проверить только B006 в конкретном файле
ruff check --only B006 src/module.py
--only игнорирует select и ignore — он включает только указанное правило. Это идеальный способ проверить, какие проблемы конкретное правило найдёт в вашем коде.
Частые ошибки и их решения
select = ["I", "N"], но Ruff перестал проверять E и F.
select заменяет значения по умолчанию, а не дополняет их. Используйте extend-select вместо select, если хотите сохранить E и F: extend-select = ["I", "N"].
"ALL" в select, но Ruff не проверяет import сортировку.
"ALL" включает все правила, включая I. Возможно, у вас включён ignore = ["I"] или используется ruff check --no-fix без явного исправления. Проверьте ruff check --show-settings.
ruff rule S105.
select = ["ALL"], но Ruff выдаёт слишком много ошибок.
ignore для отключения самых шумных правил. Для больших проектов не используйте "ALL" — лучше включайте категории по одной. Начните с ["E", "F", "I"] и добавляйте остальные постепенно.
extend-select, но Ruff всё равно проверяет только E и F.
select выше по иерархии. Если в пользовательском конфиге (~/.config/ruff/ruff.toml) указан select, то локальный extend-select будет расширять именно его, а не дефолт. Используйте ruff check --show-settings для диагностики.
Итоги
| Параметр | Назначение | Заменяет дефолт? |
|---|---|---|
select |
Какие правила включить | Да |
extend-select |
Добавить к текущему select | Нет |
ignore |
Какие правила отключить | Нет (добавляется) |
extend-ignore |
Добавить к текущему ignore | Нет |
fixable |
Какие правила можно исправлять | Да |
unfixable |
Какие правила нельзя исправлять | Нет (вычитается) |
selectполностью заменяет дефолтный набор.extend-select— добавляет к нему.ignoreвсегда вычитается изselect, независимо от способа указания.ALLвключает все возможные правила, но может быть шумным.- Настройки CLI имеют приоритет над конфигурационными файлами.
- Используйте
ruff check --show-settingsдля отладки.
Урок 4.2: select и ignore
5 вопросов