"""Hiérarchie d'erreurs transversale du projet pronote-sync.""" from __future__ import annotations from enum import StrEnum class PronoteSyncError(Exception): """Erreur de base pour toutes les exceptions du projet pronote-sync. Toutes les exceptions métier héritent de cette classe pour permettre une interception unifiée des erreurs applicatives. """ def __init__(self, message: str) -> None: """Initialise l'erreur avec un message descriptif. :param message: Message décrivant la cause de l'erreur. """ super().__init__(message) self.message = message class PronoteAuthRotationError(PronoteSyncError): """Erreur de rotation du token d'authentification pronotepy (QR code / token). Levée quand le token persisté est invalide ou expiré et qu'un ré-enrôlement manuel (suppression du fichier d'état + nouveau QR code) est nécessaire. :ivar message: Message décrivant l'action à effectuer, sans secret. """ def __init__(self, message: str) -> None: """Initialise l'erreur de rotation. :param message: Message actionnable sans secret (PIN, token, URL). """ super().__init__(message) class ErrorSeverity(StrEnum): """Niveau de gravité d'une erreur produite par le pipeline.""" WARNING = "warning" CRITICAL = "critical" class PipelineError(PronoteSyncError): """Erreur structurée produite par une étape du pipeline. :ivar severity: Niveau de gravité de l'erreur. :ivar step: Étape ayant produit l'erreur, si elle est connue. :ivar recoverable: Indique si le pipeline peut poursuivre son exécution. """ def __init__( self, message: str, *, severity: ErrorSeverity = ErrorSeverity.WARNING, step: str | None = None, recoverable: bool = True, ) -> None: """Initialise une erreur de pipeline. :param message: Message descriptif expurgé. :param severity: Niveau de gravité associé. :param step: Étape ayant produit l'erreur. :param recoverable: ``True`` si le pipeline peut continuer. """ super().__init__(message) self.severity = severity self.step = step self.recoverable = recoverable class PipelineCriticalError(PipelineError): """Erreur critique du pipeline, levée quand aucune récupération n'est possible. Par exemple : échec simultané des sources iCal et pronotepy, rendant impossible toute synchronisation. """ def __init__(self, message: str, step: str | None = None) -> None: """Initialise l'erreur critique avec un message descriptif. :param message: Message décrivant la cause de l'erreur critique. :param step: Étape ayant produit l'erreur critique. """ super().__init__( message, severity=ErrorSeverity.CRITICAL, step=step, recoverable=False, ) class PipelineWarning(PipelineError): """Avertissement non bloquant pour une erreur récupérable du pipeline. Contrairement à :class:`PipelineCriticalError`, cet avertissement signale un problème récupérable : le pipeline peut poursuivre son exécution en mode dégradé. Il hérite volontairement de :class:`PronoteSyncError` (et non de la classe native :class:`Warning`) afin de rester dans la hiérarchie canonique des erreurs du projet. :ivar recoverable: Indique que l'erreur est récupérable (toujours ``True``). :ivar step: Étape du pipeline ayant produit l'avertissement. """ def __init__(self, message: str, step: str | None = None) -> None: """Initialise l'avertissement avec un message descriptif. :param message: Message décrivant la cause de l'avertissement. :param step: Étape du pipeline ayant produit l'avertissement. """ super().__init__( message, severity=ErrorSeverity.WARNING, step=step, recoverable=True, )