ivoryos 0.1.18__tar.gz → 0.1.19__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.

Files changed (54) hide show
  1. {ivoryos-0.1.18/ivoryos.egg-info → ivoryos-0.1.19}/PKG-INFO +10 -1
  2. {ivoryos-0.1.18 → ivoryos-0.1.19}/README.md +9 -0
  3. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/design/design.py +21 -7
  4. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/design/templates/design/experiment_run.html +21 -5
  5. ivoryos-0.1.19/ivoryos/static/js/socket_handler.js +62 -0
  6. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/utils/db_models.py +8 -41
  7. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/utils/script_runner.py +85 -39
  8. ivoryos-0.1.19/ivoryos/version.py +1 -0
  9. {ivoryos-0.1.18 → ivoryos-0.1.19/ivoryos.egg-info}/PKG-INFO +10 -1
  10. ivoryos-0.1.18/ivoryos/static/js/socket_handler.js +0 -34
  11. ivoryos-0.1.18/ivoryos/version.py +0 -1
  12. {ivoryos-0.1.18 → ivoryos-0.1.19}/LICENSE +0 -0
  13. {ivoryos-0.1.18 → ivoryos-0.1.19}/MANIFEST.in +0 -0
  14. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/__init__.py +0 -0
  15. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/config.py +0 -0
  16. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/__init__.py +0 -0
  17. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/auth/__init__.py +0 -0
  18. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/auth/auth.py +0 -0
  19. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/auth/templates/auth/login.html +0 -0
  20. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/auth/templates/auth/signup.html +0 -0
  21. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/control/__init__.py +0 -0
  22. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/control/control.py +0 -0
  23. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/control/templates/control/controllers.html +0 -0
  24. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/control/templates/control/controllers_home.html +0 -0
  25. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/control/templates/control/controllers_new.html +0 -0
  26. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/database/__init__.py +0 -0
  27. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/database/database.py +0 -0
  28. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/database/templates/database/experiment_database.html +0 -0
  29. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/design/__init__.py +0 -0
  30. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/design/templates/design/experiment_builder.html +0 -0
  31. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/main/__init__.py +0 -0
  32. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/main/main.py +0 -0
  33. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/main/templates/main/help.html +0 -0
  34. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/routes/main/templates/main/home.html +0 -0
  35. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/static/favicon.ico +0 -0
  36. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/static/gui_annotation/Slide1.png +0 -0
  37. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/static/gui_annotation/Slide2.PNG +0 -0
  38. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/static/js/overlay.js +0 -0
  39. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/static/js/sortable_card.js +0 -0
  40. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/static/js/sortable_design.js +0 -0
  41. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/static/logo.webp +0 -0
  42. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/static/style.css +0 -0
  43. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/templates/base.html +0 -0
  44. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/utils/__init__.py +0 -0
  45. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/utils/form.py +0 -0
  46. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/utils/global_config.py +0 -0
  47. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/utils/llm_agent.py +0 -0
  48. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos/utils/utils.py +0 -0
  49. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos.egg-info/SOURCES.txt +0 -0
  50. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos.egg-info/dependency_links.txt +0 -0
  51. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos.egg-info/requires.txt +0 -0
  52. {ivoryos-0.1.18 → ivoryos-0.1.19}/ivoryos.egg-info/top_level.txt +0 -0
  53. {ivoryos-0.1.18 → ivoryos-0.1.19}/setup.cfg +0 -0
  54. {ivoryos-0.1.18 → ivoryos-0.1.19}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ivoryos
3
- Version: 0.1.18
3
+ Version: 0.1.19
4
4
  Summary: an open-source Python package enabling Self-Driving Labs (SDLs) interoperability
5
5
  Home-page: https://gitlab.com/heingroup/ivoryos
6
6
  Author: Ivory Zhang
@@ -157,6 +157,15 @@ Intro + Tutorial + Demo with PurPOSE platform
157
157
  https://youtu.be/dFfJv9I2-1g
158
158
 
159
159
 
