-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtimetable.py
More file actions
140 lines (123 loc) · 5.76 KB
/
timetable.py
File metadata and controls
140 lines (123 loc) · 5.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import re
from datetime import datetime, time, date, timedelta
from typing import Optional, List, Tuple
from openpyxl import load_workbook
from dataclass.lesson_data import LessonData
import config
# Regex for parsing lesson information
LESSON_REGEX = (
r'(?P<lesson_specific_date>\d{1,2}\.\d{1,2})? ?'
r'(?P<lesson_specific_start_time>\d{1,2}:\d{1,2})? ?'
r'(?P<lesson_name>[A-ZА-ЯЁ,\-() ]+)? ?'
r'(?P<lesson_type>\(пр\)|\(лек\)|\(лаб\))? ?'
r'(?P<tutor_role>пр\.|асс\.|ст\. пр\.|зав\. каф\.|доц\.|про.|тренер-преподаватель)? ?'
r'(?P<tutor_initials>[А-ЯЁ][а-яё]+ [А-ЯЁ]\.[А-ЯЁ]\.)? ?'
r'(?P<swimming_time>\d{1,2}:\d{1,2})? ?'
r'(?P<swimming_pool>Бассейн)? ?'
r'(?P<manufactory>ПНППК)? ?'
r'(?P<audience>\d+[а-яё]*)? ?'
r'(?P<housing>\гл\.к\. ?|гл\. ?|к\. ?[АБВГД])'
)
class TimeTable:
def __init__(self, time_table_path: str):
self.timetable_path = time_table_path
self.workbook = load_workbook(self.timetable_path)
self.sheet = self.workbook.active
self.months_dict = {
'января': 1, 'февраля': 2, 'марта': 3, 'апреля': 4,
'мая': 5, 'июня': 6, 'июля': 7, 'августа': 8,
'сентября': 9, 'октября': 10, 'ноября': 11, 'декабря': 12
}
self.start_times = {
1: time(hour=8),
2: time(hour=9, minute=40),
3: time(hour=11, minute=30),
4: time(hour=13, minute=20),
5: time(hour=15),
6: time(hour=16, minute=40)
}
def get_start_date(self) -> date:
value = self.sheet[config.DATE_INFO_CELL].value
if not value:
return date.today()
commons = value.split()
if len(commons) < 5:
return date.today()
try:
day = int(commons[3])
month = self.months_dict.get(commons[4].lower(), 1)
return date(datetime.now().year, month, day)
except (IndexError, ValueError):
return date.today()
def get_week_parity(self) -> int:
value = self.sheet[config.DATE_INFO_CELL].value
if not value:
return 1
try:
return int(value.split()[-2])
except (IndexError, ValueError):
return 1
def _format_cell_info(self, lesson_data: LessonData) -> str:
aud = f', ауд. {lesson_data.audience}' if lesson_data.housing and lesson_data.audience else ''
info = (f'{lesson_data.lesson_specific_start_time or lesson_data.swimming_time or ""} '
f'{lesson_data.lesson_specific_date or ""} '
f'{lesson_data.lesson_name.title() if lesson_data.lesson_name else ""}\n'
f'{lesson_data.tutor_role or ""} {lesson_data.tutor_initials or ""}\n'
f'{lesson_data.housing or lesson_data.swimming_pool or lesson_data.manufactory or ""}{aud}')
return info.strip().replace(' ', ' ')
def parse_timetable(self, push: bool = False, until: str = '', calendar_id: str = '', calendar_worker=None) -> Tuple[List[str], List[str]]:
lesson_num = 0
i = config.START_ROW
current_date = self.get_start_date()
week_parity = self.get_week_parity()
first_week = []
second_week = []
while i <= config.END_ROW:
lesson_str = self.sheet[f'{config.LESSON_COLUMN}{i}'].value
lesson_str = '---' if lesson_str is None else (
lesson_str.replace('\n', ' ').replace('\u00A0', ' ').replace(' ', ' '))
matches = re.search(LESSON_REGEX, lesson_str)
lesson_data = LessonData(**matches.groupdict()) if matches else None
cell_info = self._format_cell_info(lesson_data) if lesson_data else ''
is_merged = self.is_cell_merged(f'{config.LESSON_COLUMN}{i}')
if is_merged:
first_week.append(cell_info)
second_week.append(cell_info)
if push and lesson_data and calendar_worker:
calendar_worker.insert_lesson_event(
calendar_id=calendar_id,
lesson_data=lesson_data,
start_time=self.start_times[lesson_num % config.LESSONS_PER_DAY + 1],
lesson_date=current_date,
until=until,
interval=1
)
i += 1
else:
if i % 2 == 0:
first_week.append(cell_info)
else:
second_week.append(cell_info)
if push and lesson_data and calendar_worker:
lesson_date = current_date + timedelta(days=7 if i % 2 == week_parity % 2 else 0)
calendar_worker.insert_lesson_event(
calendar_id=calendar_id,
lesson_data=lesson_data,
start_time=self.start_times[lesson_num % config.LESSONS_PER_DAY + 1],
lesson_date=lesson_date,
until=until,
interval=2
)
i += 1
if i % 2 == 0:
lesson_num += 1
if (i - config.START_ROW) % config.ROWS_PER_DAY == 0:
current_date += timedelta(days=1)
return first_week, second_week
def is_cell_merged(self, cell_to_check: str) -> bool:
for merged_range in self.sheet.merged_cells.ranges:
if cell_to_check in merged_range:
min_col, min_row, max_col, max_row = merged_range.bounds
if min_col == max_col or min_col + min_row + 2 == max_col + max_row:
return True
return False