ivoryos 0.1.12__py3-none-any.whl → 0.1.18__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 +50 -14
- ivoryos/routes/control/templates/control/controllers.html +3 -0
- ivoryos/routes/design/design.py +46 -40
- ivoryos/routes/design/templates/design/experiment_builder.html +23 -10
- ivoryos/routes/main/templates/main/home.html +19 -17
- ivoryos/templates/base.html +20 -10
- ivoryos/utils/db_models.py +157 -61
- ivoryos/utils/form.py +192 -81
- ivoryos/utils/script_runner.py +11 -8
- ivoryos/utils/utils.py +13 -41
- ivoryos/version.py +1 -1
- {ivoryos-0.1.12.dist-info → ivoryos-0.1.18.dist-info}/METADATA +4 -1
- {ivoryos-0.1.12.dist-info → ivoryos-0.1.18.dist-info}/RECORD +16 -17
- {ivoryos-0.1.12.dist-info → ivoryos-0.1.18.dist-info}/WHEEL +1 -1
- ivoryos/static/.DS_Store +0 -0
- {ivoryos-0.1.12.dist-info → ivoryos-0.1.18.dist-info}/LICENSE +0 -0
- {ivoryos-0.1.12.dist-info → ivoryos-0.1.18.dist-info}/top_level.txt +0 -0
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
76
|
+
variable, variable_type = find_variable(valuelist[0], self.script)
|
|
77
77
|
if variable:
|
|
78
|
-
|
|
79
|
-
|
|
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,
|
|
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,
|
|
117
|
+
variable, variable_type = find_variable(valuelist[0], self.script)
|
|
137
118
|
if variable:
|
|
138
119
|
try:
|
|
139
|
-
|
|
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,
|
|
150
|
+
variable, variable_type = find_variable(value, self.script)
|
|
167
151
|
if variable:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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=
|
|
253
|
-
|
|
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
|
-
|
|
257
|
-
if inspect.ismethod(
|
|
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
|
-
|
|
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
|
|
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(
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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
|
-
|
|
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
|
-
|
|
328
|
-
|
|
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'])
|
ivoryos/utils/script_runner.py
CHANGED
|
@@ -80,14 +80,17 @@ class ScriptRunner:
|
|
|
80
80
|
|
|
81
81
|
def _run_actions(self, actions, section_name="", run_name=None, logger=None):
|
|
82
82
|
logger.info(f'Executing {section_name} steps') if actions else logger.info(f'No {section_name} steps')
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
83
|
+
if self.stop_event.is_set():
|
|
84
|
+
logger.info(f"Stopping execution during {section_name} section.")
|
|
85
|
+
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()
|
|
91
94
|
|
|
92
95
|
def _run_config_section(self, config, arg_type, output_list, return_list, run_name, logger, socketio):
|
|
93
96
|
compiled = True
|
ivoryos/utils/utils.py
CHANGED
|
@@ -7,7 +7,6 @@ import pickle
|
|
|
7
7
|
import subprocess
|
|
8
8
|
import sys
|
|
9
9
|
from collections import Counter
|
|
10
|
-
from typing import Optional, Dict, Tuple
|
|
11
10
|
|
|
12
11
|
from flask import session
|
|
13
12
|
from flask_socketio import SocketIO
|
|
@@ -84,7 +83,6 @@ def available_pseudo_deck(path):
|
|
|
84
83
|
"""
|
|
85
84
|
load pseudo deck (snapshot) from connection history
|
|
86
85
|
"""
|
|
87
|
-
import os
|
|
88
86
|
return os.listdir(path)
|
|
89
87
|
|
|
90
88
|
|
|
@@ -103,20 +101,9 @@ def _inspect_class(class_object=None, debug=False):
|
|
|
103
101
|
if not function.startswith(under_score) and not function.isupper():
|
|
104
102
|
try:
|
|
105
103
|
annotation = inspect.signature(method)
|
|
106
|
-
# if doc_string:
|
|
107
104
|
docstring = inspect.getdoc(method)
|
|
108
105
|
functions[function] = dict(signature=annotation, docstring=docstring)
|
|
109
106
|
|
|
110
|
-
# handle getter setters todo
|
|
111
|
-
# if callable(att):
|
|
112
|
-
# functions[function] = inspect.signature(att)
|
|
113
|
-
# else:
|
|
114
|
-
# att = getattr(class_object.__class__, function)
|
|
115
|
-
# if isinstance(att, property) and att.fset is not None:
|
|
116
|
-
# setter = att.fset.__annotations__
|
|
117
|
-
# setter.pop('return', None)
|
|
118
|
-
# if setter:
|
|
119
|
-
# functions[function] = setter
|
|
120
107
|
except Exception:
|
|
121
108
|
pass
|
|
122
109
|
return functions
|
|
@@ -132,36 +119,22 @@ def _get_type_from_parameters(arg, parameters):
|
|
|
132
119
|
if annotation is not inspect._empty:
|
|
133
120
|
# print(p[arg].annotation)
|
|
134
121
|
if annotation.__module__ == 'typing':
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
122
|
+
|
|
123
|
+
if hasattr(annotation, '__origin__'):
|
|
124
|
+
origin = annotation.__origin__
|
|
125
|
+
if hasattr(origin, '_name') and origin._name in ["Optional", "Union"]:
|
|
126
|
+
arg_type = [i.__name__ for i in annotation.__args__]
|
|
127
|
+
elif hasattr(origin, '__name__'):
|
|
128
|
+
arg_type = origin.__name__
|
|
129
|
+
# todo other types
|
|
130
|
+
elif annotation.__module__ == 'types':
|
|
131
|
+
arg_type = [i.__name__ for i in annotation.__args__]
|
|
132
|
+
|
|
143
133
|
else:
|
|
144
134
|
arg_type = annotation.__name__
|
|
145
135
|
return arg_type
|
|
146
136
|
|
|
147
137
|
|
|
148
|
-
def find_variable_in_script(script: Script, args: Dict[str, str]) -> Optional[Tuple[Dict[str, str], Dict[str, str]]]:
|
|
149
|
-
# TODO: need to search for if the variable exists
|
|
150
|
-
added_variables: list[Dict[str, str]] = [action for action in script.currently_editing_script if
|
|
151
|
-
action["instrument"] == "variable"]
|
|
152
|
-
|
|
153
|
-
possible_variable_arguments = {}
|
|
154
|
-
possible_variable_types = {}
|
|
155
|
-
|
|
156
|
-
for arg_name, arg_val in args.items():
|
|
157
|
-
for added_variable in added_variables:
|
|
158
|
-
if added_variable["action"] == arg_val:
|
|
159
|
-
possible_variable_arguments[arg_name] = added_variable["action"]
|
|
160
|
-
possible_variable_types[arg_name] = "variable"
|
|
161
|
-
|
|
162
|
-
return possible_variable_arguments, possible_variable_types
|
|
163
|
-
|
|
164
|
-
|
|
165
138
|
def _convert_by_str(args, arg_types):
|
|
166
139
|
"""
|
|
167
140
|
Converts a value to type through eval(f'{type}("{args}")')
|
|
@@ -201,9 +174,6 @@ def convert_config_type(args, arg_types, is_class: bool = False):
|
|
|
201
174
|
"""
|
|
202
175
|
Converts an argument from str to an arg type
|
|
203
176
|
"""
|
|
204
|
-
bool_dict = {"True": True, "False": False}
|
|
205
|
-
# print(args, arg_types)
|
|
206
|
-
# print(globals())
|
|
207
177
|
if args:
|
|
208
178
|
for arg in args:
|
|
209
179
|
if arg not in arg_types.keys():
|
|
@@ -338,8 +308,10 @@ def ax_initiation(data, arg_types):
|
|
|
338
308
|
|
|
339
309
|
|
|
340
310
|
def get_arg_type(args, parameters):
|
|
311
|
+
"""get argument type from signature"""
|
|
341
312
|
arg_types = {}
|
|
342
313
|
# print(args, parameters)
|
|
314
|
+
parameters = parameters.get("signature")
|
|
343
315
|
if args:
|
|
344
316
|
for arg in args:
|
|
345
317
|
arg_types[arg] = _get_type_from_parameters(arg, parameters)
|
ivoryos/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.18"
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ivoryos
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.18
|
|
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
|
|
7
7
|
Author-email: ivoryzhang@chem.ubc.ca
|
|
8
8
|
License: MIT
|
|
9
|
+
Platform: UNKNOWN
|
|
9
10
|
Description-Content-Type: text/markdown
|
|
10
11
|
License-File: LICENSE
|
|
11
12
|
Requires-Dist: bcrypt
|
|
@@ -168,3 +169,5 @@ https://youtu.be/dFfJv9I2-1g
|
|
|
168
169
|
Ivory Zhang, Lucy Hao
|
|
169
170
|
|
|
170
171
|
Authors acknowledge all former and current Hein Lab members for their valuable suggestions.
|
|
172
|
+
|
|
173
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
ivoryos/__init__.py,sha256=
|
|
1
|
+
ivoryos/__init__.py,sha256=F3KenDZX1zqei3PZ3tx1U77yXsbeytgMMhVJyJMkmJ0,6071
|
|
2
2
|
ivoryos/config.py,sha256=3FPBYTIBhQTKDvsEoR8ZeTmg65D-CSFEdGmOuIL4pSI,1311
|
|
3
|
-
ivoryos/version.py,sha256=
|
|
3
|
+
ivoryos/version.py,sha256=6BiuMUkhwQp6bzUZSF8np8F1NwCltEtK0sPBF__tepU,23
|
|
4
4
|
ivoryos/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
ivoryos/routes/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
ivoryos/routes/auth/auth.py,sha256=7CdXjGAr1B_xsmwweakTWOoROgsOJf0MNTzlMP_5Nus,3240
|
|
@@ -8,21 +8,20 @@ ivoryos/routes/auth/templates/auth/login.html,sha256=WSRrKbdM_oobqSXFRTo-j9UlOgp
|
|
|
8
8
|
ivoryos/routes/auth/templates/auth/signup.html,sha256=b5LTXtpfTSkSS7X8u1ldwQbbgEFTk6UNMAediA5BwBY,1465
|
|
9
9
|
ivoryos/routes/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
ivoryos/routes/control/control.py,sha256=MmrcKrkjSKS589XhDdvPc7kWO0ApCNVZCtrgfzTAAN8,14163
|
|
11
|
-
ivoryos/routes/control/templates/control/controllers.html,sha256=
|
|
11
|
+
ivoryos/routes/control/templates/control/controllers.html,sha256=iIp0h6WA68gQj9OsoiB7dU1BqH8CGomTueR73F4C8eY,4274
|
|
12
12
|
ivoryos/routes/control/templates/control/controllers_home.html,sha256=xFnBXTWMlyi2naMSsCEqFlX-Z1HJJDDtzITPvq-3nng,2733
|
|
13
13
|
ivoryos/routes/control/templates/control/controllers_new.html,sha256=uOQo9kYmwX2jk3KZDkMUF_ylfNUIs_oIWb_kk_MMVDM,4921
|
|
14
14
|
ivoryos/routes/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
ivoryos/routes/database/database.py,sha256=IOrdtdsZ28bV7R1ZQfcwAeS5JDCkX-QYsP9i8BseD38,5684
|
|
16
16
|
ivoryos/routes/database/templates/database/experiment_database.html,sha256=ABchwHYDovzwECc7UD4Mh8C_9JUl0YZpAAF9sFjNCs0,3434
|
|
17
17
|
ivoryos/routes/design/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
-
ivoryos/routes/design/design.py,sha256=
|
|
19
|
-
ivoryos/routes/design/templates/design/experiment_builder.html,sha256
|
|
18
|
+
ivoryos/routes/design/design.py,sha256=489QCfjcCZuL7HKAvZVrxIL1wK4IhE0zUef_mmbNuMs,21003
|
|
19
|
+
ivoryos/routes/design/templates/design/experiment_builder.html,sha256=-C84nHcK1grC8b_B5Lgbg6StJcP8x1oj2XAjRPj1oU0,28239
|
|
20
20
|
ivoryos/routes/design/templates/design/experiment_run.html,sha256=JxYEbJqeJH8vZaSVI25EtNYmI_W5GSFdc02Y8y3kZGc,22543
|
|
21
21
|
ivoryos/routes/main/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
ivoryos/routes/main/main.py,sha256=yuVJzXAob1kc1dfflkTBIZQ0tdf6kChfuq-uQlN1e9Q,957
|
|
23
23
|
ivoryos/routes/main/templates/main/help.html,sha256=IOktMEsOPk0SCiMBXZ4mpffClERAyX8W82fel71M3M0,9370
|
|
24
|
-
ivoryos/routes/main/templates/main/home.html,sha256=
|
|
25
|
-
ivoryos/static/.DS_Store,sha256=skh9ta8MJo1eOfvLDKqqVRNKQXFH2Wfse7ybGMLytNs,6148
|
|
24
|
+
ivoryos/routes/main/templates/main/home.html,sha256=ujM0YC0yrHhCfkuprNnZZZd8XEEguS_6NjrY5ktfctg,3356
|
|
26
25
|
ivoryos/static/favicon.ico,sha256=RhlrPtfITOkzC9BjP1UB1V5L9Oyp6NwNtWeMcGOnpyc,15406
|
|
27
26
|
ivoryos/static/logo.webp,sha256=lXgfQR-4mHTH83k7VV9iB54-oC2ipe6uZvbwdOnLETc,14974
|
|
28
27
|
ivoryos/static/style.css,sha256=cbQ8T8h42smwuyF5qQ_pNhlptDXGcuyK2u4sUppqnyI,3717
|
|
@@ -32,16 +31,16 @@ ivoryos/static/js/overlay.js,sha256=dPxop19es0E0ZUSY3d_4exIk7CJuQEnlW5uTt5fZfzI,
|
|
|
32
31
|
ivoryos/static/js/socket_handler.js,sha256=O7r33couafOE9QCvUK9mP0kJRiBFw2K-Qk1cjtMI5Vg,1415
|
|
33
32
|
ivoryos/static/js/sortable_card.js,sha256=ifmlGe3yy0U_KzMphV4ClRhK2DLOvkELYMlq1vECuac,807
|
|
34
33
|
ivoryos/static/js/sortable_design.js,sha256=1lI1I8FbL66tv6n-SX2FkbHNDYo36xVo2qDBKVLmxnQ,1120
|
|
35
|
-
ivoryos/templates/base.html,sha256=
|
|
34
|
+
ivoryos/templates/base.html,sha256=8HDi7I74ugcCAV4c3ha4C__-7xopt4ZsC0OQ2E_AsQ8,8313
|
|
36
35
|
ivoryos/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
|
-
ivoryos/utils/db_models.py,sha256=
|
|
38
|
-
ivoryos/utils/form.py,sha256=
|
|
36
|
+
ivoryos/utils/db_models.py,sha256=Y0KymXvb5uHwXwDrtUpc9DNxCBH9pHCmU39Hf4Hwlv4,24835
|
|
37
|
+
ivoryos/utils/form.py,sha256=1h6eytHz1tv5_CIc_C6KGYn5JEPYniIOxo49yzM37o0,17149
|
|
39
38
|
ivoryos/utils/global_config.py,sha256=Ojcz6xKATSbMLnTT0kiKqSnu_bNqCMyIAnZyHaKxJns,1589
|
|
40
39
|
ivoryos/utils/llm_agent.py,sha256=DTf-AF56vy1Em1fUKagl5NURKittmNoxTKIw1PlyC2o,6413
|
|
41
|
-
ivoryos/utils/script_runner.py,sha256=
|
|
42
|
-
ivoryos/utils/utils.py,sha256=
|
|
43
|
-
ivoryos-0.1.
|
|
44
|
-
ivoryos-0.1.
|
|
45
|
-
ivoryos-0.1.
|
|
46
|
-
ivoryos-0.1.
|
|
47
|
-
ivoryos-0.1.
|
|
40
|
+
ivoryos/utils/script_runner.py,sha256=DImUy5jfv64lrF8CnQf0HGJjnesi7D8uqh4a939ihEQ,7231
|
|
41
|
+
ivoryos/utils/utils.py,sha256=nQbGSR_FmlZyBb9lwKy3ws4FDAWWfDyu96hZg2DVIeI,14081
|
|
42
|
+
ivoryos-0.1.18.dist-info/LICENSE,sha256=p2c8S8i-8YqMpZCJnadLz1-ofxnRMILzz6NCMIypRag,1084
|
|
43
|
+
ivoryos-0.1.18.dist-info/METADATA,sha256=ldWGQwTTe0M5hF4qi-kWrB0NJUCFvHjRL7F0cOwxq4g,6355
|
|
44
|
+
ivoryos-0.1.18.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
45
|
+
ivoryos-0.1.18.dist-info/top_level.txt,sha256=FRIWWdiEvRKqw-XfF_UK3XV0CrnNb6EmVbEgjaVazRM,8
|
|
46
|
+
ivoryos-0.1.18.dist-info/RECORD,,
|
ivoryos/static/.DS_Store
DELETED
|
Binary file
|
|
File without changes
|
|
File without changes
|