ivoryos 0.1.12__py3-none-any.whl → 0.1.19__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/utils/form.py CHANGED
@@ -1,3 +1,4 @@
1
+ from wtforms.fields.choices import SelectField
1
2
  from wtforms.fields.core import Field
2
3
  from wtforms.validators import InputRequired
3
4
  from wtforms.widgets.core import TextInput
@@ -8,16 +9,15 @@ import inspect
8
9
 
9
10
 
10
11
  def find_variable(data, script):
11
- # TODO: needs to check for valid order of variables, important when editting
12
- added_variables: list[dict[str, str]] = [action for action in script.currently_editing_script if
13
- action["instrument"] == "variable"
14
- # or action["return"] # TODO find returns
15
- ]
16
- for added_variable in added_variables:
17
- if added_variable["action"] == data:
18
- return data, added_variable["args"]
19
- # if added_variable["return"] == data:
20
- # return data, None
12
+ """
13
+ find user defined variables and return values in the script:Script
14
+ :param data: string of input variable name
15
+ :param script:Script object
16
+ """
17
+ variables: dict[str, str] = script.get_variables()
18
+ for variable_name, variable_type in variables.items():
19
+ if variable_name == data:
20
+ return data, variable_type # variable_type int float str or "function_output"
21
21
  return None, None
22
22
 
23
23
 
@@ -36,7 +36,7 @@ class VariableOrStringField(Field):
36
36
 
37
37
  def _value(self):
38
38
  if self.script:
39
- variable, value = find_variable(self.data, self.script)
39
+ variable, variable_type = find_variable(self.data, self.script)
40
40
  if variable:
41
41
  return variable
42
42
 
@@ -52,7 +52,7 @@ class VariableOrFloatField(Field):
52
52
 
53
53
  def _value(self):
54
54
  if self.script:
55
- variable, value = find_variable(self.data, self.script)
55
+ variable, variable_type = find_variable(self.data, self.script)
56
56
  if variable:
57
57
  return variable
58
58
 
@@ -73,14 +73,15 @@ class VariableOrFloatField(Field):
73
73
  try:
74
74
  if self.script:
75
75
  try:
76
- variable, value = find_variable(valuelist[0], self.script)
76
+ variable, variable_type = find_variable(valuelist[0], self.script)
77
77
  if variable:
78
- float(value)
79
- self.data = str(variable)
78
+ if not variable_type == "function_output":
79
+ if variable_type not in ["float", "int"]:
80
+ raise ValueError("Variable is not a valid float")
81
+ self.data = variable
80
82
  return
81
83
  except ValueError:
82
84
  pass
83
-
84
85
  self.data = float(valuelist[0])
85
86
  except ValueError as exc:
86
87
  self.data = None
@@ -99,7 +100,7 @@ class VariableOrIntField(Field):
99
100
 
100
101
  def _value(self):
101
102
  if self.script:
102
- variable, value = find_variable(self.data, self.script)
103
+ variable, variable_type = find_variable(self.data, self.script)
103
104
  if variable:
104
105
  return variable
105
106
 
@@ -109,34 +110,16 @@ class VariableOrIntField(Field):
109
110
  return str(self.data)
110
111
  return ""
111
112
 
112
- # def process_data(self, value):
113
- #
114
- # if self.script:
115
- # variable, var_value = find_variable(value, self.script)
116
- # if variable:
117
- # try:
118
- # int(var_value)
119
- # self.data = str(variable)
120
- # return
121
- # except ValueError:
122
- # pass
123
- # if value is None or value is unset_value:
124
- # self.data = None
125
- # return
126
- # try:
127
- # self.data = int(value)
128
- # except (ValueError, TypeError) as exc:
129
- # self.data = None
130
- # raise ValueError(self.gettext("Not a valid integer value.")) from exc
131
-
132
113
  def process_formdata(self, valuelist):
133
114
  if not valuelist:
134
115
  return
135
116
  if self.script:
136
- variable, var_value = find_variable(valuelist[0], self.script)
117
+ variable, variable_type = find_variable(valuelist[0], self.script)
137
118
  if variable:
138
119
  try:
139
- int(var_value)
120
+ if not variable_type == "function_output":
121
+ if not variable_type == "int":
122
+ raise ValueError("Not a valid integer value")
140
123
  self.data = str(variable)
