ivoryos 1.0.3__py3-none-any.whl → 1.0.4__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.

@@ -21,7 +21,7 @@ $(document).ready(function () {
21
21
  success: function (data) {
22
22
  $("#response").html(data);
23
23
  $("#response").slideDown("slow");
24
- slideout();
24
+ window.location.href = window.location.href;
25
25
  }
26
26
  });
27
27
  }
ivoryos/utils/form.py CHANGED
@@ -1,8 +1,9 @@
1
1
  from enum import Enum
2
+ from typing import get_origin, get_args, Union, Any
2
3
 
3
4
  from wtforms.fields.choices import SelectField
4
5
  from wtforms.fields.core import Field
5
- from wtforms.validators import InputRequired, ValidationError
6
+ from wtforms.validators import InputRequired, ValidationError, Optional
6
7
  from wtforms.widgets.core import TextInput
7
8
 
8
9
  from flask_wtf import FlaskForm
@@ -219,6 +220,26 @@ def format_name(name):
219
220
  text = ' '.join(word for word in name.split('_'))
220
221
  return text.capitalize()
221
222
 
223
+ def parse_annotation(annotation):
224
+ """
225
+ Given a type annotation, return:
226
+ - a list of all valid types (excluding NoneType)
227
+ - a boolean indicating if the value can be None (optional)
228
+ """
229
+ origin = get_origin(annotation)
230
+ args = get_args(annotation)
231
+
232
+ if annotation is Any:
233
+ return [str], True # fallback: accept any string, optional
234
+
235
+ if origin is Union:
236
+ types = list(set(args))
237
+ is_optional = type(None) in types
238
+ non_none_types = [t for t in types if t is not type(None)]
239
+ return non_none_types, is_optional
240
+
241
+ # Not a Union, just a regular type
242
+ return [annotation], False
222
243
 
223
244
  def create_form_for_method(method, autofill, script=None, design=True):
