model states ench
This commit is contained in:
parent
9e29e5f9c8
commit
1d05a67a89
9
forms.py
9
forms.py
@ -18,7 +18,9 @@ ID_ADD_MODEL_SELECTED = wx.NewId()
|
||||
ID_DUPLICATE_MODEL = wx.NewId()
|
||||
ID_DUPLICATE_TREE = wx.NewId()
|
||||
ID_DELETE_MODEL = wx.NewId()
|
||||
|
||||
ID_PROCESS_MODEL = wx.NewId()
|
||||
ID_STOP_MODEL = wx.NewId()
|
||||
|
||||
ID_SHOW_RESULT = wx.NewId()
|
||||
|
||||
@ -152,6 +154,8 @@ class MainFrame(wx.Frame):
|
||||
icons.mready = ilist.Add(wx.Bitmap('share/model-ready.png'))
|
||||
icons.mrun = ilist.Add(wx.Bitmap('share/model-run.png'))
|
||||
icons.mcomplete = ilist.Add(wx.Bitmap('share/model-complete.png'))
|
||||
icons.mstopped = ilist.Add(wx.Bitmap('share/model-stop.png'))
|
||||
icons.mnoexec = ilist.Add(wx.Bitmap('share/model-no-exec.png'))
|
||||
|
||||
icons.porg = ilist.Add(wx.Bitmap('share/plot-org.png'))
|
||||
icons.pline = ilist.Add(wx.Bitmap('share/plot-line.png'))
|
||||
@ -182,6 +186,7 @@ class MainFrame(wx.Frame):
|
||||
|
||||
menu = wx.Menu()
|
||||
menu.Append(ID_PROCESS_MODEL, 'Process\tF5')
|
||||
menu.Append(ID_STOP_MODEL, 'Stop\tF6')
|
||||
#menu.AppendSeparator()
|
||||
menubar.Append(menu, '&Run')
|
||||
|
||||
@ -237,7 +242,9 @@ class MainFrame(wx.Frame):
|
||||
'Delete selected model')
|
||||
tb1.AddSeparator()
|
||||
tb1.AddSimpleTool(ID_PROCESS_MODEL, "model-go", wx.Bitmap('share/model-go.png'),
|
||||
'Start process selected model')
|
||||
'Start processing of selected models')
|
||||
tb1.AddSimpleTool(ID_STOP_MODEL, "model-stop", wx.Bitmap('share/model-cancel.png'),
|
||||
'Stop processing of selected models')
|
||||
tb1.AddSeparator()
|
||||
tb1.AddSimpleTool(ID_SHOW_PLOT, "plot-quick", wx.Bitmap('share/plot-line.png'),
|
||||
'Show quick plot for selected model')
|
||||
|
152
opal.py
152
opal.py
@ -27,21 +27,43 @@ import json
|
||||
import zlib
|
||||
from pprint import pprint
|
||||
|
||||
# состояния модели, унаследованные от состояния задачи
|
||||
MODEL_READY = server.JOB_READY
|
||||
MODEL_RUNNING = server.JOB_RUNNING
|
||||
MODEL_STOPPED = server.JOB_STOPPED
|
||||
MODEL_COMPLETED = server.JOB_COMPLETED
|
||||
# собственные состояния модели
|
||||
MODEL_NO_EXEC = 101
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Данные о пользовательской модели
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
class ModelData:
|
||||
def __init__(self, server, model, parent_data = None):
|
||||
# если мы создаем новый набор данных из описания модели
|
||||
if isinstance(model, task.DataDescription):
|
||||
self.mdef = task.DataDefinition(model, parent_data)
|
||||
self.jid = server.CreateJob() if model.IsExecutable() else None
|
||||
self.jid = server.CreateJob() if model.IsExecutable() else None
|
||||
# если мы создаем набор данных из другого набора данных
|
||||
elif isinstance(model, ModelData):
|
||||
self.mdef = model.mdef.Copy()
|
||||
self.jid = server.CreateJob() if model.jid else None
|
||||
self.jid = server.CreateJob() if model.jid else None
|
||||
else:
|
||||
self.mdef = None
|
||||
self.jid = None
|
||||
self.jid = None
|
||||
|
||||
self.res = None
|
||||
assert self.mdef
|
||||
|
||||
self.res = None # результаты выполнения работы
|
||||
if self.jid:
|
||||
self.state = MODEL_READY # состояние модели
|
||||
else:
|
||||
self.state = MODEL_NO_EXEC # состояние модели
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Данные о линии в графике
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
LINE_CURVE = 1
|
||||
LINE_MARKER = 2
|
||||
@ -96,6 +118,10 @@ class LineData:
|
||||
assert data.res # если результата нет, то а-та-та
|
||||
return data.res.Zip(*self.columns)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Ошибки доступа к элементам в контейнерах
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
class ItemError(Exception):
|
||||
pass
|
||||
|
||||
@ -156,8 +182,11 @@ class MainFrame(forms.MainFrame):
|
||||
id = forms.ID_DUPLICATE_TREE)
|
||||
self.Bind(wx.EVT_MENU, self.OnDeleteModel,
|
||||
id = forms.ID_DELETE_MODEL)
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnModelProcess,
|
||||
id = forms.ID_PROCESS_MODEL)
|
||||
self.Bind(wx.EVT_MENU, self.OnModelStop,
|
||||
id = forms.ID_STOP_MODEL)
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnShowResult,
|
||||
id = forms.ID_SHOW_RESULT)
|
||||
@ -214,19 +243,6 @@ class MainFrame(forms.MainFrame):
|
||||
состояние окружения, выводит информацию, подгружает результаты
|
||||
выполнения работ и др.
|
||||
"""
|
||||
|
||||
def StateToStr(state):
|
||||
if state == server.JOB_READY:
|
||||
return 'Ready'
|
||||
elif state == server.JOB_RUNNING:
|
||||
return 'Running'
|
||||
elif state == server.JOB_STOPPED:
|
||||
return 'Stopped'
|
||||
elif state == server.JOB_COMPLETED:
|
||||
return 'Completed'
|
||||
else:
|
||||
return 'Unknown'
|
||||
|
||||
try:
|
||||
um = self.m_user_models
|
||||
cycle_count = 0
|
||||
@ -247,25 +263,29 @@ class MainFrame(forms.MainFrame):
|
||||
if not data:
|
||||
continue
|
||||
jid = data.jid
|
||||
if jid != None and self.server.IsJobChanged(jid):
|
||||
if jid and self.server.IsJobChanged(jid):
|
||||
# таким образом, тут мы обрабатываем новое состояние
|
||||
# работы (модели)
|
||||
|
||||
state, percent, comment = self.server.GetJobState(jid)
|
||||
um.SetItemText(item, StateToStr(state), 1)
|
||||
|
||||
data.state = state
|
||||
self.SetModelState(item, data.state)
|
||||
|
||||
p = 'Unknown' if percent < 0 else '{:%}'.format(percent)
|
||||
um.SetItemText(item, p, 2)
|
||||
um.SetItemText(item, comment, 3)
|
||||
|
||||
print 'JID', jid, (state, percent, comment)
|
||||
|
||||
# завершающие действия по окончанию выполнения работы
|
||||
if state == server.JOB_COMPLETED:
|
||||
# устанавливаем иконку для завершенной модели
|
||||
um.SetItemImage(item, self.icons.mcomplete)
|
||||
# получаем результаты выполнения
|
||||
data.res = self.server.GetJobResult(jid)
|
||||
# если завершившаяся задача в данный момент выделена
|
||||
# то сразу же показываем этот результат
|
||||
if um.IsSelected(item):
|
||||
self.ShowQuickResult(data.res)
|
||||
else:
|
||||
um.SetItemImage(item, self.icons.mrun)
|
||||
finally:
|
||||
wx.MutexGuiLeave()
|
||||
pass
|
||||
@ -396,7 +416,6 @@ class MainFrame(forms.MainFrame):
|
||||
except Exception, e:
|
||||
print 'Oops', type(e), e
|
||||
|
||||
|
||||
def OnSaveProject(self, event):
|
||||
|
||||
def WalkModels(item, dest):
|
||||
@ -407,7 +426,8 @@ class MainFrame(forms.MainFrame):
|
||||
dest[title] = {
|
||||
'model': mdef.DD.GetLabel(),
|
||||
'data': mdef.params,
|
||||
'um': {}
|
||||
'um': {},
|
||||
'state': data.state,
|
||||
}
|
||||
if data.res:
|
||||
dest[title]['result'] = data.res.DumpData()
|
||||
@ -457,9 +477,9 @@ class MainFrame(forms.MainFrame):
|
||||
|
||||
# pprint(data)
|
||||
dump = json.dumps(data, indent = 2)
|
||||
with open('data.opl', 'wb') as f:
|
||||
f.write(zlib.compress(dump, 9))
|
||||
# f.write(dump)
|
||||
with open('data.opl', 'w') as f:
|
||||
# f.write(zlib.compress(dump, 9))
|
||||
f.write(dump)
|
||||
|
||||
wx.EndBusyCursor()
|
||||
|
||||
@ -495,6 +515,41 @@ class MainFrame(forms.MainFrame):
|
||||
|
||||
# Добавление новых моделей
|
||||
|
||||
def SetModelState(self, item, state):
|
||||
if state == MODEL_READY:
|
||||
icon = self.icons.mready
|
||||
text = 'Ready'
|
||||
|
||||
elif state == MODEL_RUNNING:
|
||||
icon = self.icons.mrun
|
||||
text = 'Running'
|
||||
|
||||
elif state == MODEL_COMPLETED:
|
||||
icon = self.icons.mcomplete
|
||||
text = 'Completed'
|
||||
|
||||
elif state == MODEL_STOPPED:
|
||||
icon = self.icons.mstopped
|
||||
text = 'Stopped'
|
||||
|
||||
else:
|
||||
icon = self.icons.mnoexec
|
||||
text = 'No executable'
|
||||
|
||||
self.m_user_models.SetItemImage(item, icon)
|
||||
self.m_user_models.SetItemText(item, text, 1)
|
||||
|
||||
def AddModel(self, item, title, model_data):
|
||||
"""
|
||||
Добавляет модель к указанной,
|
||||
устанавливает имя, данные, состояние, иконку
|
||||
"""
|
||||
um = self.m_user_models
|
||||
item = um.AppendItem(item, title)
|
||||
um.SetPyData(item, model_data)
|
||||
self.SetModelState(item, model_data.state)
|
||||
return item
|
||||
|
||||
def AddModelToRoot(self, model):
|
||||
"""
|
||||
Добавляет пользовательскую модель или спецификацию
|
||||
@ -514,13 +569,11 @@ class MainFrame(forms.MainFrame):
|
||||
root = None
|
||||
for i, m in enumerate(ms):
|
||||
name = self.GenerateName(m.GetTitle())
|
||||
item = um.AppendItem(item, name)
|
||||
um.SetItemImage(item, self.icons.mready)
|
||||
if not i:
|
||||
root = item
|
||||
data = ModelData(self.server, m, defparent)
|
||||
item = self.AddModel(item, name, data)
|
||||
defparent = data.mdef
|
||||
um.SetPyData(item, data)
|
||||
if root:
|
||||
um.Expand(root)
|
||||
um.SelectItem(item)
|
||||
@ -543,10 +596,8 @@ class MainFrame(forms.MainFrame):
|
||||
# если новая модель может быть присоединена...
|
||||
if pmdef.DD == model.parent:
|
||||
name = self.GenerateName(model.GetTitle())
|
||||
child = um.AppendItem(item, name)
|
||||
new_data = ModelData(self.server, model, pmdef)
|
||||
um.SetPyData(child, new_data)
|
||||
um.SetItemImage(child, self.icons.mready)
|
||||
child = self.AddModel(item, name, new_data)
|
||||
um.SetFocus()
|
||||
um.Expand(item)
|
||||
um.SelectItem(child)
|
||||
@ -616,7 +667,11 @@ class MainFrame(forms.MainFrame):
|
||||
def OnParamChanged(self, event):
|
||||
|
||||
def Walk(item):
|
||||
um.SetItemImage(item, self.icons.mready)
|
||||
data = um.GetPyData(item)
|
||||
if data.state != MODEL_NO_EXEC:
|
||||
data.state = MODEL_READY
|
||||
self.SetModelState(item, data.state)
|
||||
|
||||
child, _ = um.GetFirstChild(item)
|
||||
while child.IsOk():
|
||||
Walk(child)
|
||||
@ -635,17 +690,7 @@ class MainFrame(forms.MainFrame):
|
||||
Walk(item)
|
||||
|
||||
def OnTest(self, event):
|
||||
|
||||
def Walk(item):
|
||||
print um.GetItemText(item)
|
||||
um.SetItemImage(item, self.icons.mready)
|
||||
child, cookie = um.GetFirstChild(item)
|
||||
while child.IsOk():
|
||||
Walk(child)
|
||||
child = um.GetNextSibling(child)
|
||||
|
||||
um = self.m_user_models
|
||||
Walk(um.GetRootItem())
|
||||
pass
|
||||
|
||||
# Получение данных выбранной модели
|
||||
|
||||
@ -678,7 +723,7 @@ class MainFrame(forms.MainFrame):
|
||||
new_data = ModelData(self.server, data)
|
||||
um.SetItemText(item_dst, self.GenerateName(title))
|
||||
um.SetPyData(item_dst, new_data)
|
||||
um.SetItemImage(item_dst, self.icons.mready)
|
||||
self.SetModelState(item_dst, new_data.state)
|
||||
|
||||
def OnDuplicate(self, event):
|
||||
"""
|
||||
@ -731,7 +776,15 @@ class MainFrame(forms.MainFrame):
|
||||
um = self.m_user_models
|
||||
for i in um.GetSelections():
|
||||
data = um.GetItemPyData(i)
|
||||
self.server.LaunchJob(data.jid, data.mdef)
|
||||
if data.jid:
|
||||
self.server.LaunchJob(data.jid, data.mdef)
|
||||
|
||||
def OnModelStop(self, event):
|
||||
um = self.m_user_models
|
||||
for i in um.GetSelections():
|
||||
data = um.GetItemPyData(i)
|
||||
if data.jid:
|
||||
self.server.StopJob(data.jid)
|
||||
|
||||
# Функции управления таблицами и отчетами
|
||||
|
||||
@ -842,7 +895,8 @@ class MainFrame(forms.MainFrame):
|
||||
def ShowPlot(self, lines, plot_title = ''):
|
||||
if lines:
|
||||
p = PlotFrame(self, 'Plot', lines)
|
||||
p.Show()
|
||||
wx.FutureCall(20, p.Show)
|
||||
# p.Show()
|
||||
|
||||
def OnQuickShowPlot(self, event):
|
||||
lines = self.GetLines(LINE_CURVE)
|
||||
|
16
server.py
16
server.py
@ -219,16 +219,23 @@ class Worker(threading.Thread):
|
||||
proc.stdin.flush()
|
||||
# пока процесс не завершится (или его не прибьют)
|
||||
while proc.poll() == None:
|
||||
# читаем и обрабатываем сообщение
|
||||
msg = proc.stdout.readline()
|
||||
self.ProcessMessage(job, msg)
|
||||
|
||||
# сервер был остановлен, завершаем выполнение всех работ
|
||||
if not self.server.running:
|
||||
proc.kill()
|
||||
raise KeyError
|
||||
|
||||
except Exception, e:
|
||||
# любая нестандартная исключительная ситуация
|
||||
# приводит к немедленному завершанию работы
|
||||
WriteToLog('Job loop failed: ' + str(e))
|
||||
job.Finish(JOB_STOPPED)
|
||||
else:
|
||||
job.Finish(JOB_COMPLETED, 1.0)
|
||||
# только если работа уже не была остановлена
|
||||
if job.state != JOB_STOPPED:
|
||||
job.Finish(JOB_COMPLETED, 1.0)
|
||||
|
||||
def ProcessMessage(self, job, msg):
|
||||
try:
|
||||
@ -246,7 +253,10 @@ class Worker(threading.Thread):
|
||||
job.result = task.ResultData(data['result'])
|
||||
# произошла ошибка
|
||||
elif ans == 'error':
|
||||
# произошла серьезная ошибка
|
||||
# завршаем выполнение работы
|
||||
WriteToLog('Error! ' + msg)
|
||||
raise RuntimeError, msg
|
||||
# недокументированный ответ приложения
|
||||
else:
|
||||
pass
|
||||
@ -318,7 +328,7 @@ class Job:
|
||||
if self.proc and self.proc.poll() == None:
|
||||
WriteToLog('Try to kill')
|
||||
self.proc.kill()
|
||||
self.ChangeState()
|
||||
self.Finish(JOB_STOPPED)
|
||||
WriteToLog('Job killed')
|
||||
|
||||
def Finish(self, state, percent = None):
|
||||
|
BIN
share/model-cancel.png
Normal file
BIN
share/model-cancel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 727 B |
BIN
share/model-no-exec.png
Normal file
BIN
share/model-no-exec.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 518 B |
BIN
share/model-stop.png
Normal file
BIN
share/model-stop.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 560 B |
@ -52,7 +52,8 @@ def serie(n, d, h, l = 0):
|
||||
y = sin_taylor(l, d)
|
||||
yield (l, y)
|
||||
l += h
|
||||
# time.sleep(0.002)
|
||||
# assert 0
|
||||
time.sleep(0.002)
|
||||
|
||||
def main():
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user