sapiopycommons 2025.7.9a582__py3-none-any.whl → 2025.7.10a595__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 (60) hide show
  1. sapiopycommons/callbacks/callback_util.py +665 -332
  2. sapiopycommons/callbacks/field_builder.py +2 -0
  3. sapiopycommons/chem/IndigoMolecules.py +31 -1
  4. sapiopycommons/chem/Molecules.py +3 -3
  5. sapiopycommons/chem/ps_commons.py +523 -0
  6. sapiopycommons/customreport/auto_pagers.py +26 -1
  7. sapiopycommons/customreport/term_builder.py +1 -1
  8. sapiopycommons/datatype/pseudo_data_types.py +349 -326
  9. sapiopycommons/eln/experiment_cache.py +188 -0
  10. sapiopycommons/eln/experiment_handler.py +408 -767
  11. sapiopycommons/eln/experiment_report_util.py +11 -6
  12. sapiopycommons/eln/experiment_step_factory.py +476 -0
  13. sapiopycommons/eln/plate_designer.py +7 -2
  14. sapiopycommons/eln/step_creation.py +236 -0
  15. sapiopycommons/files/file_util.py +7 -5
  16. sapiopycommons/general/accession_service.py +2 -2
  17. sapiopycommons/general/aliases.py +3 -1
  18. sapiopycommons/general/audit_log.py +7 -0
  19. sapiopycommons/general/custom_report_util.py +12 -0
  20. sapiopycommons/general/data_structure_util.py +115 -0
  21. sapiopycommons/processtracking/custom_workflow_handler.py +11 -1
  22. sapiopycommons/processtracking/endpoints.py +27 -0
  23. sapiopycommons/recordmodel/record_handler.py +657 -317
  24. sapiopycommons/rules/eln_rule_handler.py +8 -1
  25. sapiopycommons/rules/on_save_rule_handler.py +8 -1
  26. sapiopycommons/webhook/webhook_handlers.py +3 -0
  27. sapiopycommons/webhook/webservice_handlers.py +2 -2
  28. {sapiopycommons-2025.7.9a582.dist-info → sapiopycommons-2025.7.10a595.dist-info}/METADATA +2 -2
  29. sapiopycommons-2025.7.10a595.dist-info/RECORD +69 -0
  30. sapiopycommons/ai/__init__.py +0 -0
  31. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.py +0 -43
  32. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.pyi +0 -31
  33. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2_grpc.py +0 -24
  34. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.py +0 -123
  35. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.pyi +0 -598
  36. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2_grpc.py +0 -24
  37. sapiopycommons/ai/api/plan/proto/step_output_pb2.py +0 -45
  38. sapiopycommons/ai/api/plan/proto/step_output_pb2.pyi +0 -42
  39. sapiopycommons/ai/api/plan/proto/step_output_pb2_grpc.py +0 -24
  40. sapiopycommons/ai/api/plan/proto/step_pb2.py +0 -43
  41. sapiopycommons/ai/api/plan/proto/step_pb2.pyi +0 -43
  42. sapiopycommons/ai/api/plan/proto/step_pb2_grpc.py +0 -24
  43. sapiopycommons/ai/api/plan/script/proto/script_pb2.py +0 -55
  44. sapiopycommons/ai/api/plan/script/proto/script_pb2.pyi +0 -115
  45. sapiopycommons/ai/api/plan/script/proto/script_pb2_grpc.py +0 -153
  46. sapiopycommons/ai/api/plan/tool/proto/entry_pb2.py +0 -57
  47. sapiopycommons/ai/api/plan/tool/proto/entry_pb2.pyi +0 -96
  48. sapiopycommons/ai/api/plan/tool/proto/entry_pb2_grpc.py +0 -24
  49. sapiopycommons/ai/api/plan/tool/proto/tool_pb2.py +0 -67
  50. sapiopycommons/ai/api/plan/tool/proto/tool_pb2.pyi +0 -220
  51. sapiopycommons/ai/api/plan/tool/proto/tool_pb2_grpc.py +0 -154
  52. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.py +0 -39
  53. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.pyi +0 -32
  54. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2_grpc.py +0 -24
  55. sapiopycommons/ai/protobuf_utils.py +0 -508
  56. sapiopycommons/ai/test_client.py +0 -251
  57. sapiopycommons/ai/tool_service_base.py +0 -798
  58. sapiopycommons-2025.7.9a582.dist-info/RECORD +0 -92
  59. {sapiopycommons-2025.7.9a582.dist-info → sapiopycommons-2025.7.10a595.dist-info}/WHEEL +0 -0
  60. {sapiopycommons-2025.7.9a582.dist-info → sapiopycommons-2025.7.10a595.dist-info}/licenses/LICENSE +0 -0