224
245
  """
@@ -258,7 +279,7 @@ def create_form_for_method(method, autofill, script=None, design=True):
258
279
  field_kwargs = {
259
280
  "label": formatted_param_name,
260
281
  "default": default_value,
261
- "validators": [InputRequired()] if param.default is param.empty else None,
282
+ "validators": [InputRequired()] if param.default is param.empty else [Optional()],
262
283
  **({"script": script} if (autofill or design) else {})
263
284
  }
264
285
  if isinstance(param.annotation, type) and issubclass(param.annotation, Enum):
@@ -267,11 +288,17 @@ def create_form_for_method(method, autofill, script=None, design=True):
267
288
  placeholder_text = f"Choose or type a value for {param.annotation.__name__} (start with # for custom)"
268
289
  extra_kwargs = {"choices": param.annotation}
269
290
  else:
291
+ # print(param.annotation)
292
+ annotation, optional = parse_annotation(param.annotation)
293
+ annotation = annotation[0]
270
294
  field_class, placeholder_text = annotation_mapping.get(
271
- param.annotation,
295
+ annotation,
272
296
  (VariableOrStringField if design else StringField, f'Enter {param.annotation} value')
273
297
  )
274
298
  extra_kwargs = {}
299
+ if optional:
300
+ field_kwargs["filters"] = [lambda x: x if x != '' else None]
301
+
275
302
 
276
303
  render_kwargs = {"placeholder": placeholder_text}
277
304
 
ivoryos/utils/utils.py CHANGED
@@ -4,6 +4,7 @@ import inspect
4
4
  import logging
5
5
  import os
6
6
  import pickle
7
+ import socket
7
8
  import subprocess
8
9
  import sys
9
10
  from collections import Counter
@@ -407,3 +408,15 @@ def get_method_from_workflow(function_string, func_name="workflow"):
407
408
  # method = get_method_from_workflow(compiled_strs, func_name=workflow.name)
408
409
  # setattr(RegisteredWorkflows, workflow.name, staticmethod(method))
409
410
  # global_config.registered_workflows = RegisteredWorkflows()
411
+
412
+
413
+ def get_local_ip():
414
+ try:
415
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
416
+ s.connect(('10.255.255.255', 1)) # Dummy address to get interface IP
417
+ ip = s.getsockname()[0]
418
+ except Exception:
419
+ ip = '127.0.0.1'
420
+ finally:
421
+ s.close()
422
+ return ip
ivoryos/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.0.3"
1
+ __version__ = "1.0.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ivoryos
3
- Version: 1.0.3
3
+ Version: 1.0.4
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
@@ -176,6 +176,42 @@ When you run the application for the first time, it will automatically create th
176
176
  - [x] show line number option ✅
177
177
  - [ ] snapshot version control
178
178
 
179
+ ## Citing
180
+
181
+ If you find this project useful, please consider citing the following manuscript:
182
+
183
+ > Zhang, W., Hao, L., Lai, V. et al. [IvoryOS: an interoperable web interface for orchestrating Python-based self-driving laboratories.](https://www.nature.com/articles/s41467-025-60514-w) Nat Commun 16, 5182 (2025).
184
+
185
+ ```bibtex
186
+ @article{zhang_et_al_2025,
187
+ author = {Wenyu Zhang and Lucy Hao and Veronica Lai and Ryan Corkery and Jacob Jessiman and Jiayu Zhang and Junliang Liu and Yusuke Sato and Maria Politi and Matthew E. Reish and Rebekah Greenwood and Noah Depner and Jiyoon Min and Rama El-khawaldeh and Paloma Prieto and Ekaterina Trushina and Jason E. Hein},
188
+ title = {{IvoryOS}: an interoperable web interface for orchestrating {Python-based} self-driving laboratories},
189
+ journal = {Nature Communications},
190
+ year = {2025},
191
+ volume = {16},
192
+ number = {1},
193
+ pages = {5182},
194
+ doi = {10.1038/s41467-025-60514-w},
195
+ url = {https://doi.org/10.1038/s41467-025-60514-w}
196
+ }
197
+ ```
198
+
199
+ For an additional perspective related to the development of the tool, please see:
200
+
201
+ > Zhang, W., Hein, J. [Behind IvoryOS: Empowering Scientists to Harness Self-Driving Labs for Accelerated Discovery](https://communities.springernature.com/posts/behind-ivoryos-empowering-scientists-to-harness-self-driving-labs-for-accelerated-discovery). Springer Nature Research Communities (2025).
202
+
203
+ ```bibtex
204
+ @misc{zhang_hein_2025,
205
+ author = {Wenyu Zhang and Jason Hein},
206
+ title = {Behind {IvoryOS}: Empowering Scientists to Harness Self-Driving Labs for Accelerated Discovery},
207
+ howpublished = {Springer Nature Research Communities},
208
+ year = {2025},
209
+ month = {Jun},
210
+ day = {18},
211
+ url = {https://communities.springernature.com/posts/behind-ivoryos-empowering-scientists-to-harness-self-driving-labs-for-accelerated-discovery}
212
+ }
213
+ ```
214
+
179
215
  ## Authors and Acknowledgement
180
216
  Ivory Zhang, Lucy Hao
181
217
 
@@ -1,9 +1,9 @@
1
- ivoryos/__init__.py,sha256=1v6LwuIao8WbmSskifzdfde7E_gH3PWCYaNpLaRtYZk,7341
1
+ ivoryos/__init__.py,sha256=6zTQ5B7Pu99pv33LMpyYb6u0dz_TVSY9TVShXKAkrFs,7959
2
2
  ivoryos/config.py,sha256=3FPBYTIBhQTKDvsEoR8ZeTmg65D-CSFEdGmOuIL4pSI,1311
3
- ivoryos/version.py,sha256=2plzdEEb24FLjE2I2XyBBcJEPYWHccNL4SgtLC_6erg,22
3
+ ivoryos/version.py,sha256=acuR_XSJzp4OrQ5T8-Ac5gYe48mUwObuwjRmisFmZ7k,22
4
4
  ivoryos/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  ivoryos/routes/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- ivoryos/routes/auth/auth.py,sha256=rvqMf4oeYXIjcsNWPbHoxK4QJRbM4YSMCl3IDRMnYtM,3255
6
+ ivoryos/routes/auth/auth.py,sha256=pvrYQN2XqH2OpZMxirFQZr9-c8yO29CpvQg9VR6JFsE,3256
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
@@ -12,15 +12,15 @@ ivoryos/routes/control/templates/control/controllers.html,sha256=iIp0h6WA68gQj9O
12
12
  ivoryos/routes/control/templates/control/controllers_home.html,sha256=qAM4iZBEuXvSgGUWWVVIe2E9MPJOeG7U214hYM84jIE,2976
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
- ivoryos/routes/database/database.py,sha256=kP5dEb5TvX3GlePk2sxlpwer8AsTM36kdeCkzAiFkR8,9837
15
+ ivoryos/routes/database/database.py,sha256=JwFuWf9WHju0CepkuSz6OaOwV6O2f76Vv_0myCFMPFc,9833
16
16
  ivoryos/routes/database/templates/database/scripts_database.html,sha256=tEpKOj1UGz7mcDq11guwP48XJxwawjxjPvxRhKiIG2I,3640
17
17
  ivoryos/routes/database/templates/database/step_card.html,sha256=F4JRfacrEQfk2rrEbcI_i7G84nzKKDmCrMSmStLb4W4,290
18
18
  ivoryos/routes/database/templates/database/workflow_database.html,sha256=fsJHrYeEHGBKRn1pIxWITE6e93tdZsXH3zRs9Ob5FX0,4467
19
19
  ivoryos/routes/database/templates/database/workflow_view.html,sha256=u8_XYhiZ98PzglMzFEkuM1Tk9hVWf79xXIrpHVDxKa0,3618
20
20
  ivoryos/routes/design/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- ivoryos/routes/design/design.py,sha256=Ju9Hz0khhAk6HmnZd3Er3PglFkvZBNPAJ-fPJMfrrIM,29328
22
- ivoryos/routes/design/templates/design/experiment_builder.html,sha256=rEdcHj5onJG_4MejdFBPnJVzsvCMp1KDteqNkpx24kQ,29430
23
- ivoryos/routes/design/templates/design/experiment_run.html,sha256=7VP0Vo98phcYnFennd5vqaMK1M1QBwDmM-b9aZb8jOw,26282
21
+ ivoryos/routes/design/design.py,sha256=ui9GvLoJ-0XNZT6q13KPgDh4NEEbVxaHKYcBtDqEkao,29866
22
+ ivoryos/routes/design/templates/design/experiment_builder.html,sha256=4JjkwdMAWZA1XrGtoqBKykDikf-Qg7RbjqedqY_J-fU,32326
23
+ ivoryos/routes/design/templates/design/experiment_run.html,sha256=UFqg6GMgkyYJfc1Ifg1jhyJggdZkCYpgQrNotiXWzwc,25582
24
24
  ivoryos/routes/main/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  ivoryos/routes/main/main.py,sha256=yuVJzXAob1kc1dfflkTBIZQ0tdf6kChfuq-uQlN1e9Q,957
26
26
  ivoryos/routes/main/templates/main/help.html,sha256=IOktMEsOPk0SCiMBXZ4mpffClERAyX8W82fel71M3M0,9370
@@ -33,20 +33,20 @@ ivoryos/static/gui_annotation/Slide2.PNG,sha256=z3wQ9oVgg4JTWVLQGKK_KhtepRHUYP1e
33
33
  ivoryos/static/js/overlay.js,sha256=dPxop19es0E0ZUSY3d_4exIk7CJuQEnlW5uTt5fZfzI,483
34
34
  ivoryos/static/js/socket_handler.js,sha256=2Iyv_3METjhSlSavs_L9FE3PKY4xDEpfzJpd2FywY9o,5300
35
35
  ivoryos/static/js/sortable_card.js,sha256=ifmlGe3yy0U_KzMphV4ClRhK2DLOvkELYMlq1vECuac,807
36
- ivoryos/static/js/sortable_design.js,sha256=wwpKfIzZGDxfX3moNz0cvPvm9YyHmopZK3wmkUdnBiw,4333
36
+ ivoryos/static/js/sortable_design.js,sha256=d55AEz8LpPX_j-hREom-I19i4l-SOG2RVSR4CnozRtY,4366
37
37
  ivoryos/templates/base.html,sha256=sDdwqOIUP2Get-py4E59PkieoGWLFpX6wAJe93s4aRo,8518
38
38
  ivoryos/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  ivoryos/utils/bo_campaign.py,sha256=CVs7q15Pm2SRuJNaCvZKIxOFuv1xibM2yymtpAMAWOk,3285
40
40
  ivoryos/utils/client_proxy.py,sha256=0OT2xTMkqh_2ybgCxMV_71ZVUThWwrsnAhTIBY5vDR8,2095
41
41
  ivoryos/utils/db_models.py,sha256=zlmmD2600CYyn79gQq8k0Vra7BDBKJBAyNLYclIWdvs,27382
42
- ivoryos/utils/form.py,sha256=b3JKxRc1jN45-bXyfzSJT1lcssUuxT86FhRmNUDv5-U,20973
42
+ ivoryos/utils/form.py,sha256=k9d4AZz74FeOh4gkhDsZx3g4LZti_aJm9ZPRBkpOsE0,21933
43
43
  ivoryos/utils/global_config.py,sha256=OqfDrPgOzRdIUMD4V3pA9t6b-BATMjGZl8Jn7nkI56k,2138
44
44
  ivoryos/utils/llm_agent.py,sha256=-lVCkjPlpLues9sNTmaT7bT4sdhWvV2DiojNwzB2Lcw,6422
45
45
  ivoryos/utils/script_runner.py,sha256=0b5hLKAF2o0SQKiArhUsG8-4MA-eniAcjwi8gCNVwtY,14542
46
46
  ivoryos/utils/task_runner.py,sha256=u4nF0wOADu_HVlGYVTOXnUm1woWGgYAccr-ZCzgtb6Q,2899
47
- ivoryos/utils/utils.py,sha256=OBwrRu02yh7pqG_lyl10zWr_RYes3xhMporxIz8lGYI,13579
48
- ivoryos-1.0.3.dist-info/LICENSE,sha256=p2c8S8i-8YqMpZCJnadLz1-ofxnRMILzz6NCMIypRag,1084
49
- ivoryos-1.0.3.dist-info/METADATA,sha256=XE0dH-qpGIUYCXwkzDULsuTLOJPlGj0AnUwhtjeiQPY,6992
50
- ivoryos-1.0.3.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
51
- ivoryos-1.0.3.dist-info/top_level.txt,sha256=FRIWWdiEvRKqw-XfF_UK3XV0CrnNb6EmVbEgjaVazRM,8
52
- ivoryos-1.0.3.dist-info/RECORD,,
47
+ ivoryos/utils/utils.py,sha256=nGSw3vHkxXedX4T-AFEWGzDIU7h0NjrAf0wBt0Og9pk,13886
48
+ ivoryos-1.0.4.dist-info/LICENSE,sha256=p2c8S8i-8YqMpZCJnadLz1-ofxnRMILzz6NCMIypRag,1084
49
+ ivoryos-1.0.4.dist-info/METADATA,sha256=Z1w1rUuHTx3MWyDwSYo3dIj6bdoUhcSHgUvVYnSVU74,8906
50
+ ivoryos-1.0.4.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
51
+ ivoryos-1.0.4.dist-info/top_level.txt,sha256=FRIWWdiEvRKqw-XfF_UK3XV0CrnNb6EmVbEgjaVazRM,8
52
+ ivoryos-1.0.4.dist-info/RECORD,,