Merge commit '59e6a1a' into fix/target-school-day-30

This commit is contained in:
2026-09-12 14:41:34 +02:00
2 changed files with 28 additions and 21 deletions
+14 -21
View File
@@ -43,16 +43,16 @@ def collapse_replaced_lessons(lessons: list[Lesson]) -> list[Lesson]:
"""Supprime l'ancien exemplaire annulé lorsqu'un cours déplacé est présent. """Supprime l'ancien exemplaire annulé lorsqu'un cours déplacé est présent.
Deux cours sont considérés comme les exemplaires d'une même modification Deux cours sont considérés comme les exemplaires d'une même modification
lorsqu'ils partagent les dates, la matière, les enseignants et le groupe. lorsqu'ils partagent les dates, la matière, les enseignants et le groupe,
Une annulation isolée est toujours conservée ; seule l'annulation associée et qu'une seule annulation et un seul déplacement se distinguent par leur
à un exemplaire ``MOVED`` est retirée. salle. Une annulation isolée ou ambiguë est toujours conservée.
:param lessons: Cours issus d'une source Pronote. :param lessons: Cours issus d'une source Pronote.
:return: Cours consolidés dans leur ordre d'origine. :return: Cours consolidés dans leur ordre d'origine.
:rtype: list[Lesson] :rtype: list[Lesson]
""" """
grouped: dict[tuple[object, ...], list[Lesson]] = defaultdict(list) grouped: dict[tuple[object, ...], list[tuple[int, Lesson]]] = defaultdict(list)
for lesson in lessons: for index, lesson in enumerate(lessons):
key = ( key = (
lesson.start, lesson.start,
lesson.end, lesson.end,
@@ -60,20 +60,13 @@ def collapse_replaced_lessons(lessons: list[Lesson]) -> list[Lesson]:
tuple(teacher.casefold() for teacher in lesson.teachers), tuple(teacher.casefold() for teacher in lesson.teachers),
(lesson.group or "").casefold(), (lesson.group or "").casefold(),
) )
grouped[key].append(lesson) grouped[key].append((index, lesson))
result: list[Lesson] = [] replaced_indexes: set[int] = set()
for lesson in lessons: for siblings in grouped.values():
key = ( cancelled = [item for item in siblings if item[1].status == LessonStatus.CANCELLED]
lesson.start, moved = [item for item in siblings if item[1].status == LessonStatus.MOVED]
lesson.end, if len(cancelled) == 1 and len(moved) == 1 and cancelled[0][1].rooms != moved[0][1].rooms:
lesson.subject.casefold(), replaced_indexes.add(cancelled[0][0])
tuple(teacher.casefold() for teacher in lesson.teachers),
(lesson.group or "").casefold(), return [lesson for index, lesson in enumerate(lessons) if index not in replaced_indexes]
)
siblings = grouped[key]
has_moved = any(sibling.status == LessonStatus.MOVED for sibling in siblings)
if has_moved and lesson.status == LessonStatus.CANCELLED:
continue
result.append(lesson)
return result
+14
View File
@@ -75,3 +75,17 @@ def test_collapse_replaced_lessons_keeps_real_cancellation() -> None:
cancelled = _lesson(LessonStatus.CANCELLED, "101") cancelled = _lesson(LessonStatus.CANCELLED, "101")
assert collapse_replaced_lessons([cancelled]) == [cancelled] assert collapse_replaced_lessons([cancelled]) == [cancelled]
def test_collapse_replaced_lessons_keeps_ambiguous_cancellations() -> None:
"""Conserve les annulations lorsqu'une paire de remplacement est ambiguë.
:return: None
"""
cancelled_old = _lesson(LessonStatus.CANCELLED, "101")
cancelled_real = _lesson(LessonStatus.CANCELLED, "305")
moved = _lesson(LessonStatus.MOVED, "204")
result = collapse_replaced_lessons([cancelled_old, cancelled_real, moved])
assert result == [cancelled_old, cancelled_real, moved]