feat: orchestrer le pipeline M11

Co-authored-by: Codex/gpt-5.6-terra <codex-gpt-5-6-terra@agents.invalid>
This commit is contained in:
2026-09-08 11:28:02 +02:00
parent be5beb45aa
commit d7d31e14ff
14 changed files with 1154 additions and 20 deletions

View File

@@ -16,6 +16,8 @@ d'origine ne sont jamais chaînées (``from None``).
from __future__ import annotations
import logging
from collections.abc import Iterator
from contextlib import contextmanager
from datetime import date, timedelta
from enum import StrEnum
from typing import Literal, Protocol
@@ -100,6 +102,30 @@ class PronoteFetcher:
"""
self._settings: Settings = settings
self._pronote_client: PronoteClientProtocol = pronote_client
self._run_ical_agenda: tuple[list[Lesson], list[SchoolEvent]] | None = None
self._cache_ical_for_run = False
@contextmanager
def run_context(self) -> Iterator[None]:
"""Active un cache iCal éphémère pour une exécution du pipeline.
Le cache couvre à la fois le téléchargement et le parsing du flux.
Il est toujours supprimé à la sortie du contexte, y compris si une
étape échoue : il ne peut donc pas devenir un cache global ou
persistant entre deux exécutions.
:yield: Aucun objet.
:rtype: Iterator[None]
"""
previous_cache = self._run_ical_agenda
previous_enabled = self._cache_ical_for_run
self._run_ical_agenda = None
self._cache_ical_for_run = True
try:
yield
finally:
self._run_ical_agenda = previous_cache
self._cache_ical_for_run = previous_enabled
def _fetch_window(self) -> tuple[date, date]:
"""Calcule la fenêtre de synchronisation autour de la date du jour.
@@ -144,12 +170,17 @@ class PronoteFetcher:
:raises OSError: Si le fichier iCal local est illisible.
:raises requests.RequestException: Si la récupération HTTP échoue.
"""
if self._cache_ical_for_run and self._run_ical_agenda is not None:
return self._run_ical_agenda
ical_url = self._settings.pronote.ical_url
if ical_url is None:
raise ValueError("PRONOTE_ICAL_URL est requis pour la source iCal")
raw_ical = fetch_ical(ical_url.get_secret_value())
lessons, _, school_events = parse_ical(raw_ical)
return lessons, school_events
result = (lessons, school_events)
if self._cache_ical_for_run:
self._run_ical_agenda = result
return result
def _fetch_agenda_pronotepy(self) -> tuple[list[Lesson], list[SchoolEvent]]:
"""Récupère l'agenda depuis pronotepy.