sapiopycommons 2025.7.17a612__py3-none-any.whl → 2025.7.18a614__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 sapiopycommons might be problematic. Click here for more details.

Files changed (59) hide show
  1. sapiopycommons/ai/__init__.py +0 -0
  2. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.py +43 -0
  3. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.pyi +31 -0
  4. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2_grpc.py +24 -0
  5. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.py +123 -0
  6. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.pyi +598 -0
  7. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2_grpc.py +24 -0
  8. sapiopycommons/ai/api/plan/proto/step_output_pb2.py +45 -0
  9. sapiopycommons/ai/api/plan/proto/step_output_pb2.pyi +42 -0
  10. sapiopycommons/ai/api/plan/proto/step_output_pb2_grpc.py +24 -0
  11. sapiopycommons/ai/api/plan/proto/step_pb2.py +43 -0
  12. sapiopycommons/ai/api/plan/proto/step_pb2.pyi +43 -0
  13. sapiopycommons/ai/api/plan/proto/step_pb2_grpc.py +24 -0
  14. sapiopycommons/ai/api/plan/script/proto/script_pb2.py +55 -0
  15. sapiopycommons/ai/api/plan/script/proto/script_pb2.pyi +115 -0
  16. sapiopycommons/ai/api/plan/script/proto/script_pb2_grpc.py +153 -0
  17. sapiopycommons/ai/api/plan/tool/proto/entry_pb2.py +57 -0
  18. sapiopycommons/ai/api/plan/tool/proto/entry_pb2.pyi +96 -0
  19. sapiopycommons/ai/api/plan/tool/proto/entry_pb2_grpc.py +24 -0
  20. sapiopycommons/ai/api/plan/tool/proto/tool_pb2.py +69 -0
  21. sapiopycommons/ai/api/plan/tool/proto/tool_pb2.pyi +232 -0
  22. sapiopycommons/ai/api/plan/tool/proto/tool_pb2_grpc.py +154 -0
  23. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.py +39 -0
  24. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.pyi +32 -0
  25. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2_grpc.py +24 -0
  26. sapiopycommons/ai/protobuf_utils.py +508 -0
  27. sapiopycommons/ai/test_client.py +251 -0
  28. sapiopycommons/ai/tool_service_base.py +826 -0
  29. sapiopycommons/callbacks/callback_util.py +332 -665
  30. sapiopycommons/callbacks/field_builder.py +0 -2
  31. sapiopycommons/chem/IndigoMolecules.py +1 -29
  32. sapiopycommons/chem/Molecules.py +3 -3
  33. sapiopycommons/customreport/auto_pagers.py +1 -26
  34. sapiopycommons/customreport/term_builder.py +1 -1
  35. sapiopycommons/datatype/pseudo_data_types.py +326 -349
  36. sapiopycommons/eln/experiment_handler.py +767 -408
  37. sapiopycommons/eln/experiment_report_util.py +6 -11
  38. sapiopycommons/eln/plate_designer.py +2 -7
  39. sapiopycommons/files/file_util.py +5 -7
  40. sapiopycommons/general/accession_service.py +2 -2
  41. sapiopycommons/general/aliases.py +1 -3
  42. sapiopycommons/general/audit_log.py +0 -7
  43. sapiopycommons/general/custom_report_util.py +0 -12
  44. sapiopycommons/processtracking/custom_workflow_handler.py +1 -11
  45. sapiopycommons/processtracking/endpoints.py +0 -27
  46. sapiopycommons/recordmodel/record_handler.py +391 -785
  47. sapiopycommons/rules/eln_rule_handler.py +1 -8
  48. sapiopycommons/rules/on_save_rule_handler.py +1 -8
  49. sapiopycommons/webhook/webhook_handlers.py +4 -9
  50. sapiopycommons/webhook/webservice_handlers.py +2 -2
  51. {sapiopycommons-2025.7.17a612.dist-info → sapiopycommons-2025.7.18a614.dist-info}/METADATA +2 -2
  52. sapiopycommons-2025.7.18a614.dist-info/RECORD +92 -0
  53. sapiopycommons/eln/experiment_cache.py +0 -188
  54. sapiopycommons/eln/experiment_step_factory.py +0 -476
  55. sapiopycommons/eln/step_creation.py +0 -236
  56. sapiopycommons/general/data_structure_util.py +0 -115
  57. sapiopycommons-2025.7.17a612.dist-info/RECORD +0 -68
  58. {sapiopycommons-2025.7.17a612.dist-info → sapiopycommons-2025.7.18a614.dist-info}/WHEEL +0 -0
  59. {sapiopycommons-2025.7.17a612.dist-info → sapiopycommons-2025.7.18a614.dist-info}/licenses/LICENSE +0 -0
