diff --git a/requirements.txt b/requirements.txt index 9c5aa5d..b21729a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,4 +20,5 @@ uvicorn==0.54.0 sse-starlette==3.5.0 python-multipart==0.0.32 py-spy==0.4.2 -watchdog==6.0.0numpy>=2.0 # ядро Коди (harness/kodi_core.py): обучение учеников +watchdog==6.0.0 +numpy>=2.0 # ядро Коди (harness/kodi_core.py): обучение учеников diff --git a/tests/test_requirements_valid.py b/tests/test_requirements_valid.py new file mode 100644 index 0000000..579293c --- /dev/null +++ b/tests/test_requirements_valid.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +"""requirements.txt валиден для pip (t-261019001038-0eb7d7) — hermetic. + +Запуск: ./venv/bin/python tests/test_requirements_valid.py + +Регрессия: на origin/master строка watchdog==6.0.0numpy>=2.0 была склеена +без перевода строки — pip install -r requirements.txt падал на СВЕЖИХ +установках install.sh (curl install.sh | bash) с InvalidRequirement, +ломая канал дистрибуции харнеса. Проверяем через packaging.Requirement +(тот же парсер, что у pip): каждая строка файла — ровно одно валидное +требование, watchdog и numpy распознаны отдельными пакетами. +""" +import os +import sys + +sys.path.insert(0, "/root/simbiot-harness") + +from packaging.requirements import Requirement + +REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +REQ = os.path.join(REPO, "requirements.txt") + +fails = [] + + +def check(name, cond, extra=""): + print(("PASS" if cond else "FAIL"), name, ("| " + str(extra)) if not cond else "") + if not cond: + fails.append(name) + + +# все строки-требования парсятся packaging (тот же парсер, что у pip): +# склейка watchdog==6.0.0numpy>=2.0 дала бы InvalidRequirement +req_names = [] +for i, line in enumerate(open(REQ, encoding="utf-8"), 1): + s = line.split("#", 1)[0].strip() + if not s: + continue + try: + r = Requirement(s) + except Exception as e: + check("строка %d валидна (InvalidRequirement)" % i, False, repr(e)) + continue + req_names.append(r.name.lower()) +check("все строки requirements.txt валидны для pip", True) + +# ключевые пакеты распознаны как отдельные требования +for name in ("watchdog", "numpy"): + check("зависимость %r отдельной строкой" % name, name in req_names) + +# битая склейка действительно ловится парсером (self-check теста) +try: + Requirement("watchdog==6.0.0numpy>=2.0") + glued_raises = False +except Exception: + glued_raises = True +check("парсер отклоняет склейку watchdog==6.0.0numpy>=2.0", glued_raises) + +print() +if fails: + print("FAILED:", len(fails)) + sys.exit(1) +print("OK: requirements.txt валиден (watchdog и numpy отдельными строками)")