Skip to content

Commit

Permalink
Merge pull request #167 from ArtrenH/main
Browse files Browse the repository at this point in the history
2023-09-23
  • Loading branch information
Belissimo-T authored Sep 22, 2023
2 parents 5a9e89e + 980260c commit 67d837a
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 30 deletions.
2 changes: 1 addition & 1 deletion backend/lesson_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@


class _InfoParsers:
_teacher_name = r"[A-ZÄÖÜ][a-zäöüß]+(?: [A-ZÄÖÜ][a-zäöüß]+(?:-[A-ZÄÖÜ][a-zäöüß]+)?)+"
_teacher_name = r"[A-ZÄÖÜ][a-zäöüß]+(?: [A-ZÄÖÜ][a-zäöüß]+(?:-[A-ZÄÖÜ][a-zäöüß]+|\.)?)+"
_teacher_abbreviation = r"[A-ZÄÖÜ][A-ZÄÖÜa-zäöüß]*"
_teacher = fr"(?:{_teacher_name})|(?:{_teacher_abbreviation})"

Expand Down
13 changes: 10 additions & 3 deletions backend/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,11 @@ def create(cls, current_lesson: Lesson | None, scheduled_lesson: Lesson | None,
(_scheduled_lesson.class_opt.number or _current_lesson.class_opt.number)
if _scheduled_lesson is not None else _current_lesson.class_opt.number
),
subject_changed=_current_lesson.subject_changed if _current_lesson._origin_plan_type == plan_type else (_current_lesson.course != _scheduled_lesson.course),
subject_changed=(
_current_lesson.subject_changed
if _current_lesson._origin_plan_type == plan_type
else (_current_lesson.course != _scheduled_lesson.course)
),
teacher_changed=_current_lesson.teacher_changed,
room_changed=_current_lesson.room_changed,
forms_changed=(_current_lesson.forms != _scheduled_lesson.forms) if _scheduled_lesson is not None else True,
Expand Down Expand Up @@ -618,13 +622,16 @@ def from_form_plan(cls, form_plan: indiware_mobil.IndiwareMobilPlan) -> Plan:
end=lesson.end,

forms={form.short_name},
teachers={class_data.teacher} if class_data is not None else None,
teachers=(
(current_lesson.teachers if not current_lesson.teacher_changed else None)
or ({class_data.teacher} if class_data is not None else None)
),
rooms=current_lesson.rooms if not current_lesson.room_changed else None,
course=(
lesson.course2
or (current_lesson.course if not current_lesson.subject_changed else None)
or (class_data.group if class_data is not None else None)
or (class_data.subject if class_data is not None else None)
or (current_lesson.course if not current_lesson.room_changed else None)
),
parsed_info=current_lesson.parsed_info,

Expand Down
17 changes: 13 additions & 4 deletions backend/plan_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
from .meta_extractor import MetaExtractor
from .models import Teachers, Exam, Teacher, PlanLesson
from .vplan_utils import group_forms, ParsedForm
from .stats import LessonsStatistics


class PlanProcessor:
VERSION = "70"
VERSION = "74"

def __init__(self, cache: Cache, school_number: str, *, logger: logging.Logger):
self._logger = logger
Expand Down Expand Up @@ -91,13 +92,21 @@ def compute_plans(self, date: datetime.date, timestamp: datetime.datetime):
# self.cache.store_plan_file(
# date, timestamp,
# json.dumps({
# "rooms": plan_extractor.forms_lessons_grouped.group_by("rooms"),
# "teachers": plan_extractor.forms_lessons_grouped.group_by("teachers"),
# "forms": plan_extractor.forms_lessons_grouped.group_by("forms")
# "rooms": plan_extractor.room_plan_extractor.forms_lessons_grouped.group_by("rooms"),
# "teachers": plan_extractor.teacher_plan_extractor.forms_lessons_grouped.group_by("teachers"),
# "forms": plan_extractor.form_plan_extractor.forms_lessons_grouped.group_by("forms")
# }, default=Lessons.serialize),
# "_plans_raw.json"
# )

self.cache.store_plan_file(
date, timestamp,
json.dumps({
"all_lessons": LessonsStatistics.from_lessons(plan_extractor.forms_plan.lessons).serialize()
}),
"statistics.json"
)