@@ -126,16 +126,12 @@ class ElnRuleHandler:
126
126
  """
127
127
  return list(self._entry_to_field_maps.keys())
128
128
 
129
- # CR-47529: Add info about HVDT behavior to the docstring of these functions.
130
129
  def get_records(self, data_type: DataTypeIdentifier, entry: str | None = None) -> list[DataRecord]:
131
130
  """
132
131
  Get records from the cached context with the given data type. Capable of being filtered to searching within
133
132
  the context of an entry name. If the given data type or entry does not exist in the context,
134
133
  returns an empty list.
135
134
 
136
- Note that if you are attempting to retrieve record that are high volume data types and are receiving nothing,
137
- the HVDTs may have been sent as field maps. Consider using the get_field_maps function if this occurs.
138
-
139
135
  :param data_type: The data type of the records to return.
140
136
  :param entry: The name of the entry to grab the records from. If None, returns the records that match the data
141
137
  type from every entry. If an entry is provided, but it does not exist in the context, returns an empty list.
@@ -154,7 +150,7 @@ class ElnRuleHandler:
154
150
 
155
151
  Field maps will only exist in the context if the data record that the fields are from is no longer accessible
156
152
  to the user. This can occur because the data record was deleted, or because the user does not have access to the
157
- record due to ACL. This can also occur under certain circumstances if the records are HVDTs.
153
+ record due to ACL.
158
154
 
159
155
  :param data_type: The data type of the field maps to return.
160
156
  :param entry: The name of the entry to grab the field maps from. If None, returns the field maps that match the
@@ -174,9 +170,6 @@ class ElnRuleHandler:
174
170
  within the context of an entry name. If the given data type or entry does not exist in the context,
175
171
  returns an empty list.
176
172
 
177
- Note that if you are attempting to retrieve record that are high volume data types and are receiving nothing,
178
- the HVDTs may have been sent as field maps. Consider using the get_field_maps function if this occurs.
179
-
180
173
  :param wrapper_type: The record model wrapper or data type name of the record to get from the context.
181
174
  :param entry: The name of the entry to grab the records from. If None, returns the records that match the data
182
175
  type from every entry. If an entry is provided, but it does not exist in the context, returns an empty list.
@@ -122,16 +122,12 @@ class OnSaveRuleHandler:
122
122
  """
123
123
  return list(self._base_id_to_field_maps.keys())
124
124
 
125
- # CR-47529: Add info about HVDT behavior to the docstring of these functions.
126
125
  def get_records(self, data_type: DataTypeIdentifier, record_id: int | None = None) -> list[DataRecord]:
127
126
  """
128
127
  Get records from the cached context with the given data type. Capable of being filtered to searching within
129
128
  the context of a record ID. If the given data type or record ID does not exist in the context,
130
129
  returns an empty list.
131
130
 
132
- Note that if you are attempting to retrieve record that are high volume data types and are receiving nothing,
133
- the HVDTs may have been sent as field maps. Consider using the get_field_maps function if this occurs.
134
-
135
131
  :param data_type: The data type of the records to return.
136
132
  :param record_id: The record ID of the base record to search from. If None, returns the records that match the
137
133
  data type from every ID. If an ID is provided, but it does not exist in the context, returns an empty list.
@@ -150,7 +146,7 @@ class OnSaveRuleHandler:
150
146
 
151
147
  Field maps will only exist in the context if the data record that the fields are from is no longer accessible
152
148
  to the user. This can occur because the data record was deleted, or because the user does not have access to the
153
- record due to ACL. This can also occur under certain circumstances if the records are HVDTs.
149
+ record due to ACL.
154
150
 
155
151
  :param data_type: The data type of the field maps to return.
156
152
  :param record_id: The record ID of the base record to search from. If None, returns the field maps that match
@@ -170,9 +166,6 @@ class OnSaveRuleHandler:
170
166
  the context of a record ID. If the given data type or record ID does not exist in the context,
171
167
  returns an empty list.
172
168
 
173
- Note that if you are attempting to retrieve record that are high volume data types and are receiving nothing,
174
- the HVDTs may have been sent as field maps. Consider using the get_field_maps function if this occurs.
175
-
176
169
  :param wrapper_type: The record model wrapper or data type name of the record to get from the context.
177
170
  :param record_id: The record ID of the base record to search from. If None, returns the records that match the
178
171
  data type from ID. If an ID is provided, but it does not exist in the context, returns an empty list.
@@ -7,6 +7,7 @@ import traceback
7
7
  from abc import abstractmethod
8
8
  from logging import Logger
9
9
 
