sapiopycommons 2024.3.19a157__py3-none-any.whl → 2025.1.17a402__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 (52) hide show
  1. sapiopycommons/callbacks/__init__.py +0 -0
  2. sapiopycommons/callbacks/callback_util.py +2041 -0
  3. sapiopycommons/callbacks/field_builder.py +545 -0
  4. sapiopycommons/chem/IndigoMolecules.py +46 -1
  5. sapiopycommons/chem/Molecules.py +100 -21
  6. sapiopycommons/customreport/__init__.py +0 -0
  7. sapiopycommons/customreport/column_builder.py +60 -0
  8. sapiopycommons/customreport/custom_report_builder.py +137 -0
  9. sapiopycommons/customreport/term_builder.py +315 -0
  10. sapiopycommons/datatype/attachment_util.py +14 -15
  11. sapiopycommons/datatype/data_fields.py +61 -0
  12. sapiopycommons/datatype/pseudo_data_types.py +440 -0
  13. sapiopycommons/eln/experiment_handler.py +355 -91
  14. sapiopycommons/eln/experiment_report_util.py +649 -0
  15. sapiopycommons/eln/plate_designer.py +152 -0
  16. sapiopycommons/files/complex_data_loader.py +31 -0
  17. sapiopycommons/files/file_bridge.py +149 -25
  18. sapiopycommons/files/file_bridge_handler.py +555 -0
  19. sapiopycommons/files/file_data_handler.py +633 -0
  20. sapiopycommons/files/file_util.py +263 -163
  21. sapiopycommons/files/file_validator.py +569 -0
  22. sapiopycommons/files/file_writer.py +377 -0
  23. sapiopycommons/flowcyto/flow_cyto.py +77 -0
  24. sapiopycommons/flowcyto/flowcyto_data.py +75 -0
  25. sapiopycommons/general/accession_service.py +375 -0
  26. sapiopycommons/general/aliases.py +250 -15
  27. sapiopycommons/general/audit_log.py +185 -0
  28. sapiopycommons/general/custom_report_util.py +251 -31
  29. sapiopycommons/general/directive_util.py +86 -0
  30. sapiopycommons/general/exceptions.py +69 -7
  31. sapiopycommons/general/popup_util.py +59 -7
  32. sapiopycommons/general/sapio_links.py +50 -0
  33. sapiopycommons/general/storage_util.py +148 -0
  34. sapiopycommons/general/time_util.py +91 -7
  35. sapiopycommons/multimodal/multimodal.py +146 -0
  36. sapiopycommons/multimodal/multimodal_data.py +490 -0
  37. sapiopycommons/processtracking/__init__.py +0 -0
  38. sapiopycommons/processtracking/custom_workflow_handler.py +406 -0
  39. sapiopycommons/processtracking/endpoints.py +192 -0
  40. sapiopycommons/recordmodel/record_handler.py +621 -148
  41. sapiopycommons/rules/eln_rule_handler.py +87 -8
  42. sapiopycommons/rules/on_save_rule_handler.py +87 -12
  43. sapiopycommons/sftpconnect/__init__.py +0 -0
  44. sapiopycommons/sftpconnect/sftp_builder.py +70 -0
  45. sapiopycommons/webhook/webhook_context.py +39 -0
  46. sapiopycommons/webhook/webhook_handlers.py +614 -71
  47. sapiopycommons/webhook/webservice_handlers.py +317 -0
  48. {sapiopycommons-2024.3.19a157.dist-info → sapiopycommons-2025.1.17a402.dist-info}/METADATA +5 -4
  49. sapiopycommons-2025.1.17a402.dist-info/RECORD +60 -0
  50. {sapiopycommons-2024.3.19a157.dist-info → sapiopycommons-2025.1.17a402.dist-info}/WHEEL +1 -1
  51. sapiopycommons-2024.3.19a157.dist-info/RECORD +0 -28
  52. {sapiopycommons-2024.3.19a157.dist-info → sapiopycommons-2025.1.17a402.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,317 @@
1
+ import sys
2
+ import traceback
3
+ from abc import abstractmethod, ABC
4
+ from base64 import b64decode
5
+ from logging import Logger
6
+ from typing import Any
7
+
8
+ from flask import request, Response, Request
9
+ from sapiopylib.rest.DataRecordManagerService import DataRecordManager
10
+ from sapiopylib.rest.User import SapioUser
11
+ from sapiopylib.rest.WebhookService import AbstractWebhookHandler
12
+ from sapiopylib.rest.utils.DataTypeCacheManager import DataTypeCacheManager
13
+ from sapiopylib.rest.utils.recordmodel.RecordModelManager import RecordModelManager, RecordModelInstanceManager, \
14
+ RecordModelRelationshipManager
15
+ from sapiopylib.rest.utils.recordmodel.ancestry import RecordModelAncestorManager
16
+ from werkzeug.datastructures import Headers
17
+ from werkzeug.datastructures.structures import MultiDict
18
+ from werkzeug.exceptions import UnsupportedMediaType, BadRequest
19
+
20
+ from sapiopycommons.general.exceptions import SapioException
21
+ from sapiopycommons.recordmodel.record_handler import RecordHandler
22
+
23
+
24
+ class SapioWebserviceException(Exception):
25
+ """
26
+ An exception to be thrown by webservice classes when responding to a request with an error.
27
+ """
28
+ msg: str
29
+ code: int
30
+
31
+ def __init__(self, msg: str, code: int = 500):
32
+ """
33
+ :param msg: The message to return in the webservice response.
34
+ :param code: The status code to return in the webservice response.
35
+ """
36
+ self.msg = msg
37
+ self.code = code
38
+
39
+
40
+ class SapioWebserviceResult:
41
+ """
42
+ A result to be returned by AbstractWebserviceHandler endpoints, for sending information back to the caller.
43
+ """
44
+ message: str
45
+ is_error: bool
46
+ status_code: int
47
+ payload: dict[str, Any]
48
+
49
+ def __init__(self, message: str = "Success", status_code: int = 200, is_error: bool = False,
50
+ payload: dict[str, Any] | None = None):
51
+ """
52
+ :param message: A message to return to the sender describing what happened.
53
+ :param status_code: An HTTP status code to return to the sender.
54
+ :param is_error: Whether the webservice had an error during processing.
55
+ :param payload: A payload of additional information to return to the sender.
56
+ """
57
+ self.message = message
58
+ self.status_code = status_code
59
+ self.is_error = is_error
60
+ self.payload = payload
61
+ if payload is None:
62
+ self.payload = {}
63
+
64
+ def to_json(self) -> dict[str, Any]:
65
+ return {"message": self.message,
66
+ "statusCode": self.status_code,
67
+ "isError": self.is_error,
68
+ "payload": self.payload}
69
+
70
+ def to_result(self) -> tuple[dict[str, Any], int]:
71
+ return self.to_json(), self.status_code
72
+
73
+
74
+ WebserviceResponse = SapioWebserviceResult | Response | tuple[dict[str, Any] | int]
75
+
76
+
77
+ class AbstractWebserviceHandler(AbstractWebhookHandler):
78
+ """
79
+ A base class for constructing POST webservice endpoints on your webhook server. These are endpoints that can be
80
+ communicated with by external sources without needing to format the request in the webhook context format that
81
+ normal webhook handlers expect.
82
+
83
+ Since this extends AbstractWebhookHandler, you can still register endpoints from this class in the same way you
84
+ would normal webhook endpoints.
85
+ """
86
+ request: Request
87
+
88
+ def post(self) -> Response | tuple[dict[str, Any], int]:
89
+ """
90
+ Internal method to be executed to translate incoming POST requests.
91
+ """
92
+ # noinspection PyBroadException
93
+ try:
94
+ self.request = request
95
+ try:
96
+ raw_json = request.json
97
+ headers = request.headers
98
+ params = request.args
99
+ except UnsupportedMediaType as e:
100
+ return SapioWebserviceResult(str(e), 415, True).to_json(), 415
101
+ except BadRequest as e:
102
+ return SapioWebserviceResult(str(e), 400, True).to_json(), 400
103
+ ret_val: WebserviceResponse = self.run(raw_json, headers, params)
104
+ if isinstance(ret_val, SapioWebserviceResult):
105
+ return ret_val.to_result()
106
+ return ret_val
107
+ except Exception:
108
+ print('Error occurred while running webservice custom logic. See traceback.', file=sys.stderr)
109
+ traceback.print_exc()
110
+ return SapioWebserviceResult("Unexpected error occurred.", 500, True).to_json(), 500
111
+
112
+ # noinspection PyMethodOverriding
113
+ @abstractmethod
114
+ def run(self, payload: Any, headers: Headers, params: MultiDict[str, str]) -> WebserviceResponse:
115
+ """
116
+ The execution details for this endpoint.
117
+
118
+ :param payload: The JSON payload from the request. Usually a dictionary of strings to Any.
119
+ :param headers: The headers from the request. Can be used like a dictionary.
120
+ :param params: The URL parameters from the request.
121
+ :return: A response object to send back to the requester.
122
+ """
123
+ pass
124
+
125
+ def authenticate_user(self, headers: dict[str, str]) -> SapioUser:
126
+ """
127
+ Authenticate a user for making requests to a Sapio server using the provided headers. If no user can be
128
+ authenticated, then an exception will be thrown.
129
+
130
+ :param headers: The headers of the webservice request.
131
+ :return: A SapioUser object used to make requests to a Sapio server as authorized by the headers.
132
+ """
133
+ # Get the system URL from the headers.
134
+ if "System-URL" not in headers:
135
+ raise SapioWebserviceException("No \"System-URL\" provided in headers.", 400)
136
+ url: str = headers.get("System-URL")
137
+ if not url.endswith("/webservice/api"):
138
+ raise SapioWebserviceException(f"\"System-URL\" must be a webservice API URL for the target system: {url}", 400)
139
+
140
+ # Get the login credentials from the headers.
141
+ auth: str = headers.get("Authorization")
142
+ if auth and auth.startswith("Basic "):
143
+ credentials: list[str] = b64decode(auth.split("Basic ")[1]).decode().split(":")
144
+ user = self.basic_auth(url, credentials[0], credentials[1])
145
+ elif auth and auth.startswith("Bearer "):
146
+ user = self.bearer_token_auth(url, auth.split("Bearer ")[1])
147
+ elif "X-API-TOKEN" in headers:
148
+ user = self.api_token_auth(url, headers.get("X-API-TOKEN"))
149
+ else:
150
+ raise SapioWebserviceException(f"Unrecognized Authorization method.", 400)
151
+ # Make a simple webservice call to confirm that the credentials are valid.
152
+ try:
153
+ # noinspection PyStatementEffect
154
+ user.session_additional_data
155
+ except Exception:
156
+ if "Unauthorized (javax.ws.rs.NotAuthorizedException: Incorrect username or password.)" in traceback.format_exc():
157
+ raise SapioWebserviceException("Unauthorized. Incorrect username or password.", 401)
158
+ else:
159
+ raise SapioWebserviceException("System-URL is invalid or user cannot be authenticated.", 401)
160
+ return user
161
+
162
+ def basic_auth(self, url: str, username: str, password: str) -> SapioUser:
163
+ """
164
+ :param url: The URL of the Sapio system that requests from this user will be sent to.
165
+ Must end in /webservice/api
166
+ :param username: The username to authenticate requests with.
167
+ :param password: The password to authenticate requests with.
168
+ :return: A SapioUser that will authenticate requests using basic auth.
169
+ """
170
+ return SapioUser(url, self.verify_sapio_cert, self.client_timeout_seconds, username=username, password=password)
171
+
172
+ def api_token_auth(self, url: str, api_token: str) -> SapioUser:
173
+ """
174
+ :param url: The URL of the Sapio system that requests from this user will be sent to.
175
+ Must end in /webservice/api
176
+ :param api_token: The API token to authenticate requests with.
177
+ :return: A SapioUser that will authenticate requests using an API token.
178
+ """
179
+ return SapioUser(url, self.verify_sapio_cert, self.client_timeout_seconds, api_token=api_token)
180
+
181
+ def bearer_token_auth(self, url: str, bearer_token: str) -> SapioUser:
182
+ """
183
+ :param url: The URL of the Sapio system that requests from this user will be sent to.
184
+ Must end in /webservice/api
185
+ :param bearer_token: The bearer token to authenticate requests with.
186
+ :return: A SapioUser that will authenticate requests using a bearer token.
187
+ """
188
+ return SapioUser(url, self.verify_sapio_cert, self.client_timeout_seconds, bearer_token=bearer_token)
189
+
190
+
191
+ class CommonsWebserviceHandler(AbstractWebserviceHandler, ABC):
192
+ """
193
+ A subclass of AbstractWebservicePostHandler that provides additional quality of life features, including
194
+ authentication of a SapioUser from the request headers, initialization of various commonly used managers, and more.
195
+ """
196
+ logger: Logger
197
+
198
+ user: SapioUser | None
199
+
200
+ dr_man: DataRecordManager
201
+ rec_man: RecordModelManager
202
+ inst_man: RecordModelInstanceManager
203
+ rel_man: RecordModelRelationshipManager
204
+ an_man: RecordModelAncestorManager
205
+
206
+ dt_cache: DataTypeCacheManager
207
+ rec_handler: RecordHandler
208
+
209
+ def run(self, payload: Any, headers: Headers, params: MultiDict[str, str]) -> WebserviceResponse:
210
+ try:
211
+ self.initialize(headers)
212
+ result = self.execute(self.user, payload, headers, params)
213
+ if result is None:
214
+ raise SapioException("Your execute function returned a None result! Don't forget your return statement!")
215
+ return result
216
+ except SapioWebserviceException as e:
217
+ return self.handle_webservice_exception(e)
218
+ except Exception as e:
219
+ return self.handle_unexpected_exception(e)
220
+
221
+ def initialize(self, headers: Headers) -> None:
222
+ """
223
+ A function that can be optionally overridden by your classes to initialize additional instance variables,
224
+ or set up whatever else you wish to set up before the execute function is ran. Default behavior initializes a
225
+ SapioUser and various manager classes to make requests from.
226
+ """
227
+ self.user = None
228
+ self.user = self.authenticate_user(headers)
229
+
230
+ self.logger = self.user.logger
231
+
232
+ self.dr_man = DataRecordManager(self.user)
233
+ self.rec_man = RecordModelManager(self.user)
234
+ self.inst_man = self.rec_man.instance_manager
235
+ self.rel_man = self.rec_man.relationship_manager
236
+ self.an_man = RecordModelAncestorManager(self.rec_man)
237
+
238
+ self.dt_cache = DataTypeCacheManager(self.user)
239
+ self.rec_handler = RecordHandler(self.user)
240
+
241
+ @abstractmethod
242
+ def execute(self, user: SapioUser, payload: Any, headers: Headers, params: MultiDict[str, str]) \
243
+ -> SapioWebserviceResult:
244
+ """
245
+ The execution details for this endpoint.
246
+
247
+ :param user: The SapioUser object authenticated from the request headers.
248
+ :param payload: The JSON payload from the request. Usually a dictionary of strings to Any.
249
+ :param headers: The headers from the request. Can be used like a dictionary.
250
+ :param params: The URL parameters from the request.
251
+ :return: A response object to send back to the requester.
252
+ """
253
+ pass
254
+
255
+ def handle_webservice_exception(self, e: SapioWebserviceException) -> WebserviceResponse:
256
+ """
257
+ Handle a generic exception which isn't one of the handled Sapio exceptions.
258
+
259
+ Default behavior returns a webservice result with the message and error code of the webservice exception.
260
+ Additionally, the stack trace of the exception that was thrown is logged to the webhook server.
261
+
262
+ :param e: The exception that was raised.
263
+ :return: A webservice result to return to the requester.
264
+ """
265
+ result: WebserviceResponse | None = self.handle_any_exception(e)
266
+ if result is not None:
267
+ return result
268
+ msg: str = traceback.format_exc()
269
+ self.log_error(msg)
270
+ return SapioWebserviceResult(e.msg, e.code, True)
271
+
272
+ def handle_unexpected_exception(self, e: Exception) -> WebserviceResponse:
273
+ """
274
+ Handle a generic exception which isn't one of the handled Sapio exceptions.
275
+
276
+ Default behavior returns a 500 code result with a generic error message informing the user to contact Sapio
277
+ support. Additionally, the stack trace of the exception that was thrown is logged to the webhook server.
278
+
279
+ :param e: The exception that was raised.
280
+ :return: A webservice result to return to the requester.
281
+ """
282
+ result: SapioWebserviceResult | None = self.handle_any_exception(e)
283
+ if result is not None:
284
+ return result
285
+ msg: str = traceback.format_exc()
286
+ self.log_error(msg)
287
+ return SapioWebserviceResult("Unexpected error occurred during webservice execution. "
288
+ "Please contact Sapio support.", 500, True)
289
+
290
+ # noinspection PyMethodMayBeStatic,PyUnusedLocal
291
+ def handle_any_exception(self, e: Exception) -> WebserviceResponse | None:
292
+ """
293
+ An exception handler which runs regardless of the type of exception that was raised. Can be used to "rollback"
294
+ the client if an error occurs. Default behavior does nothing and returns None.
295
+
296
+ :param e: The exception that was raised.
297
+ :return: An optional response to the caller. May return a custom message to the client that wouldn't have been
298
+ sent by one of the normal exception handlers, or may return None if no result needs returned. If a result is
299
+ returned, then the default behavior of other exception handlers is skipped.
300
+ """
301
+ return None
302
+
303
+ def log_info(self, msg: str) -> None:
304
+ """
305
+ Write an info message to the webhook server log. Log destination is stdout.
306
+ """
307
+ # If there's no user, then there's no logger.
308
+ if self.user:
309
+ self.logger.info(msg)
310
+
311
+ def log_error(self, msg: str) -> None:
312
+ """
313
+ Write an error message to the webhook server log. Log destination is stderr.
314
+ """
315
+ # If there's no user, then there's no logger.
316
+ if self.user:
317
+ self.logger.error(msg)
@@ -1,11 +1,10 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sapiopycommons
3
- Version: 2024.3.19a157
3
+ Version: 2025.1.17a402
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-Expression: MPL-2.0
8
- License-File: LICENSE
7
+ License: MPL-2.0
9
8
  Keywords: eln,lims,rest,sapio
10
9
  Classifier: Development Status :: 5 - Production/Stable
11
10
  Classifier: Intended Audience :: Developers
@@ -17,7 +16,8 @@ Classifier: Programming Language :: Python :: 3.10
17
16
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
18
17
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
18
  Requires-Python: >=3.10
20
- Requires-Dist: sapiopylib>=2023.12.13.174
19
+ Requires-Dist: databind>=4.5
20
+ Requires-Dist: sapiopylib>=2024.5.24.210
21
21
  Description-Content-Type: text/markdown
22
22
 
23
23
 
@@ -50,6 +50,7 @@ This license does not provide any rights to use any other copyrighted artifacts
50
50
  ## Dependencies
51
51
  The following dependencies are required for this package:
52
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/)
53
54
 
