-
Notifications
You must be signed in to change notification settings - Fork 0
/
baseline.py
347 lines (301 loc) · 14.4 KB
/
baseline.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
import fire, os, json, psutil
import mureq
from ipcqueue import posixmq
from baseline_constants import session_start_success_const, solution_file_doesnt_exist_const
from baseline_constants import data_not_resolved_const
from cfg_support import get_current_session_id
from cfg_support import get_current_epicrisis_id
from cfg_support import get_current_task_id
from validator import Validator, NotJsonContentInFileError, TooManyObjectsInTheArrayError
from validator import JsonIsEmpty, StructureJsonIsIncorrect, LimitKeysInJson, DiagnosisMainLength
from validator import IncorrectKeyValues
from validator import ThereIsNoMainDiagnosis
from cfg_support import get_perfomance
import socketio
import datetime as dt
from push_log import logger
class BaselineCommands(object):
def __init__(self):
self.main_input_queue = posixmq.Queue('/baseline')
self.main_output_queue = posixmq.Queue('/inline')
def core(self):
perfomance = get_perfomance()
pid = None
for proc in psutil.process_iter(['pid', 'name', 'username']):
if proc.cmdline()[-2:] == ['python', 'core.py']:
pid = proc.pid
if pid:
print("Baseline process is already started. PID - " + str(pid))
return
try:
# standard Python
ping = 'ping'
sio = socketio.Client()
sio.connect(f'{perfomance["aimed_host"]}?token={perfomance["token"]}&ping={ping}',
namespaces=['/baselinezcllbpxcgrye'],
transports=['websocket'], wait=True, wait_timeout=3)
sio.disconnect()
except Exception as e:
print(e)
print(f'Please check the correctness of the entered address in the creds.cfg file or contact'
f' the platform administrator.'
f' The platform does not respond to connection requests over WS.')
return
try:
os.system('python core.py')
print(f'Core start successfully.')
except Exception as error:
print(error)
print(f'An error occurred while starting the core.')
def kill(self):
'''ЗАВЕРШЕНИЕ ГЛАВНОГО ПРОЦЕССА. ЭКВИВАЛЕНТНО "docker compose down". Пример для Docker - LINUX - "./baseline kill" -
WINDOWS - docker-compose exec -iT baseline sh -c "python baseline.py kill".
Подробнее об этом в файлах docs/commands-native.md и docs/commands-windows.md'''
try:
pid = None
for proc in psutil.process_iter(['pid', 'name', 'username']):
if proc.cmdline()[-2:] == ['python', 'core.py']:
proc.kill()
print("Core successfully killed.")
except:
print("An exception occurred.")
def start(self, contest, stage, type, count=None, timeout=None, nosology=None):
'''СТАРТ СЕССИИ. Пример для Docker - LINUX - "./baseline start --contest=<contest> --stage=<stage> --type=<type> --count=<int> --timeout=<int>" -
WINDOWS - docker-compose exec -iT baseline sh -c "python baseline.py start --contest=<contest> --stage=<stage> --type=<type> --count=<int> --timeout=<int>".
Подробнее об этом в файлах docs/commands-native.md и docs/commands-windows.md'''
pid = None
for proc in psutil.process_iter(['pid', 'name', 'username']):
if proc.cmdline()[-2:] == ['python', 'core.py']:
pid = proc.pid
if not pid:
print(f'Baseline CORE was not started, the command cannot be executed')
return
print(contest, stage, type, count, timeout, nosology)
if type not in ["training", "estimated-training"]:
print(type)
if count or timeout:
print(f'Parameter setting is allowed only in the training session.')
return
if contest in ["doctor"]:
if type in ["training"]:
if not count:
count = 100
if type in [ "estimated-training"]:
if count:
print(f'Parameter count cannot be specified in this session type.')
return
if type in [ "challenge"]:
if nosology:
print(f'Parameter setting is allowed only in the training session.')
return
nosology_string = ''
if nosology:
if isinstance(nosology, int):
nosology_string = str(nosology)
else:
nosology_string = ','.join(map(str,nosology))
initial_params = dict(
op='start',
data={
'contest': contest,
'params': {
'stage': stage,
'sessionType': type,
}
}
)
print(f'Parameter - contest - {contest}')
print(f'Parameter - stage - {stage}')
print(f'Parameter - type - {type}')
if count:
initial_params["data"]["params"]["countFiles"] = count
print(f'Parameter - count - {count}')
if timeout:
initial_params["data"]["params"]["time"] = timeout
print(f'Parameter - timeout - {timeout}')
if nosology_string != "":
initial_params["data"]["params"]["nosologyString"] = nosology_string
print(f'Parameter - nosology string - {nosology_string}')
self.main_input_queue.put(
initial_params,
priority=1
)
answer = self.main_output_queue.get()
print(answer)
pass
def send(self, path, taskid):
'''ОТПРАВКА РЕЗУЛЬТАТА НА ПЛАТФОРМУ. Пример для Docker - LINUX - "./baseline send --path=<path_to_solution_json> --taskid=<ID_задачи>" -
WINDOWS - docker-compose exec -iT baseline sh -c "python baseline.py send --path=<path_to_solution_json> --taskid=<ID_задачи>".
Подробнее об этом в файлах docs/commands-native.md и docs/commands-windows.md'''
pid = None
for proc in psutil.process_iter(['pid', 'name', 'username']):
if proc.cmdline()[-2:] == ['python', 'core.py']:
pid = proc.pid
if not pid:
print(f'Baseline CORE was not started, the command cannot be executed')
return
check_file = os.path.isfile(path)
if not check_file:
print(solution_file_doesnt_exist_const)
return
if not taskid:
print(f'taskid is required argument, the command cannot be executed')
return
currentsessionid = get_current_session_id()
currentepicrisisid = get_current_epicrisis_id()
currenttasksid = get_current_task_id()
if not currentsessionid or not currentepicrisisid or not currenttasksid:
print(data_not_resolved_const)
return
try:
validator = Validator(path)
validator.validate()
except NotJsonContentInFileError as nje:
print(nje)
return
except TooManyObjectsInTheArrayError as tmo:
print(tmo)
return
except JsonIsEmpty as jie:
print(jie)
return
except StructureJsonIsIncorrect as sjii:
print(sjii)
return
except LimitKeysInJson as lkij:
print(lkij)
return
except DiagnosisMainLength as dml:
print(dml)
return
except IncorrectKeyValues as ikv:
print(ikv)
return
except ThereIsNoMainDiagnosis as tinmd:
print(tinmd)
return
try:
a = dt.datetime.now()
perfomance = get_perfomance()
main_dir = os.path.dirname(os.path.abspath(__file__))
check_file = os.path.join(main_dir, path)
with open(check_file, 'r') as f:
solution_raw_content = f.read()
solution_from_file = json.loads(solution_raw_content)
response = mureq.post(perfomance["download_host"] + '/upload-result',
json={'token': perfomance["token"], 'taskId': taskid, 'answer': solution_from_file})
b = dt.datetime.now()
less = (b-a).total_seconds()
if response.status_code == 201:
logger.info(dict(op='file-send', status='success',
message=dict(session=currentsessionid, task=taskid, time=less)))
print(f'File task ID - {taskid} - successfuly sent. Upload time - {less}')
return
else:
raise Exception
except Exception as e:
logger.info(dict(op='file-send', status='error',
message=dict(session=currentsessionid, task=taskid)))
print('File do not sent. Error.')
print(e)
return
def abort(self):
'''ПРЕРЫВАНИЕ СЕССИИ. Пример для Docker - LINUX - "./baseline abort" -
WINDOWS - docker-compose exec -iT baseline sh -c "python baseline.py abort".
Подробнее об этом в файлах docs/commands-native.md и docs/commands-windows.md'''
pid = None
for proc in psutil.process_iter(['pid', 'name', 'username']):
if proc.cmdline()[-2:] == ['python', 'core.py']:
pid = proc.pid
if not pid:
print(f'Baseline CORE was not started, the command cannot be executed')
return
try:
perfomance = get_perfomance()
response = mureq.post(perfomance["download_host"] + '/abort', json={'token': perfomance["token"]}, timeout=120)
if response.status_code == 201:
logger.info(dict(op='session-abort', status='success',
message='Termination of session completed successfully'))
print('Session abort success.')
return
else:
raise Exception
except Exception as e:
logger.info(dict(op='session-abort', status='error',
message='Session - was not aborted.'))
print('Session - was not aborted.')
print(e)
return
def check(self):
'''ПРЕРЫВАНИЕ СОСТОЯНИЯ УТИЛИТЫ. Пример для Docker - LINUX - "./baseline check" -
WINDOWS - docker-compose exec -iT baseline sh -c "python baseline.py check".
Подробнее об этом в файлах docs/commands-native.md и docs/commands-windows.md'''
pid = None
for proc in psutil.process_iter(['pid', 'name', 'username']):
if proc.cmdline()[-2:] == ['python', 'core.py']:
pid = proc.pid
if pid:
print("Baseline process is now started. PID - " + str(pid))
print("Current INPUT queue state - " + str(self.main_input_queue.qsize()))
print("Current OUTPUT queue state - " + str(self.main_output_queue.qsize()))
else:
print("Baseline process not launched. \nIf you want to raise the connection to the AIMED platform"
" - enter the command `python baseline.py core`")
def flush(self):
'''ОЧИСТКА ВНУТРЕННЕЙ ОЧЕРЕДИ КОМАНД. Пример для Docker - LINUX - "./baseline flush" -
WINDOWS - docker-compose exec -iT baseline sh -c "python baseline.py flush".
Подробнее об этом в файлах docs/commands-native.md и docs/commands-windows.md'''
input_queue_size = self.main_input_queue.qsize()
if input_queue_size > 0:
print("Current INPUT queue state - " + str(self.main_input_queue.qsize()) + ". Delete pending tasks")
for i in range(0, input_queue_size, 1):
self.main_input_queue.get_nowait()
else:
print("INPUT queue is empty. Skip.")
output_queue_size = self.main_output_queue.qsize()
if output_queue_size > 0:
print("Current OUTPUT queue state - " + str(self.main_output_queue.qsize()) + ". Delete pending tasks")
for i in range(0, output_queue_size, 1):
self.main_output_queue.get_nowait()
else:
print("OUTPUT queue is empty. Skip.")
## python baseline.py test --test_id=1 --description="Lorem ipsum dolor sit amet"
## ограничение на кол-во символов в обосновании диагноза (500)
## давать список исследований нельзя - это подсказка (но а как узнать, что вообще представлено и как обрабатывать случаи матчинга имён?) (!)
## нужна проверка на сумму 100% для всех гипотез
## не пускаем на платформу невалидный запрос исследований или проверяем - проверяем по справочнику
## - список нозологий закладываем в бейзлайн (!)
def test(self, test_id: int, description: str):
pid = None
for proc in psutil.process_iter(['pid', 'name', 'username']):
if proc.cmdline()[-2:] == ['python', 'core.py']:
pid = proc.pid
if not pid:
print(f'Baseline CORE was not started, the command cannot be executed')
return
if len(description) > 500:
print("The 'description' field is limited to 500 characters")
return
if test_id not in [1, 2, 3, 4, 5, 6]:
print("Test with this ID (test_id param) does not exist")
return
currentsessionid = get_current_session_id()
currentepicrisisid = get_current_epicrisis_id()
currenttaskid = get_current_task_id()
self.main_input_queue.put(
dict(
op="gettest",
data={
"description": description,
"sessionId": currentsessionid,
"epicrisisId": currentepicrisisid,
"testId": test_id,
"taskId": currenttaskid
}
)
)
answer = self.main_output_queue.get()
print(answer)
pass
if __name__ == '__main__':
fire.Fire(BaselineCommands)