Single quotes black

d4ee3e9b086bb33f45c2fa1f2ff21bff.png

Когда проект на python долгое время живет без правил по формату строк, то в один прекрасный момент оказывается, что 90% кода используют одинарные кавычки, а 10% — двойные.

Добавление flake8-quotes с соответствующими правилами перестало пускать новый код с двойными кавычками дальше пул-реквеста, но начало требовать ручной правки формата в уже существующем коде, чего хотелось бы избежать.

Первой мыслью было задействовать black, но предлагаемый им формат предполагает исключительно использование двойных кавычек. В 2018 в github black был запрос Single quotes option формата строк, обсуждение было жарким, но закончилось оно лишь введением опции --skip-string-normalization, позволявшей не трогать формат строк в проверяемом коде.

Самым простым в данной ситуации было просто согласиться с black, но команда и бóльшая часть кода были против. Пришлось искать другое решение, которое оказалось в модификации исходного кода black.

Сразу скажу, что все правила реализовать не получилось, так как в flake8-quotes можно задать разные правила для docstring и остальных многострочных строк, а логика black их, насколько удалось разобраться, не различает.

Тем не менее, с двойными кавычками в простых строках справиться удалось,

и вот что для этого потребовалось:

  • были скачаны исходники black 22.1.0 (это первая не-бета версия black и наш CI в данный момент использует эту версию в режиме проверки кода).

  • установлены необходимые ему библиотеки

Для Python 3.8:

click             8.1.3
colorama          0.4.4
mypy-extensions   0.4.3
pathspec          0.9.0
pip               21.3.1
platformdirs      2.5.2
tomli             2.0.1
typing_extensions 4.2.0
wheel             0.37.1

Основные правки оказались сконцентрированы в методе normalize_string_quotes модуля src/black/stringы.py:

Условие на входе метода

    if value[:3] == '"""':
        return s

    elif value[:3] == "'''":
        orig_quote = "'''"
        new_quote = '"""'
    elif value[0] == '"':
        orig_quote = '"'
        new_quote = "'"
    else:
        orig_quote = "'"
        new_quote = '"'

заменил на 

if value[:3] == '"""':
    return s

elif value[:3] == "'''":
    return s  # оставляем как есть и строки с ''', и строки с """
elif value[0] == '"':
    orig_quote = '"'
    new_quote = "'"
else:
    orig_quote = "'"
    new_quote = '"'

а условие на выходе метода

    if new_escape_count == orig_escape_count and orig_quote == '"':
        return s  # Prefer double quotes

заменил на

    if new_escape_count == orig_escape_count and orig_quote == "'":
        return s  # Prefer single quotes

Через несколько минут работы модифицированного black проблема двойных кавычек в нашем проекте была решена (хорошо, остался еще этап ручного исправления """ в многострочных строках на ''', но он тоже не занял много времени).

Из приятного. В коде нашлось несколько строк вида u'\xa0' — видимо скопированных из советов для python 2 — и исправилось (удалило u в начале). Также исправились сами экранированные строки "\"" в '"'

Из неожиданного. Строки fr'\abc' заменило на rf'\abc'. Таких правок при необходимости легко было избежав закомментировав вызов метода normalize_string_prefix.

В итоге хотелось бы сказать, что пока все это делал, почти согласился с идеологией black, хотя доводы апологетов одинарных кавычек — они не требуют нажатия Shift для ввода, сам интерпретатор Python в консоли использует именно их, код выглядит прозрачней и тем самым более pythonic — тоже заслуживают внимания.

Что же касается opensource проектов, тут, я полагаю, все уже давно решено и black с его двойными кавычками победил.

© Habrahabr.ru