sapiopycommons 2024.3.18a156__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.
- sapiopycommons/callbacks/__init__.py +0 -0
- sapiopycommons/callbacks/callback_util.py +2041 -0
- sapiopycommons/callbacks/field_builder.py +545 -0
- sapiopycommons/chem/IndigoMolecules.py +52 -5
- sapiopycommons/chem/Molecules.py +114 -30
- sapiopycommons/customreport/__init__.py +0 -0
- sapiopycommons/customreport/column_builder.py +60 -0
- sapiopycommons/customreport/custom_report_builder.py +137 -0
- sapiopycommons/customreport/term_builder.py +315 -0
- sapiopycommons/datatype/attachment_util.py +17 -15
- sapiopycommons/datatype/data_fields.py +61 -0
- sapiopycommons/datatype/pseudo_data_types.py +440 -0
- sapiopycommons/eln/experiment_handler.py +390 -90
- sapiopycommons/eln/experiment_report_util.py +649 -0
- sapiopycommons/eln/plate_designer.py +152 -0
- sapiopycommons/files/complex_data_loader.py +31 -0
- sapiopycommons/files/file_bridge.py +153 -25
- sapiopycommons/files/file_bridge_handler.py +555 -0
- sapiopycommons/files/file_data_handler.py +633 -0
- sapiopycommons/files/file_util.py +270 -158
- sapiopycommons/files/file_validator.py +569 -0
- sapiopycommons/files/file_writer.py +377 -0
- sapiopycommons/flowcyto/flow_cyto.py +77 -0
- sapiopycommons/flowcyto/flowcyto_data.py +75 -0
- sapiopycommons/general/accession_service.py +375 -0
- sapiopycommons/general/aliases.py +259 -18
- sapiopycommons/general/audit_log.py +185 -0
- sapiopycommons/general/custom_report_util.py +252 -31
- sapiopycommons/general/directive_util.py +86 -0
- sapiopycommons/general/exceptions.py +69 -7
- sapiopycommons/general/popup_util.py +85 -18
- sapiopycommons/general/sapio_links.py +50 -0
- sapiopycommons/general/storage_util.py +148 -0
- sapiopycommons/general/time_util.py +97 -7
- sapiopycommons/multimodal/multimodal.py +146 -0
- sapiopycommons/multimodal/multimodal_data.py +490 -0
- sapiopycommons/processtracking/__init__.py +0 -0
- sapiopycommons/processtracking/custom_workflow_handler.py +406 -0
- sapiopycommons/processtracking/endpoints.py +192 -0
- sapiopycommons/recordmodel/record_handler.py +653 -149
- sapiopycommons/rules/eln_rule_handler.py +89 -8
- sapiopycommons/rules/on_save_rule_handler.py +89 -12
- sapiopycommons/sftpconnect/__init__.py +0 -0
- sapiopycommons/sftpconnect/sftp_builder.py +70 -0
- sapiopycommons/webhook/webhook_context.py +39 -0
- sapiopycommons/webhook/webhook_handlers.py +617 -69
- sapiopycommons/webhook/webservice_handlers.py +317 -0
- {sapiopycommons-2024.3.18a156.dist-info → sapiopycommons-2025.1.17a402.dist-info}/METADATA +5 -4
- sapiopycommons-2025.1.17a402.dist-info/RECORD +60 -0
- {sapiopycommons-2024.3.18a156.dist-info → sapiopycommons-2025.1.17a402.dist-info}/WHEEL +1 -1
- sapiopycommons-2024.3.18a156.dist-info/RECORD +0 -28
- {sapiopycommons-2024.3.18a156.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:
|
|
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
|
|
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:
|
|
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,28 +0,0 @@
|
|
|
1
|
-
sapiopycommons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
sapiopycommons/chem/IndigoMolecules.py,sha256=4XK-hpsCvU5vGwdGq6DvELQbqD1U-ObJ4h-ubz0lcds,1939
|
|
3
|
-
sapiopycommons/chem/Molecules.py,sha256=9qrjQG77WdfKfi_EepVPPvGbzhD_LBcQbzu8En4iRRQ,8593
|
|
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=BQdwpMHrLlspeBmv_oZLHc98rVE0x85253eyzY_oGxM,3374
|
|
7
|
-
sapiopycommons/eln/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
sapiopycommons/eln/experiment_handler.py,sha256=S5TKqudGnl403hOjXWv4xZYj7m5sUTIXy6eTlqaRm4c,54381
|
|
9
|
-
sapiopycommons/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
sapiopycommons/files/file_bridge.py,sha256=7LXrK3SptDB73jHhbIkTO9_tYc4eGV3bV3m58-LoevA,3739
|
|
11
|
-
sapiopycommons/files/file_util.py,sha256=oODNh1ycbtw_Xd-57glvjAAIRUVImsMCYxhkQ1yxe0I,23138
|
|
12
|
-
sapiopycommons/general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
sapiopycommons/general/aliases.py,sha256=nAFa_fbAOXGtvd4xEB1VmXGfe6SeX5CWv6HkUXZ-bjw,2458
|
|
14
|
-
sapiopycommons/general/custom_report_util.py,sha256=4SzzHBa7oduehUTxzpfyTwEEVLNGR96qQX1PaJAOE3A,3149
|
|
15
|
-
sapiopycommons/general/exceptions.py,sha256=R_DQyX3nl-KD3ufS55SSrlCYvP9FzwZwkefQlcCjWo0,1238
|
|
16
|
-
sapiopycommons/general/popup_util.py,sha256=_GX_B1MsSHm0vC9N2FPEpmyjDqBuiP3WFm3ZFx4DWw8,28858
|
|
17
|
-
sapiopycommons/general/time_util.py,sha256=1joSerNTUtrYwsJqK9H7qe32C8RRenqONaBVz20DB_0,7284
|
|
18
|
-
sapiopycommons/recordmodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
sapiopycommons/recordmodel/record_handler.py,sha256=DnzMN04-PQQ7EXmTtO35_z5L5HfauVFavzC6-NJ0ZZs,34307
|
|
20
|
-
sapiopycommons/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
-
sapiopycommons/rules/eln_rule_handler.py,sha256=nb9M85_4TM9u3VD6hlN2-ojvBDVxZuVEU5OXc-2_AVY,6029
|
|
22
|
-
sapiopycommons/rules/on_save_rule_handler.py,sha256=jcbJjLb46Yn9w_xNwukIS89f6tiVDMVoOX3PEviIWr0,6040
|
|
23
|
-
sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
-
sapiopycommons/webhook/webhook_handlers.py,sha256=cohzDzfKZNB1hmkUAXa9PdQzCMpE3Ci7cWJjxmKRPcY,11789
|
|
25
|
-
sapiopycommons-2024.3.18a156.dist-info/METADATA,sha256=DaBdpbMRG1rPcPU80SY_Y_twmIEP1eqx8FRagS6bqv0,3009
|
|
26
|
-
sapiopycommons-2024.3.18a156.dist-info/WHEEL,sha256=LL0B1KxSLwaTWceo7tT-0aDLd-qq9dmbnsnk1DnXlg8,87
|
|
27
|
-
sapiopycommons-2024.3.18a156.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
28
|
-
sapiopycommons-2024.3.18a156.dist-info/RECORD,,
|
{sapiopycommons-2024.3.18a156.dist-info → sapiopycommons-2025.1.17a402.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|