54
55
  ## Getting Help
55
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,60 @@
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=68lPK8GtE6zd8C0fQaMLxT57PtU-6HnO37Zk-u56Mrs,129933
4
+ sapiopycommons/callbacks/field_builder.py,sha256=p2XacN99MuKk3ite8GAqstUMpixqugul2CsC4gB83-o,38620
5
+ sapiopycommons/chem/IndigoMolecules.py,sha256=slM2y39zZFHc468c366EqR8T-GYJ24UnM9HWAqWFEwQ,3900
6
+ sapiopycommons/chem/Molecules.py,sha256=9B4sbwbvYs50XHRn0TZiu-D1Oa3pKrI9qE5vNW8zv-U,12464
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=BlTxZ4t1sfZA2Ciur1EfYvkZxHxJ7ADwYNAe2zwiN0c,7176
11
+ sapiopycommons/customreport/term_builder.py,sha256=PNp71NF1vFxidk5v6uQNi9oQR9KJIk8WfhyntvvZN-U,18573
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=6TG7aJxgmUZ8FQkWBcgmbK5oy7AFFNtKOPpi1w1OOYA,27657
16
+ sapiopycommons/eln/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ sapiopycommons/eln/experiment_handler.py,sha256=8hmR7sawDo9K6iBwB44QSoxlH1M91inor7dfuXQ4LKs,69323
18
+ sapiopycommons/eln/experiment_report_util.py,sha256=bs9zSUgRo40q2VYtjDCVPsT-D1umdNfl5s4oZrY4uuc,36597
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=vKbqxPexi15epr_-_qLrEfYoxNxB031mXN92iVtOMqE,9511
23
+ sapiopycommons/files/file_bridge_handler.py,sha256=SEYDIQhSCmjI6qyLdDJE8JVKSd0WYvF7JvAq_Ahp9Do,25503
24
+ sapiopycommons/files/file_data_handler.py,sha256=f96MlkMuQhUCi4oLnzJK5AiuElCp5jLI8_sJkZVwpws,36779
25
+ sapiopycommons/files/file_util.py,sha256=wbL3rxcFc-t2mXaPWWkoFWYGopvTcQts9Wf-L5GkhT8,29498
26
+ sapiopycommons/files/file_validator.py,sha256=utV0-d1-AmwgPILifAbUYufOx-ihBHVT-o5SdhJ7MpQ,28737
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=jh68NG8VSrgfQNDiPlMv_o5qHEFFBed55-cXHxHdCyw,13806
33
+ sapiopycommons/general/audit_log.py,sha256=pvXPfLr4Rw2X52wAXJGsX5fsPllswnCqaFZQ181j_GU,8727
34
+ sapiopycommons/general/custom_report_util.py,sha256=6ZIg_Jl02TYUygfc5xqBoI1srPsSxLyxaJ9jwTolGcM,16671
35
+ sapiopycommons/general/directive_util.py,sha256=7SeQrd2Ye5JHlXZtJZaVGgtaSLdq_Vm9EObuxf44Pz8,3905
36
+ sapiopycommons/general/exceptions.py,sha256=aPlzK1cvxeMU5UsokYlLrIBGltUfJZ7LH8zvLh9DxpI,3233
37
+ sapiopycommons/general/popup_util.py,sha256=L-4qpTemSZdlD6_6oEsDYIzLOCiZgDK6wC6DqUwzOYA,31925
38
+ sapiopycommons/general/sapio_links.py,sha256=o9Z-8y2rz6AI0Cy6tq58ElPge9RBnisGc9NyccbaJxs,2610
39
+ sapiopycommons/general/storage_util.py,sha256=ovmK_jN7v09BoX07XxwShpBUC5WYQOM7dbKV_VeLXJU,8892
40
+ sapiopycommons/general/time_util.py,sha256=jU1urPoZRv6evNucR0-288EyT4PrsDpCr-H1-7BKq9A,12363
41
+ sapiopycommons/multimodal/multimodal.py,sha256=A1QsC8QTPmgZyPr7KtMbPRedn2Ie4WIErodUvQ9otgU,6724
42
+ sapiopycommons/multimodal/multimodal_data.py,sha256=0BeVPr9HaC0hNTF1v1phTIKGruvNnwerHsD994qJKBg,15099
43
+ sapiopycommons/processtracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
+ sapiopycommons/processtracking/custom_workflow_handler.py,sha256=B8KxQlwlLGkxnEid2jb9igGyGqrtcsBMhcOb9MfnO9E,23465
45
+ sapiopycommons/processtracking/endpoints.py,sha256=w5bziI2xC7450M95rCF8JpRwkoni1kEDibyAux9B12Q,10848
46
+ sapiopycommons/recordmodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
+ sapiopycommons/recordmodel/record_handler.py,sha256=5kCO5zsSg0kp3uYpgw1vf0WLHw30pMNC_6Bn3G7iQkI,64796
48
+ sapiopycommons/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
+ sapiopycommons/rules/eln_rule_handler.py,sha256=JYzDA_14D2nLnlqwbpIxVOrfKWzbOS27AYf4TQfGr4Q,10469
50
+ sapiopycommons/rules/on_save_rule_handler.py,sha256=Rkqvph20RbNq6m-RF4fbvCP-YfD2CZYBM2iTr3nl0eY,10236
51
+ sapiopycommons/sftpconnect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
+ sapiopycommons/sftpconnect/sftp_builder.py,sha256=lFK3FeXk-sFLefW0hqY8WGUQDeYiGaT6yDACzT_zFgQ,3015
53
+ sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
+ sapiopycommons/webhook/webhook_context.py,sha256=D793uLsb1691SalaPnBUk3rOSxn_hYLhdvkaIxjNXss,1909
55
+ sapiopycommons/webhook/webhook_handlers.py,sha256=M5PMt-j7PpnzUQMUQDTvqwJUyJNxuFtC9wdnk5VRNpI,39703
56
+ sapiopycommons/webhook/webservice_handlers.py,sha256=Y5dHx_UFWFuSqaoPL6Re-fsKYRuxvCWZ8bj6KSZ3jfM,14285
57
+ sapiopycommons-2025.1.17a402.dist-info/METADATA,sha256=aZYfmNTbM2shH0lpUurRTLU7Z1PbFyWeuF9ygM815Cg,3143
58
+ sapiopycommons-2025.1.17a402.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
59
+ sapiopycommons-2025.1.17a402.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
60
+ sapiopycommons-2025.1.17a402.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.22.3
2
+ Generator: hatchling 1.26.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,28 +0,0 @@
1
- sapiopycommons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- sapiopycommons/chem/IndigoMolecules.py,sha256=ukZcX6TMEgkNdD1L1GnH3tp5rGplFNPlGoChAHXbsxw,1945
3
- sapiopycommons/chem/Molecules.py,sha256=tOkn3fg4QizgqjkRLuvRdVy0JpTD3QEOSvZPxmIyT4c,8607
4
- sapiopycommons/chem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- sapiopycommons/datatype/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- sapiopycommons/datatype/attachment_util.py,sha256=BqB8zhGTEDhiVS5yvrYzqIGlq7NM1MAUhMYxGjjjHbI,3377
7
- sapiopycommons/eln/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- sapiopycommons/eln/experiment_handler.py,sha256=4dX2SwSIaS5STsI9gGaIFaWfRoqyPNP2zI1mibWFTWI,54417
9
- sapiopycommons/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- sapiopycommons/files/file_bridge.py,sha256=uobt21sgf-ak17EtpbFRU75SXpAnAhRXXAT-AIdd0AA,3743
11
- sapiopycommons/files/file_util.py,sha256=XIZgcm3Mlnk2O1TIO_ydaoKIIF_qaOE3rpo2JScy-Wo,23142
12
- sapiopycommons/general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- sapiopycommons/general/aliases.py,sha256=ymKIZcr4_XK4PyiGPQZ7vnh5bNs2YTTyvdi0-iWee40,2598
14
- sapiopycommons/general/custom_report_util.py,sha256=KLiV9pU8VB5501lNRYJzE6-55S8Y0GRWeSMmqkE6Mv0,3150
15
- sapiopycommons/general/exceptions.py,sha256=R_DQyX3nl-KD3ufS55SSrlCYvP9FzwZwkefQlcCjWo0,1238
16
- sapiopycommons/general/popup_util.py,sha256=EtzZXFNKkua9vK0KvIV62yEy5HKtqXntnym703cucdk,29150
17
- sapiopycommons/general/time_util.py,sha256=jiJUh7jc1ZRCOem880S3HaLPZ4RboBtSl4_U9sqAQuM,7290
18
- sapiopycommons/recordmodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- sapiopycommons/recordmodel/record_handler.py,sha256=-W54tBAQ4lzQSBH9H2KluXy5IbWRWd6nptnfqFzWdZ4,34338
20
- sapiopycommons/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- sapiopycommons/rules/eln_rule_handler.py,sha256=DY-uqQdhQ9UEN_7fIluHgdsFfGBOdTYJS4WyoNdSQyk,6031
22
- sapiopycommons/rules/on_save_rule_handler.py,sha256=1zk6032rl7izDuEsMamSA5sWoIKNpUjhRkKrhS6oyD0,6042
23
- sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- sapiopycommons/webhook/webhook_handlers.py,sha256=-Wz7VAnJPEVTf5MbsRUfIlulwoPZCOpFe7eMrbx-PB4,11794
25
- sapiopycommons-2024.3.19a157.dist-info/METADATA,sha256=RgYNCJxRI3vc3U8-yB6n6MJ5Y7nKSUT01hke9JE9VQ4,3009
26
- sapiopycommons-2024.3.19a157.dist-info/WHEEL,sha256=bq9SyP5NxIRA9EpQgMCd-9RmPHWvbH-4lTDGwxgIR64,87
27
- sapiopycommons-2024.3.19a157.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
28
- sapiopycommons-2024.3.19a157.dist-info/RECORD,,