10
+ from sapiopylib.rest import UserManagerService, GroupManagerService, MessengerService
10
11
  from sapiopylib.rest.AccessionService import AccessionManager
11
12
  from sapiopylib.rest.CustomReportService import CustomReportManager
12
13
  from sapiopylib.rest.DashboardManager import DashboardManager
@@ -15,13 +16,10 @@ from sapiopylib.rest.DataRecordManagerService import DataRecordManager
15
16
  from sapiopylib.rest.DataService import DataManager
16
17
  from sapiopylib.rest.DataTypeService import DataTypeManager
17
18
  from sapiopylib.rest.ELNService import ElnManager
18
- from sapiopylib.rest.GroupManagerService import VeloxGroupManager
19
- from sapiopylib.rest.MessengerService import SapioMessenger
20
19
  from sapiopylib.rest.PicklistService import PickListManager
21
20
  from sapiopylib.rest.ReportManager import ReportManager
22
21
  from sapiopylib.rest.SesssionManagerService import SessionManager
23
22
  from sapiopylib.rest.User import SapioUser
24
- from sapiopylib.rest.UserManagerService import VeloxUserManager
25
23
  from sapiopylib.rest.WebhookService import AbstractWebhookHandler
26
24
  from sapiopylib.rest.pojo.Message import VeloxLogMessage, VeloxLogLevel
27
25
  from sapiopylib.rest.pojo.webhook.ClientCallbackRequest import PopupType
@@ -87,9 +85,9 @@ class CommonsWebhookHandler(AbstractWebhookHandler):
87
85
  """A class for making requests to the data type webservice endpoints."""
88
86
  eln_man: ElnManager
89
87
  """A class for making requests to the ELN management webservice endpoints."""
90
- group_man: VeloxGroupManager
88
+ group_man: GroupManagerService
91
89
  """A class for making requests to the group management webservice endpoints."""
92
- messenger: SapioMessenger
90
+ messenger: MessengerService
93
91
  """A class for making requests to the message webservice endpoints."""
94
92
  list_man: PickListManager
95
93
  """A class for making requests to the pick list webservice endpoints."""
@@ -97,7 +95,7 @@ class CommonsWebhookHandler(AbstractWebhookHandler):
97
95
  """A class for making requests to the report webservice endpoints."""
98
96
  session_man: SessionManager
99
97
  """A class for making requests to the session management webservice endpoints."""
100
- user_man: VeloxUserManager
98
+ user_man: UserManagerService
101
99
  """A class for making requests to the user management webservice endpoints."""
102
100
 
103
101
  rec_man: RecordModelManager
@@ -222,9 +220,6 @@ class CommonsWebhookHandler(AbstractWebhookHandler):
222
220
  else:
223
221
  self.custom_context = None
224
222
 
225
- # CR-47526: Set the dialog timeout to 1 hour by default. This can be overridden by the webhook.
226
- self.callback.set_dialog_timeout(3600)
227
-
228
223
  # Set the default display types, titles, and messages for each type of exception that can display a message.
229
224
  self.default_user_error_display_type = MessageDisplayType.TOASTER_WARNING
230
225
  self.default_critical_error_display_type = MessageDisplayType.DISPLAY_ERROR
@@ -3,7 +3,7 @@ import traceback
3
3
  from abc import abstractmethod, ABC
4
4
  from base64 import b64decode
5
5
  from logging import Logger
6
- from typing import Any, Mapping
6
+ from typing import Any
7
7
 
8
8
  from flask import request, Response, Request
9
9
  from sapiopylib.rest.DataRecordManagerService import DataRecordManager
@@ -122,7 +122,7 @@ class AbstractWebserviceHandler(AbstractWebhookHandler):
122
122
  """
123
123
  pass
124
124
 
125
- def authenticate_user(self, headers: Mapping[str, str]) -> SapioUser:
125
+ def authenticate_user(self, headers: dict[str, str]) -> SapioUser:
126
126
  """
127
127
  Authenticate a user for making requests to a Sapio server using the provided headers. If no user can be
128
128
  authenticated, then an exception will be thrown.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sapiopycommons
3
- Version: 2025.7.17a612
3
+ Version: 2025.7.18a614
4
4
  Summary: Official Sapio Python API Utilities Package
5
5
  Project-URL: Homepage, https://github.com/sapiosciences
6
6
  Author-email: Jonathan Steck <jsteck@sapiosciences.com>, Yechen Qiao <yqiao@sapiosciences.com>
@@ -17,7 +17,7 @@ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
17
17
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
18
  Requires-Python: >=3.10
19
19
  Requires-Dist: databind>=4.5
20
- Requires-Dist: sapiopylib>=2025.4.17.264
20
+ Requires-Dist: sapiopylib>=2024.5.24.210
21
21
  Description-Content-Type: text/markdown
