fix(ical): fiabiliser l’extraction des devoirs et événements Pronote 2026 #28
Notifications
Due Date
No due date set.
Depends on
#29 test(pronote): constituer un corpus anonymisé d’exports iCal et réponses API
AntoineVe/college-infos
Reference: AntoineVe/college-infos#28
Reference in New Issue
Block a user
Objectif
Rendre le parsing iCal Pronote tolérant aux variations observées dans les exports récents et préserver correctement le contexte des devoirs, afin que le digest ne perde ni événement scolaire ni devoir distinct.
Constats dans le code actuel
Événements scolaires
parse_ical()classe uniquement les catégories exactesCongésetVacancescomme congés, puis les représente toutes parSchoolEventKind.HOLIDAY.Le parser ne distingue donc pas les jours fériés des vacances et risque d'ignorer une catégorie Pronote comme
Jours fériés. Le modèle possède pourtant déjàPUBLIC_HOLIDAY.En-tête de description
parse_header()reconnaîtMatière,Professeur(s),Salle(s)etGroupe, mais pas les champs complémentaires observés dans les exports, notammentPartie(s) de classe. Les champs inconnus sont ignorés sans signalement.Sections HTML
parse_body()dépend de motifs très stricts : balise<strong>sans attribut, libellé et espaces précis, date obligatoirement au formatJJ/MM/AAAA. Une variation mineure de HTML générée par Pronote peut faire disparaître le contenu ou les devoirs sans erreur explicite.Déduplication et date de distribution
collect_homeworks()déduplique uniquement sur le texte normalisé. Deux devoirs différents ayant la même consigne, mais concernant des matières ou enseignants différents, peuvent donc être fusionnés.Inversement, Pronote peut recopier le même devoir dans plusieurs cours ; le contexte enseignant doit participer à la clé de déduplication. La date
assigned_ond’un bloc « Pour le » est actuellement déduite delesson.start.date(), alors que la date explicite « Donné le » peut être différente.Preuves externes
Le projet pronote-digest documente des exports Pronote 2026 observés sur le terrain :
Matière :,Professeur(s) :,Salle(s) :,Groupe :etPartie(s) de classe :;Jours fériés;Son parseur conserve séparément le HTML et le texte, attribue un décalage explicite
Europe/Parisaux horaires et déduplique en tenant compte du contexte enseignant (parse.ts).Risques actuels
Périmètre attendu
HOLIDAYetPUBLIC_HOLIDAY, en conservant la date de fin iCalendar comme borne exclusive.Critères d’acceptation
Jours fériés→PUBLIC_HOLIDAY.Professeur(s),Salle(s),Partie(s) de classeet entités HTML.strongavec variations d’espacement ou attributs sans perte de sections.due_onetassigned_oncorrects.html, texte nettoyé danstext, sans script ni style exécutable.ruff/mypy/tests.Conclusion opérationnelle
Prioriser ce ticket avant d’ajouter de nouveaux consommateurs de devoirs : le contrat iCal doit être fidèle et explicite. Toute donnée absente ou libellé inconnu doit produire un comportement documenté et observable, jamais une liste partielle silencieuse.
Complément — salle et fuseau horaire
La comparaison avec le parseur de pronote-digest apporte deux cas à intégrer au périmètre de #28 :
LOCATION, puis utilise les salles extraites deDESCRIPTIONen repli ; le parseur local ne lit actuellement pasLOCATION. Une salle présente uniquement dans cette propriété est donc perdue ;Europe/Pariset valide des dates ISO avec décalage explicite. Le modèle local accepte desdatetimenaïves, ce qui peut provoquer des comparaisons ou des UID différents selon le fuseau du processus.Critères complémentaires :
LOCATIONmulti-valeurs et paramètres iCalendar sont décodés sans écraser une salle déjà mieux qualifiée.TZID=Europe/Parisreprésentant le même instant sont interprétés selon le contrat local documenté.datetimesortant du parser ont un fuseau explicite, ou le choix d’interprétation des horaires flottants est documenté et testé.Conclusion opérationnelle : traiter
LOCATIONet le fuseau avant de considérer le parser iCal comme compatible avec des exports d’établissements différents.Complément après lecture ciblée du code
Le défaut de conservation HTML est plus direct que ne le laissait entendre le constat initial :
Le ticket doit donc préciser où conserver deux représentations dès l'extraction : texte nettoyé pour l'affichage/déduplication et fragment HTML original assaini pour les consommateurs qui en ont besoin. Les tests doivent vérifier cette propriété de bout en bout, et pas seulement le résultat de _strip_html().
Ticket traité par la PR #31, fusionnée en squash (
d45d38d365bbc721040b60e329c429f4ea234cfd). Les variantes iCal, les événements scolaires et la déduplication des devoirs sont couvertes ; la validation intégrée finale est verte. Clôture manuelle car Gitea n’a pas appliqué cette seconde référenceClosesdu corps de la PR.