Настройка форматировщика
Длина строки, кавычки, отступы — настраиваем под свой стиль.
Обзор настроек форматирования
Ruff format предлагает несколько опций конфигурации, которые позволяют настроить стиль форматирования под нужды вашего проекта. Все настройки располагаются в секции [tool.ruff.format] в pyproject.toml (или [format] в ruff.toml).
В отличие от линтера, у форматтера минимальное количество настроек. Это сознательное решение: форматтер должен быть детерминированным и предсказуемым. Слишком много настроек ведёт к спорам о стиле, которых форматтеры призваны избегать.
Полная конфигурация форматирования:
[tool.ruff]
line-length = 88 # Длина строки (по умолчанию: 88)
[tool.ruff.format]
indent-width = 4 # Ширина отступа (по умолчанию: 4)
indent-style = "space" # "space" или "tab" (по умолчанию: space)
quote-style = "double" # "double" или "single" (по умолчанию: double)
[tool.ruff.format]
magic-trailing-comma = true # Уважать trailing comma (по умолчанию: true)
[tool.ruff.format]
docstring-code-format = false # Форматировать код в docstrings (по умолчанию: false)
docstring-code-line-length = "dynamic" # Длина строки в docstrings (по умолчанию: dynamic)
[tool.ruff.format]
line-ending = "auto" # "auto", "lf", "crlf", "native" (по умолчанию: auto)
[tool.ruff.format]), так и в отдельном ruff.toml (секция [format]).
line-length — длина строки
Настройка line-length (находится в секции [tool.ruff], не внутри format) определяет максимальную длину строки в символах. Ruff format будет переносить строки, превышающие этот лимит. Значение по умолчанию — 88 (как у Black).
| Значение | Описание | Когда использовать |
|---|---|---|
| 79 | PEP 8 recommendation | Строгий стандарт PEP 8 |
| 88 | Black default | Настройка по умолчанию, большинство проектов |
| 100 | Popular in Django | Крупные проекты, где длинные имена — норма |
| 120 | Максимальная | Команды, предпочитающие компактность |
# pyproject.toml — line-length 79 (PEP 8)
[tool.ruff]
line-length = 79
# or 100 для больших проектов
[tool.ruff]
line-length = 100
Влияние line-length на форматирование:
# С line-length = 79:
result = some_function_with_long_name(
arg1, arg2, arg3, arg4, arg5
)
# С line-length = 120:
result = some_function_with_long_name(arg1, arg2, arg3, arg4, arg5)
line-length влияет и на линтер (правило E501), и на форматтер. Может быть полезна в больших проектах с глубокой вложенностью и длинными именами.
indent-width — ширина отступа
Настройка indent-width определяет количество пробелов для одного уровня отступа. По умолчанию — 4 (стандарт PEP 8).
# pyproject.toml
[tool.ruff.lint] # indent-width доступен и в lint, и в format
indent-width = 4 # стандарт для Python
# или наоборот — 2 пробела:
[tool.ruff.format]
indent-width = 2 # нестандартно для Python, но возможно
Сравнение indent-width:
# indent-width = 4:
def foo():
if True:
for i in range(10):
print(i)
# indent-width = 2:
def foo():
if True:
for i in range(10):
print(i)
indent-style — пробелы или табуляция
Настройка indent-style определяет, использовать ли пробелы или табуляцию для отступов:
"space"(по умолчанию) — пробелы. Стандарт для Python согласно PEP 8"tab"— табуляция. Редко используется в Python
# pyproject.toml
[tool.ruff.format]
indent-style = "space" # пробелы (по умолчанию, рекомендуется)
# или
[tool.ruff.format]
indent-style = "tab" # табуляция (нестандартно)
quote-style — тип кавычек
Настройка quote-style определяет, какие кавычки использовать для строк: двойные (" ") или одинарные (' '). По умолчанию — double (как в Black).
| Значение | Пример | Примечание |
|---|---|---|
"double" |
x = "hello" |
Стандарт Black, PEP 8 рекомендует |
"single" |
x = 'hello' |
Популярно в некоторых командах |
# pyproject.toml
[tool.ruff.format]
quote-style = "single" # одинарные кавычки
# Результат:
name = 'Alice'
greeting = f'Hello, {name}!'
items = ['one', 'two', 'three']
# С quote-style = "double" (по умолчанию):
name = "Alice"
greeting = f"Hello, {name}!"
items = ["one", "two", "three"]
"it\'s" при quote-style = "double"), Ruff автоматически использует другой тип кавычек для этой строки, чтобы избежать экранирования.
docstring-code-format и docstring-code-line-length
Опция docstring-code-format включает форматирование примеров кода внутри docstring-блоков. Это полезно, если вы документируете API с примерами использования внутри тройных кавычек.
docstring-code-line-length определяет максимальную длину строки для кода внутри docstring. Может быть:
"dynamic"(по умолчанию) — использует то же значение, что и общийline-length- Число — фиксированная длина, отличная от основной
# pyproject.toml
[tool.ruff.format]
docstring-code-format = true
docstring-code-line-length = "dynamic" # или число, например 60
# Пример docstring до форматирования:
def calculate(a, b, c, d, e, f):
\"\"\"Calculate something.
Example:
result = calculate(1, 2, 3, 4, 5, 6)
print(f"The result is {result}")
\"\"\"
return a + b + c + d + e + f
Важно: Ruff форматирует только те блоки внутри docstring, которые распознаются как Python-код (начинаются с >>>, ... или являются примерами с $ python).
docstring-code-format может изменить внешний вид примеров в документации. Убедитесь, что это подходит вашей команде.
magic-trailing-comma
Настройка magic-trailing-comma управляет поведением "волшебной завершающей запятой". Когда включено (по умолчанию), наличие запятой после последнего элемента заставляет форматировщик разбить коллекцию на несколько строк:
# C magic-trailing-comma = true (по умолчанию):
# эта запятая = форматировщик сделает многострочным
items = [
"one",
"two",
"three", # <-- trailing comma
]
# без trailing comma — может схлопнуть в одну строку
items = ["one", "two", "three"]
# С magic-trailing-comma = false:
# trailing comma игнорируется — всё схлопнется
items = ["one", "two", "three"]
line-ending — концы строк
Настройка line-ending определяет, какие символы конца строки использовать:
| Значение | Символ | Когда использовать |
|---|---|---|
"auto" |
Определяется автоматически | По умолчанию |
"lf" |
\n (Unix/macOS) | Кроссплатформенные проекты |
"crlf" |
\r\n (Windows) | Windows-only проекты |
"native" |
Системный | Одно-ОС проекты |
# pyproject.toml
[tool.ruff.format]
line-ending = "lf" # всегда использовать LF (Unix-style)
# или для Windows-проекта:
[tool.ruff.format]
line-ending = "crlf"
line-ending = "lf" и настройка .gitattributes с * text=auto.
Полная конфигурация с комментариями
# ruff.toml — полная конфигурация форматирования
line-length = 88
indent-width = 4
[format]
indent-style = "space" # пробелы или табуляция
quote-style = "double" # двойные или одинарные кавычки
magic-trailing-comma = true # уважать trailing comma
docstring-code-format = true # форматировать код в docstrings
docstring-code-line-length = "dynamic" # или число
line-ending = "auto" # LF, CRLF, native, auto
Примеры разных конфигураций
Конфигурация A: Стандартная (Black-совместимая)
# ruff.toml — полностью как Black
line-length = 88
indent-width = 4
[format]
indent-style = "space"
quote-style = "double"
magic-trailing-comma = true
docstring-code-format = false
Конфигурация B: Одинарные кавычки и 100 символов
# ruff.toml — для команд, предпочитающих одинарные кавычки
line-length = 100
indent-width = 4
[format]
quote-style = "single"
magic-trailing-comma = false
Конфигурация C: Строгий PEP 8
# ruff.toml — строгий PEP 8
line-length = 79
indent-width = 4
[format]
indent-style = "space"
quote-style = "double"
magic-trailing-comma = true
Конфигурация D: Документация с примерами
# ruff.toml — для проектов с богатой документацией
line-length = 88
[format]
docstring-code-format = true
docstring-code-line-length = 60
quote-style = "double"
Настройка для Jupyter Notebooks
Для форматирования Jupyter Notebooks нужна дополнительная настройка include:
# pyproject.toml
[tool.ruff]
include = ["*.py", "*.pyi", "*.ipynb"]
[tool.ruff.format]
# настройки форматтера те же самые
Ruff будет форматировать код внутри каждой ячейки ноутбука, не затрагивая метаданные и non-code ячейки.
Отладка конфигурации форматтера
Используйте ruff check --show-settings для просмотра активных настроек. Вы увидите все применённые настройки, включая те, что относятся к форматтеру:
ruff check --show-settings . | grep -A 20 "\[format\]"
# [format]
# indent-style = "space"
# indent-width = 4
# line-ending = "auto"
# magic-trailing-comma = true
# quote-style = "double"
# docstring-code-format = false
# docstring-code-line-length = "dynamic"
Если что-то работает не так, как ожидалось, проверьте:
- Какой конфигурационный файл используется (ruff.toml, pyproject.toml)
- Не переопределяются ли настройки вложенными конфигами
- Правильно ли указана секция (не перепутаны [tool.ruff] и [tool.ruff.format])
Совместимость с другими инструментами
Поскольку ruff format стремится быть заменой Black, он совместим с экосистемой инструментов, которые ожидают Black-стиль:
- pre-commit — используйте ruff-format хук
- VS Code — расширение Ruff форматирует при сохранении
- pyproject.toml — настройки в том же файле, что и остальные инструменты
- tox/nox — можно запускать ruff format как команду
- CI/CD — GitHub Actions, GitLab CI, Jenkins
| Инструмент | Способ интеграции |
|---|---|
| pre-commit | id: ruff-format |
| VS Code | editor.defaultFormatter = "charliermarsh.ruff" |
| PyCharm | File Watcher с ruff format |
| Neovim | conform.nvim или null-ls |
Резюме настроек
| Опция | Секция | По умолчанию | Возможные значения |
|---|---|---|---|
| line-length | [tool.ruff] |
88 | Число |
| indent-width | [tool.ruff] |
4 | Число |
| indent-style | [tool.ruff.format] |
"space" | "space", "tab" |
| quote-style | [tool.ruff.format] |
"double" | "double", "single" |
| magic-trailing-comma | [tool.ruff.format] |
true | true, false |
| docstring-code-format | [tool.ruff.format] |
false | true, false |
| docstring-code-line-length | [tool.ruff.format] |
"dynamic" | "dynamic", число |
| line-ending | [tool.ruff.format] |
"auto" | "auto", "lf", "crlf", "native" |
Подробное сравнение с Black
Хотя ruff format стремится к 100% совместимости с Black, есть несколько известных различий. Вот они с примерами:
Различие 1: Обработка пустых строк в начале функций
# Black оставляет:
def foo():
x = 1
return x
# Ruff format удаляет пустую строку после def:
def foo():
x = 1
return x
Различие 2: Форматирование trailing comma в импортах
# Black:
from typing import (
Optional,
Union,
)
# Ruff format то же самое — совпадает
Различие 3: Обработка однострочных if/else
# Black:
x = 1 if some_long_condition_here else 2
# Ruff format:
x = 1 if some_long_condition_here else 2
# Совпадают
История и мотивация
До появления Black (2018) в Python-сообществе не было единого стандарта форматирования. Каждый проект использовал свой стиль, код-ревью часто превращались в споры о пробелах и отступах. Black изменил это, предложив "бескомпромиссный форматтер" — ты либо принимаешь его стиль полностью, либо не используешь его.
Ruff format наследует эту философию, но добавляет несколько опций для гибкости (quote-style, indent-style). Главная мотивация создания Ruff format — скорость и интеграция с линтером в одном инструменте.
Ключевые даты:
- 2018 — Релиз Black
- 2022 — Первый релиз Ruff (только линтер)
- 2023 — Релиз ruff format (v0.1.0)
- 2024 — Стабилизация ruff format, совместимость ~99% с Black
Рекомендации по настройкам для разных команд
| Тип команды | line-length | quote-style | magic-trailing-comma |
|---|---|---|---|
| Open source библиотека | 88 | double | true |
| Корпоративное приложение | 100 | double | true |
| Django проект | 100-120 | double | true |
| Data Science / Notebooks | 88 | double | true |
Практическое задание
- Создайте файл с разными стилями форматирования (разные отступы, кавычки, пробелы)
- Настройте ruff format с quote-style = "single" и line-length = 79
- Запустите ruff format и проверьте результат
- Поменяйте настройки на quote-style = "double" и line-length = 100
- Снова запустите форматирование — увидите разницу
- Попробуйте magic-trailing-comma = false и посмотрите, как изменится форматирование коллекций
# файл для теста: test_format.py
x = { "key1": 1, "key2": 2 }
data = [1,2,3,4,5,6,7,8,9,10]
items = [ { "nested": True }, { "nested": False } ]
long_string = "This is a very long string that exceeds the line length limit and should be wrapped by the formatter"
def foo(x,y,z):
return x+y+z
Программное использование ruff format
Ruff можно использовать как библиотеку из Python для программного форматирования:
import subprocess
# Форматирование одного файла
def format_file(filepath):
result = subprocess.run(
["ruff", "format", filepath],
capture_output=True, text=True
)
if result.returncode == 0:
if result.stdout:
print(f"Файл {filepath} отформатирован")
else:
print(f"Файл {filepath} уже отформатирован")
else:
print(f"Ошибка: {result.stderr}")
# Проверка без изменений
def check_formatting(filepath):
result = subprocess.run(
["ruff", "format", "--check", filepath],
capture_output=True, text=True
)
return result.returncode == 0
# Пакетное форматирование с прогрессом
import glob
py_files = glob.glob("**/*.py", recursive=True)
for i, f in enumerate(py_files):
format_file(f)
print(f"Progress: {i+1}/{len(py_files)}", end="\r")
ruff модуль, если он установлен как библиотека: from ruff import format, check.
Если ruff format меняет слишком много
На больших проектах первый запуск ruff format может изменить тысячи файлов. Вот стратегия мягкого внедрения:
- Сначала посмотрите масштаб:
ruff format --check . | wc -l— сколько файлов изменится - Форматируйте поэтапно: по директориям:
ruff format src/core/; ruff format src/api/ - Используйте .gitattributes: добавьте
*.py diff=pythonдля лучшего отображения diff - Добавьте exclude для критических файлов:
exclude = ["legacy/", "vendor/"] - Запустите в отдельной ветке:
git checkout -b format-all-the-things
# Стратегия поэтапного форматирования
# Шаг 1: проверить масштаб
ruff format --check . | wc -l
# Шаг 2: отформатировать основные модули
ruff format src/main_module/
# Шаг 3: проверить тесты
ruff format --check tests/
# Шаг 4: закоммитить изменения
git add -A && git commit -m "style: apply ruff format"
# Шаг 5: продолжать с остальными модулями
Бенчмарки производительности
Независимые бенчмарки показывают, что ruff format значительно быстрее Black. Вот сравнение на реальных проектах:
| Проект | Файлы | ruff format (сек) | Black (сек) | Ускорение |
|---|---|---|---|---|
| CPython | ~3,000 | 0.42 | 8.1 | 19x |
| Django | ~2,000 | 0.31 | 6.4 | 20x |
| Apache Airflow | ~1,500 | 0.25 | 5.2 | 21x |
| Zulip | ~800 | 0.12 | 2.8 | 23x |
Это ускорение достигается благодаря реализации на Rust, параллельной обработке файлов и эффективному AST-анализу.
Чеклист внедрения ruff format в проект
- [ ] Установить Ruff:
pip install ruffили через менеджер пакетов - [ ] Создать конфигурационный файл (pyproject.toml или ruff.toml)
- [ ] Настроить
[tool.ruff.format]с нужными параметрами - [ ] Запустить
ruff format .на всём проекте - [ ] Проверить изменения через
git diff - [ ] Запустить тесты:
pytest - [ ] Настроить pre-commit с ruff-format
- [ ] Добавить
ruff format --check .в CI - [ ] Обновить документацию проекта
Урок 3.2: Настройка форматировщика
5 вопросов