160
+ ## Roadmap
161
+
162
+ - [x] Allow plugin pages ✅
163
+ - [ ] pause, resume, abort current and pending workflows
164
+ - [ ] snapshot version control
165
+ - [ ] dropdown input
166
+ - [ ] show line number option
167
+
168
+
160
169
  ## Authors and Acknowledgement
161
170
  Ivory Zhang, Lucy Hao
162
171
 
@@ -145,6 +145,15 @@ Intro + Tutorial + Demo with PurPOSE platform
145
145
  https://youtu.be/dFfJv9I2-1g
146
146
 
147
147
 
148
+ ## Roadmap
149
+
150
+ - [x] Allow plugin pages ✅
151
+ - [ ] pause, resume, abort current and pending workflows
152
+ - [ ] snapshot version control
153
+ - [ ] dropdown input
154
+ - [ ] show line number option
155
+
156
+
148
157
  ## Authors and Acknowledgement
149
158
  Ivory Zhang, Lucy Hao
150
159
 
@@ -24,10 +24,22 @@ global_config = GlobalConfig()
24
24
  runner = ScriptRunner()
25
25
 
26
26
 
27
- @socketio.on('abort_action')
28
- def handle_abort_action():
27
+ @socketio.on('abort_pending')
28
+ def handle_abort_pending():
29
+ runner.abort_pending()
30
+ socketio.emit('log', {'message': "aborted pending iterations"})
31
+
32
+
33
+ @socketio.on('abort_current')
34
+ def handle_abort_current():
29
35
  runner.stop_execution()
30
- socketio.emit('log', {'message': "aborted pending tasks"})
36
+ socketio.emit('log', {'message': "stopped next task"})
37
+
38
+
39
+ @socketio.on('pause')
40
+ def handle_pause():
41
+ msg = runner.toggle_pause()
42
+ socketio.emit('log', {'message': msg})
31
43
 
32
44
 
33
45
  @socketio.on('connect')
@@ -266,9 +278,10 @@ def experiment_run():
266
278
  config_preview = config[1:6]
267
279
  arg_type = config.pop(0) # first entry is types
268
280
  try:
269
- exec(exec_string)
281
+ for key, func_str in exec_string.items():
282
+ exec(func_str)
270
283
  except Exception:
271
- flash("Please check syntax!!")
284
+ flash(f"Please check {key} syntax!!")
272
285
  return redirect(url_for("design.experiment_builder"))
273
286
  # runner.globals_dict.update(globals())
274
287
  run_name = script.name if script.name else "untitled"
@@ -313,7 +326,8 @@ def experiment_run():
313
326
  return render_template('experiment_run.html', script=script.script_dict, filename=filename, dot_py=exec_string,
314
327
  return_list=return_list, config_list=config_list, config_file_list=config_file_list,
315
328
  config_preview=config_preview, data_list=data_list, config_type_list=config_type_list,
316
- no_deck_warning=no_deck_warning, dismiss=dismiss, design_buttons=design_buttons, history=deck_list)
329
+ no_deck_warning=no_deck_warning, dismiss=dismiss, design_buttons=design_buttons,
330
+ history=deck_list)
317
331
 
318
332
 
319
333
  @design.route("/toggle_script_type/<stype>")
@@ -547,4 +561,4 @@ def duplicate_action(id: int):
547
561
  script = utils.get_script_file()
548
562
  script.duplicate_action(id)
549
563
  utils.post_script_file(script)
550
- return redirect(back)
564
+ return redirect(back)
@@ -219,10 +219,24 @@
219
219
  </div>
220
220
  <div class="col-lg-6 col-sm-12 logging-panel">
221
221
  <p>