@@ -1,251 +0,0 @@
1
- import json
2
- from typing import Mapping, Any
3
-
4
- import grpc
5
-
6
- from sapiopycommons.ai.api.fielddefinitions.proto.fields_pb2 import FieldValuePbo
7
- from sapiopycommons.ai.api.plan.tool.proto.entry_pb2 import DataTypePbo, StepBinaryContainerPbo, StepCsvRowPbo, \
8
- StepCsvHeaderRowPbo, StepCsvContainerPbo, StepJsonContainerPbo, StepImageContainerPbo, StepTextContainerPbo, \
9
- StepItemContainerPbo, StepInputBatchPbo
10
- from sapiopycommons.ai.api.plan.tool.proto.tool_pb2 import ProcessStepResponsePbo, ProcessStepRequestPbo, \
11
- ToolDetailsRequestPbo, ToolDetailsResponsePbo
12
- from sapiopycommons.ai.api.plan.tool.proto.tool_pb2_grpc import ToolServiceStub
13
- from sapiopycommons.ai.api.session.proto.sapio_conn_info_pb2 import SapioConnectionInfoPbo, SapioUserSecretTypePbo
14
-
15
-
16
- class ToolOutput:
17
- """
18
- A class for holding the output of a TestClient that calls a ToolService. ToolOutput objects an be
19
- printed to show the output of the tool in a human-readable format.
20
- """
21
- tool_name: str
22
-
23
- binary_output: list[bytes]
24
- csv_output: list[dict[str, Any]]
25
- json_output: list[Any]
26
- image_output: list[bytes]
27
- text_output: list[str]
28
-
29
- new_records: list[Mapping[str, FieldValuePbo]]
30
-
31
- logs: list[str]
32
-
33
- def __init__(self, tool_name: str):
34
- self.tool_name = tool_name
35
- self.binary_output = []
36
- self.csv_output = []
37
- self.json_output = []
38
- self.image_output = []
39
- self.text_output = []
40
- self.new_records = []
41
- self.logs = []
42
-
43
- def __str__(self):
44
- ret_val: str = f"{self.tool_name} Output:\n"
45
- ret_val += "-" * 25 + "\n"
46
- ret_val += f"Binary Output: {len(self.binary_output)} item(s)\n"
47
- for binary in self.binary_output:
48
- ret_val += f"\t{len(binary)} byte(s)\n"
49
- ret_val += f"\t{binary[:50]}...\n"
50
- ret_val += f"CSV Output: {len(self.csv_output)} item(s)\n"
51
- if self.csv_output:
52
- ret_val += f"\tHeaders: {', '.join(self.csv_output[0].keys())}\n"
53
- for i, csv_row in enumerate(self.csv_output):
54
- ret_val += f"\t{i}: {', '.join(f'{v}' for k, v in csv_row.items())}\n"
55
- ret_val += f"JSON Output: {len(self.json_output)} item(s)\n"
56
- if self.json_output:
57
- ret_val += f"\t{json.dumps(self.json_output, indent=2)}\n"
58
- ret_val += f"Image Output: {len(self.image_output)} item(s)\n"
59
- for image in self.image_output:
60
- ret_val += f"\t{len(image)} bytes\n"
61
- ret_val += f"\t{image[:50]}...\n"
62
- ret_val += f"Text Output: {len(self.text_output)} item(s)\n"
63
- for text in self.text_output:
64
- ret_val += f"\t{text}...\n"
65
- ret_val += f"New Records: {len(self.new_records)} item(s)\n"
66
- for record in self.new_records:
67
- ret_val += f"\t{json.dumps(record, indent=2)}\n"
68
- ret_val += f"Logs: {len(self.logs)} item(s)\n"
69
- for log in self.logs:
70
- ret_val += f"\t{log}\n"
71
- return ret_val
72
-
73
-
74
- class TestClient:
75
- """
76
- A client for testing a ToolService. This client can be used to send requests to a tool and receive
77
- responses.
78
- """
79
- server_url: str
80
- connection: SapioConnectionInfoPbo
81
- _request_inputs: list[Any]
82
- _config_fields: dict[str, Any]
83
-
84
- def __init__(self, server_url: str):
85
- """
86
- :param server_url: The URL of the gRPC server to connect to.
87
- """
88
- self.create_user()
89
- self.server_url = server_url
90
- self._request_inputs = []
91
- self._config_fields = {}
92
-
93
- def create_user(self):
94
- """
95
- Create a SapioConnectionInfoPbo object with test credentials. This method can be overridden to
96
- create a user with specific credentials for testing.
97
- """
98
- self.connection = SapioConnectionInfoPbo()
99
- self.connection.username = "Testing"
100
- self.connection.webservice_url = "https://localhost:8080/webservice/api"
101
- self.connection.app_guid = "1234567890"
102
- self.connection.secret_type = SapioUserSecretTypePbo.PASSWORD
103
- self.connection.rmi_host.append("Testing")
104
- self.connection.rmi_port = 9001
105
- self.connection.secret = "password"
106
-
107
- def add_input_input(self, input_data: list[bytes]) -> None:
108
- """
109
- Add a binary input to the the next request.
110
- """
111
- self._add_input(DataTypePbo.BINARY, StepBinaryContainerPbo(items=input_data))
112
-
113
- def add_csv_input(self, input_data: list[dict[str, Any]]) -> None:
114
- """
115
- Add a CSV input to the next request.
116
- """
117
- csv_items = []
118
- for row in input_data:
119
- csv_items.append(StepCsvRowPbo(cells=[str(value) for value in row.values()]))
120
- header = StepCsvHeaderRowPbo(cells=list(input_data[0].keys()))
121
- self._add_input(DataTypePbo.CSV, StepCsvContainerPbo(header=header, items=csv_items))
122
-
123
- def add_json_input(self, input_data: list[dict[str, Any]]) -> None:
124
- """
125
- Add a JSON input to the next request.
126
- """
127
- self._add_input(DataTypePbo.JSON, StepJsonContainerPbo(items=[json.dumps(x) for x in input_data]))
128
-
129
- def add_image_input(self, input_data: list[bytes], image_format: str = "png") -> None:
130
- """
131
- Add an image input to the next request.
132
- """
133
- self._add_input(DataTypePbo.IMAGE, StepImageContainerPbo(items=input_data, image_format=image_format))
134
-
135
- def add_text_input(self, input_data: list[str]) -> None:
136
- """
137
- Add a text input to the next request.
138
- """
139
- self._add_input(DataTypePbo.TEXT, StepTextContainerPbo(items=input_data))
140
-
141
- def clear_inputs(self) -> None:
142
- """
143
- Clear all inputs that have been added to the next request.
144
- This is useful if you want to start a new request without the previous inputs.
145
- """
146
- self._request_inputs.clear()
147
-
148
- def add_config_field(self, field_name: str, value: Any) -> None:
149
- """
150
- Add a configuration field value to the next request.
151
-
152
- :param field_name: The name of the configuration field.
153
- :param value: The value to set for the configuration field.
154
- """
155
- self._config_fields[field_name] = value
156
-
157
- def add_config_fields(self, config_fields: dict[str, Any]) -> None:
158
- """
159
- Add multiple configuration field values to the next request.
160
-
161
- :param config_fields: A dictionary of configuration field names and their corresponding values.
162
- """
163
- self._config_fields.update(config_fields)
164
-
165
- def clear_configs(self) -> None:
166
- """
167
- Clear all configuration field values that have been added to the next request.
168
- This is useful if you want to start a new request without the previous configurations.
169
- """
170
- self._config_fields.clear()
171
-
172
- def clear_request(self) -> None:
173
- """
174
- Clear all inputs and configuration fields that have been added to the next request.
175
- This is useful if you want to start a new request without the previous inputs and configurations.
176
- """
177
- self.clear_inputs()
178
- self.clear_configs()
179
-
180
- def _add_input(self, data_type: DataTypePbo, items: Any) -> None:
181
- """
182
- Helper method for adding inputs to the next request.
183
- """
184
- match data_type:
185
- case DataTypePbo.BINARY:
186
- container = StepItemContainerPbo(dataType=data_type, binary_container=items)
187
- case DataTypePbo.CSV:
188
- container = StepItemContainerPbo(dataType=data_type, csv_container=items)
189
- case DataTypePbo.JSON:
190
- container = StepItemContainerPbo(dataType=data_type, json_container=items)
191
- case DataTypePbo.IMAGE:
192
- container = StepItemContainerPbo(dataType=data_type, image_container=items)
193
- case DataTypePbo.TEXT:
194
- container = StepItemContainerPbo(dataType=data_type, text_container=items)
195
- case _:
196
- raise ValueError(f"Unsupported data type: {data_type}")
197
- self._request_inputs.append(container)
198
-
199
- def get_service_details(self) -> ToolDetailsResponsePbo:
200
- """
201
- Get the details of the tools from the server.
202
-
203
- :return: A ToolDetailsResponsePbo object containing the details of the tool service.
204
- """
205
- with grpc.insecure_channel(self.server_url) as channel:
206
- stub = ToolServiceStub(channel)
207
- return stub.GetToolDetails(ToolDetailsRequestPbo(sapio_conn_info=self.connection))
208
-
209
- def call_tool(self, tool_name: str) -> ToolOutput:
210
- """
211
- Send the request to the tool service for a particular tool name. This will send all the inputs that have been
212
- added using the add_X_input functions.
213
-
214
- :param tool_name: The name of the tool to call on the server.
215
- :return: A ToolOutput object containing the results of the tool service call.
216
- """
217
- with grpc.insecure_channel(self.server_url) as channel:
218
- stub = ToolServiceStub(channel)
219
-
220
- response: ProcessStepResponsePbo = stub.ProcessData(
221
- ProcessStepRequestPbo(
222
- sapio_user=self.connection,
223
- tool_name=tool_name,
224
- config_field_values=self._config_fields,
225
- input=[
226
- StepInputBatchPbo(is_partial=False, item_container=item)
227
- for item in self._request_inputs
228
- ]
229
- )
230
- )
231
-
232
- results = ToolOutput(tool_name)
233
- for item in response.output:
234
- container = item.item_container
235
-
236
- results.binary_output.extend(container.binary_container.items)
237
- for header in container.csv_container.header.cells:
238
- output_row: dict[str, Any] = {}
239
- for i, row in enumerate(container.csv_container.items):
240
- output_row[header] = row.cells[i]
241
- results.csv_output.append(output_row)
242
- results.json_output.extend([json.loads(x) for x in container.json_container.items])
243
- results.image_output.extend(container.image_container.items)
244
- results.text_output.extend(container.text_container.items)
245
-
246
- for record in response.new_records:
247
- results.new_records.append(record.fields)
248
-
249
- results.logs.extend(response.log)
250
-
251
- return results