141
124
  return
142
125
  except ValueError:
@@ -155,6 +138,7 @@ class VariableOrIntField(Field):
155
138
 
156
139
  class VariableOrBoolField(BooleanField):
157
140
  widget = TextInput()
141
+ false_values = (False, "false", "", "False", "f", "F")
158
142
 
159
143
  def __init__(self, label='', validators=None, script=None, **kwargs):
160
144
  super(VariableOrBoolField, self).__init__(label, validators, **kwargs)
@@ -163,30 +147,34 @@ class VariableOrBoolField(BooleanField):
163
147
  def process_data(self, value):
164
148
 
165
149
  if self.script:
166
- variable, var_value = find_variable(value, self.script)
150
+ variable, variable_type = find_variable(value, self.script)
167
151
  if variable:
168
- try:
169
- bool(var_value)
170
- return variable
171
- except ValueError:
172
- return
152
+ if not variable_type == "function_output":
153
+ raise ValueError("Not accepting boolean variables")
154
+ return variable
173
155
 
174
156
  self.data = bool(value)
175
157
 
176
158
  def process_formdata(self, valuelist):
177
- if not valuelist or type(valuelist) is list and valuelist[0] == '':
159
+ # todo
160
+ # print(valuelist)
161
+ if not valuelist or not type(valuelist) is list:
178
162
  self.data = False
179
- elif valuelist and valuelist[0].startswith("#"):
180
- if not self.script.editing_type == "script":
181
- raise ValueError(self.gettext("Variable is not supported in prep/cleanup"))
182
- self.data = valuelist[0]
183
163
  else:
184
- self.data = True
164
+ value = valuelist[0] if type(valuelist) is list else valuelist
165
+ if value.startswith("#"):
166
+ if not self.script.editing_type == "script":
167
+ raise ValueError(self.gettext("Variable is not supported in prep/cleanup"))
168
+ self.data = valuelist[0]
169
+ elif value in self.false_values:
170
+ self.data = False
171
+ else:
172
+ self.data = True
185
173
 
186
174
  def _value(self):
187
175
 
188
176
  if self.script:
189
- variable, value = find_variable(self.raw_data, self.script)
177
+ variable, variable_type = find_variable(self.raw_data, self.script)
190
178
  if variable:
191
179
  return variable
192
180
 
@@ -202,7 +190,15 @@ def format_name(name):
202
190
  return text.capitalize()
203
191
 
204
192
 
205
- def create_form_for_method(method, method_name, autofill, script=None, design=True):
193
+ def create_form_for_method(method, autofill, script=None, design=True):
194
+ """
195
+ Create forms for each method or signature
196
+ :param method: dict(docstring, signature)
197
+ :param autofill:bool if autofill is enabled
198
+ :param script:Script object
199
+ :param design: if design is enabled
200
+ """
201
+
206
202
  class DynamicForm(FlaskForm):
207
203
  pass
208
204
 
