Категории правил
E, F, I, N, UP, B, S и другие — что за каждой буквой.
Что такое категории правил
Ruff группирует правила в категории по префиксам. Каждый префикс соответствует определённому классу проверок — стиль, безопасность, типы, импорты и так далее. Это позволяет включать или отключать целые группы правил одной строкой конфигурации.
Всего в Ruff более 800 правил, объединённых в ~40 категорий. Категории (префиксы) используются в параметрах select, ignore, fixable и других, как вы уже знаете из урока 4.2.
F401. Первая часть — префикс категории (F), вторая — номер внутри категории (401). Некоторые категории имеют длинные префиксы: C90, UP, ANN, PL.
Полный список категорий правил
| Префикс | Название | Описание | Пример |
|---|---|---|---|
E |
pycodestyle errors | Нарушения PEP 8: пробелы, отступы, пустые строки, длина строки | E501 line too long |
W |
pycodestyle warnings | Предупреждения о стиле: trailing whitespace, лишние пустые строки | W291 trailing whitespace |
F |
Pyflakes | Логические ошибки: неиспользуемые импорты/переменные, неопределённые имена | F401 unused import |
I |
isort | Порядок и группировка импортов по PEP 8 | I001 unsorted imports |
N |
pep8-naming | Именование: классы CamelCase, функции snake_case, константы UPPER_CASE | N801 class name |
UP |
pyupgrade | Обновление синтаксиса до современных версий Python | UP006 typing → builtins |
B |
flake8-bugbear | Распространённые баги: mutable default args, голые except, assert False | B006 mutable default |
S |
flake8-bandit | Безопасность: SQL-инъекции, небезопасные вызовы, hardcoded пароли | S105 hardcoded password |
C90 |
mccabe | Цикломатическая сложность — находит слишком сложные функции | C901 too complex |
ANN |
flake8-annotations | Аннотации типов у функций и методов | ANN001 missing type arg |
ARG |
flake8-unused-arguments | Неиспользуемые аргументы функций | ARG001 unused argument |
D |
pydocstyle | Проверка docstring'ов: наличие, формат, соответствие PEP 257 | D100 missing docstring |
RUF |
Ruff-specific | Уникальные правила Ruff без аналогов в других линтерах | RUF100 unused noqa |
PL |
Pylint | Реализация правил Pylint (около 200 правил) | PLR0911 too many returns |
SIM |
flake8-simplify | Упрощение кода: замена сложных конструкций на простые | SIM101 duplicate isinstance |
T20 |
flake8-print | Запрет на print() в production-коде | T201 print statement |
PT |
flake8-pytest-style | Лучшие практики pytest: правильные assert, именование тестов | PT001 pytest fixture |
RET |
flake8-return | Проверка корректности return в функциях | RET501 explicit return None |
SLF |
flake8-self | Запрет на обращение к приватным членам (self.__x) |
SLF001 private member access |
ERA |
eradicate | Находит закомментированный код (dead code) | ERA001 commented code |
PD |
pandas-vet | Проверка pandas кода: inplace, chained indexing | PD002 inplace=True |
NPY |
NumPy-specific | Правила для работы с NumPy | NPY001 numpy deprecation |
FA |
flake8-future-annotations | Проверка from __future__ import annotations |
FA100 missing future import |
ISC |
flake8-implicit-str-concat | Проверка неявной конкатенации строк | ISC001 implicit concat |
IC |
flake8-import-conventions | Стандартные соглашения по импортам (например, import numpy as np) |
IC001 import convention |
PTH |
flake8-use-pathlib | Использовать pathlib вместо os.path |
PTH101 use pathlib |
TD |
flake8-todos | Проверка TODO/FIXME комментариев | TD001 TODO format |
DJ |
flake8-django | Лучшие практики Django: модели, views, urls | DJ001 model null field |
ASYNC |
flake8-async | Правила для асинхронного кода | ASYNC100 async function |
TCH |
flake8-type-checking | Правила для TYPE_CHECKING блоков | TCH001 type check import |
PYI |
flake8-pyi | Правила для stub-файлов (.pyi) | PYI001 stub syntax |
EXE |
flake8-executable | Проверка shebang и прав на выполнение | EXE001 shebang |
RSE |
flake8-raise | Правила для raise: избегать дублирования | RSE001 raise from |
FURB |
refurb | Модернизация и упрощение кода (от проекта Refurb) | FURB101 simplify |
COM |
flake8-commas | Проверка запятых в кортежах/списках/словарях | COM812 trailing comma |
FLY |
flynt | Замена % и .format() на f-strings |
FLY001 use f-string |
PERF |
perflint | Проверки производительности Python | PERF101 manual loop |
DOC |
pydoclint | Проверка соответствия docstring'ов сигнатурам функций | DOC001 docstring mismatch |
DTZ |
flake8-datetimez | Проверка timezone-aware datetime | DTZ001 naive datetime |
EM |
flake8-errmsg | Проверка сообщений об ошибках | EM101 error message |
G |
flake8-logging-format | Проверка форматирования логов | G001 logging format |
LOG |
flake8-logging | Правила для logging: уровень, lazy formatting | LOG001 logging call |
INP |
flake8-ini | Проверка .ini файлов | INP001 ini file |
PIE |
flake8-pie | Разные полезные проверки (prefer fstrings, prefer is over ==) | PIE781 prefer is None |
Q |
flake8-quotes | Проверка стиля кавычек (одинарные/двойные) | Q000 bad quotes |
R |
ruff-format | Встроенные правила форматирования Ruff | R001 format |
E — pycodestyle errors (PEP 8)
Категория E — это ядро стилистических проверок. Они следят за соблюдением PEP 8 — официального руководства по стилю кода Python. Эти правила включены по умолчанию вместе с категорией F.
Что проверяет категория E:
- E101-E111 — отступы (пробелы vs табы)
- E201-E262 — пробелы вокруг операторов и скобок
- E301-E306 — количество пустых строк
- E401-E501 — импорты, длина строки
- E701-E742 — составные statements
- W — предупреждения (trailing whitespace, лишние пустые строки)
Самые частые правила:
# E501: line too long (> 88 символов по умолчанию)
x = "very long string that exceeds the maximum line length configured in ruff" # E501
# E302: expected 2 blank lines before class/function definition
class MyClass:
pass
# E225: missing whitespace around operator
x=1 # должно быть x = 1
# E111: indentation is not a multiple of 4
print("wrong indent") # 2 spaces вместо 4
# W291: trailing whitespace
print("hello") # пробел в конце строки
F — Pyflakes (логические ошибки)
Категория F (Pyflakes) — одна из самых важных. Она находит реальные логические ошибки в коде, которые могут привести к багам. Pyflakes известен своей скоростью и точностью — он не выполняет код, но находит проблемы статически.
# F401: imported but unused
import os # F401 — os не используется
# F841: local variable assigned but never used
def foo():
result = compute() # F841 — result нигде не используется
return "done"
# F811: redefinition of unused variable
def foo():
x = 1
x = 2 # F811 — x переопределён без использования
# F821: undefined name
print(undefined_var) # F821 — имя не определено
# F601: dictionary key repeated
d = {"a": 1, "a": 2} # F601 — ключ 'a' повторяется
# F403: from module import *
from math import * # F403 — может конфликтовать с локальными именами
# F541: f-string without any placeholders
x = f"hello" # F541 — f-string не нужен, можно обычную строку
_ как имя переменной или явно вызывая del result. Ruff не ругается на односимвольные имена.
I — isort (импорты)
Категория I заменяет популярный инструмент isort. Она проверяет порядок и группировку импортов согласно PEP 8 и настраиваемым правилам.
Порядок импортов по умолчанию:
- Стандартная библиотека — os, sys, json, typing...
- Третьесторонние библиотеки — django, requests, numpy...
- Локальные модули — импорты из вашего проекта
# I001: Unsorted imports
# Плохо:
from myproject.models import User
import os
import django.db.models
# Хорошо:
import os
import django.db.models
from myproject.models import User
Настройка isort в Ruff:
[tool.ruff.lint]
# Включить сортировку импортов
extend-select = ["I"]
# Настройка порядка импортов
[tool.ruff.lint.isort]
known-third-party = ["django", "flask", "fastapi"]
known-first-party = ["myproject", "tests"]
required-imports = ["from __future__ import annotations"]
extra-standard-library = ["tomllib"]
ruff check --fix. В VS Code можно настроить автоисправление при сохранении через source.organizeImports.ruff.
N — pep8-naming (именование)
Категория N проверяет соответствие имён переменных, функций, классов и констант правилам PEP 8:
| Правило | Требование | Пример ошибки |
|---|---|---|
N801 |
Классы — CamelCase | class my_class: → class MyClass: |
N802 |
Функции — snake_case | def MyFunction(): → def my_function(): |
N803 |
Аргументы — snake_case | def foo(MyArg): → def foo(my_arg): |
N804 |
Первый аргумент метода — cls (classmethod) | def foo(self, x): над classmethod |
N805 |
Первый аргумент метода — self | def foo(cls, x): над обычным методом |
N806 |
Константы — UPPER_CASE | my_constant = 42 на уровне модуля |
N807 |
Функции с __ — специальные (dunder) | def __foo__(): не специальный метод |
N815 |
mixedCase в глобальных переменных | myGlobal = 1 |
N816 |
mixedCase в переменных класса | self.myVariable = 1 |
# N801: класс должен быть CamelCase
class my_class: # N801
pass
# N802: функция должна быть snake_case
def MyFunction(): # N802
pass
# N803: аргумент должен быть snake_case
def foo(MyArg): # N803
pass
# N806: константы — UPPER_CASE
my_constant = 42 # N806
UP — pyupgrade (синтаксис)
Категория UP (pyupgrade) предлагает заменить устаревшие конструкции на современные синтаксические возможности Python. Это помогает поддерживать код в актуальном состоянии и использовать новые возможности языка.
Категория UP зависит от target-version — минимальной версии Python, которую вы поддерживаете:
[tool.ruff]
target-version = "py310" # минимальная версия — Python 3.10
Примеры правил UP:
# UP006: typing.List/Dict → list/dict (Python 3.9+)
from typing import List
x: List[str] = [] # UP006 → x: list[str] = []
# UP007: Optional/Union → | (Python 3.10+)
from typing import Optional
def foo(x: Optional[str]): # UP007 → def foo(x: str | None):
pass
# UP008: super() without arguments
class Child(Parent):
def __init__(self):
super(Child, self).__init__() # UP008 → super().__init__()
# UP009: UTF-8 encoding declaration (не нужно в Python 3)
# -*- coding: utf-8 -*- # UP009 — удалить
# UP012: f-strings with datetime
f"Today is {datetime.now()}" # UP012 → datetime.now().isoformat()
# UP018: float() → литерал
x = float(1) # UP018 → x = 1.0
# UP024: replace os.path with pathlib
import os
os.path.join("a", "b") # UP024 → Path("a") / "b"
# UP025: удалить лишние скобки в кортежах
x = (1 + 2) # UP025 → x = 1 + 2
# UP031: printf-style → f-string (Python 3.6+)
name = "World"
print("Hello, %s" % name) # UP031 → f"Hello, {name}"
# UP034: лишние скобки с return
def foo():
return (x) # UP034 → return x
target-version в минимальную версию Python, которую вы поддерживаете. Ruff будет предлагать только те upgrade'ы, которые совместимы с этой версией. Например, если target-version = "py39", то UP007 (Union с |) не будет предлагаться.
B — flake8-bugbear (баги)
Категория B (Bugbear) находит распространённые баги и анти-паттерны в Python-коде. Это одна из самых полезных категорий для production-проектов.
# B006: mutable argument default
def append(item, lst=[]): # B006 → lst=None
lst.append(item)
return lst
# B007: loop variable not used
for i in range(10): # B007 → for _ in range(10):
print("hello")
# B008: function call in default argument
def create_user(name, time=datetime.now()): # B008
pass
# B009: getattr with constant
value = getattr(obj, "name") # B009 → obj.name
# B010: setattr with constant
setattr(obj, "name", value) # B010 → obj.name = value
# B011: assert False
assert False, "error" # B011 → raise AssertionError или raise ValueError
# B012: return inside finally
def foo():
try:
return 1
finally:
return 2 # B012 — предыдущий return потерян
# B013: except with tuple
except (ValueError, TypeError): # B013 → except (ValueError, TypeError):
pass
# B014: duplicate exception in except
except (ValueError, ValueError): # B014
# B015: useless comparison
x == 1 # B015 — сравнение без использования
# B016: raise with exception instance
raise ValueError # B016 → raise ... from ...
S — flake8-bandit (безопасность)
Категория S (Bandit) проверяет код на уязвимости безопасности: hardcoded пароли, SQL-инъекции, небезопасные вызовы и другие проблемы.
# S101: use of assert (может быть отключено в production)
assert user.is_admin # S101
# S102: exec used
exec(code) # S102 — exec опасен
# S103: eval used
eval("1+1") # S103 — eval опасен
# S104: hardcoded binding to all interfaces
app.run(host="0.0.0.0") # S104
# S105: hardcoded password
PASSWORD = "super-secret" # S105
# S106: hardcoded password (named)
DB_PASSWORD = "password123" # S106
# S107: hardcoded password in function
def login(password="admin123"): # S107
pass
# S108: hardcoded temporary directory
TEMP = "/tmp" # S108
# S324: subprocess with shell=True
import subprocess
subprocess.run("ls", shell=True) # S324 — shell injection risk
# S501: request without verification
import requests
requests.get("https://example.com", verify=False) # S501
# S701: jinja2 with autoescape=False
import jinja2
jinja2.Environment(autoescape=False) # S701
PASSWORD в переменных окружения (значение берётся из os.environ). Используйте per-file-ignores для конфигурационных файлов.
PL — Pylint (реализация)
Ruff включает большую часть правил Pylint (~200 правил с префиксом PL). Pylint — один из самых старых и всесторонних линтеров для Python, но он известен своей медлительностью. Ruff реализует его правила со скоростью Ruff.
# PLR0911: too many return statements
def foo():
if a: return 1
if b: return 2
if c: return 3 # PLR0911
# PLR0913: too many function arguments
def foo(a, b, c, d, e, f): # PLR0913
pass
# PLR0915: too many statements
def foo():
# много строк...
pass # PLR0915
# PLC3001: unnecessary lambda
sorted(x, key=lambda a: a.name) # → attrgetter
# PLR1704: redefined argument name
def foo(x):
x = 1 # PLR1704
# PLW0120: useless else on loop
for x in items:
if condition:
break
else: # PLW0120 — else не нужен, т.к. без break он всегда выполняется
print("not found")
RUF — Ruff-specific (уникальные правила)
Категория RUF содержит правила, созданные специально для Ruff. У них нет аналогов в других инструментах. Эти правила решают проблемы, характерные именно для экосистемы Ruff, или предлагают уникальные проверки.
# RUF100: unused noqa directive
import os # noqa: F401 # RUF100 — F401 не срабатывает, noqa не нужен
# RUF001: ambiguous unicode character
print("книга") # RUF001 — если строка содержит кириллицу в ASCII контексте
# RUF002: ambiguous unicode character in docstring
def foo():
"""Описание с кириллицей.""" # RUF002
# RUF003: ambiguous unicode character in comment
# комментарий с кириллицей # RUF003
# RUF005: use of collections.abc instead of typing
from typing import Iterable # RUF005 → from collections.abc import Iterable
# RUF006: asyncio.sleep(0) → await asyncio.sleep(0)
import asyncio
asyncio.sleep(0) # RUF006 → await asyncio.sleep(0)
# RUF010: use of explicit f-string conversion
f"{value!r}" # RUF010 — можно repr(value)
# RUF012: mutable class attribute
class Foo:
items = [] # RUF012 — mutable class attribute
Дополнительные категории
SIM — flake8-simplify (упрощение)
# SIM101: duplicate isinstance
if isinstance(x, int) or isinstance(x, float): # SIM101
...
# SIM102: nested if → single if with and
if a:
if b: # SIM102 → if a and b:
pass
# SIM103: unnecessary else after return
def foo():
if x:
return True
else: # SIM103
return False
# SIM108: if-else → ternary
if x:
y = 1
else: # SIM108 → y = 1 if x else 2
y = 2
# SIM115: open → Path.open
file = open("file.txt") # SIM115 → Path("file.txt").open()
ANN — flake8-annotations (типы)
# ANN001: missing type for function argument
def foo(x): # ANN001 → def foo(x: int):
pass
# ANN201: missing return type for public function
def foo(): # ANN201 → def foo() -> str:
return "hello"
# ANN202: missing return type for private function
def _foo(): # ANN202 → def _foo() -> str:
return "hello"
# ANN401: Any → avoid Any
from typing import Any
def foo(x: Any): # ANN401 — лучше использовать конкретный тип
pass
ANN201 (публичные функции) и ANN001 (аргументы). Добавляйте остальные правила постепенно.
T20 — flake8-print
# T201: print statement in production
print(f"User {user} not found") # T201 — используй logging
PT — flake8-pytest-style
# PT001: pytest fixtures should use (scope="...")
@pytest.fixture
def user(): # PT001 → @pytest.fixture()
pass
# PT009: unittest-style assert
assert something == True # PT009 → assert something
# PT022: no teardown in fixture with yield
@pytest.fixture
def db():
conn = connect()
yield conn
# PT022 — нет conn.close()
C90 — mccabe (цикломатическая сложность)
# C901: function is too complex (по умолчанию > 10)
def very_complex_function(): # C901
if a:
for b in c:
while d:
if e:
# ...
# сложность > 10
Настройка порога сложности:
[tool.ruff.lint.mccabe]
max-complexity = 15 # по умолчанию 10
D — pydocstyle (документация)
# D100: missing docstring in public module
# D101: missing docstring in public class
# D102: missing docstring in public method
# D103: missing docstring in public function
# D104: missing docstring in public package
# D105: missing docstring in magic method
# D107: missing docstring in __init__
class Calculator: # D101
def add(self, x, y): # D102
return x + y
Ruff поддерживает все основные стили docstring:
- Google-style
- NumPy-style
- Sphinx-style (reStructuredText)
- PEP 257
[tool.ruff.lint.pydocstyle]
convention = "google" # google, numpy, pep257 (по умолчанию)
Просмотр правил через CLI
Ruff предоставляет удобные CLI-команды для просмотра документации правил и категорий.
ruff rule — детали конкретного правила
ruff rule F401
# Вывод:
# F401: module-imported-but-unused (Pyflakes)
# A module is imported but not used.
#
# Пример:
# import os # F401
#
# Автоисправление: Safe (удаляет неиспользуемый импорт)
Что показывает ruff rule:
- Код и название правила
- Категорию, к которой относится правило
- Описание нарушения
- Пример кода
- Тип автоисправления (safe / unsafe / none)
ruff rule --all — все правила
ruff rule --all # очень длинный список
# Фильтрация по категории через grep:
ruff rule --all | grep "^F" # только Pyflakes
ruff rule --all | grep "^UP" # только pyupgrade
ruff rule --all | grep "^PLR" # только Pylint Refactoring
ruff rule --all > rules.txt и просматривайте файл в редакторе. Это даст полную картину всех доступных проверок.
Пример: найти правило для вашей задачи
# Найти все правила, связанные с "except"
ruff rule --all | grep -i "except"
# Найти все правила с автоисправлением
ruff rule --all | grep "Safe fix"
# Найти правила для pandas
ruff rule --all | grep "^PD"
# Сколько всего правил в категории?
ruff rule --all | grep "^B" | wc -l
Рекомендуемые наборы категорий
| Уровень | Категории | Для кого |
|---|---|---|
| Минимальный | E, F |
Дефолт — стиль + логика |
| Базовый | E, F, I, N |
Стиль + логика + импорты + именование |
| Средний | E, F, I, N, UP, B |
+ pyupgrade + bugbear |
| Продвинутый | E, F, I, N, UP, B, S, C90 |
+ безопасность + сложность |
| Строгий | ALL |
Новые проекты, open-source библиотеки |
| Django | E, F, I, N, UP, B, S, C90, DJ |
Django-проекты |
| FastAPI | E, F, I, N, UP, B, ANN, ARG |
API-сервисы с типизацией |
| Data Science | E, F, I, N, UP, B, PD, NPY, PERF |
pandas/NumPy + производительность |
ignore.
Итоги
- Ruff имеет более 800 правил в ~40 категориях.
- Категории включаются через префиксы:
E,F,I,N,UP,B,S... - E + F включены по умолчанию — это стиль и логика.
- I (isort) — обязательная категория для порядка в импортах.
- UP (pyupgrade) зависит от
target-version. - B (bugbear) находит реальные баги — очень рекомендуется.
- RUF — уникальные правила Ruff (RUF100 для noqa).
- Используйте
ruff rule F401для документации правила. - Используйте
ruff rule --allдля полного списка. - Начинайте с малого набора, добавляйте категории постепенно.
Урок 5.1: Категории правил
5 вопросов