ivoryos 0.1.10__py3-none-any.whl → 0.1.12__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 CHANGED
@@ -51,6 +51,10 @@ def create_app(config_class=None):
51
51
 
52
52
  @app.before_request
53
53
  def before_request():
54
+ """
55
+ Called before
56
+
57
+ """
54
58
  from flask import g
55
59
  g.logger = logger
56
60
  g.socketio = socketio
@@ -187,7 +187,7 @@ def backend_control(instrument: str=None):
187
187
  return json_output, 400
188
188
  else:
189
189
  return "instrument not exist", 400
190
- return '', 200
190
+ return json_output, 200
191
191
 
192
192
 
193
193
  @control.route("/backend_control", methods=['GET'])
@@ -106,8 +106,8 @@ def experiment_builder(instrument=None):
106
106
  deck_variables = list(pseudo_deck.keys()) if pseudo_deck else []
107
107
  deck_variables.remove("deck_name") if len(deck_variables) > 0 else deck_variables
108
108
  if instrument:
109
- if instrument in ['if', 'while', 'variable', 'wait']:
110
- forms = create_builtin_form(instrument)
109
+ if instrument in ['if', 'while', 'variable', 'wait', 'repeat']:
110
+ forms = create_builtin_form(instrument, autofill=autofill, script=script)
111
111
  else:
112
112
  if deck:
113
113
  function_metadata = global_config.deck_snapshot.get(instrument, {})
@@ -306,6 +306,8 @@ def experiment_run():
306
306
  logger=g.logger, socketio=g.socketio, repeat_count=repeat,
307
307
  output_path=datapath
308
308
  )
309
+ if utils.check_config_duplicate(config):
310
+ flash(f"WARNING: Duplicate in config entries.")
309
311
  except Exception as e:
310
312
  flash(e)
311
313
  return render_template('experiment_run.html', script=script.script_dict, filename=filename, dot_py=exec_string,
@@ -72,7 +72,7 @@
72
72
  <!-- <div class="rounded flex-fill" style="height: 30px;background-color: aliceblue">-->
73
73
  <!-- <h6 style=" text-align: center; ">{{ format_name(instrument) }}</h6>-->
74
74
  <!-- </div>-->
75
- {% if instrument in ['if' , 'while' , 'variable' ,'wait'] %}
75
+ {% if instrument in ['if' , 'while' , 'variable' ,'wait', 'repeat'] %}
76
76
  {# form for builtin functions #}
77
77
  <form role="form" method='POST' name="{{instrument}}" action="{{url_for('design.experiment_builder',instrument=instrument)}}" >
78
78
  <div class="form-group">
@@ -185,7 +185,7 @@
185
185
  </h5>
186
186
  <div class="accordion-collapse collapse show" id="advanced">
187
187
  <ul class="list-group">
188
- {% for instrument in ['if', 'while', 'variable', 'wait'] %}
188
+ {% for instrument in ['if', 'while', 'variable', 'wait', 'repeat'] %}
189
189
  <form role="form" method='GET' name="device" action="{{url_for('design.experiment_builder',instrument=instrument)}}">
190
190
  <div class="form-group">
191
191
  <button class="list-group-item list-group-item-action" aria-current="true" type="submit">{{instrument}}</button>
@@ -302,7 +302,7 @@
302
302
  {% for button in buttons %}
303
303
  <li id="{{ button['id'] }}" style="list-style-type: none;">
304
304
  <a href="{{ url_for('design.edit_action', uuid=button['uuid']) }}" type="button" class="btn btn-light" style="{{ button['style'] }}">{{ button['label'] }}</a>
305
- {% if not button["instrument"] in ["if","while"] %}
305
+ {% if not button["instrument"] in ["if","while","repeat"] %}
306
306
  <a href="{{ url_for('design.duplicate_action', id=button['id']) }}" type="button" class="btn btn-light"><span class="bi bi-copy"></span></a>
307
307
  {% endif %}
308
308
  <a href="{{ url_for('design.delete_action', id=button['id']) }}" type="button" class="btn btn-light"><span class="bi bi-trash"></span></a>
@@ -403,7 +403,7 @@
403
403
  </div>
404
404
  </div>
405
405
 
406
- {% if instrument and not instrument in ['if' , 'while' , 'variable' ,'wait'] and use_llm %}
406
+ {% if instrument and not instrument in ['if' , 'while' , 'variable' ,'wait', 'repeat'] and use_llm %}
407
407
  <script>
408
408
  const buttonIds = {{ ['generate'] | tojson }};
409
409
  </script>
@@ -50,7 +50,7 @@
50
50
  <form role="form" method='POST' name="run" action="{{url_for('design.experiment_run')}}">
51
51
  <div class="input-group mb-3">
52
52
  <label class="input-group-text" for="repeat">Repeat for </label>
53
- <input class="form-control" type="number" id="repeat" name="repeat" min="1" max="100">
53
+ <input class="form-control" type="number" id="repeat" name="repeat" min="1" max="1000" value="1">
54
54
  <label class="input-group-text" for="repeat"> times</label>
55
55
  </div>
56
56
  {# {% if not no_deck_warning%}#}
@@ -185,7 +185,7 @@
185
185
  <p><h5>Budget:</h5></p>
186
186
  <div class="input-group mb-3">
187
187
  <label class="input-group-text" for="repeat">Max iteration </label>
188
- <input class="form-control" type="number" id="repeat" name="repeat" min="1" max="100">
188
+ <input class="form-control" type="number" id="repeat" name="repeat" min="1" max="1000" value="25">
189
189
  </div>
190
190
  {% if not no_deck_warning%}
191
191
  <div class="input-group mb-3">
@@ -241,6 +241,13 @@ class Script(db.Model):
241
241
  "args": '0' if statement == '' else statement,
242
242
  "return": '', "uuid": uid, "arg_types": "float"},
243
243
  ],
244
+ "repeat":
245
+ [
246
+ {"id": current_len + 1, "instrument": 'repeat', "action": "repeat",
247
+ "args": '1' if statement == '' else statement, "return": '', "uuid": uid, "arg_types": "int"},
248
+ {"id": current_len + 2, "instrument": 'repeat', "action": 'endrepeat',
249
+ "args": '', "return": '', "uuid": uid},
250
+ ],
244
251
  }
