sapiopycommons 2024.11.11a364__py3-none-any.whl → 2024.11.18a366__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 (47) hide show
  1. sapiopycommons/callbacks/callback_util.py +532 -83
  2. sapiopycommons/callbacks/field_builder.py +537 -0
  3. sapiopycommons/chem/IndigoMolecules.py +2 -0
  4. sapiopycommons/chem/Molecules.py +77 -18
  5. sapiopycommons/customreport/__init__.py +0 -0
  6. sapiopycommons/customreport/column_builder.py +60 -0
  7. sapiopycommons/customreport/custom_report_builder.py +130 -0
  8. sapiopycommons/customreport/term_builder.py +299 -0
  9. sapiopycommons/datatype/attachment_util.py +11 -10
  10. sapiopycommons/datatype/data_fields.py +61 -0
  11. sapiopycommons/datatype/pseudo_data_types.py +440 -0
  12. sapiopycommons/eln/experiment_handler.py +272 -70
  13. sapiopycommons/eln/experiment_report_util.py +653 -0
  14. sapiopycommons/files/complex_data_loader.py +5 -4
  15. sapiopycommons/files/file_bridge.py +31 -24
  16. sapiopycommons/files/file_bridge_handler.py +340 -0
  17. sapiopycommons/files/file_data_handler.py +2 -5
  18. sapiopycommons/files/file_util.py +59 -9
  19. sapiopycommons/files/file_validator.py +92 -6
  20. sapiopycommons/files/file_writer.py +44 -15
  21. sapiopycommons/flowcyto/flow_cyto.py +77 -0
  22. sapiopycommons/flowcyto/flowcyto_data.py +75 -0
  23. sapiopycommons/general/accession_service.py +375 -0
  24. sapiopycommons/general/aliases.py +207 -6
  25. sapiopycommons/general/audit_log.py +189 -0
  26. sapiopycommons/general/custom_report_util.py +212 -37
  27. sapiopycommons/general/exceptions.py +21 -8
  28. sapiopycommons/general/popup_util.py +21 -0
  29. sapiopycommons/general/sapio_links.py +50 -0
  30. sapiopycommons/general/time_util.py +8 -2
  31. sapiopycommons/multimodal/multimodal.py +146 -0
  32. sapiopycommons/multimodal/multimodal_data.py +490 -0
  33. sapiopycommons/processtracking/custom_workflow_handler.py +406 -0
  34. sapiopycommons/processtracking/endpoints.py +22 -22
  35. sapiopycommons/recordmodel/record_handler.py +481 -97
  36. sapiopycommons/rules/eln_rule_handler.py +34 -25
  37. sapiopycommons/rules/on_save_rule_handler.py +34 -31
  38. sapiopycommons/sftpconnect/__init__.py +0 -0
  39. sapiopycommons/sftpconnect/sftp_builder.py +69 -0
  40. sapiopycommons/webhook/webhook_context.py +39 -0
  41. sapiopycommons/webhook/webhook_handlers.py +201 -42
  42. sapiopycommons/webhook/webservice_handlers.py +67 -0
  43. {sapiopycommons-2024.11.11a364.dist-info → sapiopycommons-2024.11.18a366.dist-info}/METADATA +5 -2
  44. sapiopycommons-2024.11.18a366.dist-info/RECORD +59 -0
  45. {sapiopycommons-2024.11.11a364.dist-info → sapiopycommons-2024.11.18a366.dist-info}/WHEEL +1 -1
  46. sapiopycommons-2024.11.11a364.dist-info/RECORD +0 -38
  47. {sapiopycommons-2024.11.11a364.dist-info → sapiopycommons-2024.11.18a366.dist-info}/licenses/LICENSE +0 -0
@@ -4,16 +4,25 @@ from logging import Logger
4
4
 
5
5
  from sapiopylib.rest.DataMgmtService import DataMgmtServer
6
6
  from sapiopylib.rest.DataRecordManagerService import DataRecordManager
7
+ from sapiopylib.rest.User import SapioUser
7
8
  from sapiopylib.rest.WebhookService import AbstractWebhookHandler
9
+ from sapiopylib.rest.pojo.Message import VeloxLogMessage, VeloxLogLevel
8
10
  from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
9
11
  from sapiopylib.rest.pojo.webhook.WebhookEnums import WebhookEndpointType
10
12
  from sapiopylib.rest.pojo.webhook.WebhookResult import SapioWebhookResult
13
+ from sapiopylib.rest.utils.DataTypeCacheManager import DataTypeCacheManager
11
14
  from sapiopylib.rest.utils.recordmodel.RecordModelManager import RecordModelManager, RecordModelInstanceManager, \
12
15
  RecordModelRelationshipManager
13
16
  from sapiopylib.rest.utils.recordmodel.ancestry import RecordModelAncestorManager
14
17
 
18
+ from sapiopycommons.callbacks.callback_util import CallbackUtil
19
+ from sapiopycommons.eln.experiment_handler import ExperimentHandler
15
20
  from sapiopycommons.general.exceptions import SapioUserErrorException, SapioCriticalErrorException, \
