ivoryos 1.0.9__py3-none-any.whl → 1.2.0__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 ivoryos might be problematic. Click here for more details.
- ivoryos/__init__.py +26 -7
- ivoryos/routes/api/api.py +56 -0
- ivoryos/routes/auth/auth.py +5 -5
- ivoryos/routes/control/control.py +77 -372
- ivoryos/routes/control/control_file.py +36 -0
- ivoryos/routes/control/control_new_device.py +142 -0
- ivoryos/routes/control/templates/controllers.html +166 -0
- ivoryos/routes/control/templates/controllers_new.html +112 -0
- ivoryos/routes/control/utils.py +38 -0
- ivoryos/routes/data/data.py +129 -0
- ivoryos/routes/data/templates/components/step_card.html +13 -0
- ivoryos/routes/{database/templates/database → data/templates}/workflow_database.html +14 -8
- ivoryos/routes/{database/templates/database → data/templates}/workflow_view.html +3 -3
- ivoryos/routes/design/__init__.py +4 -0
- ivoryos/routes/design/design.py +298 -656
- ivoryos/routes/design/design_file.py +68 -0
- ivoryos/routes/design/design_step.py +145 -0
- ivoryos/routes/design/templates/components/action_form.html +53 -0
- ivoryos/routes/design/templates/components/actions_panel.html +25 -0
- ivoryos/routes/design/templates/components/autofill_toggle.html +10 -0
- ivoryos/routes/design/templates/components/canvas.html +5 -0
- ivoryos/routes/design/templates/components/canvas_footer.html +9 -0
- ivoryos/routes/design/templates/components/canvas_header.html +75 -0
- ivoryos/routes/design/templates/components/canvas_main.html +34 -0
- ivoryos/routes/design/templates/components/deck_selector.html +10 -0
- ivoryos/routes/design/templates/components/edit_action_form.html +38 -0
- ivoryos/routes/design/templates/components/instruments_panel.html +66 -0
- ivoryos/routes/design/templates/components/modals/drop_modal.html +17 -0
- ivoryos/routes/design/templates/components/modals/json_modal.html +22 -0
- ivoryos/routes/design/templates/components/modals/new_script_modal.html +17 -0
- ivoryos/routes/design/templates/components/modals/rename_modal.html +23 -0
- ivoryos/routes/design/templates/components/modals/saveas_modal.html +27 -0
- ivoryos/routes/design/templates/components/modals.html +6 -0
- ivoryos/routes/design/templates/components/python_code_overlay.html +39 -0
- ivoryos/routes/design/templates/components/sidebar.html +15 -0
- ivoryos/routes/design/templates/components/text_to_code_panel.html +20 -0
- ivoryos/routes/design/templates/experiment_builder.html +41 -0
- ivoryos/routes/execute/__init__.py +0 -0
- ivoryos/routes/execute/execute.py +317 -0
- ivoryos/routes/execute/execute_file.py +78 -0
- ivoryos/routes/execute/templates/components/error_modal.html +20 -0
- ivoryos/routes/execute/templates/components/logging_panel.html +31 -0
- ivoryos/routes/execute/templates/components/progress_panel.html +27 -0
- ivoryos/routes/execute/templates/components/run_panel.html +9 -0
- ivoryos/routes/execute/templates/components/run_tabs.html +17 -0
- ivoryos/routes/execute/templates/components/tab_bayesian.html +398 -0
- ivoryos/routes/execute/templates/components/tab_configuration.html +98 -0
- ivoryos/routes/execute/templates/components/tab_repeat.html +14 -0
- ivoryos/routes/execute/templates/experiment_run.html +294 -0
- ivoryos/routes/library/__init__.py +0 -0
- ivoryos/routes/library/library.py +159 -0
- ivoryos/routes/{database/templates/database/scripts_database.html → library/templates/library.html} +30 -22
- ivoryos/routes/main/main.py +1 -1
- ivoryos/routes/main/templates/{main/home.html → home.html} +4 -4
- ivoryos/socket_handlers.py +52 -0
- ivoryos/static/js/action_handlers.js +213 -0
- ivoryos/static/js/db_delete.js +23 -0
- ivoryos/static/js/script_metadata.js +39 -0
- ivoryos/static/js/sortable_design.js +89 -56
- ivoryos/static/js/ui_state.js +113 -0
- ivoryos/templates/base.html +4 -4
- ivoryos/utils/bo_campaign.py +179 -3
- ivoryos/utils/db_models.py +14 -5
- ivoryos/utils/form.py +5 -9
- ivoryos/utils/global_config.py +13 -1
- ivoryos/utils/py_to_json.py +225 -0
- ivoryos/utils/script_runner.py +49 -7
- ivoryos/utils/serilize.py +203 -0
- ivoryos/utils/task_runner.py +4 -1
- ivoryos/version.py +1 -1
- {ivoryos-1.0.9.dist-info → ivoryos-1.2.0.dist-info}/METADATA +5 -8
- ivoryos-1.2.0.dist-info/RECORD +105 -0
- ivoryos/routes/control/templates/control/controllers.html +0 -78
- ivoryos/routes/control/templates/control/controllers_home.html +0 -55
- ivoryos/routes/control/templates/control/controllers_new.html +0 -89
- ivoryos/routes/database/database.py +0 -306
- ivoryos/routes/database/templates/database/step_card.html +0 -7
- ivoryos/routes/design/templates/design/experiment_builder.html +0 -521
- ivoryos/routes/design/templates/design/experiment_run.html +0 -558
- ivoryos-1.0.9.dist-info/RECORD +0 -61
- /ivoryos/routes/auth/templates/{auth/login.html → login.html} +0 -0
- /ivoryos/routes/auth/templates/{auth/signup.html → signup.html} +0 -0
- /ivoryos/routes/{database → data}/__init__.py +0 -0
- /ivoryos/routes/main/templates/{main/help.html → help.html} +0 -0
- {ivoryos-1.0.9.dist-info → ivoryos-1.2.0.dist-info}/LICENSE +0 -0
- {ivoryos-1.0.9.dist-info → ivoryos-1.2.0.dist-info}/WHEEL +0 -0
- {ivoryos-1.0.9.dist-info → ivoryos-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
from flask import Blueprint, redirect, url_for, flash, request, render_template, session, current_app, jsonify
|
|
2
|
-
from flask_login import login_required
|
|
3
|
-
|
|
4
|
-
from ivoryos.utils.db_models import Script, db, WorkflowRun, WorkflowStep
|
|
5
|
-
from ivoryos.utils.utils import get_script_file, post_script_file
|
|
6
|
-
|
|
7
|
-
database = Blueprint('database', __name__, template_folder='templates/database')
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@database.route("/database/scripts/edit/<script_name>")
|
|
12
|
-
@login_required
|
|
13
|
-
def edit_workflow(script_name:str):
|
|
14
|
-
"""
|
|
15
|
-
.. :quickref: Database; load workflow script to canvas
|
|
16
|
-
|
|
17
|
-
load the selected workflow to the design canvas
|
|
18
|
-
|
|
19
|
-
.. http:get:: /database/scripts/edit/<script_name>
|
|
20
|
-
|
|
21
|
-
:param script_name: script name
|
|
22
|
-
:type script_name: str
|
|
23
|
-
:status 302: redirect to :http:get:`/ivoryos/design/script/`
|
|
24
|
-
"""
|
|
25
|
-
row = Script.query.get(script_name)
|
|
26
|
-
script = Script(**row.as_dict())
|
|
27
|
-
post_script_file(script)
|
|
28
|
-
pseudo_name = session.get("pseudo_deck", "")
|
|
29
|
-
off_line = current_app.config["OFF_LINE"]
|
|
30
|
-
if off_line and pseudo_name and not script.deck == pseudo_name:
|
|
31
|
-
flash(f"Choose the deck with name {script.deck}")
|
|
32
|
-
if request.accept_mimetypes.best_match(['application/json', 'text/html']) == 'application/json':
|
|
33
|
-
return jsonify({
|
|
34
|
-
"script": script.as_dict(),
|
|
35
|
-
"python_script": script.compile(),
|
|
36
|
-
})
|
|
37
|
-
return redirect(url_for('design.experiment_builder'))
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@database.route("/database/scripts/delete/<script_name>")
|
|
41
|
-
@login_required
|
|
42
|
-
def delete_workflow(script_name: str):
|
|
43
|
-
"""
|
|
44
|
-
.. :quickref: Database; delete workflow
|
|
45
|
-
|
|
46
|
-
delete workflow from database
|
|
47
|
-
|
|
48
|
-
.. http:get:: /database/scripts/delete/<script_name>
|
|
49
|
-
|
|
50
|
-
:param script_name: workflow name
|
|
51
|
-
:type script_name: str
|
|
52
|
-
:status 302: redirect to :http:get:`/ivoryos/database/scripts/`
|
|
53
|
-
|
|
54
|
-
"""
|
|
55
|
-
Script.query.filter(Script.name == script_name).delete()
|
|
56
|
-
db.session.commit()
|
|
57
|
-
return redirect(url_for('database.load_from_database'))
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@database.route("/database/scripts/save")
|
|
61
|
-
@login_required
|
|
62
|
-
def publish():
|
|
63
|
-
"""
|
|
64
|
-
.. :quickref: Database; save workflow to database
|
|
65
|
-
|
|
66
|
-
save workflow to database
|
|
67
|
-
|
|
68
|
-
.. http:get:: /database/scripts/save
|
|
69
|
-
|
|
70
|
-
:status 302: redirect to :http:get:`/ivoryos/experiment/build/`
|
|
71
|
-
"""
|
|
72
|
-
script = get_script_file()
|
|
73
|
-
if not script.name or not script.deck:
|
|
74
|
-
flash("Deck cannot be empty, try to re-submit deck configuration on the left panel")
|
|
75
|
-
row = Script.query.get(script.name)
|
|
76
|
-
if row and row.status == "finalized":
|
|
77
|
-
flash("This is a protected script, use save as to rename.")
|
|
78
|
-
elif row and not session['user'] == row.author:
|
|
79
|
-
flash("You are not the author, use save as to rename.")
|
|
80
|
-
else:
|
|
81
|
-
db.session.merge(script)
|
|
82
|
-
db.session.commit()
|
|
83
|
-
flash("Saved!")
|
|
84
|
-
return redirect(url_for('design.experiment_builder'))
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
@database.route("/database/scripts/finalize")
|
|
88
|
-
@login_required
|
|
89
|
-
def finalize():
|
|
90
|
-
"""
|
|
91
|
-
.. :quickref: Database; finalize the workflow
|
|
92
|
-
|
|
93
|
-
[protected workflow] prevent saving edited workflow to the same workflow name
|
|
94
|
-
|
|
95
|
-
.. http:get:: /finalize
|
|
96
|
-
|
|
97
|
-
:status 302: redirect to :http:get:`/ivoryos/experiment/build/`
|
|
98
|
-
|
|
99
|
-
"""
|
|
100
|
-
script = get_script_file()
|
|
101
|
-
script.finalize()
|
|
102
|
-
if script.name:
|
|
103
|
-
db.session.merge(script)
|
|
104
|
-
db.session.commit()
|
|
105
|
-
post_script_file(script)
|
|
106
|
-
return redirect(url_for('design.experiment_builder'))
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@database.route("/database/scripts/", strict_slashes=False)
|
|
110
|
-
@database.route("/database/scripts/<deck_name>")
|
|
111
|
-
@login_required
|
|
112
|
-
def load_from_database(deck_name=None):
|
|
113
|
-
"""
|
|
114
|
-
.. :quickref: Database; database page
|
|
115
|
-
|
|
116
|
-
backend control through http requests
|
|
117
|
-
|
|
118
|
-
.. http:get:: /database/scripts/<deck_name>
|
|
119
|
-
|
|
120
|
-
:param deck_name: filter for deck name
|
|
121
|
-
:type deck_name: str
|
|
122
|
-
|
|
123
|
-
"""
|
|
124
|
-
session.pop('edit_action', None) # reset cache
|
|
125
|
-
query = Script.query
|
|
126
|
-
search_term = request.args.get("keyword", None)
|
|
127
|
-
if search_term:
|
|
128
|
-
query = query.filter(Script.name.like(f'%{search_term}%'))
|
|
129
|
-
if deck_name is None:
|
|
130
|
-
temp = Script.query.with_entities(Script.deck).distinct().all()
|
|
131
|
-
deck_list = [i[0] for i in temp]
|
|
132
|
-
else:
|
|
133
|
-
query = query.filter(Script.deck == deck_name)
|
|
134
|
-
deck_list = ["ALL"]
|
|
135
|
-
page = request.args.get('page', default=1, type=int)
|
|
136
|
-
per_page = 10
|
|
137
|
-
|
|
138
|
-
scripts = query.paginate(page=page, per_page=per_page, error_out=False)
|
|
139
|
-
if request.accept_mimetypes.best_match(['application/json', 'text/html']) == 'application/json':
|
|
140
|
-
scripts = query.all()
|
|
141
|
-
script_names = [script.name for script in scripts]
|
|
142
|
-
return jsonify({
|
|
143
|
-
"workflows": script_names,
|
|
144
|
-
})
|
|
145
|
-
else:
|
|
146
|
-
# return HTML
|
|
147
|
-
return render_template("scripts_database.html", scripts=scripts, deck_list=deck_list, deck_name=deck_name)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
@database.route("/database/scripts/rename", methods=['POST'])
|
|
151
|
-
@login_required
|
|
152
|
-
def edit_run_name():
|
|
153
|
-
"""
|
|
154
|
-
.. :quickref: Database; edit workflow name
|
|
155
|
-
|
|
156
|
-
edit the name of the current workflow, won't save to the database
|
|
157
|
-
|
|
158
|
-
.. http:post:: database/scripts/rename
|
|
159
|
-
|
|
160
|
-
: form run_name: new workflow name
|
|
161
|
-
:status 302: redirect to :http:get:`/ivoryos/experiment/build/`
|
|
162
|
-
|
|
163
|
-
"""
|
|
164
|
-
if request.method == "POST":
|
|
165
|
-
run_name = request.form.get("run_name")
|
|
166
|
-
exist_script = Script.query.get(run_name)
|
|
167
|
-
if not exist_script:
|
|
168
|
-
script = get_script_file()
|
|
169
|
-
script.save_as(run_name)
|
|
170
|
-
post_script_file(script)
|
|
171
|
-
else:
|
|
172
|
-
flash("Script name is already exist in database")
|
|
173
|
-
return redirect(url_for("design.experiment_builder"))
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
@database.route("/database/scripts/save_as", methods=['POST'])
|
|
177
|
-
@login_required
|
|
178
|
-
def save_as():
|
|
179
|
-
"""
|
|
180
|
-
.. :quickref: Database; save the run name as
|
|
181
|
-
|
|
182
|
-
save the current workflow script as
|
|
183
|
-
|
|
184
|
-
.. http:post:: /database/scripts/save_as
|
|
185
|
-
|
|
186
|
-
: form run_name: new workflow name
|
|
187
|
-
:status 302: redirect to :http:get:`/ivoryos/experiment/build/`
|
|
188
|
-
|
|
189
|
-
"""
|
|
190
|
-
if request.method == "POST":
|
|
191
|
-
run_name = request.form.get("run_name")
|
|
192
|
-
register_workflow = request.form.get("register_workflow")
|
|
193
|
-
exist_script = Script.query.get(run_name)
|
|
194
|
-
if not exist_script:
|
|
195
|
-
script = get_script_file()
|
|
196
|
-
script.save_as(run_name)
|
|
197
|
-
script.registered = register_workflow == "on"
|
|
198
|
-
script.author = session.get('user')
|
|
199
|
-
post_script_file(script)
|
|
200
|
-
publish()
|
|
201
|
-
else:
|
|
202
|
-
flash("Script name is already exist in database")
|
|
203
|
-
return redirect(url_for("design.experiment_builder"))
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
# -----------------------------------------------------------
|
|
207
|
-
# ------------------ Workflow logs -----------------------
|
|
208
|
-
# -----------------------------------------------------------
|
|
209
|
-
@database.route('/database/workflows/')
|
|
210
|
-
def list_workflows():
|
|
211
|
-
"""
|
|
212
|
-
.. :quickref: Database; list all workflow logs
|
|
213
|
-
|
|
214
|
-
list all workflow logs
|
|
215
|
-
|
|
216
|
-
.. http:get:: /database/workflows/
|
|
217
|
-
|
|
218
|
-
"""
|
|
219
|
-
query = WorkflowRun.query.order_by(WorkflowRun.id.desc())
|
|
220
|
-
search_term = request.args.get("keyword", None)
|
|
221
|
-
if search_term:
|
|
222
|
-
query = query.filter(WorkflowRun.name.like(f'%{search_term}%'))
|
|
223
|
-
page = request.args.get('page', default=1, type=int)
|
|
224
|
-
per_page = 10
|
|
225
|
-
|
|
226
|
-
workflows = query.paginate(page=page, per_page=per_page, error_out=False)
|
|
227
|
-
if request.accept_mimetypes.best_match(['application/json', 'text/html']) == 'application/json':
|
|
228
|
-
workflows = query.all()
|
|
229
|
-
workflow_data = {w.id:{"workflow_name":w.name, "start_time":w.start_time} for w in workflows}
|
|
230
|
-
return jsonify({
|
|
231
|
-
"workflow_data": workflow_data,
|
|
232
|
-
})
|
|
233
|
-
else:
|
|
234
|
-
return render_template('workflow_database.html', workflows=workflows)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
@database.route("/database/workflows/<int:workflow_id>")
|
|
238
|
-
def get_workflow_steps(workflow_id:int):
|
|
239
|
-
"""
|
|
240
|
-
.. :quickref: Database; list all workflow logs
|
|
241
|
-
|
|
242
|
-
list all workflow logs
|
|
243
|
-
|
|
244
|
-
.. http:get:: /database/workflows/<int:workflow_id>
|
|
245
|
-
|
|
246
|
-
"""
|
|
247
|
-
workflow = db.session.get(WorkflowRun, workflow_id)
|
|
248
|
-
steps = WorkflowStep.query.filter_by(workflow_id=workflow_id).order_by(WorkflowStep.start_time).all()
|
|
249
|
-
|
|
250
|
-
# Use full objects for template rendering
|
|
251
|
-
grouped = {
|
|
252
|
-
"prep": [],
|
|
253
|
-
"script": {},
|
|
254
|
-
"cleanup": [],
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
# Use dicts for JSON response
|
|
258
|
-
grouped_json = {
|
|
259
|
-
"prep": [],
|
|
260
|
-
"script": {},
|
|
261
|
-
"cleanup": [],
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
for step in steps:
|
|
265
|
-
step_dict = step.as_dict()
|
|
266
|
-
|
|
267
|
-
if step.phase == "prep":
|
|
268
|
-
grouped["prep"].append(step)
|
|
269
|
-
grouped_json["prep"].append(step_dict)
|
|
270
|
-
|
|
271
|
-
elif step.phase == "script":
|
|
272
|
-
grouped["script"].setdefault(step.repeat_index, []).append(step)
|
|
273
|
-
grouped_json["script"].setdefault(step.repeat_index, []).append(step_dict)
|
|
274
|
-
|
|
275
|
-
elif step.phase == "cleanup" or step.method_name == "stop":
|
|
276
|
-
grouped["cleanup"].append(step)
|
|
277
|
-
grouped_json["cleanup"].append(step_dict)
|
|
278
|
-
|
|
279
|
-
if request.accept_mimetypes.best_match(['application/json', 'text/html']) == 'application/json':
|
|
280
|
-
return jsonify({
|
|
281
|
-
"workflow_info": workflow.as_dict(),
|
|
282
|
-
"steps": grouped_json,
|
|
283
|
-
})
|
|
284
|
-
else:
|
|
285
|
-
return render_template("workflow_view.html", workflow=workflow, grouped=grouped)
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
@database.route("/database/workflows/delete/<int:workflow_id>")
|
|
289
|
-
@login_required
|
|
290
|
-
def delete_workflow_data(workflow_id: int):
|
|
291
|
-
"""
|
|
292
|
-
.. :quickref: Database; delete experiment data from database
|
|
293
|
-
|
|
294
|
-
delete workflow data from database
|
|
295
|
-
|
|
296
|
-
.. http:get:: /database/workflows/delete/<int:workflow_id>
|
|
297
|
-
|
|
298
|
-
:param workflow_id: workflow id
|
|
299
|
-
:type workflow_id: int
|
|
300
|
-
:status 302: redirect to :http:get:`/ivoryos/database/workflows/`
|
|
301
|
-
|
|
302
|
-
"""
|
|
303
|
-
run = WorkflowRun.query.get(workflow_id)
|
|
304
|
-
db.session.delete(run)
|
|
305
|
-
db.session.commit()
|
|
306
|
-
return redirect(url_for('database.list_workflows'))
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
<div class="card mb-2 {{ 'border-danger text-danger bg-light' if step.run_error else 'border-secondary' }}">
|
|
2
|
-
<div class="card-body p-2">
|
|
3
|
-
<strong>{{ step.method_name }}</strong>
|
|
4
|
-
<small>Start: {{ step.start_time }}</small>
|
|
5
|
-
<small>End: {{ step.end_time }}</small>
|
|
6
|
-
</div>
|
|
7
|
-
</div>
|