autorv

Автоматическое заполнение ревью в Ревизоре Яндекс Практикума

Цель

Консольная утилита, преобразующая архив с ДЗ в новый архив, который Ревизор готов принять и перенести из него комменты в исходные файлы.

Способ применения

Запуск

python autorv.py путь-к-домашке.zip

создаст (перезапишет!) файл путь-к-домашке.N-E!F+G.zip, который можно передать Ревизору.

Вместо N, E, F, G будут подставлены числа, отражающие результат работы:

  • N - число файлов, в которые попали комменты,
  • E - число ошибок (Надо исправить),
  • F - число неточностей (Можно лучше),
  • G - число удач (Отлично).

Основные идеи

(1) Искать места для комментов с помощью специальной разметки текстов.

Пример. Фрагмент

    group = models.ForeignKey(…
        ¬°
        related_name=†!<groups¦group>!†

используется так:

  • Ищется объявление поля группы.
  • Учитывается, что строка может заканчиваться на дополнительные пробелы (это ).
  • Потом допускается пропуск нескольких (от 0) строк с двойным сдвигом (из-за ¬°) до ближайшего параметра related_name.
  • Ищется один из вариантов (это из-за !<¦>!) значения, заключенный в какие-то кавычки (это ).

(2) В спец.разметку входят

  • «шаблон» - "регулярка" - поисковый фрагмент на языке re-выражений Питона.
  • "Сахар", то есть сокращения для re-выражений
    • (‡) [‡] {‡} - "парные скобки", то есть от открывающей до ее парной закрывающей.
    • - "стяжка", то есть минимальный заполняющий текст (возможно пустой), в том числе с концами строк.
    • ‡‡ - "часть имени", то есть текст (возможно пустой) из букв/цифр/_/точки.
    • - "заполнитель", то есть любой непустой текст в пределах строки.
    • - "заполнитель", то есть любой текст в пределах строки.
    • - "пробельные символы", то есть пробелов/табов/EOL (может быть 0).
    • - "пробелы", то есть несколько пробелов (может быть 0).
    • - "обязательные пробелы", то есть несколько пробелов/табов или \n.
    • - "кавычка", то есть либо ', либо ".
    • ¬° - Фрагмент из нескольких строк (м.б. 0) с такими же сдвигами.
    • !<так¦этак¦эдак>! - "варианты".
    • ╠фраза╣ - "лишний текст", которого не должно быть перед следующим подходящим символом.
  • ↓1 - Сохранение номеров строк, которые можно вставлять в комментарий. Там они будут доступны под такими же обозначениями. Но если поисковых шаблонов несколько, то еще и под уточненными именами ↓1_2 (↓2 из второго шаблона).

Применяются такие регулярные выражения

Символ Его выражение/замена Комментарий
[\'\"]
.* Мнемоника: пустой символ = "от 0"
.+ Мнемоника: непустой символ = "от 1"
\s* Мнемоника: пустой символ = "от 0"
¶± \s+ Мнемоника: непустой символ = "от 1"
 * Мнемоника: пустой символ = "от 0"
‡‡ [\w\.]* Может быть другой знак
(?s:.*?) Общий знак тут и ниже
(‡) \([^\(\)]*?(?:\([^\(\)]*?(?:\([^\(\)]*?\)[^\(\)]*?)*?\)[^\(\)]*?)*?\) Глубина вложенности <3
[‡] \[[^\[\]]*?(?:\[[^\[\]]*?(?:\[[^\[\]]*?\][^\[\]]*?)*?\][^\[\]]*?)*?\] Глубина вложенности <3
{‡} \{[^\{\}]*?(?:\{[^\{\}]*?(?:\{[^\{\}]*?\}[^\{\}]*?)*?\}[^\{\}]*?)*?\} Глубина вложенности <3
¬° \n( *)¬° заменяется на (\n\\1.*)*
!< ¦ >! !<([^¦]+)¦([^>!]+)>! заменяется на ((\\1)|(\\2)) (остальные аналогично) Ожидаются <10 вариантов
заменяется на (?<!, заменяется на )
↓0 ↓1 ... ↓(\d+) заменяется на (?P<p\1>(?<!↓)) Не будет найденных символов

(3) Минимальным хранимым элементом является рв-словарь, содержащий такие ключи и значения:

  • levl со значениями
    • 'G' Good, "Отлично",
    • 'F' False, "Можно лучше",
    • 'E' Error, "Надо исправить".
  • pttn с одним или несколькими искомыми фрагментами.
  • note с текстом коммента.

Пример. Словарь

dict(levl='F', 
    pttn='''
    group = models.ForeignKey(…
        ¬°
        related_name=†!<groups¦group>!†
'''
    note='Неудачное имя для поля связи.',
)

(3) Эти словари объединяются в списки, которые указывают, как обрабатывать один файл из ДЗ-архива

{
'hw02_community-master/yatube/posts/admin.py':[...],
'hw02_community-master/yatube/posts/models.py':[...],
...
}

Этот набор (фактически словарь) хранится в файле, который в настройках привязывается к архиву, например, этот к такому kvichans__hw02_community_1639562917.zip

(4) Система настроек и форматы хранения.

  • Код имеет умолчательные настройки, которые могут быть изменены в любой части через внешний json.
  • Каждый из символов в спец.разметке может быть заменен на любую строку (но не всякая строках, конечно, уместна, так как поиски будут вестись через регулярки).
  • С каждым из файлов в архиве может быть связан произвольный файл (или несколько) с наборами рв-словарей.
  • Файлы с наборами рв-словарей могут быть
    • в виде питон-кода {'hw02_community-master/yatube/posts/models.py':[dict(...), dict(...),]}
    • в виде yaml
"hw02_community-master/yatube/posts/models.py":
- levl: F
  pttn: |2-
    group = models.ForeignKey(…
        ¬°
        related_name=†!<groups¦group>!†
  note: "Неудачное имя для поля связи."
  • в виде json (м.б. кому-то это окажется полезно)

(4) Дополнительные возможности

  • Можно разместить общие рв-словари для нескольких файлов в по укороченному пути. Например, для index.html получиться два рв-словаря при такой настройке
{
'hw02_community-master/yatube/templates/posts/':[
dict(levl='E', pttn='{{title}}', note='Лишняя контекстная переменная.',)
]
'hw02_community-master/yatube/templates/posts/index.html':[
dict(levl='F', pttn='{% if post.group.slug %}', note='Лучше писать `{% if post.group %}`.',)
]
}
  • Если указан не один фрамент, а несколько в виде pttn=['...','...'], то полезны дополнительные ключи:
    • 'frml', например, frml='m_0 and m_1' - логическая формула из результатов поисков каждого из фрагментов. Умолчание: один из поисков успешен.
    • 'posi', например, posi='max(p_0, p_1)' - выражение из строк найденных фрагментов. Задает строку для размещения коммента. Умолчание: максимальная из строк во всех поисках.
    • Весь поиск будет успешным, если eval(frml) будет истинным.
    • Их применение свободное. Например, можно выяснить, что первый фрагмент не найден, поставить комментарий у второго найденного фрагмента.
  • Ключ rpts - настройка повторений при вставке коммента. Ожидаются значения:
    • 'one' - создавать один коммент на файл у первого найденного случая.
    • 'all' - создавать комменты у каждого найденного случая.
    • если не задан - применять 'one' для всех кроме поиска с перечислением вариантов (!<раз¦два>!), для которого 'all'.

Запуск Монитора

При запуске

    autorv -m папка-с-именами-студентов

происходит зацикливание, при котором АР наблюдает за указанной папкой и папками вхоженными в нее.

Отслеживаются:

  • Создание новой подпапки (добавился студент).
  • Появление в подпапке нового zip (скачана новая домашка).

Действия при появлении нового zip регулируюсят через настройку opts.monitor.

Умолчательный набор действий зашит в код АР. Он включает

  • Распаковку zip-а.
  • Запуск АР для создания нового zip-а.
  • Запуск сравнивающей две папки утилиты (типа WinMerge), если есть папка с предыдущей итерацией (в том числе из предыдущего ДЗ).

Запуск для удаления сахара из шаблона поиска

При запуске

    python autorv.py -ds путь-файла-знаний::путь-по-знаниям

из json-данных в указанном файле будет извлечено значение и после замены сахара на регулярки выдано в соседний файл

    путь-файла-знаний.desugar_ГГ-ММ-ДД_ЧЧ-ММ-СС.py

Путь внутри json записывается с разделителем |.

  • Спуск в словаре выглядит так
    •     путь-до-словаря|ключ
  • Спуск в списке выглядит так
    •     путь-до-словаря|номер-позиции

Пример. В знаниях к ДЗ-2 hw02_skills.py есть

'posts/models.py':[
dict(levl='G',
    frml='ITER < 2 and m_0',
    pttn='''
    group = models.ForeignKey(‡
        on_delete=models.SET_NULL''',
    note='''Удачно.''',
),
dict(levl='G',
    pttn='''
    group = models.ForeignKey(‡
        related_name=†posts†''',
    note='''Правильно!''',
),

После запуска

    python autorv.py -ds path/hw02_skills.py::posts/models.py|1|ptth

появится файл

    path/hw02_skills.py.desugar_23-01-14_01-27-07.py

с готовой для тестирования регуляркой. Содержимое файла

import re

# Регулярка c сахаром
pttn = r"""{pttn}"""

# Регулярка без сахара
pttn = r"""{dspttn}"""

# Задайте тестируемый текст из ДЗ
src = """ """ 
#src = open(r'путь к исходнику в ДЗ', encoding='utf8').read()

# Запуск теста
mt  = re.search(pttn, src)
if not mt:return print('fail')
print(mt.groupdict())

Известные проблемы

  • Ревизор глотает начальные пробелы в комментах. Поэтому autorv меняет левый пробел на символ ·. В результате примеры кодов/разметки в комментах оказываются некорректными. Ждем исправления Ревизора.

  • Взаимодействие настроек

    • rpts='all' (=комментировать все найденные в файле фрагменты),
    • note=['...', '...'] (=искать разные фрагменты),
    • note='...!<...¦...>!...' (=искать варианты)

    сейчас запутанное и иногда нелогичное. Будет переделка.

(ToDo) В планах

  • Обмен вычисленными значениями между найденными случаями.
  • Добавить в формулу для позиции posi найденные .

История обновлений

0.9.025 2022-01-19

  • [+] Добавлен ключ pttn_wo_strip, чтобы исключить умолчательные удаления пробельных символов из значения(ий) pttn.
  • [+] Добавлена возможность задавать список для note. Из него будут извлекаться последовательные значения для найденных случаев. А последнее значение будет использоваться для всех остальных случаев.
  • [+] Добавлены новые "сахарные" знаки:
    • ‡‡ – для заполнителя из букв/цифр/_/точки (м.б. пустого).
    • (‡), [‡], {‡} – для заполнителя до парной скобки.
    • – для заполнителя "в пределах строки" (непустого).

0.9.026 2022-01-21

  • [*] Добавлена возможность ставить пробелы вокрут > и ? при объединении "знаний".
  • [+] В формулах frml добавлены "внешние" значения
    • SRC_PATH - полный путь к комментируемому файлу в zip.
    • SRC_FN - имя комментируемого файла в zip.
  • [+] В рв-словаре ожидается ключ LOG=1, который запускает логгирование работы с этим словарем при каждом его применении.
  • [+] Добавлены новые "сахарные" знаки:
    • – для заполнителя "в пределах строки" (м.б. пустого).
    • – для заполнителя "в пределах строки" (непустого). Синоним к .
    • – для пробелов (м.б. пустого набора). Синоним к .
    • – для пробельных символов (непустого набора). Синоним к ¶±.

0.9.027 2022-01-23

  • [+] В формулах frml добавлены "внешние" значения, которые расчитываются от имени zip-файла. Это дает возможность делать разные комменты для разных итераций ревью. Эти значения задаются в настройках. По умолчанию задаются ITER, которые извлекаются из конца имени: name-7.zip дает ITER со значением 7.
  • [+] Добавлено ожидание в рв-словаре ключа brief для формирования общего коммента. Составленный общий коммент попадает (пока) в лог.
  • [*] Исправлено формирование архива для Ревизора
    • К имени (до расширения) дописывается статистика: name.5-4!3+2.zip - комменты в 5 файлах, 4/3/2 на уровне ошибка/неточность/удача.
    • Включено сжатие.
    • Включено сохранение дат файлов.

0.9.028 2022-02-10

  • [+] Добавлены новые "сахарные" знаки:
    • – для заполнителя из пробельных символов (м.б. пустого).
  • [*] Исправлено применение espanso. Теперь нет ожидания, что ключ будет завершаться пробелом.
  • [*] Исправлена работа с путями к zip, содержащими пробелы.

0.9.201 2022-02-25

  • [+] Добавлена возможность указывать сразу несколько файлов/папок для списка рв-словарей: {(файл_1, файл_2):[dict(...), dict(...)]}. Это предоставляет способ для синхронного комментирования в разных папках, а также для избирательного комментирования в нужных файлах.
  • [+] Появились параметры для запуска в консоли. См параметр -h.
  • [+] Монитор объединен с АвтоРевьювером. Запуск autorv -m папка.
  • [+] Добавлен третий слой для настройки. При запуске autorv -g файл.json ... умолчательные настройки будут перекрыты сначала из autorv.py.json, потом из указанного файл.json.
  • [*] АвтоРевьювер теперь выводит лог и в поток печати, и в файл autorv.py.log. Монитор выводит лог только в поток печати.

0.9.202 2022-02-26

  • [+] Добавлено заглядывание в zip для выяснения "какая это домашка": словарь opts.re4hwdir_to_skill_key. Cловарь opts.re4zipname_to_skill_key для анализ имени zip-файла теперь не обязателен.
  • [+] Добавлена реакция на пустой непоследний коммент в списке note из рв-словаря. Коммент пропускается.
  • [+] Добавлена реакция на пустой последний коммент в списке note из рв-словаря. Этот и случай ниже (в этом же файле) не комментируются. Это позволяет сделать гибче и разнообразнее комменты к одинаковым случаям.

0.9.203 2022-06-19

  • [+] Добавлены заготовки для работы с ДЗ-16/17/18/19/20.
  • [+] Добавлен отдельный "сахарный" знак (умолчание ‡‡) для "Имя с точками". До этого использовалось удвоение знака "Стяжка" (умолчание ).
  • [*] Исправлена работа шаблонами вида 'p!<p1¦p2>! m !<a1¦a2>!.a' (спасибо @EugeneSal).
  • [*] Исправлен костыль для сохранения начальных пробелов. Теперь в комменте всегда первый пробел заменяется на · (ранее искались только наборы из четырех пробелов).

0.9.204 2022-11-28

  • [+] Добавлена возможность указывать "подпись" АР для всех комментариев.
    • Внутри любого "знания" теперь ожидается ключ end_sign.
    • Его значение будут добавлено в конец к содержимому от ключа note.
    • Можно задать end_sign один раз на весь модуль - в корневом словаре через 'end_sign':'???'.
    • Заданное в корне значение будет использовано во всех "знаниях", кроме тех, где новый ключ задан явно.
    • Пример hw02_skills.py уже содержит применение нового ключа.
  • [*] Исправлена ошибка, из-за которой был пустой набор комментов при похожих именах ожидаемых главных папок в zip-ах.

0.9.206 2023-01-10

  • [+] Добавлена возможность получать все замены espanso через cli-запрос (спасибо @theoden-dd):
    • вместо "espanso:": "path/default.yml", (файла с заменами)
    • указать "espanso:": "[path/]espanso.exe", (запускаемое имя cli-клиента еспансы).
  • [*] Переработан автомат для Монитора который обновляет наборы снипов при изменении исходников:
    • Появился новый ключ ready_notes_sources в настройках АР "monitor":{"ready_notes_sources": {}}

    • Для каждого префикса (пока ожидается только "espanso:") указывается список файлов со снипами.

    • Полная структура настроек

      "monitor":{
          "ready_notes_sources": {
              "espanso:": [
                  "путь/файл1.yml",
                  "путь/файл2.yml",
              ],
          }
      }
      
  • [-] Прекращена поддержка тестов внутри Знаний. Рекомендую удалить ключи tsts.

0.9.301 2023-01-14

  • [+] Добавлена возможность "удалять сахар" через вызов:
    •   python autorv.py -ds путь-файла-знаний::путь-по-знаниям
    • Из json-данных в указанном файле будет извлечено значение и после замены сахара на регулярки выдано в соседний файл
    •   путь-файла-знаний.desugar_ГГ-ММ-ДД_ЧЧ-ММ-СС.py