16
- SapioUserCancelledException
21
+ SapioUserCancelledException, SapioException, SapioDialogTimeoutException
22
+ from sapiopycommons.general.sapio_links import SapioNavigationLinker
23
+ from sapiopycommons.recordmodel.record_handler import RecordHandler
24
+ from sapiopycommons.rules.eln_rule_handler import ElnRuleHandler
25
+ from sapiopycommons.rules.on_save_rule_handler import OnSaveRuleHandler
17
26
 
18
27
 
19
28
  # FR-46064 - Initial port of PyWebhookUtils to sapiopycommons.
@@ -25,6 +34,7 @@ class CommonsWebhookHandler(AbstractWebhookHandler):
25
34
  """
26
35
  logger: Logger
27
36
 
37
+ user: SapioUser
28
38
  context: SapioWebhookContext
29
39
 
30
40
  dr_man: DataRecordManager
@@ -34,29 +44,64 @@ class CommonsWebhookHandler(AbstractWebhookHandler):
34
44
  # FR-46329: Add the ancestor manager to CommonsWebhookHandler.
35
45
  an_man: RecordModelAncestorManager
36
46
 
47
+ dt_cache: DataTypeCacheManager
48
+ rec_handler: RecordHandler
49
+ callback: CallbackUtil
50
+ exp_handler: ExperimentHandler | None
51
+ rule_handler: OnSaveRuleHandler | ElnRuleHandler | None
52
+
37
53
  def run(self, context: SapioWebhookContext) -> SapioWebhookResult:
54
+ self.user = context.user
38
55
  self.context = context
39
- self.logger = context.user.logger
56
+
57
+ self.logger = self.user.logger
40
58
 
41
59
  self.dr_man = context.data_record_manager
42
- self.rec_man = RecordModelManager(context.user)
60
+ self.rec_man = RecordModelManager(self.user)
43
61
  self.inst_man = self.rec_man.instance_manager
44
62
  self.rel_man = self.rec_man.relationship_manager
45
63
  self.an_man = RecordModelAncestorManager(self.rec_man)
46
64
 
65
+ self.dt_cache = DataTypeCacheManager(self.user)
66
+ self.rec_handler = RecordHandler(context)
67
+ self.callback = CallbackUtil(context)
68
+ if context.eln_experiment is not None:
69
+ self.exp_handler = ExperimentHandler(context)
70
+ else:
71
+ self.exp_handler = None
72
+ if self.is_on_save_rule():
73
+ self.rule_handler = OnSaveRuleHandler(context)
74
+ elif self.is_eln_rule():
75
+ self.rule_handler = ElnRuleHandler(context)
76
+ else:
77
+ self.rule_handler = None
78
+
47
79
  # Wrap the execution of each webhook in a try/catch. If an exception occurs, handle any special sapiopycommons
48
80
  # exceptions. Otherwise, return a generic message stating that an error occurred.
49
81
  try:
50
- return self.execute(context)
82
+ self.initialize(context)
83
+ result = self.execute(context)
84
+ if result is None:
85
+ raise SapioException("Your execute function returned a None result! Don't forget your return statement!")
86
+ return result
51
87
  except SapioUserErrorException as e:
52
88
  return self.handle_user_error_exception(e)
53
89
  except SapioCriticalErrorException as e:
54
90
  return self.handle_critical_error_exception(e)
55
91
  except SapioUserCancelledException as e:
56
92
  return self.handle_user_cancelled_exception(e)
93
+ except SapioDialogTimeoutException as e:
94
+ return self.handle_dialog_timeout_exception(e)
57
95
  except Exception as e:
58
96
  return self.handle_unexpected_exception(e)
59
97
 
98
+ def initialize(self, context: SapioWebhookContext) -> None:
99
+ """
100
+ A function that can be optionally overridden by your webhooks to initialize additional instance variables,
101
+ or set up whatever else you wish to set up before the execute function is ran. Default behavior does nothing.
102
+ """
103
+ pass
104
+
60
105
  @abstractmethod
61
106
  def execute(self, context: SapioWebhookContext) -> SapioWebhookResult:
62
107
  """
@@ -68,11 +113,12 @@ class CommonsWebhookHandler(AbstractWebhookHandler):
68
113
  # the run method and into their own functions.
69
114
  def handle_user_error_exception(self, e: SapioUserErrorException) -> SapioWebhookResult:
70
115
  """
71
- Handle a SapioUserErrorException. Default behavior returns the error message as display text in a webhook
72
- result.
116
+ Handle a SapioUserErrorException.
117
+
118
+ Default behavior returns a false result and the error message as display text in a webhook result.
73
119
 
74
120
  :param e: The exception that was raised.
75
- :return: A SapioWebhookResult reporting the exception to the user.
121
+ :return: A SapioWebhookResult to end the webhook session with.
76
122
  """
77
123
  result: SapioWebhookResult | None = self.handle_any_exception(e)
78
124
  if result is not None:
@@ -82,45 +128,83 @@ class CommonsWebhookHandler(AbstractWebhookHandler):
82
128
 