222
- <div class="p d-flex justify-content-between align-items-center">
223
- <h5>Progress:</h5>
224
- <button id="abort" class="btn btn-danger ">Abort Pending Actions</button>
225
- </div>
222
+ <div class="p d-flex justify-content-between align-items-center">
223
+ <h5>Progress:</h5>
224
+ <div class="d-flex gap-2 ms-auto">
225
+ <button id="pause-resume" class="btn btn-info text-white" data-bs-toggle="tooltip" title="Pause execution">
226
+ <i class="bi bi-pause-circle"></i> <!-- Icon for Pause -->
227
+ </button>
228
+ <button id="abort-current" class="btn btn-danger text-white" data-bs-toggle="tooltip" title="Stop execution after current step">
229
+ <i class="bi bi-stop-circle"></i> <!-- Icon for Stop After This Step -->
230
+ </button>
231
+ <button id="abort-pending" class="btn btn-warning text-white" data-bs-toggle="tooltip" title="Stop execution after current iteration">
232
+ <i class="bi bi-hourglass-split"></i> <!-- Icon for Stop After This Iteration -->
233
+ </button>
234
+ </div>
235
+ </div>
236
+ <div class="text-muted mt-2">
237
+ <small><strong>Note:</strong> The current step cannot be paused or stopped until it completes. </small>
238
+ </div>
239
+
226
240
  </p>
227
241
  <div class="progress" role="progressbar" aria-label="Animated striped example" aria-valuenow="10" aria-valuemin="0" aria-valuemax="100">
228
242
  <div id="progress-bar-inner" class="progress-bar progress-bar-striped progress-bar-animated"></div>
@@ -295,7 +309,9 @@
295
309
  </h2>
296
310
  <div id="python" class="accordion-collapse collapse">
297
311
  <div class="accordion-body">
298
- <pre><code class="python" >{{dot_py}}</code></pre>
312
+ {% for stype, script in dot_py.items() %}
313
+ <pre><code class="python" >{{script}}</code></pre>
314
+ {% endfor %}
299
315
  <a href="{{ url_for('design.download', filetype='python') }}">Download <i class="bi bi-download"></i></a>
300
316
  </div>
301
317
  </div>
@@ -0,0 +1,62 @@
1
+ document.addEventListener("DOMContentLoaded", function() {
2
+ var socket = io.connect('http://' + document.domain + ':' + location.port);
3
+ socket.on('connect', function() {
4
+ console.log('Connected');
5
+ });
6
+ socket.on('progress', function(data) {
7
+ var progress = data.progress;
8
+ console.log(progress);
9
+ // Update the progress bar's width and appearance
10
+ var progressBar = document.getElementById('progress-bar-inner');
11
+ progressBar.style.width = progress + '%';
12
+ progressBar.setAttribute('aria-valuenow', progress);
13
+
14
+ if (progress === 100) {
15
+ // Remove animation and set green color when 100% is reached
16
+ progressBar.classList.remove('progress-bar-animated');
17
+ progressBar.classList.add('bg-success'); // Bootstrap class for green color
18
+ }
19
+ });
20
+ socket.on('log', function(data) {
21
+ var logMessage = data.message;
22
+ console.log(logMessage);
23
+ $('#logging-panel').append(logMessage + "<br>");
24
+ $('#logging-panel').scrollTop($('#logging-panel')[0].scrollHeight);
25
+ });
26
+
27
+ document.getElementById('abort-pending').addEventListener('click', function() {
28
+ var confirmation = confirm("Are you sure you want to stop after this iteration?");
29
+ if (confirmation) {
30
+ socket.emit('abort_pending');
31
+ console.log('Abort action sent to server.');
32
+ }
33
+ });
34
+ document.getElementById('abort-current').addEventListener('click', function() {
35
+ var confirmation = confirm("Are you sure you want to stop after this step?");
36
+ if (confirmation) {
37
+ socket.emit('abort_current');
38
+ console.log('Stop action sent to server.');
39
+ }
40
+ });
41
+
42
+ document.getElementById('pause-resume').addEventListener('click', function() {
43
+
44
+ socket.emit('pause');
45
+ console.log('Pause/Resume is toggled.');
46
+ var button = this;
47
+ var icon = button.querySelector("i");
48
+
49
+ // Toggle between Pause and Resume
50
+ if (icon.classList.contains("bi-pause-circle")) {
51
+ icon.classList.remove("bi-pause-circle");
52
+ icon.classList.add("bi-play-circle");
53
+ button.innerHTML = '<i class="bi bi-play-circle"></i>';
54
+ button.setAttribute("title", "Resume execution");
55
+ } else {
56
+ icon.classList.remove("bi-play-circle");
57
+ icon.classList.add("bi-pause-circle");
58
+ button.innerHTML = '<i class="bi bi-pause-circle"></i>';
59
+ button.setAttribute("title", "Pause execution");
60
+ }
61
+ });
62
+ });
@@ -398,35 +398,16 @@ class Script(db.Model):
398
398
  self.sort_actions()
