Внедрение Black в проект
Note
Это руководство неполное. Предложения и правки приветствуются!
Как не испортить git blame
Один из старых аргументов против перехода на автоматические форматтеры вроде Black — миграция засоряет вывод git blame. Раньше это было так, но начиная с Git 2.23 поддерживается игнорирование ревизий в blame через опцию --ignore-rev. Можно также передать файл со списком ревизий через --ignore-revs-file. Изменения из указанных ревизий не будут учитываться при назначении авторства; строкам будет приписываться последняя ревизия до игнорируемой, которая их меняла.
При переходе стиля проекта на Black отформатируйте весь код и закоммитьте изменения (лучше одним большим коммитом). Затем запишите полный 40-символьный идентификатор коммита (или несколько) в файл, обычно называемый .git-blame-ignore-revs, в корне проекта.
# Migrate code style to Black
5b4ab991dede475d393e9d69ec388fd6bd949699
После этого передавайте этот файл в git blame — авторство будет актуальным и без шума от форматирования.
$ git blame important.py --ignore-revs-file .git-blame-ignore-revs
7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 1) def very_important_function(text, file):
abdfd8b0 (Alice Doe 2019-09-23 11:39:32 -0400 2) text = text.lstrip()
7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 3) with open(file, "r+") as f:
7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 4) f.write(formatted)
Можно настроить Git так, чтобы при каждом вызове git blame автоматически использовался файл с игнорируемыми ревизиями:
$ git config blame.ignoreRevsFile .git-blame-ignore-revs
Ограничение: не все веб-интерфейсы репозиториев умеют игнорировать ревизии в своём blame. На таких платформах коммит с переформатированием всё равно будет виден. GitHub и GitLab (с версии 17.10) по умолчанию поддерживают .git-blame-ignore-revs в представлении blame.
Использование Black вместе с другими инструментами
Совместимые с Black конфигурации
Изменения Black безвредны (или должны быть такими), но часть из них конфликтует с другими инструментами. Часто вместе с Black используют линтеры и проверки типов. Некоторые из них нужно слегка подстроить. Ниже — совместимые с Black конфигурации в разных форматах для распространённых инструментов.
Black поддерживает только конфигурацию в TOML (например, pyproject.toml). Приведённые примеры задают только настройки соответствующих инструментов в их собственных форматах файлов.
Готовые совместимые конфигурации: compatible_configs.
isort
isort упорядочивает и форматирует импорты. Black тоже форматирует импорты, но иначе, чем isort по умолчанию, из-за чего возникают конфликты.
Профиль
С версии 5.0.0 isort поддерживает профили для совместимости с распространёнными стилями. Профиль Black можно задать в любом поддерживаемом isort конфиге. Пример для pyproject.toml:
[tool.isort]
profile = "black"
Ручная настройка
Если используется isort старше 5.0.0 или нужна своя настройка под Black, можно задать совместимые опции. Пример для .isort.cfg:
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0
use_parentheses = True
ensure_newline_before_comments = True
line_length = 88
Зачем эти опции
Black переносит длинные импорты, вынося идентификаторы на отдельные строки и добавляя trailing comma. Подробнее: How Black wraps lines.
Режим переноса импортов isort по умолчанию — «Grid»:
from third_party import (lib1, lib2, lib3,
lib4, lib5, ...)
Он несовместим с Black. В isort можно включить режим «Vertical Hanging Indent»:
from third_party import (
lib1,
lib2,
lib3,
lib4,
)
Это достигается опцией multi_line_output = 3. Black при переносе ставит trailing comma и использует скобки — для совпадения нужны include_trailing_comma = True и use_parentheses = True. force_grid_wrap = 0 — переносить только когда импорт длиннее line_length. Задайте line_length = 88 (как у Black) и ensure_newline_before_comments = True, чтобы секции импортов с комментариями совпадали с Black.
ensure_newline_before_comments = True работает с isort >= 5; в более старых версиях не ломает конфиг, его можно оставить.
Форматы конфигов
.isort.cfg
[settings]
profile = black
setup.cfg
[isort]
profile = black
pyproject.toml
[tool.isort]
profile = 'black'
.editorconfig
[*.py]
profile = black
pycodestyle
pycodestyle — линтер стиля кода, предупреждает о синтаксисе, возможных багах и отступлениях от PEP 8. Несколько отступлений дают конфликты с Black.
Конфигурация
max-line-length = 88
ignore = E203,E701
Зачем эти опции
max-line-length — как и для isort, разрешать строки до 88 символов (значение по умолчанию в Black).
E203 — в срезах Black по правилам PEP 8 выравнивает пробелы вокруг :, из-за чего pycodestyle выдаёт E203 whitespace before ':'. Это предупреждение не соответствует PEP 8, его нужно отключить.
E701 / E704 — Black сворачивает в одну строку тела функций и классов из одного .... В остальных случаях Black не допускает несколько утверждений в одной строке. pycodestyle может выдавать E701 multiple statements on one line (colon); правило E704 multiple statements on one line (def) по умолчанию выключено — его не включайте.
W503 — при переносе строки Black переносит перед бинарным оператором, что соответствует PEP 8 (с апреля 2016). В Flake8 есть выключенное по умолчанию предупреждение W503 line break before binary operator, противоречащее этой рекомендации — его не включайте. Можно использовать W504 line break after binary operator.
Форматы
setup.cfg, .pycodestyle, tox.ini
[pycodestyle]
max-line-length = 88
ignore = E203,E701
Flake8
Flake8 объединяет несколько линтеров, в том числе pycodestyle, поэтому у него те же конфликты.
Bugbear
Рекомендуется использовать плагин Bugbear и включить проверку B950 вместо E501 во Flake8 — она согласована с правилом 10% в Black.
Установите Bugbear и настройте так:
[flake8]
max-line-length = 80
extend-select = B950
extend-ignore = E203,E501,E701
Минимальная конфигурация
Если Bugbear установить нельзя или не хочется, можно ограничиться минимально совместимой конфигурацией:
[flake8]
max-line-length = 88
extend-ignore = E203,E701
Зачем эти опции
См. раздел про pycodestyle выше.
Форматы
.flake8, setup.cfg, tox.ini
[flake8]
max-line-length = 88
extend-ignore = E203,E701
Pylint
Pylint — линтер, во многом похожий на Flake8, с дополнительными проверками форматирования и стиля (например, именование переменных).
Конфигурация
max-line-length = 88
Зачем
Ограничить предупреждения о длине строк порогом в 88 символов.
Если используется pylint<2.6.0, отключите также C0326 и C0330 — они несовместимы с форматированием Black и в новых версиях удалены.
Форматы
pylintrc
[format]
max-line-length = 88
setup.cfg
[pylint]
max-line-length = 88
pyproject.toml
[tool.pylint.format]
max-line-length = "88"
Источники: Introducing Black to your project, Using Black with other tools. Перевод неофициальный.