83
129
  def handle_critical_error_exception(self, e: SapioCriticalErrorException) -> SapioWebhookResult:
84
130
  """
85
- Handle a SapioCriticalErrorException. Default behavior makes a display_error client callback.
131
+ Handle a SapioCriticalErrorException.
132
+
133
+ Default behavior makes a display_error client callback with the error message and returns a false result.
86
134
 
87
135
  :param e: The exception that was raised.
88
- :return: A SapioWebhookResult reporting the exception to the user.
136
+ :return: A SapioWebhookResult to end the webhook session with.
89
137
  """
90
138
  result: SapioWebhookResult | None = self.handle_any_exception(e)
91
139
  if result is not None:
92
140
  return result
93
141
  self.log_error(traceback.format_exc())
94
- DataMgmtServer.get_client_callback(self.context.user).display_error(e.args[0])
142
+ # This error can be thrown by endpoints that can't send client callbacks. If that happens, fall back onto
143
+ # sending display text instead.
144
+ if self.can_send_client_callback():
145
+ self.callback.display_error(e.args[0])
146
+ else:
147
+ return SapioWebhookResult(False, e.args[0])
95
148
  return SapioWebhookResult(False)
96
149
 
97
- def handle_unexpected_exception(self, e: Exception) -> SapioWebhookResult:
150
+ def handle_user_cancelled_exception(self, e: SapioUserCancelledException) -> SapioWebhookResult:
98
151
  """
99
- Handle a generic exception which isn't a SapioUserErrorException or SapioCriticalErrorException. Default
100
- behavior returns a generic error message as display text informing the user to contact Sapio support.
152
+ Handle a SapioUserCancelledException.
153
+
154
+ Default behavior simply ends the webhook session with a true result (since the user cancelling is a valid
155
+ action).
101
156
 
102
157
  :param e: The exception that was raised.
103
- :return: A SapioWebhookResult reporting the exception to the user.
158
+ :return: A SapioWebhookResult to end the webhook session with.
104
159
  """
105
160
  result: SapioWebhookResult | None = self.handle_any_exception(e)
106
161
  if result is not None:
107
162
  return result
108
- self.log_error(traceback.format_exc())
109
- return SapioWebhookResult(False, display_text="Unexpected error occurred during webhook execution. "
110
- "Please contact Sapio support.")
163
+ return SapioWebhookResult(True)
111
164
 
112
- def handle_user_cancelled_exception(self, e: SapioUserCancelledException) -> SapioWebhookResult:
165
+ def handle_dialog_timeout_exception(self, e: SapioDialogTimeoutException) -> SapioWebhookResult:
113
166
  """
114
- Handle a SapioUserCancelledException. Default behavior returns "User Cancelled" as display text in a webhook
115
- result.
167
+ Handle a SapioDialogTimeoutException.
168
+
169
+ Default behavior displays an OK popup notifying the user that the dialog has timed out and returns a false
170
+ webhook result.
171
+
172
+ :param e: The exception that was raised.
173
+ :return: A SapioWebhookResult to end the webhook session with.
174
+ """
175
+ result: SapioWebhookResult | None = self.handle_any_exception(e)
176
+ if result is not None:
177
+ return result
178
+ # This dialog could time out too! Ignore it if it does.
179
+ # No need to check can_send_client_callback() here, as this exception should only be thrown by endpoints that
180
+ # are capable of sending callbacks.
181
+ try:
182
+ self.callback.ok_dialog("Notice", "You have remained idle for too long and this dialog has timed out. "
183
+ "Close and re-initiate it to continue.")
184
+ except SapioDialogTimeoutException:
185
+ pass
186
+ return SapioWebhookResult(False)
187
+
188
+ def handle_unexpected_exception(self, e: Exception) -> SapioWebhookResult:
189
+ """
190
+ Handle a generic exception which isn't one of the handled Sapio exceptions.
191
+
192
+ Default behavior returns a false webhook result with a generic error message as display text informing the user
193
+ to contact Sapio support. Additionally, the stace trace of the exception that was thrown is logged to the
194
+ execution log for the webhook call in the system.
116
195
 
117
196
  :param e: The exception that was raised.
118
- :return: A SapioWebhookResult with display text saying the user cancelled the request.
197
+ :return: A SapioWebhookResult to end the webhook session with.
119
198
  """
120
199
  result: SapioWebhookResult | None = self.handle_any_exception(e)
121
200
  if result is not None:
122
201
  return result
123
- return SapioWebhookResult(False, display_text="User cancelled.")
202
+ msg: str = traceback.format_exc()
203
+ self.log_error(msg)
204
+ # FR-47079: Also log all unexpected exception messages to the webhook execution log within the platform.
205
+ self.log_error_to_webhook_execution_log(msg)
206
+ return SapioWebhookResult(False, display_text="Unexpected error occurred during webhook execution. "
207
+ "Please contact Sapio support.")
124
208
 
125
209
  # noinspection PyMethodMayBeStatic,PyUnusedLocal