22
22
 
23
23
 
@@ -0,0 +1,92 @@
1
+ sapiopycommons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ sapiopycommons/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ sapiopycommons/ai/protobuf_utils.py,sha256=5Y0z_lRVipbHPJcHJf9GosK-ZjAh_I2JI3QwV8iyfKg,24884
4
+ sapiopycommons/ai/test_client.py,sha256=8AlRTuy7XUC40aU4SgTQkNc_ZBp_ANhVNEKbUx8ABRM,10430
5
+ sapiopycommons/ai/tool_service_base.py,sha256=rKFWDWdCz7NYr6V-crprnXdrOjItWqH-1OFM4vHLSDw,37312
6
+ sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.py,sha256=YcZjb_YM-XeLErM8hEC_S7vGMVGvcXAMGs2b-u5zvOE,2377
7
+ sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.pyi,sha256=FwtXmNAf7iYGEFm4kbqb04v77jNHbZg18ZmEDhle_bU,1444
8
+ sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2_grpc.py,sha256=wPImJPdCUZNVEVoUWzsba9kGIXjEKPdUkawP5SnVyiU,932
9
+ sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.py,sha256=nWC91vR2pMgMUyNOZRZ0YiuL1-8ntnjXLqt1daxsD34,20869
10
+ sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.pyi,sha256=U5zXrbBxsWilLTsRWJd1TqjdjLKFsr3enF9OJ8GfyWw,34028
11
+ sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2_grpc.py,sha256=4vD4jWanaJ4uclSkFmS7JIz_lwYXDWBE3DomuPjUyII,941
12
+ sapiopycommons/ai/api/plan/proto/step_output_pb2.py,sha256=JpBZSyoYyPTEaaXjW664PeJNK0zxV1mly_kp5re42z4,2661
13
+ sapiopycommons/ai/api/plan/proto/step_output_pb2.pyi,sha256=yuxOYnDZ9DRuu-TLzaKOW_B4LUiYxTrNc2AbssXg4kE,2022
14
+ sapiopycommons/ai/api/plan/proto/step_output_pb2_grpc.py,sha256=vDRY_pIIshQ4UpdW-ra1F5zBmntdsW2scySkMAA-zfc,925
15
+ sapiopycommons/ai/api/plan/proto/step_pb2.py,sha256=nL976oTFdX4ih4gg7_J-8eFoGB69tFvERB2gT3L2-6s,2439
16
+ sapiopycommons/ai/api/plan/proto/step_pb2.pyi,sha256=QPIcsjcUvEGQkdZMUMiVzFFNDl8yOUe_qJtf5XEp5Ck,2062
17
+ sapiopycommons/ai/api/plan/proto/step_pb2_grpc.py,sha256=DgiBYFvTNiDG_2a9Tpt5iel2fRUfePZWP41fZTC-KWk,918
18
+ sapiopycommons/ai/api/plan/script/proto/script_pb2.py,sha256=D668fAG3dAvE8ijCzaflj7o6D5M5szW4X8Wq-8EYxBU,4712
19
+ sapiopycommons/ai/api/plan/script/proto/script_pb2.pyi,sha256=VS9WXKcGuUj6ulziLxhgEBMRXP-QgHlFeMISDDOhAQY,7174
20
+ sapiopycommons/ai/api/plan/script/proto/script_pb2_grpc.py,sha256=RkShHpe_d5EJHk3qp-or1JpvSEqShb7cCiaXnJ2YSww,6931
21
+ sapiopycommons/ai/api/plan/tool/proto/entry_pb2.py,sha256=A-ufAWwbJ0odVXBZBQKvke6LYPijPl2dpb2IFRaXmPE,4124
22
+ sapiopycommons/ai/api/plan/tool/proto/entry_pb2.pyi,sha256=NNBrdHz5PzAuUEXuGgTU4THy9rx8Sr9iGTb65QtVH4Q,4589
23
+ sapiopycommons/ai/api/plan/tool/proto/entry_pb2_grpc.py,sha256=YKkX2kexERUx4asLCShufSnZhgf339Zk8Xw1FAgLfHQ,924
24
+ sapiopycommons/ai/api/plan/tool/proto/tool_pb2.py,sha256=7etun0HS16henGl8AQsPWZ3t4dRpnwBt-ophw5pETR0,7295
25
+ sapiopycommons/ai/api/plan/tool/proto/tool_pb2.pyi,sha256=_wDXVJEVctf8eQ3jJZa3gOK0yN8bV3ZugeSeLJ4mloM,16775
26
+ sapiopycommons/ai/api/plan/tool/proto/tool_pb2_grpc.py,sha256=68u5E1ZKha5frP5GuY8Ad-c0c79vBhtfnj5Q4u-8xOY,6982
27
+ sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.py,sha256=WKzNi-d5dqeJbmEXUVE5qJ4Qm34HmsqRXRtXih382g8,2100
28
+ sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.pyi,sha256=vLYA8Tkzq2AwgVadoUp5vAg4HgGlgga0kzeS3e_XkCQ,1621
29
+ sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2_grpc.py,sha256=2W0YzT4SfnGTLq98AdvkyNM0n75Tkl8DervPS1ryGao,932
30
+ sapiopycommons/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ sapiopycommons/callbacks/callback_util.py,sha256=sz76LzD9sVLPMcoOpmzPe1aILGXcpHfyZ-qex8oR11c,130849
32
+ sapiopycommons/callbacks/field_builder.py,sha256=p2XacN99MuKk3ite8GAqstUMpixqugul2CsC4gB83-o,38620
33
+ sapiopycommons/chem/IndigoMolecules.py,sha256=slM2y39zZFHc468c366EqR8T-GYJ24UnM9HWAqWFEwQ,3900
34
+ sapiopycommons/chem/Molecules.py,sha256=5PzRyE1s-Z3nfwh3Y4dCNdQOIJGhog08wyZvgTkKwyU,12384
35
+ sapiopycommons/chem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ sapiopycommons/customreport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
+ sapiopycommons/customreport/auto_pagers.py,sha256=3-XXWrP7r41a_Y-8YLPnfm0s65m4qEEUqu4azX47oPI,14828
38
+ sapiopycommons/customreport/column_builder.py,sha256=0RO53e9rKPZ07C--KcepN6_tpRw_FxF3O9vdG0ilKG8,3014
39
+ sapiopycommons/customreport/custom_report_builder.py,sha256=BlTxZ4t1sfZA2Ciur1EfYvkZxHxJ7ADwYNAe2zwiN0c,7176
40
+ sapiopycommons/customreport/term_builder.py,sha256=PNp71NF1vFxidk5v6uQNi9oQR9KJIk8WfhyntvvZN-U,18573
41
+ sapiopycommons/datatype/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
+ sapiopycommons/datatype/attachment_util.py,sha256=N-nhsJ0oxa_Ft6Y6VWeNFYLzfuQqsjhHA6_-yIt2wVw,3596
43
+ sapiopycommons/datatype/data_fields.py,sha256=pczUlEcE0TeHEDU0Gkvu7voacSLPXCB7l9UbI1Tb6V0,5656
44
+ sapiopycommons/datatype/pseudo_data_types.py,sha256=6TG7aJxgmUZ8FQkWBcgmbK5oy7AFFNtKOPpi1w1OOYA,27657
45
+ sapiopycommons/eln/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ sapiopycommons/eln/experiment_handler.py,sha256=FeqmjnxN5WyDDstN3_AMSo9r7nQi-5zou4m-3K5JsYM,123363
47
+ sapiopycommons/eln/experiment_report_util.py,sha256=NNNNPVD3_2ZAjoOqCMOnlnmPD0SCjDcgYi453ATSJBs,37027
48
+ sapiopycommons/eln/experiment_tags.py,sha256=7-fpOiSqrjbXmWIJhEhaxMgLsVCPAtKqH8xRzpDVKoE,356
49
+ sapiopycommons/eln/plate_designer.py,sha256=ix2cflz13PAHyu4deS3d5Qd3kQXk0C7IQxBQ2Dm9fEM,13692
50
+ sapiopycommons/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
+ sapiopycommons/files/complex_data_loader.py,sha256=T39veNhvYl6j_uZjIIJ8Mk5Aa7otR5RB-g8XlAdkksA,1421
52
+ sapiopycommons/files/file_bridge.py,sha256=vKbqxPexi15epr_-_qLrEfYoxNxB031mXN92iVtOMqE,9511
53
+ sapiopycommons/files/file_bridge_handler.py,sha256=SEYDIQhSCmjI6qyLdDJE8JVKSd0WYvF7JvAq_Ahp9Do,25503
54
+ sapiopycommons/files/file_data_handler.py,sha256=f96MlkMuQhUCi4oLnzJK5AiuElCp5jLI8_sJkZVwpws,36779
55
+ sapiopycommons/files/file_util.py,sha256=w4Q7zYJb9YaPxrecmT4RT_OOibKMRP0NI1CyoOLfAP4,31747
56
+ sapiopycommons/files/file_validator.py,sha256=ryg22-93csmRO_Pv0ZpWphNkB74xWZnHyJ23K56qLj0,28761
57
+ sapiopycommons/files/file_writer.py,sha256=hACVl0duCjP28gJ1NPljkjagNCLod0ygUlPbvUmRDNM,17605
58
+ sapiopycommons/flowcyto/flow_cyto.py,sha256=vs9WhXXKz3urpjL8QKSk56B-NSmQR3O3x_WFBKoeO10,3227
59
+ sapiopycommons/flowcyto/flowcyto_data.py,sha256=mYKFuLbtpJ-EsQxLGtu4tNHVlygTxKixgJxJqD68F58,2596
60
+ sapiopycommons/general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
+ sapiopycommons/general/accession_service.py,sha256=QeNGd78Zr08ezWpThTuAkxO4bXusEcp5x9jJRZRwliA,13483
62
+ sapiopycommons/general/aliases.py,sha256=alc2R5TOSKbZif3pcGZ706y23Y9F4HQPC-Kj4xJZ_Us,14503
63
+ sapiopycommons/general/audit_log.py,sha256=KQq0PsvukUoE3l6TQb3-vpu5-MbSINpWlnQ9e7jojPg,8743
64
+ sapiopycommons/general/custom_report_util.py,sha256=NwwmejSQLwSbrndEk1gPyFNYk9GZoS7Wrp9ab9moFgw,18014
65
+ sapiopycommons/general/directive_util.py,sha256=7SeQrd2Ye5JHlXZtJZaVGgtaSLdq_Vm9EObuxf44Pz8,3905
66
+ sapiopycommons/general/exceptions.py,sha256=aPlzK1cvxeMU5UsokYlLrIBGltUfJZ7LH8zvLh9DxpI,3233
67
+ sapiopycommons/general/html_formatter.py,sha256=HE3OeGgwOw6x53zGSc4-UzP4-JoOmQIz3pX-DzNVg94,17138
68
+ sapiopycommons/general/popup_util.py,sha256=HKILegU1uCL_6abNlNL0Wn3xgX2JNa_kJeq7e5CZu6Q,31923
69
+ sapiopycommons/general/sapio_links.py,sha256=YkcVKNLrSGoM7tCCXBAsIbIxylctwdcEyhePrRMODe0,2859
70
+ sapiopycommons/general/storage_util.py,sha256=ovmK_jN7v09BoX07XxwShpBUC5WYQOM7dbKV_VeLXJU,8892
71
+ sapiopycommons/general/time_util.py,sha256=jU1urPoZRv6evNucR0-288EyT4PrsDpCr-H1-7BKq9A,12363
72
+ sapiopycommons/multimodal/multimodal.py,sha256=PFaGJPbKvW__tnxb8KkgkJZOKjQdgxF_kGfD5chet1s,6779
73
+ sapiopycommons/multimodal/multimodal_data.py,sha256=0BeVPr9HaC0hNTF1v1phTIKGruvNnwerHsD994qJKBg,15099
74
+ sapiopycommons/processtracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
+ sapiopycommons/processtracking/custom_workflow_handler.py,sha256=QZVRDUXpHfYIKD9LtaOcOt0Sr3RGDaeGQb-LZYAgkCc,25117
76
+ sapiopycommons/processtracking/endpoints.py,sha256=w5bziI2xC7450M95rCF8JpRwkoni1kEDibyAux9B12Q,10848
77
+ sapiopycommons/recordmodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
+ sapiopycommons/recordmodel/record_handler.py,sha256=aPbR3OS0RlsKOGztY-LZaOmkXKUB8ZTw3qqdJKXwd6U,70872
79
+ sapiopycommons/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
+ sapiopycommons/rules/eln_rule_handler.py,sha256=1aC88brATcjL1O0Hd2hQ0XNguKsKh8xELXComotk3mQ,10772
81
+ sapiopycommons/rules/on_save_rule_handler.py,sha256=J1YKjOGA1KUTwpnZMa7oIi5QU_4mBJrPygSHNDsMIIA,10539
82
+ sapiopycommons/samples/aliquot.py,sha256=mWOJUqaQh0t3HklNuGdmuV7D5zzXs6fpLwtDdM6_XTo,3018
83
+ sapiopycommons/sftpconnect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
+ sapiopycommons/sftpconnect/sftp_builder.py,sha256=lFK3FeXk-sFLefW0hqY8WGUQDeYiGaT6yDACzT_zFgQ,3015
85
+ sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
+ sapiopycommons/webhook/webhook_context.py,sha256=D793uLsb1691SalaPnBUk3rOSxn_hYLhdvkaIxjNXss,1909
87
+ sapiopycommons/webhook/webhook_handlers.py,sha256=L0HetSm43NvA5KyW3xbLpGFh2DbAaeZJVtXIEl2fvV8,39689
88
+ sapiopycommons/webhook/webservice_handlers.py,sha256=Y5dHx_UFWFuSqaoPL6Re-fsKYRuxvCWZ8bj6KSZ3jfM,14285
89
+ sapiopycommons-2025.7.18a614.dist-info/METADATA,sha256=rlFy7ClFDUE87l9zfvvvN6TJ4_EokvhxZBzJ5D0G7MQ,3143
90
+ sapiopycommons-2025.7.18a614.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
91
+ sapiopycommons-2025.7.18a614.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
92
+ sapiopycommons-2025.7.18a614.dist-info/RECORD,,
@@ -1,188 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from weakref import WeakValueDictionary
4
-
5
- from sapiopylib.rest.ELNService import ElnManager
6
- from sapiopylib.rest.User import SapioUser
7
- from sapiopylib.rest.pojo.datatype.FieldDefinition import AbstractVeloxFieldDefinition
8
- from sapiopylib.rest.pojo.eln.ElnExperiment import ElnTemplate, TemplateExperimentQuery
9
- from sapiopylib.rest.pojo.eln.SapioELNEnums import ElnBaseDataType
10
- from sapiopylib.rest.pojo.eln.field_set import ElnFieldSetInfo
11
- from sapiopylib.rest.pojo.eln.protocol_template import ProtocolTemplateInfo, ProtocolTemplateQuery
12
-
13
- from sapiopycommons.general.aliases import UserIdentifier, AliasUtil
14
- from sapiopycommons.general.exceptions import SapioException
15
-
16
-
17
- # FR-47530: Created a class that caches experiment template and predefined field information.
18
- class ExperimentCacheManager:
19
- """
20
- A class to manage the caching of experiment-related information.
21
- """
22
- user: SapioUser
23
- eln_man: ElnManager
24
-
25
- _templates: list[ElnTemplate]
26
- """A list of experiment templates. Only cached when first accessed."""
27
- _protocols: list[ProtocolTemplateInfo]
28
- """A list of protocol templates. Only cached when first accessed."""
29
- _field_sets: dict[str, ElnFieldSetInfo]
30
- """A dictionary of field set name to field set. Only cached when first accessed."""
31
- _field_set_fields: dict[int, list[AbstractVeloxFieldDefinition]]
32
- """A dictionary of field set ID to field definitions. Only cached when first accessed."""
33
- _predefined_fields: dict[str, dict[str, AbstractVeloxFieldDefinition]]
34
- """A dictionary of ELN data type name to predefined field definitions. Only cached when first accessed."""
35
-
36
- __instances: WeakValueDictionary[SapioUser, ExperimentCacheManager] = WeakValueDictionary()
37
- __initialized: bool
38
-
39
- def __new__(cls, context: UserIdentifier):
40
- """
41
- :param context: The current webhook context or a user object to send requests from.
42
- """
43
- user = AliasUtil.to_sapio_user(context)
44
- obj = cls.__instances.get(user)
45
- if not obj:
46
- obj = object.__new__(cls)
47
- obj.__initialized = False
48
- cls.__instances[user] = obj
49
- return obj
50
-
51
- def __init__(self, context: UserIdentifier):
52
- """
53
- :param context: The current webhook context or a user object to send requests from.
54
- """
55
- if self.__initialized:
56
- return
57
- self.__initialized = True
58
-
59
- self.user = AliasUtil.to_sapio_user(context)
60
- self.eln_man = ElnManager(self.user)
61
-
62
- self._field_set_fields = {}
63
- self._predefined_fields = {}
64
-
65
- def get_experiment_template(self, name: str, active: bool = True, version: int | None = None,
66
- first_match: bool = False, public: bool | None = True) -> ElnTemplate:
67
- """
68
- Get the experiment template with the given information.
69
-
70
- :param name: The name of the template.
71
- :param active: Whether the template is marked as active.
72
- :param version: The version of the template to get. If None, the latest version will be returned.
73
- :param first_match: If true, returns the first match found. If false, raises an exception.
74
- :param public: Whether the template is public. If true, only pubic templates will be queried. If false, only
75
- private templates will be queried. If None, both public and private templates will be queried. Non-public
76
- templates do not have a version number, so this will always fail if public is false and a version number is
77
- provided.
78
- :return: The experiment template with the given information.
79
- """
80
- if not hasattr(self, "_templates"):
81
- query = TemplateExperimentQuery()
82
- query.active_templates_only = False
83
- query.latest_version_only = False
84
- self._templates = self.eln_man.get_template_experiment_list(query)
85
- return self._find_template(self._templates, name, active, version, first_match, public)
86
-
87
-
88
- def get_protocol_template(self, name: str, active: bool = True, version: int | None = None,
89
- first_match: bool = False, public: bool | None = True) -> ProtocolTemplateInfo:
90
- """
91
- Get the protocol template with the given information. Will throw an exception if multiple templates match
92
- the given information.
93
-
94
- :param name: The name of the template.
95
- :param active: Whether the template is marked as active.
96
- :param version: The version of the template to get. If None, the latest version will be returned.
97
- :param first_match: If true, returns the first match found. If false, raises an exception.
98
- :param public: Whether the template is public. If true, only pubic templates will be queried. If false, only
99
- private templates will be queried. If None, both public and private templates will be queried. Non-public
100
- templates do not have a version number, so this will always fail if public is false and a version number is
101
- provided.
102
- :return: The protocol template with the given information.
103
- """
104
- if not hasattr(self, "_protocols"):
105
- query = ProtocolTemplateQuery()
106
- query.active_templates_only = False
107
- query.latest_version_only = False
108
- self._protocols = self.eln_man.get_protocol_template_info_list(query)
109
- return self._find_template(self._protocols, name, active, version, first_match, public)
110
-
111
- @staticmethod
112
- def _find_template(templates: list[ElnTemplate] | list[ProtocolTemplateInfo], name: str, active: bool,
113
- version: int, first_match: bool, public: bool | None) -> ElnTemplate | ProtocolTemplateInfo:
114
- """
115
- Find the experiment or protocol template with the given information.
116
- """
117
- matches = []
118
- for template in templates:
119
- if template.template_name != name:
120
- continue
121
- if template.active != active:
122
- continue
123
- if version is not None and template.template_version != version:
124
- continue
125
- if public is True and template.template_version is None:
126
- continue
127
- if public is False and template.template_version is not None:
128
- continue
129
- matches.append(template)
130
- if not matches:
131
- raise SapioException(f"No template with the name \"{name}\"" +
132
- ("" if version is None else f" and the version {version}") +
133
- f" found.")
134
- # Only filter for the max version number if any of the matches actually have a version number.
135
- versioned_matches = [x for x in matches if x.template_version is not None]
136
- if version is None and versioned_matches:
137
- return max(versioned_matches, key=lambda x: x.template_version)
138
- if len(matches) > 1 and not first_match:
139
- raise SapioException(f"Multiple templates with the name \"{name}\" found. Consider setting first_match to "
140
- f"true, or restrict your search criteria further.")
141
- return matches[0]
142
-
143
- def get_predefined_field(self, field_name: str, data_type: ElnBaseDataType) -> AbstractVeloxFieldDefinition:
144
- """
145
- Get the predefined field of the given name for the given ELN data type.
146
-
147
- :param field_name: The name of the field.
148
- :param data_type: The ELN data type of the field.
149
- :return: The predefined field of the given name for the given ELN data type.
150
- """
151
- return self.get_predefined_fields(data_type)[field_name]
152
-
153
- def get_predefined_fields(self, data_type: ElnBaseDataType) -> dict[str, AbstractVeloxFieldDefinition]:
154
- """
155
- Get the predefined fields for the given ELN data type.
156
-
157
- :param data_type: The ELN data type to get the predefined fields for.
158
- :return: A dictionary of field name to field definition for the given ELN data type.
159
- """
160
- if data_type.data_type_name not in self._predefined_fields:
161
- fields: list[AbstractVeloxFieldDefinition] = self.eln_man.get_predefined_fields(data_type)
162
- self._predefined_fields[data_type.data_type_name] = {x.data_field_name: x for x in fields}
163
- return self._predefined_fields[data_type.data_type_name]
164
-
165
- def get_field_set(self, name: str) -> ElnFieldSetInfo:
166
- """
167
- Get the field set with the given name.
168
-
169
- :param name: The name of the field set.
170
- :return: The field set with the given name.
171
- """
172
- if not hasattr(self, "_field_sets"):
173
- self._field_sets = {x.field_set_name: x for x in self.eln_man.get_field_set_info_list()}
174
- return self._field_sets[name]
175
-
176
- def get_field_set_fields(self, field_set: ElnFieldSetInfo | int) -> list[AbstractVeloxFieldDefinition]:
177
- """
178
- Get the fields of the given field set.
179
-
180
- :param field_set: The field set to get the fields from. Can be either an ElnFieldSetInfo object or an integer
181
- for the set ID.
182
- :return: The fields of the given field set.
183
- """
184
- field_set: int = field_set if isinstance(field_set, int) else field_set.field_set_id
185
- if field_set in self._field_set_fields:
186
- return self._field_set_fields[field_set]
187
- self._field_set_fields[field_set] = self.eln_man.get_predefined_fields_from_field_set_id(field_set)
188
- return self._field_set_fields[field_set]