245
252
  action_list = logic_dict[logic_type]
246
253
  self.currently_editing_script.extend(action_list)
@@ -366,11 +373,14 @@ class Script(db.Model):
366
373
  """
367
374
  Generate the function header.
368
375
  """
369
- configure, _ = self.config(stype)
376
+ configure, config_type = self.config(stype)
377
+
378
+ configure = [param + f":{param_type}" if not param_type == "any" else "" for param, param_type in config_type.items()]
379
+
370
380
  function_header = f"\n\ndef {run_name}_{stype}("
371
381
 
372
382
  if stype == "script":
373
- function_header += ",".join(configure)
383
+ function_header += ", ".join(configure)
374
384
 
375
385
  function_header += "):"
376
386
  function_header += self.indent(1) + f"global {run_name}_{stype}"
@@ -389,7 +399,6 @@ class Script(db.Model):
389
399
  return_str, return_list = self.config_return()
390
400
  if return_list and stype == "script":
391
401
  body += self.indent(indent_unit) + return_str
392
-
393
402
  return body
394
403
 
395
404
  def _process_action(self, indent_unit, action, index, stype):
@@ -409,6 +418,9 @@ class Script(db.Model):
409
418
  return self.indent(indent_unit) + f"{action_name} = {args}", indent_unit
410
419
  elif instrument == 'wait':
411
420
  return f"{self.indent(indent_unit)}time.sleep({args})", indent_unit
421
+ elif instrument == 'repeat':
422
+ return self._process_repeat(indent_unit, action_name, args, next_action)
423
+
412
424
  else:
413
425
  return self._process_instrument_action(indent_unit, instrument, action_name, args, save_data)
414
426
 
@@ -456,6 +468,20 @@ class Script(db.Model):
456
468
  indent_unit -= 1
457
469
  return exec_string, indent_unit