126
210
  def handle_any_exception(self, e: Exception) -> SapioWebhookResult | None:
@@ -130,38 +214,65 @@ class CommonsWebhookHandler(AbstractWebhookHandler):
130
214
 
131
215
  :param e: The exception that was raised.
132
216
  :return: An optional SapioWebhookResult. May return a custom message to the client that wouldn't have been
133
- sent by one of the normal exception handlers, or may return None if no result needs returned.
217
+ sent by one of the normal exception handlers, or may return None if no result needs returned. It a result is
218
+ returned, then the default behavior of other exception handlers is skipped.
134
219
  """
135
220
  return None
136
221
 
137
222
  def log_info(self, msg: str) -> None:
138
223
  """
139
- Write an info message to the log. Log destination is stdout. This message will be prepended with the user's
140
- username and the experiment ID of the experiment they are in, if any.
224
+ Write an info message to the webhook server log. Log destination is stdout. This message will be prepended with
225
+ the user's username and the experiment ID of the experiment they are in, if any.
141
226
  """
142
- exp_id = None
143
- if self.context.eln_experiment is not None:
144
- exp_id = self.context.eln_experiment.notebook_experiment_id
145
- # CR-46333: Add the user's group to the logging message.
146
- user = self.context.user
147
- username = user.username
148
- group_name = user.session_additional_data.current_group_name
149
- self.logger.info(f"(User: {username}, Group: {group_name}, Experiment: {exp_id}):\n{msg}")
227
+ self.logger.info(self._format_log(msg, "log_info call"))
150
228
 
151
229
  def log_error(self, msg: str) -> None:
152
230
  """
153
- Write an error message to the log. Log destination is stderr. This message will be prepended with the user's
154
- username and the experiment ID of the experiment they are in, if any.
231
+ Write an error message to the webhook server log. Log destination is stderr. This message will be prepended with
232
+ the user's username and the experiment ID of the experiment they are in, if any.
233
+ """
234
+ # PR-46209: Use logger.error instead of logger.info when logging errors.
235
+ self.logger.error(self._format_log(msg, "log_error call"))
236
+
237
+ def log_error_to_webhook_execution_log(self, msg: str) -> None:
238
+ """
239
+ Write an error message to the platform's webhook execution log. This can be reviewed by navigating to the
240
+ webhook configuration where the webhook that called this function is defined and clicking the "View Log"
241
+ button. From there, select one of the rows for the webhook executions and click "Download Log" from the right
242
+ side table.
155
243
  """
156
- exp_id = None
244
+ messenger = DataMgmtServer.get_messenger(self.user)
245
+ messenger.log_message(VeloxLogMessage(message=self._format_log(msg, "Error occurred during webhook execution."),
246
+ log_level=VeloxLogLevel.ERROR,
247
+ originating_class=self.__class__.__name__))
248
+
249
+ def _format_log(self, msg: str, prefix: str | None = None) -> str:
250
+ """
251
+ Given a message to log, populate it with some metadata about this particular webhook execution, including
252
+ the group of the user and the invocation type of the webhook call.
253
+ """
254
+ # If we're able to, provide a link to the location that the error occurred at.
255
+ navigator = SapioNavigationLinker(self.context)
157
256
  if self.context.eln_experiment is not None:
158
- exp_id = self.context.eln_experiment.notebook_experiment_id
257
+ link = navigator.experiment(self.context.eln_experiment)
258
+ elif self.context.data_record and not self.context.data_record_list:
259
+ link = navigator.data_record(self.context.data_record)
260
+ elif self.context.base_data_record:
261
+ link = navigator.data_record(self.context.base_data_record)
262
+ else:
263
+ link = None
264
+
265
+ message: str = ""
266
+ if prefix:
267
+ message += prefix + "\n"
268
+ message += f"Webhook invocation type: {self.context.end_point_type.display_name}\n"
269
+ message += f"Username: {self.user.username}\n"
159
270
  # CR-46333: Add the user's group to the logging message.
160
- user = self.context.user
161
- username = user.username
162
- group_name = user.session_additional_data.current_group_name
163
- # PR-46209: Use logger.error instead of logger.info when logging errors.
164
- self.logger.error(f"(User: {username}, Group: {group_name}, Experiment: {exp_id}):\n{msg}")
271
+ message += f"User group: {self.user.session_additional_data.current_group_name}\n"
272
+ if link:
273
+ message += f"User location: {link}\n"
274
+ message += msg
275
+ return message
165
276
 
166
277
  def is_main_toolbar(self) -> bool:
167
278
  """
@@ -237,3 +348,51 @@ class CommonsWebhookHandler(AbstractWebhookHandler):
237
348
  :return: True if this endpoint was invoked as a scheduled action.