@@ -238,40 +234,125 @@ def create_form_for_method(method, method_name, autofill, script=None, design=Tr
238
234
  return DynamicForm
239
235
 
240
236
 
241
- # Create forms for each method in DummySDLDeck
242
- def create_add_form(attr, attr_name, autofill, script=None, design=True):
243
- dynamic_form = create_form_for_method(attr, attr_name, autofill, script, design)
237
+ def create_add_form(attr, attr_name, autofill: bool, script=None, design: bool = True):
238
+ """
239
+ Create forms for each method or signature
240
+ :param attr: dict(docstring, signature)
241
+ :param attr_name: method name
242
+ :param autofill:bool if autofill is enabled
243
+ :param script:Script object
244
+ :param design: if design is enabled. Design allows string input for parameter names ("#param") for all fields
245
+ """
246
+ signature = attr.get('signature', {})
247
+ docstring = attr.get('docstring', "")
248
+ dynamic_form = create_form_for_method(signature, autofill, script, design)
244
249
  if design:
245
250
  return_value = StringField(label='Save value as', render_kw={"placeholder": "Optional"})
246
251
  setattr(dynamic_form, 'return', return_value)
247
- hidden_method_name = HiddenField(name=f'hidden_name', render_kw={"value": f'{attr_name}'})
252
+ hidden_method_name = HiddenField(name=f'hidden_name', description=docstring, render_kw={"value": f'{attr_name}'})
248
253
  setattr(dynamic_form, 'hidden_name', hidden_method_name)
249
254
  return dynamic_form
250
255
 
251
256
 
252
- def create_form_from_module(sdl_module, autofill: bool, script=None, design=True):
253
- # sdl_deck = DummySDLDeck(DummyPump("COM1"), DummyBalance("COM2"))
257
+ def create_form_from_module(sdl_module, autofill: bool = False, script=None, design: bool = False):
258
+ """
259
+ Create forms for each method, used for control routes
260
+ :param sdl_module: method module
261
+ :param autofill:bool if autofill is enabled
262
+ :param script:Script object
263
+ :param design: if design is enabled
264
+ """
254
265
  method_forms = {}
255
266
  for attr_name in dir(sdl_module):
256
- attr = getattr(sdl_module, attr_name)
257
- if inspect.ismethod(attr) and not attr_name.startswith('_'):
267
+ method = getattr(sdl_module, attr_name)
268
+ if inspect.ismethod(method) and not attr_name.startswith('_'):
269
+ signature = inspect.signature(method)
270
+ docstring = inspect.getdoc(method)
271
+ attr = dict(signature=signature, docstring=docstring)
258
272
  form_class = create_add_form(attr, attr_name, autofill, script, design)
259
273
  method_forms[attr_name] = form_class()
260
274
  return method_forms
261
275
 
262
276
 
263
277
  def create_form_from_pseudo(pseudo: dict, autofill: bool, script=None, design=True):
264
- '''{'dose_liquid': < Signature(amount_in_ml: float, rate_ml_per_minute: float) >}'''
278
+ """
279
+ Create forms for pseudo method, used for design routes
280
+ :param pseudo:{'dose_liquid': {
281
+ "docstring": "some docstring",
282
+ "signature": Signature(amount_in_ml: float, rate_ml_per_minute: float) }
283
+ }
284
+ :param autofill:bool if autofill is enabled
285
+ :param script:Script object
286
+ :param design: if design is enabled
287
+ """
265
288
  method_forms = {}
266
289
  for attr_name, signature in pseudo.items():
290
+ # signature = info.get('signature', {})
267
291
  form_class = create_add_form(signature, attr_name, autofill, script, design)
268
292
  method_forms[attr_name] = form_class()
269
293
  return method_forms
270
294
 
271
295
 
272
- def create_builtin_form(logic_type, autofill, script):
296
+ def create_form_from_action(action: dict, script=None, design=True):
297
+ '''
298
+ Create forms for single action, used for design routes
299
+ :param action: {'action': 'dose_solid', 'arg_types': {'amount_in_mg': 'float', 'bring_in': 'bool'},
300
+ 'args': {'amount_in_mg': 5.0, 'bring_in': False}, 'id': 9,
301
+ 'instrument': 'deck.sdl', 'return': '', 'uuid': 266929188668995}
302
+ :param script:Script object
303
+ :param design: if design is enabled
304
+
305
+ '''
306
+
307
+ arg_types = action.get("arg_types", {})
308
+ args = action.get("args", {})
309
+ save_as = action.get("return")
310
+
311
+ class DynamicForm(FlaskForm):
312
+ pass
313
+
314
+ annotation_mapping = {
315
+ "int": (VariableOrIntField if design else IntegerField, 'Enter integer value'),
316
+ "float": (VariableOrFloatField if design else FloatField, 'Enter numeric value'),
317
+ "str": (VariableOrStringField if design else StringField, 'Enter text'),
318
+ "bool": (VariableOrBoolField if design else BooleanField, 'Empty for false')
319
+ }
320
+
321
+ for name, param_type in arg_types.items():
322
+ formatted_param_name = format_name(name)
323
+ value = args.get(name, "")
324
+ if type(value) is dict:
325
+ value = next(iter(value))
326
+ field_kwargs = {
327
+ "label": formatted_param_name,
328
+ "default": f'{value}',
329
+ "validators": [InputRequired()],
330
+ **({"script": script})
331
+ }
332
+ param_type = param_type if type(param_type) is str else f"{param_type}"
333
+ field_class, placeholder_text = annotation_mapping.get(
334
+ param_type,
335
+ (VariableOrStringField if design else StringField, f'Enter {param_type} value')
336
+ )
337
+ render_kwargs = {"placeholder": placeholder_text}
338
+
339
+ # Create the field with additional rendering kwargs for placeholder text
340
+ field = field_class(**field_kwargs, render_kw=render_kwargs)
341
+ setattr(DynamicForm, name, field)
342
+
343
+ if design:
344
+ return_value = StringField(label='Save value as', default=f"{save_as}", render_kw={"placeholder": "Optional"})
345
+ setattr(DynamicForm, 'return', return_value)
346
+ return DynamicForm()
347
+
348
+
349
+ def create_builtin_form(logic_type, script):
350
+ """
351
+ Create a builtin form {if, while, variable, repeat, wait}
352
+ """
273
353
  class BuiltinFunctionForm(FlaskForm):
274
354
  pass
355
+
275
356
  placeholder_text = {
276
357
  'wait': 'Enter second',
277
358
  'repeat': 'Enter an integer'
@@ -296,33 +377,63 @@ def create_builtin_form(logic_type, autofill, script):
296
377
  variable_field = StringField(label=f'variable', validators=[InputRequired()],
297
378
  description="Your variable name cannot include space",
298
379
  render_kw=render_kwargs)
380
+ type_field = SelectField(
381
+ 'Select Input Type',
382
+ choices=[('int', 'Integer'), ('float', 'Float'), ('str', 'String')],
383
+ default='str' # Optional default value
384
+ )
299
385
  setattr(BuiltinFunctionForm, "variable", variable_field)
386
+ setattr(BuiltinFunctionForm, "type", type_field)
300
387
  hidden_field = HiddenField(name=f'builtin_name', render_kw={"value": f'{logic_type}'})
301
388
  setattr(BuiltinFunctionForm, "builtin_name", hidden_field)
302
389
  return BuiltinFunctionForm()
303
390
 
304
391
 
305
- def create_action_button(s: dict):
306
- if s['instrument'] in ['if', 'while', 'repeat']:
307
- text = f"{s['action']} {s['args']}"
308
- elif s['instrument'] == 'variable':
309
- text = f"{s['action']} = {s['args']}"
310
- else:
311
- # regular action button
312
- prefix = f"{s['return']} = " if s['return'] else ""
313
- action_text = f"{s['instrument'].split('.')[-1] if s['instrument'].startswith('deck') else s['instrument']}.{s['action']}"
314
- arg_string = ""
315
- if s['args']:
316
- if type(s['args']) is dict:
317
- arg_string = "(" + ", ".join([f"{k} = {v}" for k, v in s['args'].items()]) + ")"
318
- else:
319
- arg_string = f"= {s['args']}"
392
+ def create_action_button(script, stype=None):
393
+ """
394
+ Creates action buttons for design route (design canvas)
395
+ :param script: Script object
396
+ :param stype: script type (script, prep, cleanup)
397
+ """
398
+ stype = stype or script.editing_type
399
+ variables = script.get_variables()
400
+ return [_action_button(i, variables) for i in script.get_script(stype)]
320
401
 
321
- text = f"{prefix}{action_text} {arg_string}"
402
+
403
+ def _action_button(action: dict, variables: dict):
404
+ """
405
+ Creates action button for one action
406
+ :param action: Action dict
407
+ :param variables: created variable dict
408
+ """
322
409
  style = {
323
410
  "repeat": "background-color: lightsteelblue",
324
411
  "if": "background-color: salmon",
325
412
  "while": "background-color: salmon",
413
+ }.get(action['instrument'], "")
326
414
 
327
- }.get(s['instrument'], "")
328
- return dict(label=text, style=style, uuid=s["uuid"], id=s["id"], instrument=s['instrument'])
415
+ if action['instrument'] in ['if', 'while', 'repeat']:
416
+ text = f"{action['action']} {action['args'].get('statement', '')}"
417
+ elif action['instrument'] == 'variable':
418
+ text = f"{action['action']} = {action['args'].get('statement')}"
419
+ else:
420
+ # regular action button
421
+ prefix = f"{action['return']} = " if action['return'] else ""
422
+ action_text = f"{action['instrument'].split('.')[-1] if action['instrument'].startswith('deck') else action['instrument']}.{action['action']}"
423
+ arg_string = ""
424
+ if action['args']:
425
+ if type(action['args']) is dict:
426
+ arg_list = []
427
+ for k, v in action['args'].items():
428
+ if isinstance(v, dict):
429
+ value = next(iter(v)) # Extract the first key if it's a dict
430
+ # show warning color for variable calling when there is no definition
431
+ style = "background-color: khaki" if value not in variables.keys() else ""
432
+ else:
433
+ value = v # Keep the original value if not a dict
434
+ arg_list.append(f"{k} = {value}") # Format the key-value pair
435
+ arg_string = "(" + ", ".join(arg_list) + ")"
436
+ else:
437
+ arg_string = f"= {action['args']}"
438
+ text = f"{prefix}{action_text} {arg_string}"
439
+ return dict(label=text, style=style, uuid=action["uuid"], id=action["id"], instrument=action['instrument'])
@@ -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,18 +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
- for action in actions:
84
- if self.stop_event.is_set():
85
- logger.info(f"Stopping execution during {section_name} section.")
86
- break
87
- logger.info(f'Executing {action.get("action", "")} action')
88
- fname = f"{run_name}_{section_name}"
89
- function = self.globals_dict[fname]
90
- function()
136
+ if self.stop_pending_event.is_set():
137
+ logger.info(f"Stopping execution during {section_name} section.")
138
+ return
139
+ self.execute_function_line_by_line(func_str, section_name, logger)
91
140
 
92
- def _run_config_section(self, config, arg_type, output_list, return_list, run_name, logger, socketio):
141
+ def _run_config_section(self, config, arg_type, output_list, func_str, run_name, logger, socketio):
93
142
  compiled = True
94
143
  for i in config:
95
144
  try:
@@ -101,25 +150,25 @@ class ScriptRunner:
101
150
  if compiled:
102
151
  for i, kwargs in enumerate(config):
103
152
  kwargs = dict(kwargs)
104
- if self.stop_event.is_set():
153
+ if self.stop_pending_event.is_set():
105
154
  logger.info(f'Stopping execution during {run_name}: {i + 1}/{len(config)}')
106
155
  break
107
156
  logger.info(f'Executing {i + 1} of {len(config)} with kwargs = {kwargs}')
108
157
  progress = (i + 1) * 100 / len(config)
109
158
  self._emit_progress(socketio, progress)
110
- fname = f"{run_name}_script"
111
- function = self.globals_dict[fname]
112
- 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)
113
162
  if output:
