sapiopycommons 2024.8.27a310__py3-none-any.whl → 2024.8.28a313__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/callback_util.py +69 -407
- sapiopycommons/chem/IndigoMolecules.py +0 -1
- sapiopycommons/chem/Molecules.py +0 -1
- sapiopycommons/datatype/attachment_util.py +10 -11
- sapiopycommons/eln/experiment_handler.py +48 -209
- sapiopycommons/files/complex_data_loader.py +4 -5
- sapiopycommons/files/file_bridge.py +24 -31
- sapiopycommons/files/file_data_handler.py +5 -2
- sapiopycommons/files/file_util.py +10 -50
- sapiopycommons/files/file_validator.py +6 -92
- sapiopycommons/files/file_writer.py +15 -44
- sapiopycommons/general/aliases.py +3 -147
- sapiopycommons/general/custom_report_util.py +37 -211
- sapiopycommons/general/popup_util.py +0 -17
- sapiopycommons/general/time_util.py +0 -40
- sapiopycommons/processtracking/endpoints.py +22 -22
- sapiopycommons/recordmodel/record_handler.py +97 -481
- sapiopycommons/rules/eln_rule_handler.py +25 -34
- sapiopycommons/rules/on_save_rule_handler.py +31 -34
- sapiopycommons/webhook/webhook_handlers.py +26 -147
- {sapiopycommons-2024.8.27a310.dist-info → sapiopycommons-2024.8.28a313.dist-info}/METADATA +2 -4
- sapiopycommons-2024.8.28a313.dist-info/RECORD +38 -0
- sapiopycommons/customreport/__init__.py +0 -0
- sapiopycommons/customreport/column_builder.py +0 -60
- sapiopycommons/customreport/custom_report_builder.py +0 -125
- sapiopycommons/customreport/term_builder.py +0 -299
- sapiopycommons/eln/experiment_report_util.py +0 -118
- sapiopycommons/files/file_bridge_handler.py +0 -340
- sapiopycommons/general/accession_service.py +0 -375
- sapiopycommons/general/audit_log.py +0 -196
- sapiopycommons/general/sapio_links.py +0 -50
- sapiopycommons/multimodal/multimodal.py +0 -146
- sapiopycommons/multimodal/multimodal_data.py +0 -486
- sapiopycommons/webhook/webservice_handlers.py +0 -67
- sapiopycommons-2024.8.27a310.dist-info/RECORD +0 -50
- {sapiopycommons-2024.8.27a310.dist-info → sapiopycommons-2024.8.28a313.dist-info}/WHEEL +0 -0
- {sapiopycommons-2024.8.27a310.dist-info → sapiopycommons-2024.8.28a313.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
from collections.abc import Iterable
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
3
4
|
from sapiopylib.rest.DataMgmtService import DataMgmtServer
|
|
4
5
|
from sapiopylib.rest.User import SapioUser
|
|
5
|
-
from sapiopylib.rest.pojo.CustomReport import ReportColumn, CustomReport
|
|
6
|
-
|
|
7
|
-
from sapiopycommons.general.aliases import UserIdentifier, FieldValue, AliasUtil, FieldIdentifierKey
|
|
6
|
+
from sapiopylib.rest.pojo.CustomReport import ReportColumn, CustomReport
|
|
7
|
+
from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
# FR-46064 - Initial port of PyWebhookUtils to sapiopycommons.
|
|
11
11
|
class CustomReportUtil:
|
|
12
12
|
@staticmethod
|
|
13
|
-
def run_system_report(context:
|
|
13
|
+
def run_system_report(context: SapioWebhookContext | SapioUser,
|
|
14
14
|
report_name: str,
|
|
15
|
-
filters: dict[
|
|
16
|
-
page_limit: int | None = None,
|
|
17
|
-
page_size: int | None = None,
|
|
18
|
-
page_number: int | None = None) -> list[dict[str, FieldValue]]:
|
|
15
|
+
filters: dict[str, Iterable[Any]] | None = None,
|
|
16
|
+
page_limit: int | None = None) -> list[dict[str, Any]]:
|
|
19
17
|
"""
|
|
20
18
|
Run a system report and return the results of that report as a list of dictionaries for the values of each
|
|
21
19
|
column in each row.
|
|
@@ -29,97 +27,29 @@ class CustomReportUtil:
|
|
|
29
27
|
filter on. Only those headers that both the filters and the custom report share will take effect. That is,
|
|
30
28
|
any filters that have a header name that isn't in the custom report will be ignored.
|
|
31
29
|
:param page_limit: The maximum number of pages to query. If None, exhausts all possible pages.
|
|
32
|
-
:param page_size: The size of each page of results in the search. If None, the page size is set by the server.
|
|
33
|
-
:param page_number: The page number to start the search from, If None, starts on the first page.
|
|
34
|
-
:return: The results of the report listed row by row, mapping each cell to the header it is under. The header
|
|
35
|
-
values in the dicts are the data field names of the columns.
|
|
36
|
-
If two columns in the search have the same data field name but differing data type names, then the
|
|
37
|
-
dictionary key to the value in the column will be "DataTypeName.DataFieldName". For example, if you
|
|
38
|
-
had a Sample column with a data field name of Identifier and a Request column with the same data field name,
|
|
39
|
-
then the dictionary keys for these columns would be Sample.Identifier and Request.Identifier respectively.
|
|
40
|
-
"""
|
|
41
|
-
results: tuple = CustomReportUtil.__exhaust_system_report(context, report_name, page_limit,
|
|
42
|
-
page_size, page_number)
|
|
43
|
-
columns: list[ReportColumn] = results[0]
|
|
44
|
-
rows: list[list[FieldValue]] = results[1]
|
|
45
|
-
return CustomReportUtil.__process_results(rows, columns, filters)
|
|
46
|
-
|
|
47
|
-
@staticmethod
|
|
48
|
-
def run_custom_report(context: UserIdentifier,
|
|
49
|
-
report_criteria: CustomReportCriteria,
|
|
50
|
-
filters: dict[FieldIdentifierKey, Iterable[FieldValue]] | None = None,
|
|
51
|
-
page_limit: int | None = None,
|
|
52
|
-
page_size: int | None = None,
|
|
53
|
-
page_number: int | None = None) -> list[dict[str, FieldValue]]:
|
|
54
|
-
"""
|
|
55
|
-
Run a custom report and return the results of that report as a list of dictionaries for the values of each
|
|
56
|
-
column in each row.
|
|
57
|
-
|
|
58
|
-
Custom reports are constructed by the caller, specifying the report terms and the columns that will be in the
|
|
59
|
-
results. They are like advanced or predefined searches from the system, except they are constructed from
|
|
60
|
-
within the webhook instead of from within the system.
|
|
61
|
-
|
|
62
|
-
:param context: The current webhook context or a user object to send requests from.
|
|
63
|
-
:param report_criteria: The custom report criteria to run.
|
|
64
|
-
:param filters: If provided, filter the results of the report using the given mapping of headers to values to
|
|
65
|
-
filter on. Only those headers that both the filters and the custom report share will take effect. That is,
|
|
66
|
-
any filters that have a header name that isn't in the custom report will be ignored.
|
|
67
|
-
Note that this parameter is only provided for parity with the other run report functions. If you need to
|
|
68
|
-
filter the results of a search, it would likely be more beneficial to have just added a new term to the
|
|
69
|
-
input report criteria that corresponds to the filter.
|
|
70
|
-
:param page_limit: The maximum number of pages to query. If None, exhausts all possible pages.
|
|
71
|
-
:param page_size: The size of each page of results in the search. If None, uses the value from the given report
|
|
72
|
-
criteria. If not None, overwrites the value from the given report criteria.
|
|
73
|
-
:param page_number: The page number to start the search from, If None, uses the value from the given report
|
|
74
|
-
criteria. If not None, overwrites the value from the given report criteria.
|
|
75
30
|
:return: The results of the report listed row by row, mapping each cell to the header it is under. The header
|
|
76
31
|
values in the dicts are the data field names of the columns.
|
|
77
|
-
If two columns in the search have the same data field name but differing data type names, then the
|
|
78
|
-
dictionary key to the value in the column will be "DataTypeName.DataFieldName". For example, if you
|
|
79
|
-
had a Sample column with a data field name of Identifier and a Request column with the same data field name,
|
|
80
|
-
then the dictionary keys for these columns would be Sample.Identifier and Request.Identifier respectively.
|
|
81
32
|
"""
|
|
82
|
-
results
|
|
83
|
-
page_size, page_number)
|
|
33
|
+
results = CustomReportUtil.__exhaust_system_report(context, report_name, page_limit)
|
|
84
34
|
columns: list[ReportColumn] = results[0]
|
|
85
|
-
rows: list[list[
|
|
86
|
-
return CustomReportUtil.__process_results(rows, columns, filters)
|
|
87
|
-
|
|
88
|
-
@staticmethod
|
|
89
|
-
def run_quick_report(context: UserIdentifier,
|
|
90
|
-
report_term: RawReportTerm,
|
|
91
|
-
filters: dict[FieldIdentifierKey, Iterable[FieldValue]] | None = None,
|
|
92
|
-
page_limit: int | None = None,
|
|
93
|
-
page_size: int | None = None,
|
|
94
|
-
page_number: int | None = None) -> list[dict[str, FieldValue]]:
|
|
95
|
-
"""
|
|
96
|
-
Run a quick report and return the results of that report as a list of dictionaries for the values of each
|
|
97
|
-
column in each row.
|
|
35
|
+
rows: list[list[Any]] = results[1]
|
|
98
36
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
:return: The results of the report listed row by row, mapping each cell to the header it is under. The header
|
|
113
|
-
values in the dicts are the data field names of the columns.
|
|
114
|
-
"""
|
|
115
|
-
results: tuple = CustomReportUtil.__exhaust_quick_report(context, report_term, page_limit,
|
|
116
|
-
page_size, page_number)
|
|
117
|
-
columns: list[ReportColumn] = results[0]
|
|
118
|
-
rows: list[list[FieldValue]] = results[1]
|
|
119
|
-
return CustomReportUtil.__process_results(rows, columns, filters)
|
|
37
|
+
ret: list[dict[str, Any]] = []
|
|
38
|
+
for row in rows:
|
|
39
|
+
row_data: dict[str, Any] = {}
|
|
40
|
+
filter_row: bool = False
|
|
41
|
+
for value, column in zip(row, columns):
|
|
42
|
+
header: str = column.data_field_name
|
|
43
|
+
if filters is not None and header in filters and value not in filters.get(header):
|
|
44
|
+
filter_row = True
|
|
45
|
+
break
|
|
46
|
+
row_data.update({header: value})
|
|
47
|
+
if filter_row is False:
|
|
48
|
+
ret.append(row_data)
|
|
49
|
+
return ret
|
|
120
50
|
|
|
121
51
|
@staticmethod
|
|
122
|
-
def get_system_report_criteria(context:
|
|
52
|
+
def get_system_report_criteria(context: SapioWebhookContext | SapioUser, report_name: str) -> CustomReport:
|
|
123
53
|
"""
|
|
124
54
|
Retrieve a custom report from the system given the name of the report. This works by querying the system report
|
|
125
55
|
with a page number and size of 1 to minimize the amount of data transfer needed to retrieve the report's config.
|
|
@@ -134,131 +64,27 @@ class CustomReportUtil:
|
|
|
134
64
|
:param report_name: The name of the system report to run.
|
|
135
65
|
:return: The CustomReport object for the given system report name.
|
|
136
66
|
"""
|
|
137
|
-
user: SapioUser =
|
|
67
|
+
user: SapioUser = context if isinstance(context, SapioUser) else context.user
|
|
138
68
|
report_man = DataMgmtServer.get_custom_report_manager(user)
|
|
139
69
|
return report_man.run_system_report_by_name(report_name, 1, 1)
|
|
140
70
|
|
|
141
71
|
@staticmethod
|
|
142
|
-
def __exhaust_system_report(context:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
page_size: int | None,
|
|
146
|
-
page_number: int | None) \
|
|
147
|
-
-> tuple[list[ReportColumn], list[list[FieldValue]]]:
|
|
148
|
-
"""
|
|
149
|
-
Given a system report, iterate over every page of the report and collect the results
|
|
150
|
-
until there are no remaining pages.
|
|
151
|
-
"""
|
|
152
|
-
user: SapioUser = AliasUtil.to_sapio_user(context)
|
|
153
|
-
report_man = DataMgmtServer.get_custom_report_manager(user)
|
|
154
|
-
|
|
155
|
-
result = None
|
|
156
|
-
has_next_page: bool = True
|
|
157
|
-
rows: list[list[FieldValue]] = []
|
|
158
|
-
cur_page: int = 1
|
|
159
|
-
while has_next_page and (not page_limit or cur_page <= page_limit):
|
|
160
|
-
result = report_man.run_system_report_by_name(report_name, page_size, page_number)
|
|
161
|
-
page_size = result.page_size
|
|
162
|
-
page_number = result.page_number
|
|
163
|
-
has_next_page = result.has_next_page
|
|
164
|
-
rows.extend(result.result_table)
|
|
165
|
-
cur_page += 1
|
|
166
|
-
return result.column_list, rows
|
|
167
|
-
|
|
168
|
-
@staticmethod
|
|
169
|
-
def __exhaust_custom_report(context: UserIdentifier,
|
|
170
|
-
report: CustomReportCriteria,
|
|
171
|
-
page_limit: int | None,
|
|
172
|
-
page_size: int | None,
|
|
173
|
-
page_number: int | None) \
|
|
174
|
-
-> tuple[list[ReportColumn], list[list[FieldValue]]]:
|
|
175
|
-
"""
|
|
176
|
-
Given a custom report, iterate over every page of the report and collect the results
|
|
177
|
-
until there are no remaining pages.
|
|
178
|
-
"""
|
|
179
|
-
user: SapioUser = AliasUtil.to_sapio_user(context)
|
|
72
|
+
def __exhaust_system_report(context: SapioWebhookContext | SapioUser, report_name: str, page_limit: int | None = None) \
|
|
73
|
+
-> tuple[list[ReportColumn], list[list[Any]]]:
|
|
74
|
+
user: SapioUser = context if isinstance(context, SapioUser) else context.user
|
|
180
75
|
report_man = DataMgmtServer.get_custom_report_manager(user)
|
|
181
76
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if page_number is not None:
|
|
186
|
-
report.page_number = page_number
|
|
77
|
+
report = None
|
|
78
|
+
page_size: int | None = None
|
|
79
|
+
page_number: int | None = None
|
|
187
80
|
has_next_page: bool = True
|
|
188
|
-
rows: list[list[
|
|
81
|
+
rows: list[list[Any]] = []
|
|
189
82
|
cur_page: int = 1
|
|
190
|
-
while has_next_page and (not page_limit or cur_page
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
has_next_page =
|
|
195
|
-
rows.extend(
|
|
83
|
+
while has_next_page and (not page_limit or cur_page < page_limit):
|
|
84
|
+
report = report_man.run_system_report_by_name(report_name, page_size, page_number)
|
|
85
|
+
page_size = report.page_size
|
|
86
|
+
page_number = report.page_number
|
|
87
|
+
has_next_page = report.has_next_page
|
|
88
|
+
rows.extend(report.result_table)
|
|
196
89
|
cur_page += 1
|
|
197
|
-
return
|
|
198
|
-
|
|
199
|
-
@staticmethod
|
|
200
|
-
def __exhaust_quick_report(context: UserIdentifier,
|
|
201
|
-
report_term: RawReportTerm,
|
|
202
|
-
page_limit: int | None,
|
|
203
|
-
page_size: int | None,
|
|
204
|
-
page_number: int | None) \
|
|
205
|
-
-> tuple[list[ReportColumn], list[list[FieldValue]]]:
|
|
206
|
-
"""
|
|
207
|
-
Given a quick report, iterate over every page of the report and collect the results
|
|
208
|
-
until there are no remaining pages.
|
|
209
|
-
"""
|
|
210
|
-
user: SapioUser = AliasUtil.to_sapio_user(context)
|
|
211
|
-
report_man = DataMgmtServer.get_custom_report_manager(user)
|
|
212
|
-
|
|
213
|
-
result = None
|
|
214
|
-
has_next_page: bool = True
|
|
215
|
-
rows: list[list[FieldValue]] = []
|
|
216
|
-
cur_page: int = 1
|
|
217
|
-
while has_next_page and (not page_limit or cur_page <= page_limit):
|
|
218
|
-
result = report_man.run_quick_report(report_term, page_size, page_number)
|
|
219
|
-
page_size = result.page_size
|
|
220
|
-
page_number = result.page_number
|
|
221
|
-
has_next_page = result.has_next_page
|
|
222
|
-
rows.extend(result.result_table)
|
|
223
|
-
cur_page += 1
|
|
224
|
-
return result.column_list, rows
|
|
225
|
-
|
|
226
|
-
@staticmethod
|
|
227
|
-
def __process_results(rows: list[list[FieldValue]], columns: list[ReportColumn],
|
|
228
|
-
filters: dict[FieldIdentifierKey, Iterable[FieldValue]] | None) -> list[dict[str, FieldValue]]:
|
|
229
|
-
"""
|
|
230
|
-
Given the results of a report as a list of row values and the report's columns, combine these lists to
|
|
231
|
-
result in a singular list of dictionaries for each row in the results.
|
|
232
|
-
|
|
233
|
-
If any filter criteria has been provided, also use that to filter the row.
|
|
234
|
-
"""
|
|
235
|
-
# It may be the case that two columns have the same data field name but differing data type names.
|
|
236
|
-
# If this occurs, then we need to be able to differentiate these columns in the resulting dictionary.
|
|
237
|
-
prepend_dt: set[str] = set()
|
|
238
|
-
encountered_names: list[str] = []
|
|
239
|
-
for column in columns:
|
|
240
|
-
field_name: str = column.data_field_name
|
|
241
|
-
if field_name in encountered_names:
|
|
242
|
-
prepend_dt.add(field_name)
|
|
243
|
-
else:
|
|
244
|
-
encountered_names.append(field_name)
|
|
245
|
-
|
|
246
|
-
filters: dict[str, Iterable[FieldValue]] = AliasUtil.to_data_field_names_dict(filters)
|
|
247
|
-
|
|
248
|
-
ret: list[dict[str, FieldValue]] = []
|
|
249
|
-
for row in rows:
|
|
250
|
-
row_data: dict[str, FieldValue] = {}
|
|
251
|
-
filter_row: bool = False
|
|
252
|
-
for value, column in zip(row, columns):
|
|
253
|
-
header: str = column.data_field_name
|
|
254
|
-
# If two columns share the same data field name, prepend the data type name of the column to the
|
|
255
|
-
# data field name.
|
|
256
|
-
if header in prepend_dt:
|
|
257
|
-
header = column.data_type_name + "." + header
|
|
258
|
-
if filters is not None and header in filters and value not in filters.get(header):
|
|
259
|
-
filter_row = True
|
|
260
|
-
break
|
|
261
|
-
row_data.update({header: value})
|
|
262
|
-
if filter_row is False:
|
|
263
|
-
ret.append(row_data)
|
|
264
|
-
return ret
|
|
90
|
+
return report.column_list, rows
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import warnings
|
|
2
|
-
|
|
3
1
|
from sapiopylib.rest.DataMgmtService import DataMgmtServer
|
|
4
2
|
from sapiopylib.rest.pojo.datatype.DataType import DataTypeDefinition
|
|
5
3
|
from sapiopylib.rest.pojo.datatype.FieldDefinition import VeloxStringFieldDefinition, AbstractVeloxFieldDefinition, \
|
|
@@ -53,7 +51,6 @@ class PopupUtil:
|
|
|
53
51
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
54
52
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
55
53
|
"""
|
|
56
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
57
54
|
if display_name is None:
|
|
58
55
|
display_name = data_type
|
|
59
56
|
if plural_display_name is None:
|
|
@@ -100,7 +97,6 @@ class PopupUtil:
|
|
|
100
97
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
101
98
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
102
99
|
"""
|
|
103
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
104
100
|
# Get the field definitions of the data type.
|
|
105
101
|
data_type: str = record.data_type_name
|
|
106
102
|
type_man = DataMgmtServer.get_data_type_manager(context.user)
|
|
@@ -159,7 +155,6 @@ class PopupUtil:
|
|
|
159
155
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
160
156
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
161
157
|
"""
|
|
162
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
163
158
|
if max_length is None:
|
|
164
159
|
max_length = len(default_value) if default_value else 100
|
|
165
160
|
string_field = VeloxStringFieldDefinition(data_type, field_name, field_name, default_value=default_value,
|
|
@@ -196,7 +191,6 @@ class PopupUtil:
|
|
|
196
191
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
197
192
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
198
193
|
"""
|
|
199
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
200
194
|
if default_value is None:
|
|
201
195
|
default_value = max(0, min_value)
|
|
202
196
|
integer_field = VeloxIntegerFieldDefinition(data_type, field_name, field_name, default_value=default_value,
|
|
@@ -235,7 +229,6 @@ class PopupUtil:
|
|
|
235
229
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
236
230
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
237
231
|
"""
|
|
238
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
239
232
|
if default_value is None:
|
|
240
233
|
default_value = min_value
|
|
241
234
|
double_field = VeloxDoubleFieldDefinition(data_type, field_name, field_name, default_value=default_value,
|
|
@@ -267,7 +260,6 @@ class PopupUtil:
|
|
|
267
260
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
268
261
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
269
262
|
"""
|
|
270
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
271
263
|
if display_name is None:
|
|
272
264
|
display_name = data_type
|
|
273
265
|
if plural_display_name is None:
|
|
@@ -303,7 +295,6 @@ class PopupUtil:
|
|
|
303
295
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
304
296
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
305
297
|
"""
|
|
306
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
307
298
|
data_types: set[str] = {x.data_type_name for x in records}
|
|
308
299
|
if len(data_types) > 1:
|
|
309
300
|
raise SapioException("Multiple data type names encountered in records list for record table popup.")
|
|
@@ -356,7 +347,6 @@ class PopupUtil:
|
|
|
356
347
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
357
348
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
358
349
|
"""
|
|
359
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
360
350
|
data_types: set[str] = {x.data_type_name for x in records}
|
|
361
351
|
if len(data_types) > 1:
|
|
362
352
|
raise SapioException("Multiple data type names encountered in records list for record table popup.")
|
|
@@ -401,7 +391,6 @@ class PopupUtil:
|
|
|
401
391
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
402
392
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
403
393
|
"""
|
|
404
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
405
394
|
callback = ListDialogRequest(title, multi_select, options,
|
|
406
395
|
callback_context_data=request_context)
|
|
407
396
|
return SapioWebhookResult(True, client_callback_request=callback)
|
|
@@ -426,7 +415,6 @@ class PopupUtil:
|
|
|
426
415
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
427
416
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
428
417
|
"""
|
|
429
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
430
418
|
callback = OptionDialogRequest(title, msg, options, default_option, user_can_cancel,
|
|
431
419
|
callback_context_data=request_context)
|
|
432
420
|
return SapioWebhookResult(True, client_callback_request=callback)
|
|
@@ -449,7 +437,6 @@ class PopupUtil:
|
|
|
449
437
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
450
438
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
451
439
|
"""
|
|
452
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
453
440
|
return PopupUtil.option_popup(title, msg, ["OK"], 0, user_can_cancel, request_context=request_context)
|
|
454
441
|
|
|
455
442
|
@staticmethod
|
|
@@ -471,7 +458,6 @@ class PopupUtil:
|
|
|
471
458
|
:param request_context: Context that will be returned to the webhook server in the client callback result.
|
|
472
459
|
:return: A SapioWebhookResult with the popup as its client callback request.
|
|
473
460
|
"""
|
|
474
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
475
461
|
return PopupUtil.option_popup(title, msg, ["Yes", "No"], 0 if default_yes else 1, user_can_cancel,
|
|
476
462
|
request_context=request_context)
|
|
477
463
|
|
|
@@ -484,7 +470,6 @@ class PopupUtil:
|
|
|
484
470
|
|
|
485
471
|
Deprecated for PopupUtil.text_field_popup.
|
|
486
472
|
"""
|
|
487
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
488
473
|
return PopupUtil.string_field_popup(title, "", field_name, msg, len(msg), False, data_type,
|
|
489
474
|
request_context=request_context, auto_size=True)
|
|
490
475
|
|
|
@@ -496,7 +481,6 @@ class PopupUtil:
|
|
|
496
481
|
|
|
497
482
|
Deprecated for PopupUtil.option_popup.
|
|
498
483
|
"""
|
|
499
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
500
484
|
return PopupUtil.option_popup(title, msg, options, 0, user_can_cancel, request_context=request_context)
|
|
501
485
|
|
|
502
486
|
@staticmethod
|
|
@@ -506,5 +490,4 @@ class PopupUtil:
|
|
|
506
490
|
|
|
507
491
|
Deprecated for PopupUtil.ok_popup.
|
|
508
492
|
"""
|
|
509
|
-
warnings.warn("PopupUtil is deprecated as of 24.5+. Use CallbackUtil instead.", DeprecationWarning)
|
|
510
493
|
return PopupUtil.ok_popup(title, msg, False, request_context=request_context)
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
import time
|
|
4
2
|
from datetime import datetime
|
|
5
3
|
|
|
6
4
|
import pytz
|
|
7
5
|
|
|
8
|
-
from sapiopycommons.general.exceptions import SapioException
|
|
9
|
-
|
|
10
6
|
__timezone = None
|
|
11
7
|
"""The default timezone. Use TimeUtil.set_default_timezone in a global context before making use of TimeUtil."""
|
|
12
8
|
|
|
@@ -141,39 +137,3 @@ class TimeUtil:
|
|
|
141
137
|
return True
|
|
142
138
|
except Exception:
|
|
143
139
|
return False
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
class DateRange:
|
|
147
|
-
start: int | None
|
|
148
|
-
end: int | None
|
|
149
|
-
|
|
150
|
-
@staticmethod
|
|
151
|
-
def from_string(value: str | None) -> DateRange:
|
|
152
|
-
"""
|
|
153
|
-
Construct a DateRange object from a string. The field value of date range fields is a string of the form
|
|
154
|
-
<start timestamp>/<end timestamp>.
|
|
155
|
-
|
|
156
|
-
:param value: A date range field value.
|
|
157
|
-
:return: A DateRange object matching the input field value.
|
|
158
|
-
"""
|
|
159
|
-
if not value:
|
|
160
|
-
return DateRange(None, None)
|
|
161
|
-
values: list[str] = value.split("/")
|
|
162
|
-
return DateRange(int(values[0]), int(values[1]))
|
|
163
|
-
|
|
164
|
-
def __init__(self, start: int | None, end: int | None):
|
|
165
|
-
"""
|
|
166
|
-
:param start: The timestamp for the start of the date range.
|
|
167
|
-
:param end: The timestamp for the end of the date rate.
|
|
168
|
-
"""
|
|
169
|
-
if (start and end is None) or (end and start is None):
|
|
170
|
-
raise SapioException("Both start and end values must be present in a date range.")
|
|
171
|
-
if start and end and end < start:
|
|
172
|
-
raise SapioException(f"End timestamp {end} is earlier than the start timestamp {start}.")
|
|
173
|
-
self.start = start
|
|
174
|
-
self.end = end
|
|
175
|
-
|
|
176
|
-
def __str__(self) -> str | None:
|
|
177
|
-
if not self.start and not self.end:
|
|
178
|
-
return None
|
|
179
|
-
return f"{self.start}/{self.end}"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from sapiopylib.rest.User import SapioUser
|
|
2
|
+
from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
|
|
2
3
|
|
|
3
|
-
from sapiopycommons.general.aliases import RecordIdentifier, AliasUtil, ExperimentIdentifier
|
|
4
|
-
UserIdentifier
|
|
4
|
+
from sapiopycommons.general.aliases import RecordIdentifier, AliasUtil, ExperimentIdentifier
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class ProcessTracking:
|
|
8
8
|
@staticmethod
|
|
9
|
-
def assign_to_process(context:
|
|
9
|
+
def assign_to_process(context: SapioWebhookContext | SapioUser, data_type: str, records: list[RecordIdentifier],
|
|
10
10
|
process_name: str, step_number: int | None = None, branch_id: int | None = None,
|
|
11
11
|
request: RecordIdentifier | None = None) -> None:
|
|
12
12
|
"""
|
|
@@ -27,19 +27,19 @@ class ProcessTracking:
|
|
|
27
27
|
"""
|
|
28
28
|
sub_path = '/ext/process-tracking/assign-to-process'
|
|
29
29
|
payload = {
|
|
30
|
-
"data-type-name":
|
|
30
|
+
"data-type-name": data_type,
|
|
31
31
|
"record-ids": AliasUtil.to_record_ids(records),
|
|
32
32
|
"process-name": process_name,
|
|
33
33
|
"step-number": step_number,
|
|
34
34
|
"branch-id": branch_id,
|
|
35
35
|
"request-record-id": AliasUtil.to_record_ids([request])[0] if request is not None else None
|
|
36
36
|
}
|
|
37
|
-
user: SapioUser =
|
|
37
|
+
user: SapioUser = context if isinstance(context, SapioUser) else context.user
|
|
38
38
|
response = user.post(sub_path, payload=payload)
|
|
39
39
|
user.raise_for_status(response)
|
|
40
40
|
|
|
41
41
|
@staticmethod
|
|
42
|
-
def begin_protocol(context:
|
|
42
|
+
def begin_protocol(context: SapioWebhookContext | SapioUser, data_type: str, records: list[RecordIdentifier],
|
|
43
43
|
experiment: ExperimentIdentifier) -> None:
|
|
44
44
|
"""
|
|
45
45
|
Begin the assigned processes of the given tracked records as the given experiment. This sets the status of the
|
|
@@ -54,16 +54,16 @@ class ProcessTracking:
|
|
|
54
54
|
"""
|
|
55
55
|
sub_path = '/ext/process-tracking/begin-protocol'
|
|
56
56
|
payload = {
|
|
57
|
-
"data-type-name":
|
|
57
|
+
"data-type-name": data_type,
|
|
58
58
|
"record-ids": AliasUtil.to_record_ids(records),
|
|
59
59
|
"experiment-id": AliasUtil.to_notebook_id(experiment),
|
|
60
60
|
}
|
|
61
|
-
user: SapioUser =
|
|
61
|
+
user: SapioUser = context if isinstance(context, SapioUser) else context.user
|
|
62
62
|
response = user.post(sub_path, payload=payload)
|
|
63
63
|
user.raise_for_status(response)
|
|
64
64
|
|
|
65
65
|
@staticmethod
|
|
66
|
-
def complete_protocol(context:
|
|
66
|
+
def complete_protocol(context: SapioWebhookContext | SapioUser, data_type: str, records: list[RecordIdentifier],
|
|
67
67
|
experiment: ExperimentIdentifier) -> None:
|
|
68
68
|
"""
|
|
69
69
|
Complete the current step that the given tracked records are at given the experiment.
|
|
@@ -80,16 +80,16 @@ class ProcessTracking:
|
|
|
80
80
|
"""
|
|
81
81
|
sub_path = '/ext/process-tracking/complete-protocol'
|
|
82
82
|
payload = {
|
|
83
|
-
"data-type-name":
|
|
83
|
+
"data-type-name": data_type,
|
|
84
84
|
"record-ids": AliasUtil.to_record_ids(records),
|
|
85
85
|
"experiment-id": AliasUtil.to_notebook_id(experiment),
|
|
86
86
|
}
|
|
87
|
-
user: SapioUser =
|
|
87
|
+
user: SapioUser = context if isinstance(context, SapioUser) else context.user
|
|
88
88
|
response = user.post(sub_path, payload=payload)
|
|
89
89
|
user.raise_for_status(response)
|
|
90
90
|
|
|
91
91
|
@staticmethod
|
|
92
|
-
def fail(context:
|
|
92
|
+
def fail(context: SapioWebhookContext | SapioUser, data_type: str, records: list[RecordIdentifier],
|
|
93
93
|
experiment: ExperimentIdentifier) -> None:
|
|
94
94
|
"""
|
|
95
95
|
Fail the assigned processes of the given tracked records, changing their statuses to "Failed -". The tracked
|
|
@@ -103,16 +103,16 @@ class ProcessTracking:
|
|
|
103
103
|
"""
|
|
104
104
|
sub_path = '/ext/process-tracking/fail'
|
|
105
105
|
payload = {
|
|
106
|
-
"data-type-name":
|
|
106
|
+
"data-type-name": data_type,
|
|
107
107
|
"record-ids": AliasUtil.to_record_ids(records),
|
|
108
108
|
"experiment-id": AliasUtil.to_notebook_id(experiment),
|
|
109
109
|
}
|
|
110
|
-
user: SapioUser =
|
|
110
|
+
user: SapioUser = context if isinstance(context, SapioUser) else context.user
|
|
111
111
|
response = user.post(sub_path, payload=payload)
|
|
112
112
|
user.raise_for_status(response)
|
|
113
113
|
|
|
114
114
|
@staticmethod
|
|
115
|
-
def promote_to_next_by_experiment(context:
|
|
115
|
+
def promote_to_next_by_experiment(context: SapioWebhookContext | SapioUser, data_type: str,
|
|
116
116
|
records: list[RecordIdentifier], experiment: ExperimentIdentifier) -> None:
|
|
117
117
|
"""
|
|
118
118
|
Promote the status of the given tracked records to the next status in their process using an experiment.
|
|
@@ -129,16 +129,16 @@ class ProcessTracking:
|
|
|
129
129
|
"""
|
|
130
130
|
sub_path = '/ext/process-tracking/promote-status-to-next'
|
|
131
131
|
payload = {
|
|
132
|
-
"data-type-name":
|
|
132
|
+
"data-type-name": data_type,
|
|
133
133
|
"record-ids": AliasUtil.to_record_ids(records),
|
|
134
134
|
"experiment-id": AliasUtil.to_notebook_id(experiment),
|
|
135
135
|
}
|
|
136
|
-
user: SapioUser =
|
|
136
|
+
user: SapioUser = context if isinstance(context, SapioUser) else context.user
|
|
137
137
|
response = user.post(sub_path, payload=payload)
|
|
138
138
|
user.raise_for_status(response)
|
|
139
139
|
|
|
140
140
|
@staticmethod
|
|
141
|
-
def promote_to_next_by_step(context:
|
|
141
|
+
def promote_to_next_by_step(context: SapioWebhookContext | SapioUser, data_type: str,
|
|
142
142
|
records: list[RecordIdentifier], process_name: str, step_number: int,
|
|
143
143
|
branch_id: int | None = None) -> None:
|
|
144
144
|
"""
|
|
@@ -159,7 +159,7 @@ class ProcessTracking:
|
|
|
159
159
|
"""
|
|
160
160
|
sub_path = '/ext/process-tracking/promote-status-to-next'
|
|
161
161
|
payload = {
|
|
162
|
-
"data-type-name":
|
|
162
|
+
"data-type-name": data_type,
|
|
163
163
|
"record-ids": AliasUtil.to_record_ids(records),
|
|
164
164
|
"current-process-status": {
|
|
165
165
|
"process-name": process_name,
|
|
@@ -167,12 +167,12 @@ class ProcessTracking:
|
|
|
167
167
|
"branch-id": branch_id
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
-
user: SapioUser =
|
|
170
|
+
user: SapioUser = context if isinstance(context, SapioUser) else context.user
|
|
171
171
|
response = user.post(sub_path, payload=payload)
|
|
172
172
|
user.raise_for_status(response)
|
|
173
173
|
|
|
174
174
|
@staticmethod
|
|
175
|
-
def reprocess(context:
|
|
175
|
+
def reprocess(context: SapioWebhookContext | SapioUser, records: list[RecordIdentifier]) -> None:
|
|
176
176
|
"""
|
|
177
177
|
Reprocess tracked records to a previous step in their process. Reprocessing is controlled by ReturnPoint records
|
|
178
178
|
which are children of the AssignedProcess on the tracked records. Creates a new AssignedProcess record for the
|
|
@@ -187,6 +187,6 @@ class ProcessTracking:
|
|
|
187
187
|
payload = {
|
|
188
188
|
"record-ids": AliasUtil.to_record_ids(records)
|
|
189
189
|
}
|
|
190
|
-
user: SapioUser =
|
|
190
|
+
user: SapioUser = context if isinstance(context, SapioUser) else context.user
|
|
191
191
|
response = user.post(sub_path, payload=payload)
|
|
192
192
|
user.raise_for_status(response)
|