feat(M3): modèles de données Pydantic (22 modèles, 10 modules)

Modèles créés :
- models/agenda.py : Status, LessonStatus, HomeworkBlock, Lesson (frozen),
  SchoolEventKind, SchoolEvent (frozen), TheoreticalLesson (frozen)
- models/homework.py : Homework (frozen)
- models/message.py : MessageType, Message (frozen)
- models/blog.py : BlogArticle (frozen), ExternalInfo (mutable)
- models/diff.py : AgendaChangeType, AgendaChange (frozen), AgendaDiff (frozen)
- models/pronote.py : PronoteData (mutable)
- models/sync.py : CalDAVSyncStatus, CalDAVSyncPlan, CalDAVSyncResult (mutable)
- models/synthesis.py : SynthesisInput, SynthesisResult (mutable)
- models/xmpp.py : XmppMessage (frozen, external_info: ExternalInfo | None)
- models/__init__.py : ré-export des 22 modèles via __all__

Conventions appliquées :
- Pydantic v2 : model_config = ConfigDict(frozen=True), pas de json_encoders
- StrEnum au lieu de (str, Enum) (ruff UP042)
- Alias _date/_time pour éviter collision champ date/type date
- Sphinx/reST docstrings sur toutes les classes
- TODO.md : 11 items M3 cochés

Validations (@verifier) :
- ruff check : PASS (0 error)
- ruff format --check : PASS (10 fichiers)
- mypy strict : PASS (10 fichiers)
- bandit : PASS (0 issue)
- import 22 modèles : OK
- sérialisation JSON (frozen + mutable) : OK
- frozen immuable, PronoteData/CalDAVSyncResult mutable : OK
- StrEnum isinstance str : OK
- pytest : 0 test (infrastructure OK)

Co-authored-by: OpenCode/orchestrator <opencode-orchestrator@agents.invalid>
This commit is contained in:
2026-09-05 23:21:39 +02:00
parent c3f76ab91b
commit 2e7dfe6e46
11 changed files with 405 additions and 11 deletions

View File

@@ -0,0 +1,42 @@
"""Modèles de données pour la synchronisation CalDAV."""
from __future__ import annotations
from enum import StrEnum
from pydantic import BaseModel, Field
from pronote_sync.models.agenda import Lesson, SchoolEvent
from pronote_sync.models.homework import Homework
class CalDAVSyncStatus(StrEnum):
"""Statut de synchronisation CalDAV."""
SUCCESS = "success"
FAILED = "failed"
SKIPPED = "skipped"
class CalDAVSyncPlan(BaseModel):
"""Plan de synchronisation CalDAV."""
lessons_to_add: list[Lesson] = Field(default_factory=list)
lessons_to_update: list[Lesson] = Field(default_factory=list)
lessons_to_remove: list[str] = Field(default_factory=list, description="Liste d'UID")
homeworks_to_add: list[Homework] = Field(default_factory=list)
homeworks_to_update: list[Homework] = Field(default_factory=list)
homeworks_to_remove: list[str] = Field(default_factory=list, description="Liste d'UID")
school_events_to_add: list[SchoolEvent] = Field(default_factory=list)
school_events_to_update: list[SchoolEvent] = Field(default_factory=list)
school_events_to_remove: list[str] = Field(default_factory=list, description="Liste d'UID")
class CalDAVSyncResult(BaseModel):
"""Résultat d'une synchronisation CalDAV (mutable)."""
status: CalDAVSyncStatus = Field(..., description="Statut global")
added: int = Field(0, description="Nombre d'événements ajoutés")
updated: int = Field(0, description="Nombre d'événements mis à jour")
removed: int = Field(0, description="Nombre d'événements supprimés")
errors: list[str] = Field(default_factory=list, description="Liste des erreurs")