Files
veye-lalwa/pipeline/chemins.py
T

84 lines
3.4 KiB
Python
Raw Normal View History

"""Localisation des fichiers du projet.
Un unique point de vérité pour les chemins, afin que les parseurs, les tests et
les collecteurs ne fassent jamais d'hypothèse sur le répertoire courant.
"""
from __future__ import annotations
import os
from pathlib import Path
from dotenv import load_dotenv
# pipeline/chemins.py → pipeline/ → racine du dépôt.
#
# Ce calcul suppose que le paquet est exécuté depuis l'arbre des sources, ce qui
# est le cas en développement. Une installation non éditable le met en défaut :
# `__file__` pointe alors vers site-packages, et le corpus de `data/input/` est
# cherché à côté du venv, où il n'est pas.
#
# `VEILLE_RACINE` lève l'ambiguïté. Les déploiements la renseignent ; sans elle,
# le comportement historique est conservé.
_RACINE_PAR_DEFAUT = Path(__file__).resolve().parent.parent
RACINE = Path(os.environ.get("VEILLE_RACINE") or _RACINE_PAR_DEFAUT).resolve()
load_dotenv(RACINE / ".env")
# ── Corpus d'entrée — LECTURE SEULE ──────────────────────────────────────────
ENTREE = RACINE / "data" / "input"
RECHERCHE = ENTREE / "research"
RAPPORT_FINAL = ENTREE / "lois-france-2026-guadeloupe.agent.final.md"
RAPPORT_OUTLINE = ENTREE / "lois-france-2026-guadeloupe.agent.outline.md"
BIBLIOGRAPHIE = ENTREE / "lois-france-2026-guadeloupe_ref.md"
CROSS_VERIFICATION = RECHERCHE / "lois-2026_cross_verification.md"
INSIGHTS = RECHERCHE / "lois-2026_insight.md"
PHASE5_VALIDATION = RECHERCHE / "lois-2026_phase5_validation.md"
def chapitre(numero: int) -> Path:
"""Chemin d'un chapitre du rapport : `chapitre(10)` → `…_sec10.md`."""
return ENTREE / f"lois-france-2026-guadeloupe_sec{numero:02d}.md"
def dimension(numero: int) -> Path:
"""Chemin d'un rapport de dimension : `dimension(7)` → `lois-2026_dim07.md`."""
return RECHERCHE / f"lois-2026_dim{numero:02d}.md"
CHAPITRES = [chapitre(n) for n in range(11)]
DIMENSIONS = [dimension(n) for n in range(1, 13)]
# ── Sorties ──────────────────────────────────────────────────────────────────
#
# Les trois chemins de sortie sont configurables par variable d'environnement,
# et acceptent une valeur absolue — `Path("/a") / "/b"` vaut `/b`.
#
# Ce n'est pas de la souplesse gratuite : sur un déploiement YunoHost, la mise
# à jour efface intégralement le répertoire d'installation (`ynh_setup_source
# --full_replace`). Tout ce qui doit survivre — base, cache, export — vit donc
# ailleurs, dans le répertoire de données persistant de l'application.
DONNEES = RACINE / "data"
BASE_SQLITE = RACINE / os.environ.get("VEILLE_DB", "data/veille.db")
DUMP_JSON = RACINE / os.environ.get("VEILLE_DUMP_JSON", "data/textes.json")
CACHE_HTTP = RACINE / os.environ.get("VEILLE_CACHE", "data/cache_http")
MIGRATIONS = Path(__file__).resolve().parent / "migrations"
CONFIG = Path(__file__).resolve().parent / "config.yaml"
def verifier_corpus() -> list[str]:
"""Retourne la liste des fichiers d'entrée attendus mais absents."""
attendus = [
RAPPORT_FINAL,
BIBLIOGRAPHIE,
CROSS_VERIFICATION,
INSIGHTS,
PHASE5_VALIDATION,
*CHAPITRES,
*DIMENSIONS,
]
return [str(p.relative_to(RACINE)) for p in attendus if not p.exists()]