399
399
  run_name = self.name if self.name else "untitled"
400
400
  run_name = self.validate_function_name(run_name)
401
- exec_string = ''
401
+ exec_str_collection = {}
402
402
 
403
403
  for i in self.stypes:
404
- exec_string += self._generate_function_header(run_name, i)
405
- exec_string += self._generate_function_body(i)
406
-
404
+ func_str = self._generate_function_header(run_name, i) + self._generate_function_body(i)
405
+ exec_str_collection[i] = func_str
407
406
  if script_path:
408
- self._write_to_file(script_path, run_name, exec_string)
407
+ self._write_to_file(script_path, run_name, exec_str_collection)
409
408
 
410
- return exec_string
409
+ return exec_str_collection
411
410
 
412
- def compile_steps(self, script_path=None):
413
- """
414
- Compile the current script to steps.
415
- :return: {"prep":[], "script":[], "cleanup":[],}.
416
- """
417
- self.sort_actions()
418
- run_name = self.name if self.name else "untitled"
419
- run_name = self.validate_function_name(run_name)
420
- exec_string = ''
421
- steps = {}
422
- for i in self.stypes:
423
- # exec_string += self._generate_function_header(run_name, i)
424
- exec_string += self._generate_function_body(i)
425
-
426
- if script_path:
427
- self._write_to_file(script_path, run_name, exec_string)
428
-
429
- return exec_string
430
411
 
431
412
 
432
413
  @staticmethod
@@ -447,7 +428,7 @@ class Script(db.Model):
447
428
  configure = [param + f":{param_type}" if not param_type == "any" else "" for param, param_type in
448
429
  config_type.items()]
449
430
 
450
- function_header = f"\n\ndef {run_name}_{stype}("
431
+ function_header = f"def {run_name}_{stype}("
451
432
 
452
433
  if stype == "script":
453
434
  function_header += ", ".join(configure)
@@ -471,21 +452,6 @@ class Script(db.Model):
471
452
  body += self.indent(indent_unit) + return_str
472
453
  return body
473
454
 
474
- # def _generate_function_body(self, stype):
475
- # """
476
- # Generate the function body for each type in stypes.
477
- # """
478
- # steps = []
479
- # indent_unit = 1
480
- #
481
- # for index, action in enumerate(self.script_dict[stype]):
482
- # text, indent_unit = self._process_action(indent_unit, action, index, stype)
483
- # body += text
484
- # return_str, return_list = self.config_return()
485
- # if return_list and stype == "script":
486
- # body += self.indent(indent_unit) + return_str
487
- # return body
488
-
489
455
  def _process_action(self, indent_unit, action, index, stype):
