-
Notifications
You must be signed in to change notification settings - Fork 0
/
diff_computer.py
148 lines (114 loc) · 4.51 KB
/
diff_computer.py
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
141
142
143
144
145
146
147
148
import json
from encoder import NoWSEncoder
from storage import Storage
class NoUpdate(Exception):
'''Exception to signify that no update is necessary'''
class DiffComputer:
'''Computes differences between the old and newly fetched data.
This is to reduce data transfer and not to update identical data.
Diffing methods return the processed data in JSON'''
def __init__(self, storage: Storage):
self.storage = storage
self.json = NoWSEncoder()
def exchange(self, key: str, value):
'''Exchanges the old data with the given key for a new value.
Returns the old data piece, JSON-decoded.
If the new value is equal to what already was in the storage or
new data failed to get fetched, raises NoUpdate'''
try:
old = json.loads(self.storage[key])
if old == value:
raise NoUpdate
except KeyError:
old = None
if value is None:
raise NoUpdate
self.storage[key] = self.json.encode(value)
return old
def diff_class_list(self, new: dict) -> str:
old = self.exchange('class_list', new)
if old is None:
return self.json.encode(new)
for form, classes in old.items():
if form in new and classes == new[form]:
new[form] = None
return self.json.encode(new)
def diff_study_plan(self, new: list) -> str:
old = self.exchange('study_plan', new)
if old is None:
return self.json.encode(new)
for m_idx, month in enumerate(old):
if month == new[m_idx]:
new[m_idx] = None
return self.json.encode(new)
def diff_rings_timetable(self, new: list) -> str:
self.exchange('rings_timetable', new)
return self.json.encode(new)
@staticmethod
def diff_timetable(old: list, new: list) -> list:
for d_idx, day in enumerate(old):
for l_idx, lesson in enumerate(day):
if lesson == new[d_idx][l_idx]:
new[d_idx][l_idx] = None
return new
def diff_full_perm_timetable(self, new: dict) -> str:
old = self.exchange('full_perm_timetable', new)
if old is None:
return self.json.encode(new)
for cls, tmtbl in old.items():
if cls in new:
new[cls] = self.diff_timetable(tmtbl, new[cls])
return self.json.encode(new)
def diff_teachers(self, new: list) -> str:
old = self.exchange('teachers', new)
if old is None:
return self.json.encode(new)
name_lookup = {i['abbr']: i for i in new if 'abbr' in i}
for teacher in old:
try:
new_tchr = name_lookup[teacher['abbr']]
except KeyError:
continue
for field in ('full', 'dep', 'job', 'classes'):
try:
if new_tchr[field] == teacher[field]:
new_tchr[field] = None
except KeyError:
pass
try:
new_tchr['timetable'] = self.diff_timetable(
teacher['timetable'],
new_tchr['timetable'])
except KeyError:
pass
return self.json.encode(new)
def diff_vacant_rooms(self, new: list) -> str:
old = self.exchange('vacant_rooms', new)
if old is None:
return self.json.encode(new)
for day_idx, old_day in enumerate(old):
for lsn_idx, lesson in enumerate(old_day):
for floor, rooms in lesson.items():
if new[day_idx][lsn_idx][floor] == rooms:
new[day_idx][lsn_idx][floor] = None
return self.json.encode(new)
def diff_changes(self, new: list) -> str:
old = self.exchange('changes', new)
if old is None:
return self.json.encode(new)
day_lookup = {(i['day'], i['month']): i for i in new}
reserved = {'day', 'month', 'wkday'}
for day in old:
try:
new_day = day_lookup[(day['day'], day['month'])]
except KeyError:
continue
for prop in day:
if prop in reserved:
continue
if day[prop] == new_day[prop]:
new_day[prop] = None
return self.json.encode(new)
def diff_class_teachers(self, new: dict) -> str:
self.exchange('class_teachers', new)
return self.json.encode(new)