requirements.txt: рассыпалась строка watchdog==6.0.0numpy>=2.0 (нет перевода строки) — pip install -r падал на свежих установках install.sh; numpy вынесен отдельной строкой

This commit is contained in:
simbiot-harness 2026-10-19 00:03:34 +00:00 committed by simbiot
parent cbf03ffac2
commit 432ba06c7a
2 changed files with 65 additions and 1 deletions

View file

@ -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): обучение учеников

View file

@ -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 отдельными строками)")