Представляем metacode: машиночитаемые инструкции в комментариях.
Даёт Python-инструментам общий синтаксис машиночитаемых инструкций, расположенных прямо в комментариях исходного кода.
На этой странице 4 раздела
Разработчику часто нужно оставить рядом с одной строкой кода короткое указание: не показывать здесь предупреждение, временно отключить форматирование или не учитывать строку при проверке покрытия тестами. Python-инструменты записывают такие указания в комментариях вроде noqa, type: ignore и fmt: off. У каждого свой синтаксис и разбор, поэтому новые анализаторы повторяют ту же работу и могут неверно понять чужой комментарий.
Настройки проекта подходят для общих правил, но не для исключения в одной конкретной строке. Таким локальным инструкциям нужен общий синтаксис, смысл которого определяет сам инструмент.
metacode — Python-библиотека для чтения специально оформленных инструкций из комментариев. Она задаёт компактную форму ключ: команда[аргументы], общую для разных инструментов, но оставляет каждому собственный ключ и набор команд. Релиз доступен на GitHub.
Синтаксис и распределение ответственности
Директива metacode содержит ключ, команду и необязательные аргументы:
# mutating: ignore[comparison]
# fmt: off
# type: ignore[attr-defined]
metacode разбирает ключ: команда[аргументы] в записи ParsedComment. Аргументы могут содержать обычные значения и имена Python или, при явном разрешении, элементы синтаксического дерева, которые metacode никогда не исполняет.
Вызывающий код передаёт собственный ключ, поэтому посторонние директивы в той же строке игнорируются:
from metacode import parse
comment = "mutating: ignore[comparison] # fmt: off"
print(parse(comment, "mutating"))
#> [ParsedComment(key='mutating', command='ignore', arguments=['comparison'])]
Несколько разделённых решётками директив могут находиться в одной строке. Каждый инструмент запрашивает свой ключ и сам определяет смысл команды.
metacode разбирает только текст комментария. Он не читает файлы, не связывает директивы с координатами или узлами и не определяет область действия команды.
Зачем ещё одно соглашение?
metacode не заменяет все pragmas. # type: ignore[code], # fmt: off и # isort: skip соответствуют его грамматике; # noqa, # nosec, # pragma: no cover и синтаксис Pylint требуют адаптеров или исходной поддержки.
doctest directives определяют язык комментариев для одной области, а директивы инструментов Go используют общий синтаксис с пространствами имён.
Комментарий размещает локальную инструкцию рядом с нужным кодом, не влияет на выполнение и не требует импортов. Конфигурация проекта лучше выражает общую политику, а директива в строке кода может описать исключение для одного выражения.
Использование в инструментах обработки исходного кода
Средства разбора исходного кода находят комментарии, а metacode читает их содержимое. Так инструмент может отдельно находить комментарии, разбирать инструкции и применять собственные правила.
Пока независимые инструменты не приняли эту грамматику, metacode остаётся переиспользуемым соглашением и парсером, а не стандартом экосистемы.
Что дальше
Проект добавит надёжные способы не только читать, но и записывать такие инструкции, не повреждая обычные комментарии.