ivoryos 1.3.4__tar.gz → 1.3.5__tar.gz
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-1.3.4 → ivoryos-1.3.5}/PKG-INFO +11 -1
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/__init__.py +6 -2
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/control/control.py +2 -2
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/design.py +9 -3
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/design_step.py +31 -10
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/canvas_main.html +6 -1
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/js/action_handlers.js +20 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/db_models.py +23 -11
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/py_to_json.py +19 -4
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/script_runner.py +23 -2
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/task_runner.py +28 -17
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/utils.py +2 -1
- ivoryos-1.3.5/ivoryos/version.py +1 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos.egg-info/PKG-INFO +11 -1
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos.egg-info/requires.txt +14 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/pyproject.toml +12 -1
- ivoryos-1.3.4/ivoryos/version.py +0 -1
- {ivoryos-1.3.4 → ivoryos-1.3.5}/LICENSE +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/README.md +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/app.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/config.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/optimizer/ax_optimizer.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/optimizer/base_optimizer.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/optimizer/baybe_optimizer.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/optimizer/registry.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/__init__.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/api/api.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/auth/__init__.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/auth/auth.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/auth/templates/login.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/auth/templates/signup.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/control/__init__.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/control/control_file.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/control/control_new_device.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/control/templates/controllers.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/control/templates/controllers_new.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/control/utils.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/data/__init__.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/data/data.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/data/templates/components/step_card.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/data/templates/workflow_database.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/data/templates/workflow_view.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/__init__.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/design_file.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/action_form.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/actions_panel.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/autofill_toggle.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/canvas.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/canvas_footer.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/canvas_header.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/deck_selector.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/edit_action_form.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/instruments_panel.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/modals/drop_modal.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/modals/json_modal.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/modals/new_script_modal.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/modals/rename_modal.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/modals/saveas_modal.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/modals.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/python_code_overlay.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/sidebar.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/text_to_code_panel.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/experiment_builder.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/__init__.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/execute.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/execute_file.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/error_modal.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/logging_panel.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/progress_panel.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/run_panel.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/run_tabs.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/tab_bayesian.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/tab_configuration.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/tab_repeat.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/experiment_run.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/library/__init__.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/library/library.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/library/templates/library.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/main/__init__.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/main/main.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/main/templates/help.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/main/templates/home.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/server.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/socket_handlers.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/favicon.ico +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/gui_annotation/Slide1.png +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/gui_annotation/Slide2.PNG +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/js/db_delete.js +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/js/overlay.js +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/js/script_metadata.js +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/js/socket_handler.js +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/js/sortable_card.js +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/js/sortable_design.js +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/js/ui_state.js +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/logo.webp +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/static/style.css +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/templates/base.html +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/__init__.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/bo_campaign.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/client_proxy.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/decorators.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/form.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/global_config.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/llm_agent.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/utils/serilize.py +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos.egg-info/SOURCES.txt +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos.egg-info/dependency_links.txt +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos.egg-info/top_level.txt +0 -0
- {ivoryos-1.3.4 → ivoryos-1.3.5}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ivoryos
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.5
|
|
4
4
|
Summary: an open-source Python package enabling Self-Driving Labs (SDLs) interoperability
|
|
5
5
|
Author-email: Ivory Zhang <ivoryzhang@chem.ubc.ca>
|
|
6
6
|
License: MIT
|
|
@@ -17,9 +17,19 @@ Requires-Dist: Flask-WTF
|
|
|
17
17
|
Requires-Dist: SQLAlchemy-Utils
|
|
18
18
|
Requires-Dist: python-dotenv
|
|
19
19
|
Requires-Dist: astor; python_version < "3.9"
|
|
20
|
+
Provides-Extra: optimizer-ax
|
|
21
|
+
Requires-Dist: ax-platform; extra == "optimizer-ax"
|
|
22
|
+
Provides-Extra: optimizer-baybe
|
|
23
|
+
Requires-Dist: baybe; extra == "optimizer-baybe"
|
|
20
24
|
Provides-Extra: optimizer
|
|
21
25
|
Requires-Dist: ax-platform; extra == "optimizer"
|
|
22
26
|
Requires-Dist: baybe; extra == "optimizer"
|
|
27
|
+
Provides-Extra: doc
|
|
28
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
29
|
+
Requires-Dist: sphinx-rtd-theme; extra == "doc"
|
|
30
|
+
Requires-Dist: sphinxcontrib-httpdomain; extra == "doc"
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest; extra == "dev"
|
|
23
33
|
Dynamic: license-file
|
|
24
34
|
|
|
25
35
|
[](https://ivoryos.readthedocs.io/en/latest/?badge=latest)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from ivoryos.server import run
|
|
1
|
+
from ivoryos.server import run, global_config
|
|
2
2
|
from ivoryos.optimizer.registry import OPTIMIZER_REGISTRY
|
|
3
3
|
from ivoryos.version import __version__ as ivoryos_version
|
|
4
4
|
from ivoryos.utils.decorators import block, BUILDING_BLOCKS
|
|
5
|
-
from ivoryos.app import app
|
|
5
|
+
from ivoryos.app import app, create_app, socketio, db
|
|
6
6
|
|
|
7
7
|
__all__ = [
|
|
8
8
|
"block",
|
|
@@ -11,4 +11,8 @@ __all__ = [
|
|
|
11
11
|
"run",
|
|
12
12
|
"app",
|
|
13
13
|
"ivoryos_version",
|
|
14
|
+
"create_app",
|
|
15
|
+
"socketio",
|
|
16
|
+
"global_config",
|
|
17
|
+
"db"
|
|
14
18
|
]
|
|
@@ -23,7 +23,7 @@ control.register_blueprint(control_temp)
|
|
|
23
23
|
@control.route("/", strict_slashes=False, methods=["GET", "POST"])
|
|
24
24
|
@control.route("/<string:instrument>", strict_slashes=False, methods=["GET", "POST"])
|
|
25
25
|
@login_required
|
|
26
|
-
def deck_controllers(instrument: str = None):
|
|
26
|
+
async def deck_controllers(instrument: str = None):
|
|
27
27
|
"""
|
|
28
28
|
.. :quickref: Direct Control; device (instruments) and methods
|
|
29
29
|
|
|
@@ -82,7 +82,7 @@ def deck_controllers(instrument: str = None):
|
|
|
82
82
|
|
|
83
83
|
wait = str(payload.get("hidden_wait", "true")).lower() == "true"
|
|
84
84
|
|
|
85
|
-
output = runner.run_single_step(
|
|
85
|
+
output = await runner.run_single_step(
|
|
86
86
|
component=instrument, method=method_name, kwargs=kwargs, wait=wait,
|
|
87
87
|
current_app=current_app._get_current_object()
|
|
88
88
|
)
|
|
@@ -87,8 +87,11 @@ def experiment_builder():
|
|
|
87
87
|
|
|
88
88
|
# edit_action_info = session.get("edit_action")
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
try:
|
|
91
|
+
exec_string = script.python_script if script.python_script else script.compile(current_app.config['SCRIPT_FOLDER'])
|
|
92
|
+
except Exception as e:
|
|
93
|
+
exec_string = {}
|
|
94
|
+
flash(f"Error in Python script: {e}")
|
|
92
95
|
session['python_code'] = exec_string
|
|
93
96
|
|
|
94
97
|
design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
|
|
@@ -316,6 +319,7 @@ def methods_handler(instrument: str = ''):
|
|
|
316
319
|
msg = ""
|
|
317
320
|
request.form
|
|
318
321
|
if "hidden_name" in request.form:
|
|
322
|
+
deck_snapshot = global_config.deck_snapshot
|
|
319
323
|
method_name = request.form.get("hidden_name", None)
|
|
320
324
|
form = forms.get(method_name) if forms else None
|
|
321
325
|
insert_position = request.form.get("drop_target_id", None)
|
|
@@ -334,7 +338,9 @@ def methods_handler(instrument: str = ''):
|
|
|
334
338
|
action = {"instrument": instrument, "action": function_name,
|
|
335
339
|
"args": kwargs,
|
|
336
340
|
"return": save_data,
|
|
337
|
-
'arg_types': primitive_arg_types
|
|
341
|
+
'arg_types': primitive_arg_types,
|
|
342
|
+
"coroutine": deck_snapshot[instrument][function_name].get("coroutine", False) if deck_snapshot else False,
|
|
343
|
+
}
|
|
338
344
|
script.add_action(action=action, insert_position=insert_position)
|
|
339
345
|
else:
|
|
340
346
|
msg = [f"{field}: {', '.join(messages)}" for field, messages in form.errors.items()]
|
|
@@ -47,6 +47,7 @@ def save_step(uuid: int):
|
|
|
47
47
|
"""
|
|
48
48
|
script = utils.get_script_file()
|
|
49
49
|
action = script.find_by_uuid(uuid)
|
|
50
|
+
warning = None
|
|
50
51
|
if action is not None:
|
|
51
52
|
forms = create_form_from_action(action, script=script)
|
|
52
53
|
kwargs = {field.name: field.data for field in forms if field.name != 'csrf_token'}
|
|
@@ -55,14 +56,19 @@ def save_step(uuid: int):
|
|
|
55
56
|
kwargs = script.validate_variables(kwargs)
|
|
56
57
|
script.update_by_uuid(uuid=uuid, args=kwargs, output=save_as)
|
|
57
58
|
else:
|
|
58
|
-
|
|
59
|
+
warning = f"Compilation failed: {str(forms.errors)}"
|
|
59
60
|
utils.post_script_file(script)
|
|
60
|
-
|
|
61
|
+
try:
|
|
62
|
+
exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
|
|
63
|
+
except Exception as e:
|
|
64
|
+
exec_string = {}
|
|
65
|
+
warning = f"Compilation failed: {str(e)}"
|
|
61
66
|
session['python_code'] = exec_string
|
|
62
67
|
design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
|
|
63
68
|
return render_template("components/canvas_main.html",
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
script=script,
|
|
70
|
+
buttons_dict=design_buttons,
|
|
71
|
+
warning=warning)
|
|
66
72
|
|
|
67
73
|
@steps.delete("/draft/steps/<int:uuid>")
|
|
68
74
|
def delete_step(uuid: int):
|
|
@@ -82,12 +88,17 @@ def delete_step(uuid: int):
|
|
|
82
88
|
if request.method == 'DELETE':
|
|
83
89
|
script.delete_action(uuid)
|
|
84
90
|
utils.post_script_file(script)
|
|
85
|
-
|
|
91
|
+
warning = None
|
|
92
|
+
try:
|
|
93
|
+
exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
|
|
94
|
+
except Exception as e:
|
|
95
|
+
exec_string = {}
|
|
96
|
+
warning = f"Compilation failed: {str(e)}"
|
|
86
97
|
session['python_code'] = exec_string
|
|
87
98
|
design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
|
|
88
99
|
return render_template("components/canvas_main.html",
|
|
89
100
|
script=script,
|
|
90
|
-
buttons_dict=design_buttons)
|
|
101
|
+
buttons_dict=design_buttons, warning=warning)
|
|
91
102
|
|
|
92
103
|
|
|
93
104
|
@steps.route("/draft/steps/<int:uuid>/duplicate", methods=["POST"], strict_slashes=False,)
|
|
@@ -107,13 +118,18 @@ def duplicate_action(uuid: int):
|
|
|
107
118
|
script = utils.get_script_file()
|
|
108
119
|
script.duplicate_action(uuid)
|
|
109
120
|
utils.post_script_file(script)
|
|
110
|
-
|
|
121
|
+
warning = None
|
|
122
|
+
try:
|
|
123
|
+
exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
|
|
124
|
+
except Exception as e:
|
|
125
|
+
exec_string = {}
|
|
126
|
+
warning = f"Compilation failed: {str(e)}"
|
|
111
127
|
session['python_code'] = exec_string
|
|
112
128
|
design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
|
|
113
129
|
|
|
114
130
|
return render_template("components/canvas_main.html",
|
|
115
131
|
script=script,
|
|
116
|
-
buttons_dict=design_buttons)
|
|
132
|
+
buttons_dict=design_buttons, warning=warning)
|
|
117
133
|
|
|
118
134
|
|
|
119
135
|
@steps.route("/draft/steps/order", methods=['POST'])
|
|
@@ -133,13 +149,18 @@ def update_list():
|
|
|
133
149
|
script = utils.get_script_file()
|
|
134
150
|
script.currently_editing_order = order.split(",", len(script.currently_editing_script))
|
|
135
151
|
script.sort_actions()
|
|
152
|
+
warning = None
|
|
136
153
|
|
|
137
154
|
utils.post_script_file(script)
|
|
138
|
-
|
|
155
|
+
try:
|
|
156
|
+
exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
|
|
157
|
+
except Exception as e:
|
|
158
|
+
exec_string = {}
|
|
159
|
+
warning = f"Compilation failed: {str(e)}"
|
|
139
160
|
session['python_code'] = exec_string
|
|
140
161
|
|
|
141
162
|
# Return the updated canvas HTML instead of JSON
|
|
142
163
|
design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
|
|
143
164
|
return render_template("components/canvas_main.html",
|
|
144
165
|
script=script,
|
|
145
|
-
buttons_dict=design_buttons)
|
|
166
|
+
buttons_dict=design_buttons, warning=warning)
|
|
@@ -103,6 +103,12 @@ function submitEditForm(event) {
|
|
|
103
103
|
document.getElementById('instrument-panel').innerHTML = previousHtmlState;
|
|
104
104
|
previousHtmlState = null; // Clear the stored state
|
|
105
105
|
}
|
|
106
|
+
const parser = new DOMParser();
|
|
107
|
+
const doc = parser.parseFromString(html, 'text/html');
|
|
108
|
+
const warningDiv = doc.querySelector('#warning');
|
|
109
|
+
if (warningDiv && warningDiv.textContent.trim()) {
|
|
110
|
+
alert(warningDiv.textContent.trim()); // or use a nicer toast
|
|
111
|
+
}
|
|
106
112
|
}
|
|
107
113
|
})
|
|
108
114
|
.catch(error => {
|
|
@@ -149,6 +155,13 @@ function duplicateAction(uuid) {
|
|
|
149
155
|
.then(response => response.text())
|
|
150
156
|
.then(html => {
|
|
151
157
|
updateActionCanvas(html);
|
|
158
|
+
|
|
159
|
+
const parser = new DOMParser();
|
|
160
|
+
const doc = parser.parseFromString(html, 'text/html');
|
|
161
|
+
const warningDiv = doc.querySelector('#warning');
|
|
162
|
+
if (warningDiv && warningDiv.textContent.trim()) {
|
|
163
|
+
alert(warningDiv.textContent.trim()); // or use a nicer toast
|
|
164
|
+
}
|
|
152
165
|
})
|
|
153
166
|
.catch(error => console.error('Error:', error));
|
|
154
167
|
}
|
|
@@ -202,6 +215,13 @@ function deleteAction(uuid) {
|
|
|
202
215
|
.then(html => {
|
|
203
216
|
// Find the first list element's content and replace it
|
|
204
217
|
updateActionCanvas(html);
|
|
218
|
+
// Optionally, check if a warning element exists
|
|
219
|
+
const parser = new DOMParser();
|
|
220
|
+
const doc = parser.parseFromString(html, 'text/html');
|
|
221
|
+
const warningDiv = doc.querySelector('#warning');
|
|
222
|
+
if (warningDiv && warningDiv.textContent.trim()) {
|
|
223
|
+
alert(warningDiv.textContent.trim()); // or use a nicer toast
|
|
224
|
+
}
|
|
205
225
|
})
|
|
206
226
|
.catch(error => console.error('Error:', error));
|
|
207
227
|
}
|
|
@@ -434,14 +434,21 @@ class Script(db.Model):
|
|
|
434
434
|
:return: A dict containing script types as keys and lists of function body lines as values.
|
|
435
435
|
"""
|
|
436
436
|
line_collection = {}
|
|
437
|
+
|
|
437
438
|
for stype, func_str in exec_str_collection.items():
|
|
438
439
|
if func_str:
|
|
439
440
|
module = ast.parse(func_str)
|
|
440
|
-
func_def = next(node for node in module.body if isinstance(node, ast.FunctionDef))
|
|
441
441
|
|
|
442
|
-
#
|
|
443
|
-
|
|
444
|
-
|
|
442
|
+
# Find the first function (regular or async)
|
|
443
|
+
func_def = next(
|
|
444
|
+
node for node in module.body
|
|
445
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
# Extract function body as source lines, skipping 'return' nodes
|
|
449
|
+
line_collection[stype] = [
|
|
450
|
+
ast_unparse(node) for node in func_def.body if not isinstance(node, ast.Return)
|
|
451
|
+
]
|
|
445
452
|
return line_collection
|
|
446
453
|
|
|
447
454
|
def compile(self, script_path=None):
|
|
@@ -459,7 +466,8 @@ class Script(db.Model):
|
|
|
459
466
|
|
|
460
467
|
for i in self.stypes:
|
|
461
468
|
if self.script_dict[i]:
|
|
462
|
-
|
|
469
|
+
is_async = any(a.get("coroutine", False) for a in self.script_dict[i])
|
|
470
|
+
func_str = self._generate_function_header(run_name, i, is_async) + self._generate_function_body(i)
|
|
463
471
|
exec_str_collection[i] = func_str
|
|
464
472
|
if script_path:
|
|
465
473
|
self._write_to_file(script_path, run_name, exec_str_collection)
|
|
@@ -477,7 +485,7 @@ class Script(db.Model):
|
|
|
477
485
|
name += '_'
|
|
478
486
|
return name
|
|
479
487
|
|
|
480
|
-
def _generate_function_header(self, run_name, stype):
|
|
488
|
+
def _generate_function_header(self, run_name, stype, is_async):
|
|
481
489
|
"""
|
|
482
490
|
Generate the function header.
|
|
483
491
|
"""
|
|
@@ -487,7 +495,8 @@ class Script(db.Model):
|
|
|
487
495
|
config_type.items()]
|
|
488
496
|
|
|
489
497
|
script_type = f"_{stype}" if stype != "script" else ""
|
|
490
|
-
|
|
498
|
+
async_str = "async " if is_async else ""
|
|
499
|
+
function_header = f"{async_str}def {run_name}{script_type}("
|
|
491
500
|
|
|
492
501
|
if stype == "script":
|
|
493
502
|
function_header += ", ".join(configure)
|
|
@@ -540,7 +549,8 @@ class Script(db.Model):
|
|
|
540
549
|
# elif instrument == 'registered_workflows':
|
|
541
550
|
# return inspect.getsource(my_function)
|
|
542
551
|
else:
|
|
543
|
-
|
|
552
|
+
is_async = action.get("coroutine", False)
|
|
553
|
+
return self._process_instrument_action(indent_unit, instrument, action_name, args, save_data, is_async)
|
|
544
554
|
|
|
545
555
|
def _process_args(self, args):
|
|
546
556
|
"""
|
|
@@ -600,10 +610,12 @@ class Script(db.Model):
|
|
|
600
610
|
indent_unit -= 1
|
|
601
611
|
return exec_string, indent_unit
|
|
602
612
|
|
|
603
|
-
def _process_instrument_action(self, indent_unit, instrument, action, args, save_data):
|
|
613
|
+
def _process_instrument_action(self, indent_unit, instrument, action, args, save_data, is_async=False):
|
|
604
614
|
"""
|
|
605
615
|
Process actions related to instruments.
|
|
606
616
|
"""
|
|
617
|
+
async_str = "await " if is_async else ""
|
|
618
|
+
|
|
607
619
|
function_call = f"{instrument}.{action}"
|
|
608
620
|
if instrument.startswith("blocks"):
|
|
609
621
|
self.blocks_included = True
|
|
@@ -611,11 +623,11 @@ class Script(db.Model):
|
|
|
611
623
|
|
|
612
624
|
if isinstance(args, dict) and args != {}:
|
|
613
625
|
args_str = self._process_dict_args(args)
|
|
614
|
-
single_line = f"{function_call}(**{args_str})"
|
|
626
|
+
single_line = f"{async_str}{function_call}(**{args_str})"
|
|
615
627
|
elif isinstance(args, str):
|
|
616
628
|
single_line = f"{function_call} = {args}"
|
|
617
629
|
else:
|
|
618
|
-
single_line = f"{function_call}()"
|
|
630
|
+
single_line = f"{async_str}{function_call}()"
|
|
619
631
|
|
|
620
632
|
if save_data:
|
|
621
633
|
save_data += " = "
|
|
@@ -55,6 +55,10 @@ def convert_to_cards(source_code: str):
|
|
|
55
55
|
)
|
|
56
56
|
|
|
57
57
|
class CardVisitor(ast.NodeVisitor):
|
|
58
|
+
def __init__(self):
|
|
59
|
+
self.defined_types = {} # <-- always exists
|
|
60
|
+
|
|
61
|
+
|
|
58
62
|
def visit_FunctionDef(self, node):
|
|
59
63
|
self.defined_types = {
|
|
60
64
|
arg.arg: ast.unparse(arg.annotation) if arg.annotation else "float"
|
|
@@ -142,14 +146,20 @@ def convert_to_cards(source_code: str):
|
|
|
142
146
|
"return": "",
|
|
143
147
|
"uuid": generate_uuid()
|
|
144
148
|
})
|
|
149
|
+
elif isinstance(node.value, ast.Await):
|
|
150
|
+
self.handle_call(node.value.value, ret_var=node.targets[0].id, awaited=True)
|
|
151
|
+
|
|
145
152
|
elif isinstance(node.value, ast.Call):
|
|
146
153
|
self.handle_call(node.value, ret_var=node.targets[0].id)
|
|
147
154
|
|
|
148
155
|
def visit_Expr(self, node):
|
|
149
|
-
if isinstance(node.value, ast.
|
|
156
|
+
if isinstance(node.value, ast.Await):
|
|
157
|
+
# node.value is ast.Await
|
|
158
|
+
self.handle_call(node.value.value, awaited=True)
|
|
159
|
+
elif isinstance(node.value, ast.Call):
|
|
150
160
|
self.handle_call(node.value)
|
|
151
161
|
|
|
152
|
-
def handle_call(self, node, ret_var=""):
|
|
162
|
+
def handle_call(self, node, ret_var="", awaited=False):
|
|
153
163
|
func_parts = []
|
|
154
164
|
f = node.func
|
|
155
165
|
while isinstance(f, ast.Attribute):
|
|
@@ -229,7 +239,7 @@ def convert_to_cards(source_code: str):
|
|
|
229
239
|
else infer_type(value)
|
|
230
240
|
)
|
|
231
241
|
|
|
232
|
-
|
|
242
|
+
card = {
|
|
233
243
|
"action": action,
|
|
234
244
|
"arg_types": arg_types,
|
|
235
245
|
"args": args,
|
|
@@ -237,7 +247,12 @@ def convert_to_cards(source_code: str):
|
|
|
237
247
|
"instrument": instrument,
|
|
238
248
|
"return": ret_var,
|
|
239
249
|
"uuid": generate_uuid()
|
|
240
|
-
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if awaited:
|
|
253
|
+
card["coroutine"] = True # mark as coroutine if awaited
|
|
254
|
+
|
|
255
|
+
add_card(card)
|
|
241
256
|
|
|
242
257
|
CardVisitor().visit(tree)
|
|
243
258
|
return cards
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ast
|
|
2
|
+
import asyncio
|
|
2
3
|
import os
|
|
3
4
|
import csv
|
|
4
5
|
import threading
|
|
@@ -182,7 +183,26 @@ class ScriptRunner:
|
|
|
182
183
|
duration = float(duration_str)
|
|
183
184
|
self.safe_sleep(duration)
|
|
184
185
|
else:
|
|
185
|
-
|
|
186
|
+
if "await " in line:
|
|
187
|
+
async_code = f"async def __async_exec_wrapper():\n"
|
|
188
|
+
# indent all code lines by 4 spaces
|
|
189
|
+
async_code += "\n".join(" " + line for line in line.splitlines())
|
|
190
|
+
async_code += f"\n return locals()"
|
|
191
|
+
exec(async_code, exec_globals, exec_locals)
|
|
192
|
+
func = exec_locals.get("__async_exec_wrapper") or exec_globals.get("__async_exec_wrapper")
|
|
193
|
+
# Capture the return value from asyncio.run
|
|
194
|
+
result_locals = asyncio.run(func())
|
|
195
|
+
|
|
196
|
+
# Update exec_locals with the returned locals
|
|
197
|
+
exec_locals.update(result_locals)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
else:
|
|
201
|
+
print("just exec synchronously")
|
|
202
|
+
exec(line, exec_globals, exec_locals)
|
|
203
|
+
exec_globals.update(exec_locals)
|
|
204
|
+
# return locals_dict
|
|
205
|
+
# exec(line, exec_globals, exec_locals)
|
|
186
206
|
# step.run_error = False
|
|
187
207
|
|
|
188
208
|
except HumanInterventionRequired as e:
|
|
@@ -198,6 +218,7 @@ class ScriptRunner:
|
|
|
198
218
|
|
|
199
219
|
step.run_error = True
|
|
200
220
|
self.toggle_pause()
|
|
221
|
+
exec_locals.pop("__async_exec_wrapper", None)
|
|
201
222
|
step.end_time = datetime.now()
|
|
202
223
|
step.output = exec_locals
|
|
203
224
|
db.session.commit()
|
|
@@ -249,7 +270,7 @@ class ScriptRunner:
|
|
|
249
270
|
self._run_actions(script, section_name="cleanup", logger=logger, socketio=socketio,run_id=run_id)
|
|
250
271
|
# Reset the running flag when done
|
|
251
272
|
# Save results if necessary
|
|
252
|
-
if not script.python_script and
|
|
273
|
+
if not script.python_script and return_list:
|
|
253
274
|
filename = self._save_results(run_name, arg_type, return_list, output_list, logger, output_path)
|
|
254
275
|
self._emit_progress(socketio, 100)
|
|
255
276
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import asyncio
|
|
1
3
|
import threading
|
|
2
4
|
import time
|
|
3
5
|
from datetime import datetime
|
|
@@ -19,8 +21,7 @@ class TaskRunner:
|
|
|
19
21
|
self.globals_dict = globals_dict
|
|
20
22
|
self.lock = global_config.runner_lock
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
def run_single_step(self, component, method, kwargs, wait=True, current_app=None):
|
|
24
|
+
async def run_single_step(self, component, method, kwargs, wait=True, current_app=None):
|
|
24
25
|
global deck
|
|
25
26
|
if deck is None:
|
|
26
27
|
deck = global_config.deck
|
|
@@ -32,16 +33,15 @@ class TaskRunner:
|
|
|
32
33
|
current_status["output"] = "busy"
|
|
33
34
|
return current_status
|
|
34
35
|
|
|
35
|
-
|
|
36
36
|
if wait:
|
|
37
|
-
output = self._run_single_step(component, method, kwargs, current_app)
|
|
37
|
+
output = await self._run_single_step(component, method, kwargs, current_app)
|
|
38
38
|
else:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
# Create background task properly
|
|
40
|
+
async def background_runner():
|
|
41
|
+
await self._run_single_step(component, method, kwargs, current_app)
|
|
42
|
+
|
|
43
|
+
asyncio.create_task(background_runner())
|
|
44
|
+
await asyncio.sleep(0.1) # Change time.sleep to await asyncio.sleep
|
|
45
45
|
output = {"status": "task started", "task_id": global_config.runner_status.get("id")}
|
|
46
46
|
|
|
47
47
|
return output
|
|
@@ -60,22 +60,32 @@ class TaskRunner:
|
|
|
60
60
|
function_executable = getattr(instrument, method)
|
|
61
61
|
return function_executable
|
|
62
62
|
|
|
63
|
-
def _run_single_step(self, component, method, kwargs, current_app=None):
|
|
63
|
+
async def _run_single_step(self, component, method, kwargs, current_app=None):
|
|
64
64
|
try:
|
|
65
65
|
function_executable = self._get_executable(component, deck, method)
|
|
66
66
|
method_name = f"{component}.{method}"
|
|
67
67
|
except Exception as e:
|
|
68
68
|
self.lock.release()
|
|
69
|
-
return {"status": "error", "msg": e
|
|
69
|
+
return {"status": "error", "msg": str(e)}
|
|
70
70
|
|
|
71
|
-
# with
|
|
71
|
+
# Flask context is NOT async → just use normal "with"
|
|
72
72
|
with current_app.app_context():
|
|
73
|
-
step = SingleStep(
|
|
73
|
+
step = SingleStep(
|
|
74
|
+
method_name=method_name,
|
|
75
|
+
kwargs=kwargs,
|
|
76
|
+
run_error=None,
|
|
77
|
+
start_time=datetime.now()
|
|
78
|
+
)
|
|
74
79
|
db.session.add(step)
|
|
75
80
|
db.session.flush()
|
|
76
|
-
global_config.runner_status = {"id":step.id, "type": "task"}
|
|
81
|
+
global_config.runner_status = {"id": step.id, "type": "task"}
|
|
82
|
+
|
|
77
83
|
try:
|
|
78
|
-
|
|
84
|
+
if inspect.iscoroutinefunction(function_executable):
|
|
85
|
+
output = await function_executable(**kwargs)
|
|
86
|
+
else:
|
|
87
|
+
output = function_executable(**kwargs)
|
|
88
|
+
|
|
79
89
|
step.output = output
|
|
80
90
|
step.end_time = datetime.now()
|
|
81
91
|
success = True
|
|
@@ -87,4 +97,5 @@ class TaskRunner:
|
|
|
87
97
|
finally:
|
|
88
98
|
db.session.commit()
|
|
89
99
|
self.lock.release()
|
|
90
|
-
|
|
100
|
+
|
|
101
|
+
return dict(success=success, output=output)
|
|
@@ -105,7 +105,8 @@ def _inspect_class(class_object=None, debug=False):
|
|
|
105
105
|
try:
|
|
106
106
|
annotation = inspect.signature(method)
|
|
107
107
|
docstring = inspect.getdoc(method)
|
|
108
|
-
|
|
108
|
+
coroutine = inspect.iscoroutinefunction(method)
|
|
109
|
+
functions[function] = dict(signature=annotation, docstring=docstring, coroutine=coroutine,)
|
|
109
110
|
|
|
110
111
|
except Exception:
|
|
111
112
|
pass
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.3.5"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ivoryos
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.5
|
|
4
4
|
Summary: an open-source Python package enabling Self-Driving Labs (SDLs) interoperability
|
|
5
5
|
Author-email: Ivory Zhang <ivoryzhang@chem.ubc.ca>
|
|
6
6
|
License: MIT
|
|
@@ -17,9 +17,19 @@ Requires-Dist: Flask-WTF
|
|
|
17
17
|
Requires-Dist: SQLAlchemy-Utils
|
|
18
18
|
Requires-Dist: python-dotenv
|
|
19
19
|
Requires-Dist: astor; python_version < "3.9"
|
|
20
|
+
Provides-Extra: optimizer-ax
|
|
21
|
+
Requires-Dist: ax-platform; extra == "optimizer-ax"
|
|
22
|
+
Provides-Extra: optimizer-baybe
|
|
23
|
+
Requires-Dist: baybe; extra == "optimizer-baybe"
|
|
20
24
|
Provides-Extra: optimizer
|
|
21
25
|
Requires-Dist: ax-platform; extra == "optimizer"
|
|
22
26
|
Requires-Dist: baybe; extra == "optimizer"
|
|
27
|
+
Provides-Extra: doc
|
|
28
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
29
|
+
Requires-Dist: sphinx-rtd-theme; extra == "doc"
|
|
30
|
+
Requires-Dist: sphinxcontrib-httpdomain; extra == "doc"
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest; extra == "dev"
|
|
23
33
|
Dynamic: license-file
|
|
24
34
|
|
|
25
35
|
[](https://ivoryos.readthedocs.io/en/latest/?badge=latest)
|
|
@@ -10,6 +10,20 @@ python-dotenv
|
|
|
10
10
|
[:python_version < "3.9"]
|
|
11
11
|
astor
|
|
12
12
|
|
|
13
|
+
[dev]
|
|
14
|
+
pytest
|
|
15
|
+
|
|
16
|
+
[doc]
|
|
17
|
+
sphinx
|
|
18
|
+
sphinx-rtd-theme
|
|
19
|
+
sphinxcontrib-httpdomain
|
|
20
|
+
|
|
13
21
|
[optimizer]
|
|
14
22
|
ax-platform
|
|
15
23
|
baybe
|
|
24
|
+
|
|
25
|
+
[optimizer-ax]
|
|
26
|
+
ax-platform
|
|
27
|
+
|
|
28
|
+
[optimizer-baybe]
|
|
29
|
+
baybe
|
|
@@ -25,7 +25,18 @@ dependencies = [
|
|
|
25
25
|
]
|
|
26
26
|
|
|
27
27
|
[project.optional-dependencies]
|
|
28
|
-
optimizer = ["ax-platform"
|
|
28
|
+
optimizer-ax = ["ax-platform"]
|
|
29
|
+
optimizer-baybe = ["baybe"]
|
|
30
|
+
optimizer = [
|
|
31
|
+
"ax-platform",
|
|
32
|
+
"baybe"
|
|
33
|
+
]
|
|
34
|
+
doc = [
|
|
35
|
+
"sphinx",
|
|
36
|
+
"sphinx-rtd-theme",
|
|
37
|
+
"sphinxcontrib-httpdomain"
|
|
38
|
+
]
|
|
39
|
+
dev = ["pytest"]
|
|
29
40
|
|
|
30
41
|
[project.urls]
|
|
31
42
|
Homepage = "https://gitlab.com/heingroup/ivoryos"
|
ivoryos-1.3.4/ivoryos/version.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.3.4"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/actions_panel.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/autofill_toggle.html
RENAMED
|
File without changes
|
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/canvas_footer.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/canvas_header.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/deck_selector.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/edit_action_form.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/instruments_panel.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/modals/drop_modal.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/modals/json_modal.html
RENAMED
|
File without changes
|
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/modals/rename_modal.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/modals/saveas_modal.html
RENAMED
|
File without changes
|
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/python_code_overlay.html
RENAMED
|
File without changes
|
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/design/templates/components/text_to_code_panel.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/error_modal.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/logging_panel.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/progress_panel.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/tab_bayesian.html
RENAMED
|
File without changes
|
{ivoryos-1.3.4 → ivoryos-1.3.5}/ivoryos/routes/execute/templates/components/tab_configuration.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|