sapiopycommons 2025.4.24a494__tar.gz → 2025.4.25a496__tar.gz
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.
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/PKG-INFO +1 -1
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/pyproject.toml +1 -1
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/tool_service_base.py +229 -48
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/.gitignore +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/LICENSE +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/README.md +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.pyi +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2_grpc.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/proto/step_output_pb2.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/proto/step_output_pb2.pyi +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/proto/step_output_pb2_grpc.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/proto/step_pb2.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/proto/step_pb2.pyi +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/proto/step_pb2_grpc.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/script/proto/script_pb2.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/script/proto/script_pb2.pyi +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/script/proto/script_pb2_grpc.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/tool/proto/entry_pb2.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/tool/proto/entry_pb2.pyi +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/tool/proto/entry_pb2_grpc.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/tool/proto/tool_pb2.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/tool/proto/tool_pb2.pyi +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/plan/tool/proto/tool_pb2_grpc.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.pyi +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2_grpc.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/tool_of_tools.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/callbacks/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/callbacks/callback_util.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/callbacks/field_builder.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/chem/IndigoMolecules.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/chem/Molecules.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/chem/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/customreport/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/customreport/auto_pagers.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/customreport/column_builder.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/customreport/custom_report_builder.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/customreport/term_builder.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/datatype/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/datatype/attachment_util.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/datatype/data_fields.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/datatype/pseudo_data_types.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/eln/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/eln/experiment_handler.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/eln/experiment_report_util.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/eln/experiment_tags.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/eln/plate_designer.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/files/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/files/complex_data_loader.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/files/file_bridge.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/files/file_bridge_handler.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/files/file_data_handler.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/files/file_util.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/files/file_validator.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/files/file_writer.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/flowcyto/flow_cyto.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/flowcyto/flowcyto_data.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/accession_service.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/aliases.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/audit_log.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/custom_report_util.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/directive_util.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/exceptions.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/html_formatter.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/popup_util.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/sapio_links.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/storage_util.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/time_util.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/multimodal/multimodal.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/multimodal/multimodal_data.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/processtracking/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/processtracking/custom_workflow_handler.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/processtracking/endpoints.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/recordmodel/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/recordmodel/record_handler.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/rules/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/rules/eln_rule_handler.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/rules/on_save_rule_handler.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/samples/aliquot.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/sftpconnect/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/sftpconnect/sftp_builder.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/webhook/__init__.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/webhook/webhook_context.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/webhook/webhook_handlers.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/webhook/webservice_handlers.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/AF-A0A009IHW8-F1-model_v4.cif +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/_do_not_add_init_py_here +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/accession_test.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/aliquot_test.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/bio_reg_test.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/chem_test.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/chem_test_curation_queue.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/curation_queue_test.sdf +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/data_type_models.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/flowcyto/101_DEN084Y5_15_E01_008_clean.fcs +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/flowcyto/101_DEN084Y5_15_E03_009_clean.fcs +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/flowcyto/101_DEN084Y5_15_E05_010_clean.fcs +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/flowcyto/8_color_ICS.wsp +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/flowcyto/COVID19_W_001_O.fcs +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/flowcyto_test.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/kappa.chains.fasta +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/mafft_test.py +0 -0
- {sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/test.gb +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: sapiopycommons
|
|
3
|
-
Version: 2025.4.
|
|
3
|
+
Version: 2025.4.25a496
|
|
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>
|
|
@@ -7,7 +7,8 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
from grpc import ServicerContext
|
|
9
9
|
|
|
10
|
-
from sapiopycommons.ai.api.fielddefinitions.proto.velox_field_def_pb2 import VeloxFieldDefProto
|
|
10
|
+
from sapiopycommons.ai.api.fielddefinitions.proto.velox_field_def_pb2 import VeloxFieldDefProto, FieldTypeProto, \
|
|
11
|
+
IntegerProperties, DoubleProperties, SelectionProperties, BooleanProperties
|
|
11
12
|
from sapiopycommons.general.aliases import FieldMap
|
|
12
13
|
from sapiopylib.rest.User import SapioUser
|
|
13
14
|
|
|
@@ -183,22 +184,15 @@ class TextResult(SapioToolResult):
|
|
|
183
184
|
|
|
184
185
|
class ToolServiceBase(ToolServiceServicer, ABC):
|
|
185
186
|
"""
|
|
186
|
-
A base class for implementing a tool service.
|
|
187
|
-
|
|
188
|
-
Subclasses must implement the get_details and run methods to provide specific functionality for the tool.
|
|
187
|
+
A base class for implementing a tool service. Subclasses should implement the register_tools method to register
|
|
188
|
+
their tools with the service.
|
|
189
189
|
"""
|
|
190
|
-
tools: list[ToolBase]
|
|
191
|
-
|
|
192
190
|
def GetToolDetails(self, request: ToolDetailsRequest, context: ServicerContext) -> ToolDetailsResponse:
|
|
193
191
|
try:
|
|
194
|
-
#
|
|
195
|
-
|
|
196
|
-
# Get the tool details from the subclass.
|
|
197
|
-
# TODO: Return something other than the ToolDetails proto objects? Something that's cleaner for the
|
|
198
|
-
# implementing class to work with?
|
|
199
|
-
details: list[ToolDetails] = self.get_details(user, request, context)
|
|
192
|
+
# Get the tool details from the registered tools.
|
|
193
|
+
details: list[ToolDetails] = self.get_details()
|
|
200
194
|
return ToolDetailsResponse(tool_framework_version=self.tool_version(), tool_details=details)
|
|
201
|
-
except Exception
|
|
195
|
+
except Exception:
|
|
202
196
|
# TODO: This response doesn't even allow logs. What should we do if an exception occurs in this case?
|
|
203
197
|
return ToolDetailsResponse()
|
|
204
198
|
|
|
@@ -206,22 +200,21 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
206
200
|
try:
|
|
207
201
|
# Convert the SapioConnectionInfo proto object to a SapioUser object.
|
|
208
202
|
user = self.create_user(request.sapio_user)
|
|
209
|
-
# Get the tool results from the
|
|
203
|
+
# Get the tool results from the registered tool matching the request and convert them to proto objects.
|
|
210
204
|
entry_data: list[StepEntryOutputData] = []
|
|
211
205
|
new_records: list[StepRecord] = []
|
|
212
|
-
|
|
206
|
+
# TODO: Make use of the success value after the response object has a field for it.
|
|
207
|
+
success, results, logs = self.run(user, request, context)
|
|
208
|
+
for result in results:
|
|
213
209
|
data: StepEntryOutputData | list[StepRecord] = result.to_proto()
|
|
214
210
|
if isinstance(data, StepEntryOutputData):
|
|
215
211
|
entry_data.append(data)
|
|
216
212
|
else:
|
|
217
213
|
new_records.extend(data)
|
|
218
214
|
# Return a ProcessStepResponse proto object containing the output data and new records to the caller.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
except Exception as e:
|
|
223
|
-
# TODO: Do something other than dump the full stack trace into the logs?
|
|
224
|
-
# TODO: Eventually we'll return an is_success = false value.
|
|
215
|
+
return ProcessStepResponse(entry_data=entry_data, log=logs, new_records=new_records)
|
|
216
|
+
except Exception:
|
|
217
|
+
# TODO: Return a False success result after the response object has a field for it.
|
|
225
218
|
return ProcessStepResponse(log=[traceback.format_exc()])
|
|
226
219
|
|
|
227
220
|
@staticmethod
|
|
@@ -253,32 +246,40 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
253
246
|
|
|
254
247
|
def _get_tools(self) -> list[ToolBase]:
|
|
255
248
|
"""
|
|
256
|
-
Get the tools registered with this service.
|
|
249
|
+
return: Get the tools registered with this service.
|
|
257
250
|
"""
|
|
258
|
-
|
|
259
|
-
if not
|
|
260
|
-
self.tools = self.register_tools()
|
|
261
|
-
# If the tools are still not registered, raise an exception.
|
|
262
|
-
if not self.tools:
|
|
251
|
+
tools: list[ToolBase] = self.register_tools()
|
|
252
|
+
if not tools:
|
|
263
253
|
raise Exception("No tools registered with this service.")
|
|
264
|
-
return
|
|
254
|
+
return tools
|
|
255
|
+
|
|
256
|
+
def _get_tool(self, name: str) -> ToolBase:
|
|
257
|
+
"""
|
|
258
|
+
Get a specific tool by its name.
|
|
259
|
+
|
|
260
|
+
:param name: The name of the tool to retrieve.
|
|
261
|
+
:return: The tool object corresponding to the given name.
|
|
262
|
+
"""
|
|
263
|
+
tools: dict[str, ToolBase] = {x.name: x for x in self.register_tools()}
|
|
264
|
+
if not tools:
|
|
265
|
+
raise Exception("No tools registered with this service.")
|
|
266
|
+
if name not in tools:
|
|
267
|
+
raise Exception(f"Tool \"{name}\" not found in registered tools.")
|
|
268
|
+
return tools[name]
|
|
265
269
|
|
|
266
270
|
@abstractmethod
|
|
267
271
|
def register_tools(self) -> list[ToolBase]:
|
|
268
272
|
"""
|
|
269
|
-
Register the tools with this service.
|
|
273
|
+
Register the tools with this service. Create and instantiate ToolBase subclasses to register them.
|
|
274
|
+
|
|
275
|
+
:return: A list of tools to register to this service.
|
|
270
276
|
"""
|
|
271
277
|
pass
|
|
272
278
|
|
|
273
|
-
|
|
274
|
-
def get_details(self, user: SapioUser, request: ToolDetailsRequest, context: ServicerContext) -> list[ToolDetails]:
|
|
279
|
+
def get_details(self) -> list[ToolDetails]:
|
|
275
280
|
"""
|
|
276
281
|
Get the details of the tool.
|
|
277
282
|
|
|
278
|
-
:param user: A user object that can be used to initialize manager classes using DataMgmtServer to query the
|
|
279
|
-
system.
|
|
280
|
-
:param request: The request object containing the input data.
|
|
281
|
-
:param context: The gRPC context.
|
|
282
283
|
:return: A ToolDetailsResponse object containing the tool details.
|
|
283
284
|
"""
|
|
284
285
|
tool_details: list[ToolDetails] = []
|
|
@@ -286,8 +287,8 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
286
287
|
tool_details.append(tool.to_proto())
|
|
287
288
|
return tool_details
|
|
288
289
|
|
|
289
|
-
|
|
290
|
-
|
|
290
|
+
def run(self, user: SapioUser, request: ProcessStepRequest, context: ServicerContext) \
|
|
291
|
+
-> tuple[bool, list[SapioToolResult], list[str]]:
|
|
291
292
|
"""
|
|
292
293
|
Execute a tool from this service.
|
|
293
294
|
|
|
@@ -295,32 +296,48 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
295
296
|
system.
|
|
296
297
|
:param request: The request object containing the input data.
|
|
297
298
|
:param context: The gRPC context.
|
|
298
|
-
:return:
|
|
299
|
+
:return: Whether or not the tool succeeded, the results of the tool, and any logs generated by the tool.
|
|
299
300
|
"""
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
301
|
+
tool = self._get_tool(request.tool_name)
|
|
302
|
+
try:
|
|
303
|
+
results = tool.run(user, request, context)
|
|
304
|
+
return True, results, tool.logs
|
|
305
|
+
except Exception:
|
|
306
|
+
tool.log_message(traceback.format_exc())
|
|
307
|
+
return False, [], tool.logs
|
|
304
308
|
|
|
305
309
|
|
|
306
310
|
class ToolBase(ABC):
|
|
311
|
+
"""
|
|
312
|
+
A base class for implementing a tool.
|
|
313
|
+
"""
|
|
307
314
|
name: str
|
|
308
315
|
description: str
|
|
309
316
|
data_type_name: str | None
|
|
310
317
|
inputs: list[ToolInputDetails]
|
|
311
318
|
outputs: list[ToolOutputDetails]
|
|
312
319
|
configs: list[VeloxFieldDefProto]
|
|
320
|
+
logs: list[str]
|
|
313
321
|
|
|
314
322
|
def __init__(self, name: str, description: str, data_type_name: str | None = None):
|
|
323
|
+
"""
|
|
324
|
+
:param name: The name of the tool.
|
|
325
|
+
:param description: A description of the tool.
|
|
326
|
+
:param data_type_name: The name of the output data type of this tool, if applicable. When this tool returns
|
|
327
|
+
FieldMapResult objects in its run method, this name will be used to set the data type of the output data.
|
|
328
|
+
"""
|
|
315
329
|
self.name = name
|
|
316
330
|
self.description = description
|
|
317
331
|
self.data_type_name = data_type_name
|
|
318
332
|
self.inputs = []
|
|
319
333
|
self.outputs = []
|
|
334
|
+
self.configs = []
|
|
335
|
+
self.logs = []
|
|
320
336
|
|
|
321
337
|
def add_input(self, details: ToolInputDetails) -> None:
|
|
322
338
|
"""
|
|
323
|
-
Add an input configuration to the tool.
|
|
339
|
+
Add an input configuration to the tool. This determines how many inputs this tool will accept in the plan
|
|
340
|
+
manager, as well as what those inputs are.
|
|
324
341
|
|
|
325
342
|
:param details: The input configuration details.
|
|
326
343
|
"""
|
|
@@ -328,7 +345,8 @@ class ToolBase(ABC):
|
|
|
328
345
|
|
|
329
346
|
def add_output(self, details: ToolOutputDetails) -> None:
|
|
330
347
|
"""
|
|
331
|
-
Add an output configuration to the tool.
|
|
348
|
+
Add an output configuration to the tool. This determines how many outputs this tool will return in the plan
|
|
349
|
+
manager, as well as what those outputs are.
|
|
332
350
|
|
|
333
351
|
:param details: The output configuration details.
|
|
334
352
|
"""
|
|
@@ -336,17 +354,119 @@ class ToolBase(ABC):
|
|
|
336
354
|
|
|
337
355
|
def add_config_field(self, field: VeloxFieldDefProto) -> None:
|
|
338
356
|
"""
|
|
339
|
-
Add a configuration field to the tool.
|
|
357
|
+
Add a configuration field to the tool. This field will be used to configure the tool in the plan manager.
|
|
340
358
|
|
|
341
359
|
:param field: The configuration field details.
|
|
342
360
|
"""
|
|
343
361
|
self.configs.append(field)
|
|
344
362
|
|
|
363
|
+
def add_integer_config_field(self, field_name: str, display_name: str, description: str,
|
|
364
|
+
default_value: int, min_value: int = -2**31, max_value: int = 2**31-1) -> None:
|
|
365
|
+
"""
|
|
366
|
+
Add an integer configuration field to the tool. This field will be used to configure the tool in the plan
|
|
367
|
+
manager.
|
|
368
|
+
|
|
369
|
+
:param field_name: The name of the field.
|
|
370
|
+
:param display_name: The display name of the field.
|
|
371
|
+
:param description: The description of the field.
|
|
372
|
+
:param default_value: The default value of the field.
|
|
373
|
+
:param min_value: The minimum value of the field.
|
|
374
|
+
:param max_value: The maximum value of the field.
|
|
375
|
+
"""
|
|
376
|
+
self.configs.append(VeloxFieldDefProto(
|
|
377
|
+
data_field_type=FieldTypeProto.INTEGER,
|
|
378
|
+
data_field_name=field_name,
|
|
379
|
+
display_name=display_name,
|
|
380
|
+
description=description,
|
|
381
|
+
required=True,
|
|
382
|
+
editable=True,
|
|
383
|
+
integer_properties=IntegerProperties(
|
|
384
|
+
default_value=default_value,
|
|
385
|
+
min_value=min_value,
|
|
386
|
+
max_value=max_value
|
|
387
|
+
)
|
|
388
|
+
))
|
|
389
|
+
|
|
390
|
+
def add_double_config_field(self, field_name: str, display_name: str, description: str, default_value: float,
|
|
391
|
+
min_value: float = -10.**120, max_value: float = 10.**120, precision: int = 2) -> None:
|
|
392
|
+
"""
|
|
393
|
+
Add a double configuration field to the tool. This field will be used to configure the tool in the plan
|
|
394
|
+
manager.
|
|
395
|
+
|
|
396
|
+
:param field_name: The name of the field.
|
|
397
|
+
:param display_name: The display name of the field.
|
|
398
|
+
:param description: The description of the field.
|
|
399
|
+
:param default_value: The default value of the field.
|
|
400
|
+
:param min_value: The minimum value of the field.
|
|
401
|
+
:param max_value: The maximum value of the field.
|
|
402
|
+
:param precision: The precision of the field.
|
|
403
|
+
"""
|
|
404
|
+
self.configs.append(VeloxFieldDefProto(
|
|
405
|
+
data_field_type=FieldTypeProto.DOUBLE,
|
|
406
|
+
data_field_name=field_name,
|
|
407
|
+
display_name=display_name,
|
|
408
|
+
description=description,
|
|
409
|
+
required=True,
|
|
410
|
+
editable=True,
|
|
411
|
+
double_properties=DoubleProperties(
|
|
412
|
+
default_value=default_value,
|
|
413
|
+
min_value=min_value,
|
|
414
|
+
max_value=max_value,
|
|
415
|
+
precision=precision
|
|
416
|
+
)
|
|
417
|
+
))
|
|
418
|
+
|
|
419
|
+
def add_list_config_field(self, field_name: str, display_name: str, description: str, default_value: str,
|
|
420
|
+
allowed_values: list[str]) -> None:
|
|
421
|
+
"""
|
|
422
|
+
Add a list configuration field to the tool. This field will be used to configure the tool in the plan
|
|
423
|
+
manager.
|
|
424
|
+
|
|
425
|
+
:param field_name: The name of the field.
|
|
426
|
+
:param display_name: The display name of the field.
|
|
427
|
+
:param description: The description of the field.
|
|
428
|
+
:param default_value: The default value of the field.
|
|
429
|
+
:param allowed_values: The list of allowed values for the field.
|
|
430
|
+
"""
|
|
431
|
+
self.configs.append(VeloxFieldDefProto(
|
|
432
|
+
data_field_type=FieldTypeProto.SELECTION,
|
|
433
|
+
data_field_name=field_name,
|
|
434
|
+
display_name=display_name,
|
|
435
|
+
description=description,
|
|
436
|
+
required=True,
|
|
437
|
+
editable=True,
|
|
438
|
+
selection_properties=SelectionProperties(
|
|
439
|
+
default_value=default_value,
|
|
440
|
+
static_list_values=allowed_values,
|
|
441
|
+
)
|
|
442
|
+
))
|
|
443
|
+
|
|
444
|
+
def add_boolean_config_field(self, field_name: str, display_name: str, description: str, default_value: bool) \
|
|
445
|
+
-> None:
|
|
446
|
+
"""
|
|
447
|
+
Add a boolean configuration field to the tool. This field will be used to configure the tool in the plan
|
|
448
|
+
manager.
|
|
449
|
+
|
|
450
|
+
:param field_name: The name of the field.
|
|
451
|
+
:param display_name: The display name of the field.
|
|
452
|
+
:param description: The description of the field.
|
|
453
|
+
:param default_value: The default value of the field.
|
|
454
|
+
"""
|
|
455
|
+
self.configs.append(VeloxFieldDefProto(
|
|
456
|
+
data_field_type=FieldTypeProto.BOOLEAN,
|
|
457
|
+
data_field_name=field_name,
|
|
458
|
+
display_name=display_name,
|
|
459
|
+
description=description,
|
|
460
|
+
required=True,
|
|
461
|
+
editable=True,
|
|
462
|
+
boolean_properties=BooleanProperties(
|
|
463
|
+
default_value=default_value
|
|
464
|
+
)
|
|
465
|
+
))
|
|
466
|
+
|
|
345
467
|
def to_proto(self) -> ToolDetails:
|
|
346
468
|
"""
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
:return: The ToolDetails proto object.
|
|
469
|
+
:return: The ToolDetails proto object representing this tool.
|
|
350
470
|
"""
|
|
351
471
|
return ToolDetails(
|
|
352
472
|
name=self.name,
|
|
@@ -357,6 +477,14 @@ class ToolBase(ABC):
|
|
|
357
477
|
config_fields=self.configs
|
|
358
478
|
)
|
|
359
479
|
|
|
480
|
+
def log_message(self, message: str) -> None:
|
|
481
|
+
"""
|
|
482
|
+
Log a message for this tool. This message will be included in the logs returned to the caller.
|
|
483
|
+
|
|
484
|
+
:param message: The message to log.
|
|
485
|
+
"""
|
|
486
|
+
self.logs.append(message)
|
|
487
|
+
|
|
360
488
|
@abstractmethod
|
|
361
489
|
def run(self, user: SapioUser, request: ProcessStepRequest, context: ServicerContext) -> list[SapioToolResult]:
|
|
362
490
|
"""
|
|
@@ -369,3 +497,56 @@ class ToolBase(ABC):
|
|
|
369
497
|
:return: A SapioToolResults object containing the response data.
|
|
370
498
|
"""
|
|
371
499
|
pass
|
|
500
|
+
|
|
501
|
+
@staticmethod
|
|
502
|
+
def get_request_json(request: ProcessStepRequest, index: int = 0) -> list[Any]:
|
|
503
|
+
"""
|
|
504
|
+
Parse the JSON data from the request object.
|
|
505
|
+
|
|
506
|
+
:param request: The request object containing the input data.
|
|
507
|
+
:param index: The index of the input to parse. Defaults to 0.
|
|
508
|
+
:return: A list of parsed JSON objects. Each entry in the list represents a separate JSON entry from the input.
|
|
509
|
+
"""
|
|
510
|
+
entry_data = request.entry_data
|
|
511
|
+
input_data: list[Any] = [json.loads(x) for x in entry_data[index].entry_data.json_data.entries]
|
|
512
|
+
return input_data
|
|
513
|
+
|
|
514
|
+
@staticmethod
|
|
515
|
+
def read_from_json(json_data: list[dict[str, Any]], key: str) -> list[Any]:
|
|
516
|
+
"""
|
|
517
|
+
From a list of dictionaries, return a list of values for the given key from each dictionary. Skips null values.
|
|
518
|
+
|
|
519
|
+
:param json_data: The JSON data to read from.
|
|
520
|
+
:param key: The key to read the values from.
|
|
521
|
+
:return: A list of values corresponding to the given key in the JSON data.
|
|
522
|
+
"""
|
|
523
|
+
ret_val: list[Any] = []
|
|
524
|
+
for entry in json_data:
|
|
525
|
+
if key in entry:
|
|
526
|
+
value = entry[key]
|
|
527
|
+
if isinstance(value, list):
|
|
528
|
+
ret_val.extend(value)
|
|
529
|
+
elif value is not None:
|
|
530
|
+
ret_val.append(value)
|
|
531
|
+
return ret_val
|
|
532
|
+
|
|
533
|
+
@staticmethod
|
|
534
|
+
def get_config_fields(request: ProcessStepRequest) -> dict[str, Any]:
|
|
535
|
+
"""
|
|
536
|
+
Get the configuration fields from the request object.
|
|
537
|
+
|
|
538
|
+
:param request: The request object containing the input data.
|
|
539
|
+
:return: A dictionary of configuration field names and their values.
|
|
540
|
+
"""
|
|
541
|
+
config_fields: dict[str, Any] = {}
|
|
542
|
+
for field, value in request.config_field_values.items():
|
|
543
|
+
if value.bool_value is not None:
|
|
544
|
+
value = value.bool_value
|
|
545
|
+
elif value.string_value is not None:
|
|
546
|
+
value = value.string_value
|
|
547
|
+
elif value.int_value is not None:
|
|
548
|
+
value = value.int_value
|
|
549
|
+
elif value.double_value is not None:
|
|
550
|
+
value = value.double_value
|
|
551
|
+
config_fields[field] = value
|
|
552
|
+
return config_fields
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/__init__.py
RENAMED
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/ai/tool_of_tools.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/chem/Molecules.py
RENAMED
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/chem/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/eln/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/files/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/files/file_util.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/general/aliases.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/rules/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/samples/aliquot.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/src/sapiopycommons/webhook/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/AF-A0A009IHW8-F1-model_v4.cif
RENAMED
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/_do_not_add_init_py_here
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/chem_test_curation_queue.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/flowcyto/8_color_ICS.wsp
RENAMED
|
File without changes
|
{sapiopycommons-2025.4.24a494 → sapiopycommons-2025.4.25a496}/tests/flowcyto/COVID19_W_001_O.fcs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|