490
456
  """
491
457
  Process each action within the script dictionary.
@@ -631,7 +597,8 @@ class Script(db.Model):
631
597
  else:
632
598
  s.write("deck = None")
633
599
  s.write("\nimport time")
634
- s.write(exec_string)
600
+ for i in exec_string.values():
601
+ s.write(f"\n\n\n{i}")
635
602
 
636
603
 
637
604
  if __name__ == "__main__":
@@ -1,3 +1,4 @@
1
+ import ast
1
2
  import os
2
3
  import csv
3
4
  import threading
@@ -17,25 +18,40 @@ class ScriptRunner:
17
18
  if globals_dict is None:
18
19
  globals_dict = globals()
19
20
  self.globals_dict = globals_dict
20
-
21
- self.stop_event = threading.Event()
21
+ self.pause_event = threading.Event() # A threading event to manage pause/resume
22
+ self.pause_event.set()
23
+ self.stop_pending_event = threading.Event()
24
+ self.stop_current_event = threading.Event()
22
25
  self.is_running = False
23
26
  self.lock = threading.Lock()
24
27
 
28
+ def toggle_pause(self):
29
+ """Toggles between pausing and resuming the script"""
30
+ if self.pause_event.is_set():
31
+ self.pause_event.clear() # Pause the script
32
+ return "Paused"
33
+ else:
34
+ self.pause_event.set() # Resume the script
35
+ return "Resumed"
36
+
25
37
  def reset_stop_event(self):
26
- self.stop_event.clear()
38
+ self.stop_pending_event.clear()
39
+ self.stop_current_event.clear()
27
40
 
28
- def stop_execution(self):
29
- self.stop_event.set()
41
+ def abort_pending(self):
42
+ self.stop_pending_event.set()
30
43
  # print("Stop pending tasks")
31
44
 
45
+ def stop_execution(self):
46
+ """Force stop everything, including ongoing tasks."""
47
+ self.stop_current_event.set()
48
+ self.abort_pending()
49
+
32
50
  def run_script(self, script, repeat_count=1, run_name=None, logger=None, socketio=None, config=None, bo_args=None,
33
51
  output_path=""):
34
52
  global deck
35
53
  if deck is None:
36
54
  deck = global_config.deck
37
- exec_string = script.compile()
38
- exec(exec_string)
39
55
  time.sleep(1)
40
56
  with self.lock:
41
57
  if self.is_running:
@@ -50,24 +66,61 @@ class ScriptRunner:
50
66
  thread.start()
51
67
  return thread
52
68
 
69
+ def execute_function_line_by_line(self, script, section_name, logger, **kwargs):
70
+ """
71
+ Executes a function defined in a string line by line.
72
+
73
+ :param func_str: The function as a string
74
+ :param kwargs: Arguments to pass to the function
75
+ :return: The final result of the function execution
76
+ """
77
+ global deck
78
+ if deck is None:
79
+ deck = global_config.deck
80
+ # func_str = script.compile()
81
+ # Parse function body from string
82
+ module = ast.parse(script)
83
+ func_def = next(node for node in module.body if isinstance(node, ast.FunctionDef))
84
+
85
+ # Extract function body as source lines
86
+ lines = [ast.unparse(node) for node in func_def.body if not isinstance(node, ast.Return)]
87
+ # Prepare execution environment
88
+ exec_globals = {"deck": deck} # Add required global objects
89
+ exec_locals = {} # Local execution scope
90
+
91
+ # Define function arguments manually in exec_locals
92
+ exec_locals.update(kwargs)
93
+
94
+ # Execute each line dynamically
95
+ for line in lines:
96
+ if self.stop_current_event.is_set():
97
+ logger.info(f'Stopping execution during {section_name}')
98
+ break
99
+ logger.info(f"Executing: {line}") # Debugging output
100
+ exec(line, exec_globals, exec_locals)
101
+ self.pause_event.wait()
102
+
103
+ return exec_locals # Return the 'results' variable
104
+
53
105
  def _run_with_stop_check(self, script: Script, repeat_count, run_name, logger, socketio, config, bo_args,
54
106
  output_path):
55
107
  time.sleep(1)
108
+ func_str = script.compile()
56
109
  self._emit_progress(socketio, 1)
57
110
  try:
58
111
  # Run "prep" section once
59
112
  script_dict = script.script_dict
60
- self._run_actions(script_dict.get("prep", []), section_name="prep", run_name=run_name, logger=logger)
113
+ self._run_actions(script_dict.get("prep", []), func_str.get("prep", ''), section_name="prep", logger=logger)
61
114
  output_list = []
62
115
  _, arg_type = script.config("script")
63
116
  _, return_list = script.config_return()
64
117
  # Run "script" section multiple times
65
118
  if repeat_count:
66
- self._run_repeat_section(repeat_count, arg_type, bo_args, output_list, return_list, run_name, logger, socketio)
119
+ self._run_repeat_section(repeat_count, arg_type, bo_args, output_list, func_str.get("script", ''), run_name, return_list, logger, socketio)
67
120
  elif config:
68
- self._run_config_section(config, arg_type, output_list, return_list, run_name, logger, socketio)
121
+ self._run_config_section(config, arg_type, output_list, func_str.get("script", ''), run_name, logger, socketio)
69
122
  # Run "cleanup" section once
70
- self._run_actions(script_dict.get("cleanup", []), section_name="cleanup", run_name=run_name, logger=logger)
123
+ self._run_actions(script_dict.get("cleanup", []), func_str.get("cleanup", ''), section_name="cleanup", logger=logger)
71
124
  # Save results if necessary
72
125
  if output_list:
73
126
  self._save_results(run_name, arg_type, return_list, output_list, logger, output_path)
@@ -78,21 +131,14 @@ class ScriptRunner:
78
131
  self.is_running = False # Reset the running flag when done
79
132
  self._emit_progress(socketio, 100)
80
133
 
81
- def _run_actions(self, actions, section_name="", run_name=None, logger=None):
134
+ def _run_actions(self, actions, func_str, section_name="", logger=None):
82
135
  logger.info(f'Executing {section_name} steps') if actions else logger.info(f'No {section_name} steps')
83
- if self.stop_event.is_set():
136
+ if self.stop_pending_event.is_set():
84
137
  logger.info(f"Stopping execution during {section_name} section.")
85
138
  return
86
- # for action in actions:
87
- # if self.stop_event.is_set():
88
- # logger.info(f"Stopping execution during {section_name} section.")
89
- # break
90
- # logger.info(f'Executing {action.get("action", "")} action')
91
- fname = f"{run_name}_{section_name}"
92
- function = self.globals_dict[fname]
93
- function()
94
-
95
- def _run_config_section(self, config, arg_type, output_list, return_list, run_name, logger, socketio):
139
+ self.execute_function_line_by_line(func_str, section_name, logger)
140
+
141
+ def _run_config_section(self, config, arg_type, output_list, func_str, run_name, logger, socketio):
96
142
  compiled = True
97
143
  for i in config:
98
144
  try:
@@ -104,25 +150,25 @@ class ScriptRunner:
104
150
  if compiled:
105
151
  for i, kwargs in enumerate(config):
106
152
  kwargs = dict(kwargs)
107
- if self.stop_event.is_set():
153
+ if self.stop_pending_event.is_set():
108
154
  logger.info(f'Stopping execution during {run_name}: {i + 1}/{len(config)}')
109
155
  break
110
156
  logger.info(f'Executing {i + 1} of {len(config)} with kwargs = {kwargs}')
111
157
  progress = (i + 1) * 100 / len(config)
112
158
  self._emit_progress(socketio, progress)
113
- fname = f"{run_name}_script"
114
- function = self.globals_dict[fname]
115
- output = function(**kwargs)
159
+ # fname = f"{run_name}_script"
160
+ # function = self.globals_dict[fname]
161
+ output = self.execute_function_line_by_line(func_str, "script", logger, **kwargs)
116
162
  if output:
117
- kwargs.update(output)
118
- output_list.append(kwargs)
163
+ # kwargs.update(output)
164
+ output_list.append(output)
119
165
 
120
- def _run_repeat_section(self, repeat_count, arg_types, bo_args, output_list, return_list, run_name, logger, socketio):
166
+ def _run_repeat_section(self, repeat_count, arg_types, bo_args, output_list, func_str, run_name, return_list, logger, socketio):
121
167
  if bo_args:
122
168
  logger.info('Initializing optimizer...')
123
169
  ax_client = utils.ax_initiation(bo_args, arg_types)
124
170
  for i in range(int(repeat_count)):
125
- if self.stop_event.is_set():
171
+ if self.stop_pending_event.is_set():
126
172
  logger.info(f'Stopping execution during {run_name}: {i + 1}/{int(repeat_count)}')
127
173
  break
128
174
  logger.info(f'Executing {run_name} experiment: {i + 1}/{int(repeat_count)}')
@@ -132,20 +178,20 @@ class ScriptRunner:
132
178
  try:
133
179
  parameters, trial_index = ax_client.get_next_trial()
134
180
  logger.info(f'Output value: {parameters}')
135
- fname = f"{run_name}_script"
136
- function = self.globals_dict[fname]
137
- output = function(**parameters)
138
- # output = eval(f"{run_name}_script(**{parameters})")
139
- _output = output.copy()
181
+ # fname = f"{run_name}_script"
182
+ # function = self.globals_dict[fname]
183
+ output = self.execute_function_line_by_line(func_str, "script", logger, **parameters)
184
+
185
+ _output = {key: value for key, value in output.items() if key in return_list}
140
186
  ax_client.complete_trial(trial_index=trial_index, raw_data=_output)
141
187
  output.update(parameters)
142
188
  except Exception as e:
143
189
  logger.info(f'Optimization error: {e}')
144
190
  break
145
191
  else:
146
- fname = f"{run_name}_script"
147
- function = self.globals_dict[fname]
148
- output = function()
192
+ # fname = f"{run_name}_script"
193
+ # function = self.globals_dict[fname]
194
+ output = self.execute_function_line_by_line(func_str, "script", logger)
149
195
 
150
196
  if output:
151
197
  output_list.append(output)
@@ -0,0 +1 @@
1
+ __version__ = "0.1.19"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ivoryos
3
- Version: 0.1.18
3
+ Version: 0.1.19
4
4
  Summary: an open-source Python package enabling Self-Driving Labs (SDLs) interoperability
5
5
  Home-page: https://gitlab.com/heingroup/ivoryos
6
6
  Author: Ivory Zhang
@@ -157,6 +157,15 @@ Intro + Tutorial + Demo with PurPOSE platform
157
157
  https://youtu.be/dFfJv9I2-1g
158
158
 
159
159
 
160
+ ## Roadmap
161
+
162
+ - [x] Allow plugin pages ✅
163
+ - [ ] pause, resume, abort current and pending workflows
164
+ - [ ] snapshot version control
165
+ - [ ] dropdown input
166
+ - [ ] show line number option
167
+
168
+
160
169
  ## Authors and Acknowledgement
161
170
  Ivory Zhang, Lucy Hao
162
171
 
@@ -1,34 +0,0 @@
1
- document.addEventListener("DOMContentLoaded", function() {
2
- var socket = io.connect('http://' + document.domain + ':' + location.port);
3
- socket.on('connect', function() {
4
- console.log('Connected');
5
- });
6
- socket.on('progress', function(data) {
7
- var progress = data.progress;
8
- console.log(progress);
9
- // Update the progress bar's width and appearance
10
- var progressBar = document.getElementById('progress-bar-inner');
11
- progressBar.style.width = progress + '%';
12
- progressBar.setAttribute('aria-valuenow', progress);
13
-
14
- if (progress === 100) {
15
- // Remove animation and set green color when 100% is reached
16
- progressBar.classList.remove('progress-bar-animated');
17
- progressBar.classList.add('bg-success'); // Bootstrap class for green color
18
- }
19
- });
20
- socket.on('log', function(data) {
21
- var logMessage = data.message;
22
- console.log(logMessage);
23
- $('#logging-panel').append(logMessage + "<br>");
24
- $('#logging-panel').scrollTop($('#logging-panel')[0].scrollHeight);
25
- });
26
-
27
- document.getElementById('abort').addEventListener('click', function() {
28
- var confirmation = confirm("Are you sure you want to abort pending actions?");
29
- if (confirmation) {
30
- socket.emit('abort_action');
31
- console.log('Abort action sent to server.');
32
- }
33
- });
34
- });
@@ -1 +0,0 @@
1
- __version__ = "0.1.18"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes