Перейти на компактные 12-словные записи v4 и сохранять 10 процентов банка после отключения. Добавить трёхсекундное ожидание роста ЗПТ и настраиваемый лимит пусков. Явно инициализировать состояние UART и гарантировать публикацию параметров EEPROM перед запуском Timer2. Сохранить воспроизводимые сборки, регрессионные проверки, документацию и обновлённые результаты сборки; исключить временные артефакты.
267 lines
27 KiB
Python
267 lines
27 KiB
Python
# Проверка comments на модели пк. Комментарии и исходный текст в UTF-8.
|
||
# Продолжает текущий вызов, список или выражение: """Проверка UTF-8 и русских пояснений к каждой строке исходного кода."""; порядок аргументов сохраняется.
|
||
"""Проверка UTF-8 и русских пояснений к каждой строке исходного кода."""
|
||
# Подключает модуль argparse для этой проверки или подготовки сборки.
|
||
import argparse
|
||
# Подключает модуль io для этой проверки или подготовки сборки.
|
||
import io
|
||
# Импортирует необходимые имена: from pathlib import Path.
|
||
from pathlib import Path
|
||
# Подключает модуль re для этой проверки или подготовки сборки.
|
||
import re
|
||
# Подключает модуль subprocess для этой проверки или подготовки сборки.
|
||
import subprocess
|
||
# Подключает модуль tokenize для этой проверки или подготовки сборки.
|
||
import tokenize
|
||
|
||
# Задаёт ROOT по выражению справа; значение используется последующими операциями.
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
# Задаёт RUSSIAN по выражению справа; значение используется последующими операциями.
|
||
RUSSIAN = re.compile("[А-Яа-яЁё]")
|
||
# Задаёт C_SUFFIXES по выражению справа; значение используется последующими операциями.
|
||
C_SUFFIXES = {".c", ".h", ".cmd", ".inc"}
|
||
# Задаёт TEXT_SUFFIXES по выражению справа; значение используется последующими операциями.
|
||
TEXT_SUFFIXES = C_SUFFIXES | {".asm", ".py", ".md", ".bat", ".old", ".prefs", ".json", ".pjt", ".lkf"}
|
||
# Задаёт TEXT_NAMES по выражению справа; значение используется последующими операциями.
|
||
TEXT_NAMES = {".project", ".cproject", ".ccsproject", ".gitignore", ".editorconfig"}
|
||
|
||
# Объявляет функцию c_code_lines и её входные параметры.
|
||
def c_code_lines(text):
|
||
# Задаёт block по выражению справа; значение используется последующими операциями.
|
||
block = False
|
||
# Перебирает line in text.splitlines() в указанном порядке.
|
||
for line in text.splitlines():
|
||
# Задаёт out по выражению справа; значение используется последующими операциями.
|
||
out = []
|
||
# Задаёт i по выражению справа; значение используется последующими операциями.
|
||
i = 0
|
||
# Задаёт quote по выражению справа; значение используется последующими операциями.
|
||
quote = None
|
||
# Повторяет блок при выполнении i < len(line).
|
||
while i < len(line):
|
||
# Проверяет условие if block перед выполнением следующего блока.
|
||
if block:
|
||
# Задаёт end по выражению справа; значение используется последующими операциями.
|
||
end = line.find("*/", i)
|
||
# Проверяет условие if end < 0 перед выполнением следующего блока.
|
||
if end < 0:
|
||
# Продолжает текущий вызов, список или выражение: break; порядок аргументов сохраняется.
|
||
break
|
||
# Задаёт block по выражению справа; значение используется последующими операциями.
|
||
block = False
|
||
# Задаёт i по выражению справа; значение используется последующими операциями.
|
||
i = end + 2
|
||
# Продолжает текущий вызов, список или выражение: out.append(" "); порядок аргументов сохраняется.
|
||
out.append(" ")
|
||
# Продолжает текущий вызов, список или выражение: continue; порядок аргументов сохраняется.
|
||
continue
|
||
# Задаёт c по выражению справа; значение используется последующими операциями.
|
||
c = line[i]
|
||
# Проверяет условие if quote перед выполнением следующего блока.
|
||
if quote:
|
||
# Продолжает текущий вызов, список или выражение: out.append(c); порядок аргументов сохраняется.
|
||
out.append(c)
|
||
# Проверяет условие if c == "\\" and i + 1 < len(line) перед выполнением следующего блока.
|
||
if c == "\\" and i + 1 < len(line):
|
||
# Задаёт i + по выражению справа; значение используется последующими операциями.
|
||
i += 1
|
||
# Продолжает текущий вызов, список или выражение: out.append(line[i]); порядок аргументов сохраняется.
|
||
out.append(line[i])
|
||
# Проверяет условие elif c == quote перед выполнением следующего блока.
|
||
elif c == quote:
|
||
# Задаёт quote по выражению справа; значение используется последующими операциями.
|
||
quote = None
|
||
# Задаёт i + по выражению справа; значение используется последующими операциями.
|
||
i += 1
|
||
# Продолжает текущий вызов, список или выражение: continue; порядок аргументов сохраняется.
|
||
continue
|
||
# Проверяет условие if line.startswith("//", i) перед выполнением следующего блока.
|
||
if line.startswith("//", i):
|
||
# Продолжает текущий вызов, список или выражение: break; порядок аргументов сохраняется.
|
||
break
|
||
# Проверяет условие if line.startswith("/*", i) перед выполнением следующего блока.
|
||
if line.startswith("/*", i):
|
||
# Задаёт block по выражению справа; значение используется последующими операциями.
|
||
block = True
|
||
# Задаёт i + по выражению справа; значение используется последующими операциями.
|
||
i += 2
|
||
# Продолжает текущий вызов, список или выражение: out.append(" "); порядок аргументов сохраняется.
|
||
out.append(" ")
|
||
# Продолжает текущий вызов, список или выражение: continue; порядок аргументов сохраняется.
|
||
continue
|
||
# Проверяет условие if c in "\"'" перед выполнением следующего блока.
|
||
if c in "\"'":
|
||
# Задаёт quote по выражению справа; значение используется последующими операциями.
|
||
quote = c
|
||
# Продолжает текущий вызов, список или выражение: out.append(c); порядок аргументов сохраняется.
|
||
out.append(c)
|
||
# Задаёт i + по выражению справа; значение используется последующими операциями.
|
||
i += 1
|
||
# Продолжает текущий вызов, список или выражение: yield "".join(out).strip(); порядок аргументов сохраняется.
|
||
yield "".join(out).strip()
|
||
|
||
# Объявляет функцию python_code_lines и её входные параметры.
|
||
def python_code_lines(text):
|
||
# Задаёт active по выражению справа; значение используется последующими операциями.
|
||
active = set()
|
||
# Задаёт strings по выражению справа; значение используется последующими операциями.
|
||
strings = set()
|
||
# Перебирает token in tokenize.generate_tokens(io.StringIO(text).readline) в указанном порядке.
|
||
for token in tokenize.generate_tokens(io.StringIO(text).readline):
|
||
# Проверяет условие if token.type == tokenize.STRING and token.end[0] > token.start[0] перед выполнением следующего блока.
|
||
if token.type == tokenize.STRING and token.end[0] > token.start[0]:
|
||
# Продолжает текущий вызов, список или выражение: strings.update(range(token.start[0] + 1, token.end[0] + 1)); порядок аргументов сохраняется.
|
||
strings.update(range(token.start[0] + 1, token.end[0] + 1))
|
||
# Проверяет условие if token.type not in {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE, tokenize.INDENT, tokenize.DEDENT, tokenize.ENDMARKER} перед выполнением следующего блока.
|
||
if token.type not in {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE, tokenize.INDENT, tokenize.DEDENT, tokenize.ENDMARKER}:
|
||
# Продолжает текущий вызов, список или выражение: active.add(token.start[0]); порядок аргументов сохраняется.
|
||
active.add(token.start[0])
|
||
# Задаёт lines по выражению справа; значение используется последующими операциями.
|
||
lines = text.splitlines()
|
||
# Возвращает [line.strip() if n in active and n not in strings else "" for n, line in enumerate(lines, 1)] вызывающему коду и завершает функцию.
|
||
return [line.strip() if n in active and n not in strings else "" for n, line in enumerate(lines, 1)]
|
||
|
||
# Объявляет функцию audit и её входные параметры.
|
||
def audit(path, text):
|
||
# Задаёт lines по выражению справа; значение используется последующими операциями.
|
||
lines = text.splitlines()
|
||
# Проверяет условие if path.suffix in C_SUFFIXES перед выполнением следующего блока.
|
||
if path.suffix in C_SUFFIXES:
|
||
# Задаёт code по выражению справа; значение используется последующими операциями.
|
||
code = list(c_code_lines(text))
|
||
# Проверяет условие elif path.suffix == ".asm" перед выполнением следующего блока.
|
||
elif path.suffix == ".asm":
|
||
# Задаёт code по выражению справа; значение используется последующими операциями.
|
||
code = [line.split(";")[0].strip() for line in lines]
|
||
# Проверяет условие elif path.suffix == ".py" перед выполнением следующего блока.
|
||
elif path.suffix == ".py":
|
||
# Задаёт code по выражению справа; значение используется последующими операциями.
|
||
code = python_code_lines(text)
|
||
# Обрабатывает альтернативу предыдущего условия.
|
||
else:
|
||
# Возвращает 0, [] вызывающему коду и завершает функцию.
|
||
return 0, []
|
||
# Задаёт missing по выражению справа; значение используется последующими операциями.
|
||
missing = []
|
||
# Задаёт count по выражению справа; значение используется последующими операциями.
|
||
count = 0
|
||
# Перебирает i, value in enumerate(code) в указанном порядке.
|
||
for i, value in enumerate(code):
|
||
# Проверяет условие if not value перед выполнением следующего блока.
|
||
if not value:
|
||
# Продолжает текущий вызов, список или выражение: continue; порядок аргументов сохраняется.
|
||
continue
|
||
# Задаёт count + по выражению справа; значение используется последующими операциями.
|
||
count += 1
|
||
# Эвристика ищет кириллицу в самой строке или перед ней; русский строковый литерал тоже может дать совпадение. Это проверка наличия текста рядом, а не качества и достоверности комментария.
|
||
if RUSSIAN.search(lines[i]) or (i and RUSSIAN.search(lines[i-1])):
|
||
# Продолжает текущий вызов, список или выражение: continue; порядок аргументов сохраняется.
|
||
continue
|
||
# Явное продолжение Python-выражения относится к пояснённой начальной строке.
|
||
# Проверяет условие if path.suffix == ".py" and i and lines[i-1].rstrip().endswith("\\") перед выполнением следующего блока.
|
||
if path.suffix == ".py" and i and lines[i-1].rstrip().endswith("\\"):
|
||
# Продолжает текущий вызов, список или выражение: continue; порядок аргументов сохраняется.
|
||
continue
|
||
# Продолжает текущий вызов, список или выражение: missing.append(i+1); порядок аргументов сохраняется.
|
||
missing.append(i+1)
|
||
# Возвращает count, missing вызывающему коду и завершает функцию.
|
||
return count, missing
|
||
|
||
# Объявляет функцию main и её входные параметры.
|
||
def main():
|
||
# Задаёт parser по выражению справа; значение используется последующими операциями.
|
||
parser = argparse.ArgumentParser(description=__doc__)
|
||
# Задаёт parser.add_argument("--report", type по выражению справа; значение используется последующими операциями.
|
||
parser.add_argument("--report", type=Path, help="Сохранить таблицу покрытия в Markdown")
|
||
# Задаёт args по выражению справа; значение используется последующими операциями.
|
||
args = parser.parse_args()
|
||
# Задаёт names по выражению справа; значение используется последующими операциями.
|
||
names = subprocess.check_output(["git", "ls-files", "-z"], cwd=ROOT).decode("utf-8").split("\0")
|
||
# Задаёт names по выражению справа; значение используется последующими операциями.
|
||
names = sorted(set(filter(None, names)) | {"tests/comments/run_test.py", ".editorconfig"})
|
||
# Задаёт rows по выражению справа; значение используется последующими операциями.
|
||
rows = []
|
||
# Задаёт errors по выражению справа; значение используется последующими операциями.
|
||
errors = []
|
||
# Задаёт checked по выражению справа; значение используется последующими операциями.
|
||
checked = 0
|
||
# Перебирает name in names в указанном порядке.
|
||
for name in names:
|
||
# Задаёт path по выражению справа; значение используется последующими операциями.
|
||
path = ROOT / name
|
||
# Проверяет условие if path.suffix.lower() not in TEXT_SUFFIXES and path.name not in TEXT_NAMES перед выполнением следующего блока.
|
||
if path.suffix.lower() not in TEXT_SUFFIXES and path.name not in TEXT_NAMES:
|
||
# Продолжает текущий вызов, список или выражение: continue; порядок аргументов сохраняется.
|
||
continue
|
||
# Начинает блок обработки возможной ошибки.
|
||
try:
|
||
# Читает исходный файл или образ для последующей проверки и разбора.
|
||
text = path.read_text(encoding="utf-8")
|
||
# Перехватывает указанный тип ошибки и выполняет обработку.
|
||
except UnicodeError as error:
|
||
# Продолжает текущий вызов, список или выражение: errors.append(f"{name}: неверная кодировка UTF-8: {error}"); порядок аргументов сохраняется.
|
||
errors.append(f"{name}: неверная кодировка UTF-8: {error}")
|
||
# Продолжает текущий вызов, список или выражение: continue; порядок аргументов сохраняется.
|
||
continue
|
||
# Задаёт checked + по выражению справа; значение используется последующими операциями.
|
||
checked += 1
|
||
# Задаёт count, missing по выражению справа; значение используется последующими операциями.
|
||
count, missing = audit(path, text)
|
||
# Проверяет условие if missing перед выполнением следующего блока.
|
||
if missing:
|
||
# Продолжает текущий вызов, список или выражение: errors.append(f"{name}: нет русского пояснения, строки {missing[:20]}"); порядок аргументов сохраняется.
|
||
errors.append(f"{name}: нет русского пояснения, строки {missing[:20]}")
|
||
# Проверяет условие if path.suffix in C_SUFFIXES or path.suffix in {".asm", ".py"} перед выполнением следующего блока.
|
||
if path.suffix in C_SUFFIXES or path.suffix in {".asm", ".py"}:
|
||
# Продолжает текущий вызов, список или выражение: rows.append((name, count, count-len(missing))); порядок аргументов сохраняется.
|
||
rows.append((name, count, count-len(missing)))
|
||
# Проверяет условие if args.report перед выполнением следующего блока.
|
||
if args.report:
|
||
# Задаёт report по выражению справа; значение используется последующими операциями.
|
||
report = [
|
||
# Продолжает текущий вызов, список или выражение: "# Проверка комментариев и кодировки",; порядок аргументов сохраняется.
|
||
"# Проверка комментариев и кодировки",
|
||
# Продолжает текущий вызов, список или выражение: "",; порядок аргументов сохраняется.
|
||
"",
|
||
# Продолжает текущий вызов, список или выражение: "Проверка относится к редактируемым исходникам C/H, ASM, CMD, тестовым INC и Python.",; порядок аргументов сохраняется.
|
||
"Проверка относится к редактируемым исходникам C/H, ASM, CMD, тестовым INC и Python.",
|
||
# Описывает фактический критерий покрытия, не выдавая наличие кириллицы за оценку качества пояснения.
|
||
"Для каждой непустой строки кода проверяется русский текст на ней или непосредственно перед ней.",
|
||
# Уточняет исключения счётчика, чтобы комментарии и многострочные данные не завышали объём кода.
|
||
"Пустые строки, текст комментариев и содержимое многострочных строк данных не считаются кодом.",
|
||
# Предупреждает о главном ограничении: шаблонный текст или русский строковый литерал тоже проходит эвристику.
|
||
"Качество и достоверность пояснений этой проверкой не устанавливаются; совпадение возможно и в строковом литерале.",
|
||
# Отделяет исходники репозитория от подключаемого и генерируемого кода, отсутствующего в Git-индексе.
|
||
"Охват: исходники из Git-индекса. Сгенерированные файлы и подключённые соседние библиотеки проверяются отдельно.",
|
||
# Продолжает текущий вызов, список или выражение: "Исходные уведомления TI сохранены. JSON-паспорта, индексы IDE, таблицы XLS и двоичные",; порядок аргументов сохраняется.
|
||
"Исходные уведомления TI сохранены. JSON-паспорта, индексы IDE, таблицы XLS и двоичные",
|
||
# Продолжает текущий вызов, список или выражение: "результаты сборки не допускают исходных комментариев; их назначение описано в документации.",; порядок аргументов сохраняется.
|
||
"результаты сборки не допускают исходных комментариев; их назначение описано в документации.",
|
||
# Продолжает текущий вызов, список или выражение: "",; порядок аргументов сохраняется.
|
||
"",
|
||
# Продолжает текущий вызов, список или выражение: f"UTF-8 проверен в {checked} текстовых файлах. Строк кода: {sum(r[1] for r in rows)}.",; порядок аргументов сохраняется.
|
||
f"UTF-8 проверен в {checked} текстовых файлах. Строк кода: {sum(r[1] for r in rows)}.",
|
||
# Продолжает текущий вызов, список или выражение: "",; порядок аргументов сохраняется.
|
||
"",
|
||
# Подписывает колонку строго по измеряемому признаку, не утверждая содержательность найденного текста.
|
||
"| Файл | Строк кода | С русским текстом рядом |",
|
||
# Продолжает текущий вызов, список или выражение: "| --- | ---: | ---: |",; порядок аргументов сохраняется.
|
||
"| --- | ---: | ---: |",
|
||
# Продолжает текущий вызов, список или выражение: ]; порядок аргументов сохраняется.
|
||
]
|
||
# Задаёт report + по выражению справа; значение используется последующими операциями.
|
||
report += [f"| {name} | {count} | {covered} |" for name,count,covered in rows]
|
||
# Сохраняет подготовленный файл в указанном формате для следующего шага.
|
||
args.report.write_text("\n".join(report)+"\n", encoding="utf-8")
|
||
# Проверяет условие if errors перед выполнением следующего блока.
|
||
if errors:
|
||
# Останавливает текущую операцию с исключением SystemExit("\n".join(errors)).
|
||
raise SystemExit("\n".join(errors))
|
||
# Продолжает текущий вызов, список или выражение: print(f"PASS UTF-8: {checked} files; Russian comments: {len(rows)} source files, {sum(r[1] for r in rows)} code lines"); порядок аргументов сохраняется.
|
||
print(f"PASS UTF-8: {checked} files; Russian comments: {len(rows)} source files, {sum(r[1] for r in rows)} code lines")
|
||
|
||
# Проверяет условие if __name__ == "__main__" перед выполнением следующего блока.
|
||
if __name__ == "__main__":
|
||
# Продолжает текущий вызов, список или выражение: main(); порядок аргументов сохраняется.
|
||
main()
|