238
349
  """
239
350
  return self.context.end_point_type == WebhookEndpointType.SCHEDULEDPLUGIN
351
+
352
+ def is_action_button_field(self) -> bool:
353
+ """
354
+ :return: True if this endpoint was invoked as an action button field.
355
+ """
356
+ return self.context.end_point_type == WebhookEndpointType.ACTIONDATAFIELD
357
+
358
+ def is_action_text_field(self) -> bool:
359
+ """
360
+ :return: True if this endpoint was invoked as an action text field.
361
+ """
362
+ return self.context.end_point_type == WebhookEndpointType.ACTION_TEXT_FIELD
363
+
364
+ def is_custom(self) -> bool:
365
+ """
366
+ :return: True if this endpoint was invoked from a custom point, such as a custom queue.
367
+ """
368
+ return self.context.end_point_type == WebhookEndpointType.CUSTOM
369
+
370
+ def is_calendar_event_click_handler(self) -> bool:
371
+ """
372
+ :return: True if this endpoint was invoked from a calendar event click handler.
373
+ """
374
+ return self.context.end_point_type == WebhookEndpointType.CALENDAR_EVENT_CLICK_HANDLER
375
+
376
+ def is_eln_menu_grabber(self) -> bool:
377
+ """
378
+ :return: True if this endpoint was invoked as a notebook entry grabber.
379
+ """
380
+ return self.context.end_point_type == WebhookEndpointType.NOTEBOOKEXPERIMENTGRABBER
381
+
382
+ def is_conversation_bot(self) -> bool:
383
+ """
384
+ :return: True if this endpoint was invoked as from a conversation bot.
385
+ """
386
+ return self.context.end_point_type == WebhookEndpointType.CONVERSATION_BOT
387
+
388
+ def is_multi_data_type_table_toolbar(self) -> bool:
389
+ """
390
+ :return: True if this endpoint was invoked as a multi data type table toolbar button.
391
+ """
392
+ return self.context.end_point_type == WebhookEndpointType.REPORTTOOLBAR
393
+
394
+ def can_send_client_callback(self) -> bool:
395
+ """
396
+ :return: Whether client callbacks and directives can be sent from this webhook's endpoint type.
397
+ """
398
+ return self.context.is_client_callback_available
@@ -0,0 +1,67 @@
1
+ import sys
2
+ import traceback
3
+ from abc import abstractmethod
4
+ from typing import Any
5
+
6
+ from flask import request
7
+ from sapiopylib.rest.User import SapioUser
8
+ from sapiopylib.rest.WebhookService import AbstractWebhookHandler
9
+ from sapiopylib.rest.pojo.webhook.WebhookResult import SapioWebhookResult
10
+
11
+
12
+ class AbstractWebserviceHandler(AbstractWebhookHandler):
13
+ """
14
+ A base class for constructing "webservice" endpoints on your webhook server. These are endpoints that can be
15
+ communicated with by external sources without needing to format the payload JSON in the webhook context format that
16
+ webhook handlers expect.
17
+
18
+ The entire payload JSON is sent to the run method of this class. It is up to the run method to determine how
19
+ this JSON should be parsed. In order to communicate with a Sapio system, a SapioUser object must be able to be
20
+ defined using the payload. Functions have been provided for constructing users with various authentication methods.
21
+
22
+ Since this extends AbstractWebhookHandler, you can still register endpoints from this class in the same way you
23
+ would normal webhook endpoints.
24
+ """
25
+ def post(self) -> dict[str, Any]:
26
+ """
27
+ Internal method to be executed to translate incoming requests.
28
+ """
29
+ # noinspection PyBroadException
30
+ try:
31
+ return self.run(request.json).to_json()
32
+ except Exception:
33
+ print('Error occurred while running webservice custom logic. See traceback.', file=sys.stderr)
34
+ traceback.print_exc()
35
+ return SapioWebhookResult(False, display_text="Error occurred during webservice execution.").to_json()
36
+
37
+ @abstractmethod
38
+ def run(self, payload: dict[str, Any]) -> SapioWebhookResult:
39
+ pass
40
+
41
+ def basic_auth(self, url: str, username: str, password: str) -> SapioUser:
42
+ """
43
+ :param url: The URL of the Sapio system that requests from this user will be sent to.
44
+ Must end in /webservice/api
45
+ :param username: The username to authenticate requests with.
46
+ :param password: The password to authenticate requests with.
47
+ :return: A SapioUser that will authenticate requests using basic auth.
48
+ """
49
+ return SapioUser(url, self.verify_sapio_cert, self.client_timeout_seconds, username=username, password=password)
50
+
51
+ def api_token_auth(self, url: str, api_token: str) -> SapioUser:
52
+ """
53
+ :param url: The URL of the Sapio system that requests from this user will be sent to.
54
+ Must end in /webservice/api
55
+ :param api_token: The API token to authenticate requests with.
56
+ :return: A SapioUser that will authenticate requests using an API token.
57
+ """
58
+ return SapioUser(url, self.verify_sapio_cert, self.client_timeout_seconds, api_token=api_token)
59
+
60
+ def bearer_token_auth(self, url: str, bearer_token: str) -> SapioUser:
61
+ """
62
+ :param url: The URL of the Sapio system that requests from this user will be sent to.
63
+ Must end in /webservice/api
64
+ :param bearer_token: The bearer token to authenticate requests with.
65
+ :return: A SapioUser that will authenticate requests using a bearer token.
66
+ """
67
+ return SapioUser(url, self.verify_sapio_cert, self.client_timeout_seconds, bearer_token=bearer_token)
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sapiopycommons
3
- Version: 2024.11.11a364
3
+ Version: 2024.11.18a366
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
+ License: MPL-2.0
7
8
  Keywords: eln,lims,rest,sapio
8
9
  Classifier: Development Status :: 5 - Production/Stable
9
10
  Classifier: Intended Audience :: Developers
@@ -15,7 +16,8 @@ Classifier: Programming Language :: Python :: 3.10
15
16
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
16
17
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
18
  Requires-Python: >=3.10
18
- Requires-Dist: sapiopylib>=2023.12.13.174
19
+ Requires-Dist: databind>=4.5
20
+ Requires-Dist: sapiopylib>=2024.5.24.210
19
21
  Description-Content-Type: text/markdown
20
22
 
21
23
 
@@ -48,6 +50,7 @@ This license does not provide any rights to use any other copyrighted artifacts
48
50
  ## Dependencies
49
51
  The following dependencies are required for this package:
50
52
  - [sapiopylib - The official Sapio Informatics Platform Python API package.](https://pypi.org/project/sapiopylib/)
53
+ - [databind - Databind is a library inspired by jackson-databind to de-/serialize Python dataclasses.](https://pypi.org/project/databind/)
51
54
 
52
55
  ## Getting Help
53
56
  If you have a support contract with Sapio Sciences, please use our [technical support channels](https://sapio-sciences.atlassian.net/servicedesk/customer/portals).
@@ -0,0 +1,59 @@
1
+ sapiopycommons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ sapiopycommons/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ sapiopycommons/callbacks/callback_util.py,sha256=nb6cXK8yFq96gtG0Z2NiK-qdNaRh88bavUH-ZoBjh18,67953
4
+ sapiopycommons/callbacks/field_builder.py,sha256=8n0jcbMgtMUHjie4C1-IkpAuHz4zBxbZtWpr4y0kABU,36868
5
+ sapiopycommons/chem/IndigoMolecules.py,sha256=3f-aig3AJkKJhRmhlQ0cI-5G8oeaQk_3foJTDZCvoko,2040
6
+ sapiopycommons/chem/Molecules.py,sha256=SQKnqdZnhYj_6HGtEZmE_1DormonRR1-nBAQ__z4gms,11485
7
+ sapiopycommons/chem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ sapiopycommons/customreport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ sapiopycommons/customreport/column_builder.py,sha256=0RO53e9rKPZ07C--KcepN6_tpRw_FxF3O9vdG0ilKG8,3014
10
+ sapiopycommons/customreport/custom_report_builder.py,sha256=Lsy8DQryb7wC9RmEVVLQ6Q74JiNxU-ywFX-m5zL5CSk,6896
11
+ sapiopycommons/customreport/term_builder.py,sha256=oVsr7iFPnug2TrZUCcAMhyps-b62kDodPcBxyQeneUY,16763
12
+ sapiopycommons/datatype/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ sapiopycommons/datatype/attachment_util.py,sha256=_l2swuP8noIGAl4bwzBUEhr6YlN_OVZl3-gi1XqFHYA,3364
14
+ sapiopycommons/datatype/data_fields.py,sha256=g8Ib6LH8ikNu9AzeVJs8Z2qS8A-cplACeFU7vYguNEY,4063
15
+ sapiopycommons/datatype/pseudo_data_types.py,sha256=Fe75Rnq5evyeJM1nC0sLkLGKAC74g2-GEeTdMeId80o,27649
16
+ sapiopycommons/eln/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ sapiopycommons/eln/experiment_handler.py,sha256=VJPBQSP_4QmhSGDCRDOb5neOjGM6sZ9krvJEmDkpVV8,69282
18
+ sapiopycommons/eln/experiment_report_util.py,sha256=9wWV6oEdKtfn2rI5V0BtmuW9OJlGFd9U07FIf889Gjw,37679
19
+ sapiopycommons/eln/plate_designer.py,sha256=FYJfhhNq8hdfuXgDYOYHy6g0m2zNwQXZWF_MTPzElDg,7184
20
+ sapiopycommons/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ sapiopycommons/files/complex_data_loader.py,sha256=T39veNhvYl6j_uZjIIJ8Mk5Aa7otR5RB-g8XlAdkksA,1421
22
+ sapiopycommons/files/file_bridge.py,sha256=WwCVegk0OGA8eqho8chsOsLlqg1nXctO75zfh-rHF-g,5950
23
+ sapiopycommons/files/file_bridge_handler.py,sha256=bt2IfIsxJ4lcJYo_NHvCQ17ZV6C4fSAEa8Zcgixh7B4,14263
24
+ sapiopycommons/files/file_data_handler.py,sha256=SCsjODMJIPEBSsahzXUeOM7CfSCmYwPPoGAM6aOfelo,36743
25
+ sapiopycommons/files/file_util.py,sha256=wbL3rxcFc-t2mXaPWWkoFWYGopvTcQts9Wf-L5GkhT8,29498
26
+ sapiopycommons/files/file_validator.py,sha256=4OvY98ueJWPJdpndwnKv2nqVvLP9S2W7Il_dM0Y0ojo,28709
27
+ sapiopycommons/files/file_writer.py,sha256=96Xl8TTT46Krxe_J8rmmlEMtel4nzZB961f5Yqtl1-I,17616
28
+ sapiopycommons/flowcyto/flow_cyto.py,sha256=YlkKJR_zEHYRuNW0bnTqlTyZeXs0lOaeSCfG2fnfD7E,3227
29
+ sapiopycommons/flowcyto/flowcyto_data.py,sha256=mYKFuLbtpJ-EsQxLGtu4tNHVlygTxKixgJxJqD68F58,2596
30
+ sapiopycommons/general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ sapiopycommons/general/accession_service.py,sha256=HYgyOsH_UaoRnoury-c2yTW8SeG4OtjLemdpCzoV4R8,13484
32
+ sapiopycommons/general/aliases.py,sha256=tdDBNWSGx6s39eHJ3n2kscc4xxW3ZYaUfDftct6FmJE,12910
33
+ sapiopycommons/general/audit_log.py,sha256=KQI0AGgN9WLwKqnHE4Tm0xeBCfpVBf8rIQ2HFmnyFGI,8956
34
+ sapiopycommons/general/custom_report_util.py,sha256=BGu9Ki0wn3m4Nk-LKM6inDSfe8ULUSG9d-HJJNOTtGc,15653
35
+ sapiopycommons/general/exceptions.py,sha256=GY7fe0qOgoy4kQVn_Pn3tdzHsJZyNIpa6VCChg6tzuM,1813
36
+ sapiopycommons/general/popup_util.py,sha256=L-4qpTemSZdlD6_6oEsDYIzLOCiZgDK6wC6DqUwzOYA,31925
37
+ sapiopycommons/general/sapio_links.py,sha256=o9Z-8y2rz6AI0Cy6tq58ElPge9RBnisGc9NyccbaJxs,2610
38
+ sapiopycommons/general/storage_util.py,sha256=ovmK_jN7v09BoX07XxwShpBUC5WYQOM7dbKV_VeLXJU,8892
39
+ sapiopycommons/general/time_util.py,sha256=jUAWmQLNcLHZa4UYB4ht_I3d6uoi63VxYdo7T80Ydw0,7458
40
+ sapiopycommons/multimodal/multimodal.py,sha256=A1QsC8QTPmgZyPr7KtMbPRedn2Ie4WIErodUvQ9otgU,6724
41
+ sapiopycommons/multimodal/multimodal_data.py,sha256=0BeVPr9HaC0hNTF1v1phTIKGruvNnwerHsD994qJKBg,15099
42
+ sapiopycommons/processtracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ sapiopycommons/processtracking/custom_workflow_handler.py,sha256=0Si5RQ1YFmqmcZWV8jNDKTffix2iZnQJ6b97fn31pbc,23859
44
+ sapiopycommons/processtracking/endpoints.py,sha256=w5bziI2xC7450M95rCF8JpRwkoni1kEDibyAux9B12Q,10848
45
+ sapiopycommons/recordmodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ sapiopycommons/recordmodel/record_handler.py,sha256=Uxjrq6f_cWFbqi7KRLySdOvmQGtbIBrCNyStRewqzx8,64751
47
+ sapiopycommons/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
+ sapiopycommons/rules/eln_rule_handler.py,sha256=JYzDA_14D2nLnlqwbpIxVOrfKWzbOS27AYf4TQfGr4Q,10469
49
+ sapiopycommons/rules/on_save_rule_handler.py,sha256=Rkqvph20RbNq6m-RF4fbvCP-YfD2CZYBM2iTr3nl0eY,10236
50
+ sapiopycommons/sftpconnect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
+ sapiopycommons/sftpconnect/sftp_builder.py,sha256=eKYMiyBc10DNTfbeidQUcfZgFTwhu5ZU-nNJMCK_eos,3014
52
+ sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
+ sapiopycommons/webhook/webhook_context.py,sha256=D793uLsb1691SalaPnBUk3rOSxn_hYLhdvkaIxjNXss,1909
54
+ sapiopycommons/webhook/webhook_handlers.py,sha256=JTquLBln49L1pJ9txJ4oc4Hpzy9kYtMKs0m4SLaFx78,18363
55
+ sapiopycommons/webhook/webservice_handlers.py,sha256=1J56zFI0pWl5MHoNTznvcZumITXgAHJMluj8-2BqYEw,3315
56
+ sapiopycommons-2024.11.18a366.dist-info/METADATA,sha256=0S26Z5mecoo7OCy9SdtYuR2iolc5m9fYF9LQTMuc8cQ,3144
57
+ sapiopycommons-2024.11.18a366.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
58
+ sapiopycommons-2024.11.18a366.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
59
+ sapiopycommons-2024.11.18a366.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.26.1
2
+ Generator: hatchling 1.26.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,38 +0,0 @@
1
- sapiopycommons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- sapiopycommons/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- sapiopycommons/callbacks/callback_util.py,sha256=D6whWxYWvs5rXOG2Slpi1icC18SLKmG9-MP9f0YDDNE,43256
4
- sapiopycommons/chem/IndigoMolecules.py,sha256=ukZcX6TMEgkNdD1L1GnH3tp5rGplFNPlGoChAHXbsxw,1945
5
- sapiopycommons/chem/Molecules.py,sha256=tOkn3fg4QizgqjkRLuvRdVy0JpTD3QEOSvZPxmIyT4c,8607
6
- sapiopycommons/chem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- sapiopycommons/datatype/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- sapiopycommons/datatype/attachment_util.py,sha256=YlnMprj5IGBbAZDLG2khS1P7JIYTw_NYfpJAfRZfP3M,3219
9
- sapiopycommons/eln/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- sapiopycommons/eln/experiment_handler.py,sha256=v1pG4qtZb8OSNWfKtFo6NjnEkReqnu5R9i_hqWh_xxg,57198
11
- sapiopycommons/eln/plate_designer.py,sha256=FYJfhhNq8hdfuXgDYOYHy6g0m2zNwQXZWF_MTPzElDg,7184
12
- sapiopycommons/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- sapiopycommons/files/complex_data_loader.py,sha256=XSJOl676mIklJo78v07-70u1b015a5DI4sqZPI3C-Tw,1475
14
- sapiopycommons/files/file_bridge.py,sha256=6yjUi0ejypb1nvcEvn21EuquB-SmEjB-fCZiMaNZg7Q,5757
15
- sapiopycommons/files/file_data_handler.py,sha256=3-guAdhJdeJWAFq1a27ijspkO7uMMZ6CapMCD_6o4jA,36746
16
- sapiopycommons/files/file_util.py,sha256=92SzwRif4dOcGqZ9ri90QeC20NOCenT8DxQjdSH5Uyc,25556
17
- sapiopycommons/files/file_validator.py,sha256=5DUI_h0WB1AvfoPgx8En3-sC5xlzm5Z2deoSf9qviKQ,24499
18
- sapiopycommons/files/file_writer.py,sha256=5u_iZXTQvuUU7ceHZr8Q001_tvgJhOqBwAnB_pxcAbQ,16027
19
- sapiopycommons/general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- sapiopycommons/general/aliases.py,sha256=i6af5o2oVFGNcyk7GkvTWXQs0H9xTbFKc_GIah8NKVU,3594
21
- sapiopycommons/general/custom_report_util.py,sha256=Yrq-Ize1M1jh9g3BmQT9Egedufi3Nl9xNmgNI_LGiho,4828
22
- sapiopycommons/general/exceptions.py,sha256=DOlLKnpCatxQF-lVCToa8ryJgusWLvip6N_1ALN00QE,1679
23
- sapiopycommons/general/popup_util.py,sha256=-mN5IgYPrLrOEHJ4CHPi2rec4_WAN6X0yMxHwD5h3Bs,30126
24
- sapiopycommons/general/storage_util.py,sha256=ovmK_jN7v09BoX07XxwShpBUC5WYQOM7dbKV_VeLXJU,8892
25
- sapiopycommons/general/time_util.py,sha256=jiJUh7jc1ZRCOem880S3HaLPZ4RboBtSl4_U9sqAQuM,7290
26
- sapiopycommons/processtracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
- sapiopycommons/processtracking/endpoints.py,sha256=g5h_uCVByqacYm9zWAz8TyAdRsGfaO2o0b5RSJdOaSA,10926
28
- sapiopycommons/recordmodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
- sapiopycommons/recordmodel/record_handler.py,sha256=VYUJ0bgZbyc6-XYRKvsxrpWHLdCwxzhv13Ce2tZpAQQ,39348
30
- sapiopycommons/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- sapiopycommons/rules/eln_rule_handler.py,sha256=qfkBZtck0KK1i9s9Xe2UZqkzQOgPCzDxRkhxE8Si1xk,10671
32
- sapiopycommons/rules/on_save_rule_handler.py,sha256=JY9F30IcHwFVdgPAMQtTYuRastV1jeezhVktyrzNASU,10763
33
- sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
- sapiopycommons/webhook/webhook_handlers.py,sha256=K_K7CEAMZ-bNb2LCIKdt0CxHsBKkwSBzfnp0JSdGJUM,11102
35
- sapiopycommons-2024.11.11a364.dist-info/METADATA,sha256=5yip-yt3gmB7uoUJxqyUO66vvO4TrIhR7PL36oVi8Tk,2960
36
- sapiopycommons-2024.11.11a364.dist-info/WHEEL,sha256=3U_NnUcV_1B1kPkYaPzN-irRckL5VW_lytn0ytO_kRY,87
37
- sapiopycommons-2024.11.11a364.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
38
- sapiopycommons-2024.11.11a364.dist-info/RECORD,,