458
470
 
471
+ def _process_repeat(self, indent_unit, action, args, next_action):
472
+ """
473
+ Process 'while' and 'endwhile' actions.
474
+ """
475
+ exec_string = ""
476
+ if action == 'repeat':
477
+ exec_string += self.indent(indent_unit) + f"for _ in range({args}):"
478
+ indent_unit += 1
479
+ if next_action and next_action['instrument'] == 'repeat':
480
+ exec_string += self.indent(indent_unit) + "pass"
481
+ elif action == 'endrepeat':
482
+ indent_unit -= 1
483
+ return exec_string, indent_unit
484
+
459
485
  def _process_instrument_action(self, indent_unit, instrument, action, args, save_data):
460
486
  """
461
487
  Process actions related to instruments.
ivoryos/utils/form.py CHANGED
@@ -269,17 +269,25 @@ def create_form_from_pseudo(pseudo: dict, autofill: bool, script=None, design=Tr
269
269
  return method_forms
270
270
 
271
271
 
272
- def create_builtin_form(logic_type):
272
+ def create_builtin_form(logic_type, autofill, script):
273
273
  class BuiltinFunctionForm(FlaskForm):
274
274
  pass
275
-
276
- placeholder_text = f'Enter numbers' if logic_type == 'wait' else f'Enter statement'
277
- description_text = f'Your variable can be numbers, boolean (True or False) or text ("text")' if logic_type == 'variable' else ''
278
- field_class = FloatField if logic_type == 'wait' else StringField # Default to StringField as a fallback
275
+ placeholder_text = {
276
+ 'wait': 'Enter second',
277
+ 'repeat': 'Enter an integer'
278
+ }.get(logic_type, 'Enter statement')
279
+ description_text = {
280
+ 'variable': 'Your variable can be numbers, boolean (True or False) or text ("text")',
281
+ }.get(logic_type, '')
282
+ field_class = {
283
+ 'wait': VariableOrFloatField,
284
+ 'repeat': VariableOrIntField
285
+ }.get(logic_type, VariableOrStringField) # Default to StringField as a fallback
279
286
  field_kwargs = {
280
287
  "label": f'statement',
281
288
  "validators": [InputRequired()] if logic_type in ['wait', "variable"] else [],
282
289
  "description": description_text,
290
+ "script": script
283
291
  }
284
292
  render_kwargs = {"placeholder": placeholder_text}
285
293
  field = field_class(**field_kwargs, render_kw=render_kwargs)
@@ -295,10 +303,8 @@ def create_builtin_form(logic_type):
295
303
 
296
304
 
297
305
  def create_action_button(s: dict):
298
- style = ""
299
- if s['instrument'] in ['if', 'while']:
306
+ if s['instrument'] in ['if', 'while', 'repeat']:
300
307
  text = f"{s['action']} {s['args']}"
301
- style = "background-color: tomato"
302
308
  elif s['instrument'] == 'variable':
303
309
  text = f"{s['action']} = {s['args']}"
304
310
  else:
@@ -313,4 +319,10 @@ def create_action_button(s: dict):
313
319
  arg_string = f"= {s['args']}"
314
320
 
315
321
  text = f"{prefix}{action_text} {arg_string}"
322
+ style = {
323
+ "repeat": "background-color: lightsteelblue",
324
+ "if": "background-color: salmon",
325
+ "while": "background-color: salmon",
326
+
327
+ }.get(s['instrument'], "")
316
328
  return dict(label=text, style=style, uuid=s["uuid"], id=s["id"], instrument=s['instrument'])
@@ -133,7 +133,8 @@ class ScriptRunner:
133
133
  function = self.globals_dict[fname]
134
134
  output = function(**parameters)
135
135
  # output = eval(f"{run_name}_script(**{parameters})")
136
- ax_client.complete_trial(trial_index=trial_index, raw_data=output)
136
+ _output = output.copy()
137
+ ax_client.complete_trial(trial_index=trial_index, raw_data=_output)
137
138
  output.update(parameters)
138
139
  except Exception as e:
139
140
  logger.info(f'Optimization error: {e}')
ivoryos/utils/utils.py CHANGED
@@ -6,6 +6,7 @@ import os
6
6
  import pickle
7
7
  import subprocess
8
8
  import sys
9
+ from collections import Counter
9
10
  from typing import Optional, Dict, Tuple
10
11
 
11
12
  from flask import session
@@ -317,8 +318,9 @@ def ax_wrapper(data: dict, arg_types:list):
317
318
  is_min = True if value == "minimize" else False
318
319
 
319
320
  threshold = None if f"{obj_name}_threshold" not in data else data[f"{obj_name}_threshold"]
320
- properties = ObjectiveProperties(minimize=is_min, threshold=threshold)
321
+ properties = ObjectiveProperties(minimize=is_min)
321
322
  objectives[obj_name] = properties
323
+
322
324
  return parameter, objectives
323
325
 
324
326
 
@@ -331,7 +333,7 @@ def ax_initiation(data, arg_types):
331
333
  parameter, objectives = ax_wrapper(data, arg_types)
332
334
  from ax.service.ax_client import AxClient
333
335
  ax_client = AxClient()
334
- ax_client.create_experiment(parameter, objectives)
336
+ ax_client.create_experiment(parameter, objectives=objectives)
335
337
  return ax_client
336
338
 
337
339
 
@@ -423,3 +425,13 @@ def load_deck(pkl_name: str):
423
425
  return pseudo_deck
424
426
  except FileNotFoundError:
425
427
  return None
428
+
429
+
430
+ def check_config_duplicate(config):
431
+ """
432
+ Checks if the config entry has any duplicate
433
+ :param config: [{"arg": 1}, {"arg": 1}, {"arg": 1}]
434
+ :return: [True, False]
435
+ """
436
+ hashable_data = [tuple(sorted(d.items())) for d in config]
437
+ return any(count > 1 for count in Counter(hashable_data).values())
ivoryos/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.10"
1
+ __version__ = "0.1.12"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ivoryos
3
- Version: 0.1.10
3
+ Version: 0.1.12
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
@@ -1,13 +1,13 @@
1
- ivoryos/__init__.py,sha256=UesIiRxex8LSz0zECPf6NpefKD-rwui2ZCdA5c7tAeM,4696
1
+ ivoryos/__init__.py,sha256=pKaEGt1aqh4U0ofAVm2jdhyoyrR1jYlEO-Qi2T7Sfp4,4743
2
2
  ivoryos/config.py,sha256=3FPBYTIBhQTKDvsEoR8ZeTmg65D-CSFEdGmOuIL4pSI,1311
3
- ivoryos/version.py,sha256=z0zCHFTcKSR0tJ6h5qrpNmRVP21QIPP8N0p7quCnnm0,23
3
+ ivoryos/version.py,sha256=LcIlFjHZFfiF9Rd4UHoakmombOFkxIYk00I181frGBM,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
7
7
  ivoryos/routes/auth/templates/auth/login.html,sha256=WSRrKbdM_oobqSXFRTo-j9UlOgp6sYzS9tm7TqqPULI,1207
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
- ivoryos/routes/control/control.py,sha256=iQTOKqkYFvJArNfdhv5ZtF0CVXDUmPxodHvwjmB1rdo,14154
10
+ ivoryos/routes/control/control.py,sha256=MmrcKrkjSKS589XhDdvPc7kWO0ApCNVZCtrgfzTAAN8,14163
11
11
  ivoryos/routes/control/templates/control/controllers.html,sha256=QdZAieEA4ODC-3KlsgHmFO35q8KXjm0KT43ZNpcBgEs,4084
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
@@ -15,9 +15,9 @@ ivoryos/routes/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
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=sWau2fYkwWQwlSuAZjFgbf6QRPCq7eJB5obO-kwYWZE,20715
19
- ivoryos/routes/design/templates/design/experiment_builder.html,sha256=B9JSH27oTAW5rDisaB18bIBPLINs-TDC4ol6AVjcTm4,27288
20
- ivoryos/routes/design/templates/design/experiment_run.html,sha256=u-VS6C1i_ErhrtCHGEA57i7JIB3TbKdnvNjI4ey0yXU,22520
18
+ ivoryos/routes/design/design.py,sha256=ZAUh-XOMhePCmY7q-hfru-4X6fDR3aKKyktrD2NC6M4,20876
19
+ ivoryos/routes/design/templates/design/experiment_builder.html,sha256=lF8fDMHtwQjVznbCL4klV3o1p0tkqMptPY5IXR7WSuE,27327
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
@@ -34,14 +34,14 @@ ivoryos/static/js/sortable_card.js,sha256=ifmlGe3yy0U_KzMphV4ClRhK2DLOvkELYMlq1v
34
34
  ivoryos/static/js/sortable_design.js,sha256=1lI1I8FbL66tv6n-SX2FkbHNDYo36xVo2qDBKVLmxnQ,1120
35
35
  ivoryos/templates/base.html,sha256=OR04eHEgmq4Wj0en3z6J2l-CdcJjZryRBjLsWyKdnCo,7800
36
36
  ivoryos/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
- ivoryos/utils/db_models.py,sha256=CWBPJaBiLj2QioOsBw1PxoGd6vTtQSlo67fg8nCkfL8,19691
38
- ivoryos/utils/form.py,sha256=CYS8XzJsz2ff4xalXFQXbJosCjY7P8khi7A_MmvMc2A,12028
37
+ ivoryos/utils/db_models.py,sha256=XoReukuWiroDX4OTfyd9dHRpGIN2woWL017P7N-VZ0U,20918
38
+ ivoryos/utils/form.py,sha256=zpEFUyx9nMZkkTYVL0DIT3kEWd1DQsDGSBu4UysXf4s,12338
39
39
  ivoryos/utils/global_config.py,sha256=Ojcz6xKATSbMLnTT0kiKqSnu_bNqCMyIAnZyHaKxJns,1589
40
40
  ivoryos/utils/llm_agent.py,sha256=DTf-AF56vy1Em1fUKagl5NURKittmNoxTKIw1PlyC2o,6413
41
- ivoryos/utils/script_runner.py,sha256=t0K-TxhiRDNl__tx9H4aW9K2z1k2oWBCt3qPyTTymOo,7034
42
- ivoryos/utils/utils.py,sha256=AGG_1bqV52K23ujIKXkckClUXcuvGvZdtVWJ1Pxml9Q,15025
43
- ivoryos-0.1.10.dist-info/LICENSE,sha256=p2c8S8i-8YqMpZCJnadLz1-ofxnRMILzz6NCMIypRag,1084
44
- ivoryos-0.1.10.dist-info/METADATA,sha256=NSPuLi_YIePqKUKgDBXWvupOvz1WeveHZYXJFdWk-U0,6335
45
- ivoryos-0.1.10.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
46
- ivoryos-0.1.10.dist-info/top_level.txt,sha256=FRIWWdiEvRKqw-XfF_UK3XV0CrnNb6EmVbEgjaVazRM,8
47
- ivoryos-0.1.10.dist-info/RECORD,,
41
+ ivoryos/utils/script_runner.py,sha256=sFAUGCcfsA8DEPgw7koqEAr9fnxxYNRuiOC3L3yOwwc,7079
42
+ ivoryos/utils/utils.py,sha256=5pNF5QJMXmImxDR0IRqaMzIy9n0fD_M1SUY1v9koEc8,15368
43
+ ivoryos-0.1.12.dist-info/LICENSE,sha256=p2c8S8i-8YqMpZCJnadLz1-ofxnRMILzz6NCMIypRag,1084
44
+ ivoryos-0.1.12.dist-info/METADATA,sha256=-aWjCWBd57wVqDBrPxwJdUPW3picfwV-I47vgpo0xX8,6335
45
+ ivoryos-0.1.12.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
46
+ ivoryos-0.1.12.dist-info/top_level.txt,sha256=FRIWWdiEvRKqw-XfF_UK3XV0CrnNb6EmVbEgjaVazRM,8
47
+ ivoryos-0.1.12.dist-info/RECORD,,