114
- kwargs.update(output)
115
- output_list.append(kwargs)
163
+ # kwargs.update(output)
164
+ output_list.append(output)
116
165
 
117
- 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):
118
167
  if bo_args:
119
168
  logger.info('Initializing optimizer...')
120
169
  ax_client = utils.ax_initiation(bo_args, arg_types)
121
170
  for i in range(int(repeat_count)):
122
- if self.stop_event.is_set():
171
+ if self.stop_pending_event.is_set():
123
172
  logger.info(f'Stopping execution during {run_name}: {i + 1}/{int(repeat_count)}')
124
173
  break
125
174
  logger.info(f'Executing {run_name} experiment: {i + 1}/{int(repeat_count)}')
@@ -129,20 +178,20 @@ class ScriptRunner:
129
178
  try:
130
179
  parameters, trial_index = ax_client.get_next_trial()
131
180
  logger.info(f'Output value: {parameters}')
132
- fname = f"{run_name}_script"
133
- function = self.globals_dict[fname]
134
- output = function(**parameters)
135
- # output = eval(f"{run_name}_script(**{parameters})")
136
- _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}
137
186
  ax_client.complete_trial(trial_index=trial_index, raw_data=_output)
138
187
  output.update(parameters)
139
188
  except Exception as e:
140
189
  logger.info(f'Optimization error: {e}')
141
190
  break
142
191
  else:
143
- fname = f"{run_name}_script"
144
- function = self.globals_dict[fname]
145
- 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)
146
195
 
147
196
  if output:
148
197
  output_list.append(output)