pyfemtet 0.4.9__py3-none-any.whl → 0.4.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyfemtet might be problematic. Click here for more details.
- pyfemtet/__init__.py +1 -1
- pyfemtet/opt/_femopt.py +9 -3
- pyfemtet/opt/femprj_sample/wat_ex14_parametric_parallel.py +66 -0
- pyfemtet/opt/femprj_sample_jp/wat_ex14_parametric_parallel_jp.py +64 -0
- pyfemtet/opt/interface/_femtet.py +32 -10
- pyfemtet/opt/interface/_femtet_parametric.py +5 -25
- pyfemtet/opt/opt/_base.py +9 -1
- pyfemtet/opt/opt/_optuna.py +4 -0
- pyfemtet/opt/visualization/__init__.py +0 -7
- pyfemtet/opt/visualization/_create_wrapped_components.py +93 -0
- pyfemtet/opt/visualization/base.py +254 -0
- pyfemtet/opt/visualization/complex_components/__init__.py +0 -0
- pyfemtet/opt/visualization/complex_components/alert_region.py +71 -0
- pyfemtet/opt/visualization/complex_components/control_femtet.py +195 -0
- pyfemtet/opt/visualization/{_graphs.py → complex_components/main_figure_creator.py} +13 -49
- pyfemtet/opt/visualization/complex_components/main_graph.py +263 -0
- pyfemtet/opt/visualization/process_monitor/__init__.py +0 -0
- pyfemtet/opt/visualization/process_monitor/application.py +201 -0
- pyfemtet/opt/visualization/process_monitor/pages.py +276 -0
- pyfemtet/opt/visualization/result_viewer/.gitignore +1 -0
- pyfemtet/opt/visualization/result_viewer/__init__.py +0 -0
- pyfemtet/opt/visualization/result_viewer/application.py +44 -0
- pyfemtet/opt/visualization/result_viewer/pages.py +692 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/tutorial.csv +18 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.log +81 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow.csv +28 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_heatflow_el.csv +22 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial1.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial1.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial10.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial10.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial11.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial12.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial13.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial14.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial15.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial2.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial2.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial3.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial3.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial4.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial4.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial5.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial5.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial6.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial6.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial7.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial7.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial8.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial8.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial9.jpg +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.Results/Ex14_trial9.pdt +0 -0
- pyfemtet/opt/visualization/result_viewer/tutorial/wat_ex14_parametric.femprj +0 -0
- pyfemtet/opt/visualization/wrapped_components/__init__.py +0 -0
- pyfemtet/opt/visualization/wrapped_components/dbc.py +1518 -0
- pyfemtet/opt/visualization/wrapped_components/dcc.py +609 -0
- pyfemtet/opt/visualization/wrapped_components/html.py +3570 -0
- pyfemtet/opt/visualization/wrapped_components/str_enum.py +43 -0
- {pyfemtet-0.4.9.dist-info → pyfemtet-0.4.11.dist-info}/METADATA +1 -1
- pyfemtet-0.4.11.dist-info/RECORD +136 -0
- {pyfemtet-0.4.9.dist-info → pyfemtet-0.4.11.dist-info}/entry_points.txt +1 -1
- pyfemtet/opt/visualization/_monitor.py +0 -1227
- pyfemtet/opt/visualization/result_viewer.py +0 -13
- pyfemtet-0.4.9.dist-info/RECORD +0 -81
- {pyfemtet-0.4.9.dist-info → pyfemtet-0.4.11.dist-info}/LICENSE +0 -0
- {pyfemtet-0.4.9.dist-info → pyfemtet-0.4.11.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
|
|
4
|
+
from dash import Output, Input, State, callback_context, no_update, ALL
|
|
5
|
+
from dash.exceptions import PreventUpdate
|
|
6
|
+
|
|
7
|
+
from pyfemtet.opt.visualization.wrapped_components import dcc, dbc, html
|
|
8
|
+
from pyfemtet.opt.visualization.base import AbstractPage, logger
|
|
9
|
+
from pyfemtet.opt.visualization.complex_components.main_graph import MainGraph # , FLEXBOX_STYLE_ALLOW_VERTICAL_FILL
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
DBC_COLUMN_STYLE_CENTER = {
|
|
13
|
+
'display': 'flex',
|
|
14
|
+
'justify-content': 'center',
|
|
15
|
+
'align-items': 'center',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
DBC_COLUMN_STYLE_RIGHT = {
|
|
19
|
+
'display': 'flex',
|
|
20
|
+
'justify-content': 'right',
|
|
21
|
+
'align-items': 'right',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def is_iterable(component):
|
|
26
|
+
return hasattr(component, '__len__')
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class HomePage(AbstractPage):
|
|
30
|
+
|
|
31
|
+
def __init__(self, title, rel_url='/'):
|
|
32
|
+
super().__init__(title, rel_url)
|
|
33
|
+
|
|
34
|
+
def setup_component(self):
|
|
35
|
+
# main graph
|
|
36
|
+
# noinspection PyAttributeOutsideInit
|
|
37
|
+
self.main_graph: MainGraph = MainGraph()
|
|
38
|
+
self.add_subpage(self.main_graph)
|
|
39
|
+
|
|
40
|
+
# entire optimization status
|
|
41
|
+
# noinspection PyAttributeOutsideInit
|
|
42
|
+
self.entire_status_message = html.H4(
|
|
43
|
+
'Optimization status will be shown here.',
|
|
44
|
+
className='alert-heading',
|
|
45
|
+
id='optimization-entire-status-message',
|
|
46
|
+
)
|
|
47
|
+
# noinspection PyAttributeOutsideInit
|
|
48
|
+
self.entire_status = dbc.Alert(
|
|
49
|
+
children=self.entire_status_message,
|
|
50
|
+
id='optimization-entire-status',
|
|
51
|
+
color='secondary',
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# stop update button
|
|
55
|
+
# noinspection PyAttributeOutsideInit
|
|
56
|
+
self.toggle_update_graph_button = dbc.Checkbox(
|
|
57
|
+
label='Auto-update graph',
|
|
58
|
+
class_name='form-switch',
|
|
59
|
+
id='toggle-update-graph',
|
|
60
|
+
value=True,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# interrupt button
|
|
64
|
+
# noinspection PyAttributeOutsideInit
|
|
65
|
+
self.interrupt_button = dbc.Button(
|
|
66
|
+
children='Interrupt Optimization',
|
|
67
|
+
color='danger',
|
|
68
|
+
id='interrupt-optimization-button',
|
|
69
|
+
disabled=True,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# sync interval
|
|
73
|
+
# noinspection PyAttributeOutsideInit
|
|
74
|
+
self.interval = dcc.Interval(id='process-monitor-home-interval', interval=1000)
|
|
75
|
+
|
|
76
|
+
def setup_layout(self):
|
|
77
|
+
""""""
|
|
78
|
+
"""
|
|
79
|
+
=======================
|
|
80
|
+
| | ---------------- |
|
|
81
|
+
| | | | |
|
|
82
|
+
| | | Main Graph | |
|
|
83
|
+
| | | | |
|
|
84
|
+
| | ---------------- |
|
|
85
|
+
| | [stop][interrupt]<---- Buttons
|
|
86
|
+
| | ---------------- |
|
|
87
|
+
| | | Status | |
|
|
88
|
+
| ^| ---------------- |
|
|
89
|
+
==|====================
|
|
90
|
+
|
|
|
91
|
+
SideBar
|
|
92
|
+
"""
|
|
93
|
+
self.layout = dbc.Container(
|
|
94
|
+
children=[
|
|
95
|
+
self.interval,
|
|
96
|
+
self.main_graph.layout,
|
|
97
|
+
self.entire_status,
|
|
98
|
+
dbc.Row(
|
|
99
|
+
children=[
|
|
100
|
+
dbc.Col(self.toggle_update_graph_button),
|
|
101
|
+
dbc.Col(self.interrupt_button, style=DBC_COLUMN_STYLE_RIGHT),
|
|
102
|
+
],
|
|
103
|
+
),
|
|
104
|
+
]
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def setup_callback(self):
|
|
108
|
+
# setup callback of subpages
|
|
109
|
+
super().setup_callback()
|
|
110
|
+
|
|
111
|
+
from pyfemtet.opt.visualization.process_monitor.application import ProcessMonitorApplication
|
|
112
|
+
from pyfemtet.opt._femopt_core import OptimizationStatus
|
|
113
|
+
self.application: ProcessMonitorApplication = self.application
|
|
114
|
+
|
|
115
|
+
app = self.application.app
|
|
116
|
+
|
|
117
|
+
# ===== Delete Loading Animation =====
|
|
118
|
+
@app.callback(
|
|
119
|
+
Output(self.main_graph.loading.id, self.main_graph.loading.Prop.target_components),
|
|
120
|
+
Input(self.main_graph.graph.id, 'figure'),
|
|
121
|
+
prevent_initial_call=True,
|
|
122
|
+
)
|
|
123
|
+
def disable_loading_animation(_):
|
|
124
|
+
return {}
|
|
125
|
+
|
|
126
|
+
# ===== history data to graph ======
|
|
127
|
+
@app.callback(
|
|
128
|
+
Output(self.main_graph.dummy.id, 'children', allow_duplicate=True), # fire update graph callback
|
|
129
|
+
Input(self.interval.id, self.interval.Prop.n_intervals),
|
|
130
|
+
State(self.toggle_update_graph_button.id, self.toggle_update_graph_button.Prop.value),
|
|
131
|
+
State(self.main_graph.data_length.id, self.main_graph.data_length_prop), # check should update or not
|
|
132
|
+
prevent_initial_call=True,)
|
|
133
|
+
def update_graph(_, update_switch, current_graph_data_length):
|
|
134
|
+
logger.debug('====================')
|
|
135
|
+
logger.debug(f'update_graph called by {callback_context.triggered_id}')
|
|
136
|
+
|
|
137
|
+
current_graph_data_length = 0 if current_graph_data_length is None else current_graph_data_length
|
|
138
|
+
|
|
139
|
+
if callback_context.triggered_id is None:
|
|
140
|
+
raise PreventUpdate
|
|
141
|
+
|
|
142
|
+
# update_switch is unchecked, do nothing
|
|
143
|
+
if not update_switch:
|
|
144
|
+
raise PreventUpdate
|
|
145
|
+
|
|
146
|
+
# If new data does not exist, do nothing
|
|
147
|
+
if len(self.application.local_data) <= current_graph_data_length:
|
|
148
|
+
raise PreventUpdate
|
|
149
|
+
|
|
150
|
+
# fire callback
|
|
151
|
+
return ''
|
|
152
|
+
|
|
153
|
+
# ===== show optimization state =====
|
|
154
|
+
@app.callback(
|
|
155
|
+
Output(self.entire_status.id, self.entire_status.Prop.color),
|
|
156
|
+
Output(self.entire_status_message.id, 'children'),
|
|
157
|
+
Input(self.interval.id, self.interval.Prop.n_intervals),
|
|
158
|
+
prevent_initial_call=False,)
|
|
159
|
+
def update_entire_status(*_):
|
|
160
|
+
# get status message
|
|
161
|
+
status_int = self.application.local_entire_status_int
|
|
162
|
+
msg = OptimizationStatus.const_to_str(status_int)
|
|
163
|
+
color = self.application.get_status_color(status_int)
|
|
164
|
+
return color, msg
|
|
165
|
+
|
|
166
|
+
# ===== Interrupt Optimization and Control Button Disabled =====
|
|
167
|
+
@app.callback(
|
|
168
|
+
Output(self.interrupt_button.id, self.interrupt_button.Prop.disabled),
|
|
169
|
+
Input(self.interrupt_button.id, self.interrupt_button.Prop.n_clicks),
|
|
170
|
+
prevent_initial_call=False,)
|
|
171
|
+
def interrupt_optimization(*_):
|
|
172
|
+
# If page (re)loaded,
|
|
173
|
+
if callback_context.triggered_id is None:
|
|
174
|
+
# Enable only if the entire_state < INTERRUPTING
|
|
175
|
+
if self.application.local_entire_status_int < OptimizationStatus.INTERRUPTING:
|
|
176
|
+
return False
|
|
177
|
+
# Keep disable(default) if process is interrupting or terminating.
|
|
178
|
+
else:
|
|
179
|
+
raise PreventUpdate
|
|
180
|
+
|
|
181
|
+
# If the entire_state < INTERRUPTING, set INTERRUPTING
|
|
182
|
+
if self.application.local_entire_status_int < OptimizationStatus.INTERRUPTING:
|
|
183
|
+
self.application.local_entire_status_int = OptimizationStatus.INTERRUPTING
|
|
184
|
+
return True
|
|
185
|
+
|
|
186
|
+
# keep disabled
|
|
187
|
+
raise PreventUpdate
|
|
188
|
+
|
|
189
|
+
# ===== TEST CODE =====
|
|
190
|
+
if self.application.is_debug:
|
|
191
|
+
|
|
192
|
+
# increment status
|
|
193
|
+
self.layout.children.append(dbc.Button(children='local_status を進める', id='debug-button-1'))
|
|
194
|
+
|
|
195
|
+
@app.callback(Output(self.interval.id, self.interval.Prop.interval),
|
|
196
|
+
Input('debug-button-1', 'n_clicks'),
|
|
197
|
+
prevent_initial_call=True)
|
|
198
|
+
def status_change(*_):
|
|
199
|
+
self.application.local_entire_status_int += 10
|
|
200
|
+
for i in range(len(self.application.local_worker_status_int_list)):
|
|
201
|
+
self.application.local_worker_status_int_list[i] += 10
|
|
202
|
+
raise PreventUpdate
|
|
203
|
+
|
|
204
|
+
# increment data
|
|
205
|
+
self.layout.children.append(dbc.Button(children='local_data を増やす', id='debug-button-2'))
|
|
206
|
+
|
|
207
|
+
@app.callback(Output(self.interval.id, self.interval.Prop.interval, allow_duplicate=True),
|
|
208
|
+
Input('debug-button-2', 'n_clicks'),
|
|
209
|
+
prevent_initial_call=True)
|
|
210
|
+
def add_data(*_):
|
|
211
|
+
metadata = self.application.history.metadata
|
|
212
|
+
df = self.application.local_data
|
|
213
|
+
|
|
214
|
+
new_row = df.iloc[-2:]
|
|
215
|
+
obj_index = np.where(np.array(metadata) == 'obj')[0]
|
|
216
|
+
for idx in obj_index:
|
|
217
|
+
new_row.iloc[:, idx] = np.random.rand(len(new_row))
|
|
218
|
+
|
|
219
|
+
df = pd.concat([df, new_row])
|
|
220
|
+
df.trial = np.array(range(len(df)))
|
|
221
|
+
logger.debug(df)
|
|
222
|
+
|
|
223
|
+
self.application.local_data = df
|
|
224
|
+
|
|
225
|
+
raise PreventUpdate
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class WorkerPage(AbstractPage):
|
|
229
|
+
|
|
230
|
+
def __init__(self, title, rel_url, application):
|
|
231
|
+
from pyfemtet.opt.visualization.process_monitor.application import ProcessMonitorApplication
|
|
232
|
+
self.application: ProcessMonitorApplication = None
|
|
233
|
+
super().__init__(title, rel_url, application)
|
|
234
|
+
|
|
235
|
+
def setup_component(self):
|
|
236
|
+
# noinspection PyAttributeOutsideInit
|
|
237
|
+
self.interval = dcc.Interval(id='worker-page-interval', interval=1000)
|
|
238
|
+
|
|
239
|
+
# noinspection PyAttributeOutsideInit
|
|
240
|
+
self.worker_status_alerts = []
|
|
241
|
+
for i in range(len(self.application.worker_addresses)):
|
|
242
|
+
id_worker_alert = f'worker-status-alert-{i}'
|
|
243
|
+
alert = dbc.Alert('worker status here', id=id_worker_alert, color='dark')
|
|
244
|
+
self.worker_status_alerts.append(alert)
|
|
245
|
+
|
|
246
|
+
def setup_layout(self):
|
|
247
|
+
rows = [self.interval]
|
|
248
|
+
rows.extend([dbc.Row([dbc.Col(html.Div(dcc.Loading(alert, id={"type": "loading", "index": i})))]) for i, alert in enumerate(self.worker_status_alerts)])
|
|
249
|
+
|
|
250
|
+
self.layout = dbc.Container(
|
|
251
|
+
children=rows,
|
|
252
|
+
fluid=True,
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
def setup_callback(self):
|
|
256
|
+
app = self.application.app
|
|
257
|
+
|
|
258
|
+
@app.callback(
|
|
259
|
+
[Output(alert.id, 'children') for alert in self.worker_status_alerts],
|
|
260
|
+
[Output(alert.id, 'color') for alert in self.worker_status_alerts],
|
|
261
|
+
Output({"type": "loading", "index": ALL}, "target_components"),
|
|
262
|
+
Input(self.interval.id, 'n_intervals'),
|
|
263
|
+
)
|
|
264
|
+
def update_worker_state(_):
|
|
265
|
+
from pyfemtet.opt._femopt_core import OptimizationStatus
|
|
266
|
+
|
|
267
|
+
ret = []
|
|
268
|
+
|
|
269
|
+
for worker_address, worker_status_int in zip(self.application.worker_addresses, self.application.local_worker_status_int_list):
|
|
270
|
+
worker_status_message = OptimizationStatus.const_to_str(worker_status_int)
|
|
271
|
+
ret.append(f'{worker_address} is {worker_status_message}')
|
|
272
|
+
|
|
273
|
+
ret.extend([self.application.get_status_color(status_int) for status_int in self.application.local_worker_status_int_list])
|
|
274
|
+
ret.append([({} if callback_context.triggered_id is None else no_update) for _ in range(len(self.worker_status_alerts))])
|
|
275
|
+
|
|
276
|
+
return tuple(ret)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sample
|
|
File without changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from pyfemtet.opt.visualization.base import PyFemtetApplicationBase
|
|
2
|
+
from pyfemtet.opt.visualization.result_viewer.pages import HomePage
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ResultViewerApplication(PyFemtetApplicationBase):
|
|
6
|
+
|
|
7
|
+
def __init__(self):
|
|
8
|
+
super().__init__(
|
|
9
|
+
title='PyFemtet ResultView',
|
|
10
|
+
subtitle='visualize optimization result',
|
|
11
|
+
history=None,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
def setup_callback(self):
|
|
15
|
+
super().setup_callback()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def debug():
|
|
19
|
+
import os
|
|
20
|
+
os.chdir(os.path.dirname(__file__))
|
|
21
|
+
|
|
22
|
+
g_application = ResultViewerApplication()
|
|
23
|
+
|
|
24
|
+
g_home_page = HomePage('result')
|
|
25
|
+
|
|
26
|
+
g_application.add_page(g_home_page, 0)
|
|
27
|
+
g_application.setup_callback()
|
|
28
|
+
|
|
29
|
+
g_application.run(debug=True)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def main():
|
|
33
|
+
g_application = ResultViewerApplication()
|
|
34
|
+
|
|
35
|
+
g_home_page = HomePage('result')
|
|
36
|
+
|
|
37
|
+
g_application.add_page(g_home_page, 0)
|
|
38
|
+
g_application.setup_callback()
|
|
39
|
+
|
|
40
|
+
g_application.run()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == '__main__':
|
|
44
|
+
debug()
|