"""Separación de capas. `bot/` puede importar de todo; nadie puede importar de `bot/`. El progreso y los callbacks viajan como callables genéricos justo para no necesitarlo. """ import re from pathlib import Path SRC = Path(__file__).resolve().parents[1] / "src" LOWER_LAYERS = ("generator", "scraper", "processor", "db", "seo", "news") IMPORTS_BOT = re.compile(r"^\s*(from\s+src\.bot|import\s+src\.bot|from\s+\.\.bot)", re.MULTILINE) def test_no_lower_layer_imports_from_bot(): offenders = [] for layer in LOWER_LAYERS: for path in (SRC / layer).rglob("*.py"): if IMPORTS_BOT.search(path.read_text(encoding="utf-8")): offenders.append(str(path.relative_to(SRC.parent))) assert not offenders, f"importan de bot/: {offenders}" IMPORTS_TELEGRAM = re.compile(r"^\s*(from\s+telegram|import\s+telegram)", re.MULTILINE) def test_the_short_pipeline_takes_progress_as_a_plain_callable(): """La comprobación concreta para lo añadido en fase 2: si algún día alguien mete un `Message` de Telegram aquí, este test lo dice. Nombrar Telegram en un comentario vale — importarlo, no.""" for module in ("short.py", "shortsmith.py", "shortspec.py", "grounding.py", "spec_contract.py"): source = (SRC / "generator" / module).read_text(encoding="utf-8") assert not IMPORTS_TELEGRAM.search(source), f"{module} importa telegram"