self.cache.store_plan_file(
date, timestamp,
json.dumps(plan_extractor.forms_plan.exams, default=Exam.serialize),
Expand Down
41 changes: 41 additions & 0 deletions backend/stats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import dataclasses
from collections import defaultdict

from backend import models


@dataclasses.dataclass
class LessonsStatistics:
count: int = 0
cancelled: int = 0
changed: int = 0
absent_teachers: int = 0

@classmethod
def from_lessons(cls, lessons: models.Lessons):
out = LessonsStatistics()

teacher_is_absent = defaultdict(lambda: True)

for lesson in lessons:
if lesson.is_scheduled:
continue

out.count += 1

if not lesson.takes_place:
out.cancelled += 1
out.changed += 1

elif lesson.teacher_changed or lesson.room_changed or lesson.subject_changed:
out.changed += 1

for teacher in lesson.teachers or []:
teacher_is_absent[teacher] &= not lesson.takes_place

out.absent_teachers = sum(teacher_is_absent.values())

return out

def serialize(self) -> dict:
return dataclasses.asdict(self)
63 changes: 41 additions & 22 deletions backend/vplan_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,27 +96,27 @@ def group_forms(forms: list[str]) -> dict[str, list[str]]:
return {k: v for k, v in sorted(groups.items(), key=lambda x: form_sort_key(x[0]))}


def _form_minor_to_int(minor: str) -> int | None:
def _form_minor_to_int(minor: str) -> tuple[int | None, int | None]:
try:
return int(minor)
return int(minor), 0 # 0 = numeric
except ValueError:
pass

if minor.isalpha() and len(minor) == 1:
return ord(minor.lower()) - ord("a") + 1
return ord(minor.lower()) - ord("a") + 1, 1 # 1 = alpha

return None
return None, None


def form_minor_to_int(minor: str) -> int | None:
minor_int = _form_minor_to_int(minor)
def form_minor_to_int(minor: str) -> tuple[int | None, int | None]:
minor_int, minor_type = _form_minor_to_int(minor)

if minor_int is None:
return None
return None, None
elif not 1 <= minor_int <= 13:
return None
return None, None
else:
return minor_int
return minor_int, minor_type


def _increasing_sequences(seq: typing.Iterable, key=lambda x: x) -> list[list]:
Expand All @@ -125,6 +125,10 @@ def _increasing_sequences(seq: typing.Iterable, key=lambda x: x) -> list[list]:
last = None

for elem in seq:
if last == elem:
# fallback if something bad happens
return [[elem] for elem in seq]

if last is None or key(elem) == key(last) + 1:
current_seq.append(elem)
else:
Expand All @@ -139,23 +143,38 @@ def _increasing_sequences(seq: typing.Iterable, key=lambda x: x) -> list[list]:


def _group_form_minors(first_part: str, minors: list[str]) -> list[str]:
_parsed_minors = {minor: form_minor_to_int(minor) for minor in minors}
_non_invalid_parsed_minors = {k: v for k, v in _parsed_minors.items() if v is not None}
invalid_minors = [k for k, v in _parsed_minors.items() if v is None]
parsed_minors = {k: v for k, v in sorted(_non_invalid_parsed_minors.items(), key=lambda x: x[1])}
_parsed_minors: dict[str, tuple[int | None, int | None]] = {minor: form_minor_to_int(minor) for minor in minors}
_valid_parsed_minors = {
k: (minor_int, minor_type) for k, (minor_int, minor_type) in _parsed_minors.items() if minor_int is not None
}
invalid_minors = [k for k, (minor_int, minor_type) in _parsed_minors.items() if minor_int is None]
parsed_minors_by_minor_type: dict[str, list[tuple[int, int]]] = defaultdict(list)
for minor, (minor_int, minor_type) in _valid_parsed_minors.items():
parsed_minors_by_minor_type[minor_type].append((minor, minor_int))

# sort by minor int
parsed_minors_by_minor_type = {
minor_type: sorted(parsed_minors, key=lambda x: x[1])
for minor_type, parsed_minors in parsed_minors_by_minor_type.items()
}

seqs = _increasing_sequences(parsed_minors.keys(), key=lambda x: parsed_minors[x])
# sort by minor type
parsed_minors_by_minor_type = dict(sorted(parsed_minors_by_minor_type.items(), key=lambda x: x[0]))

out = []
for seq in seqs:
if not seq:
continue

if len(seq) < 3:
for minor in seq:
out.append(minor)
else:
out.append(f"{seq[0]}-{seq[-1]}")
for minor_type, parsed_minors in parsed_minors_by_minor_type.items():
seqs = _increasing_sequences(parsed_minors, key=lambda x: x[1])

for seq in seqs:
if not seq:
continue

if len(seq) < 3:
for minor_str, minor_int in seq:
out.append(minor_str)
else:
out.append(f"{seq[0][0]}-{seq[-1][0]}")

out += invalid_minors

Expand Down

0 comments on commit 67d837a

Please sign in to comment.