sapiopycommons 2024.8.27a312__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.

@@ -4,15 +4,12 @@ from abc import abstractmethod
4
4
  from typing import Any
5
5
 
6
6
  from sapiopylib.rest.User import SapioUser
7
- from sapiopylib.rest.pojo.CustomReport import RawReportTerm, RawTermOperation
8
7
  from sapiopylib.rest.pojo.datatype.FieldDefinition import VeloxIntegerFieldDefinition, VeloxStringFieldDefinition, \
9
8
  AbstractVeloxFieldDefinition
10
- from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
11
9
  from sapiopylib.rest.pojo.webhook.WebhookResult import SapioWebhookResult
12
10
 
13
11
  from sapiopycommons.callbacks.callback_util import CallbackUtil
14
12
  from sapiopycommons.files.file_data_handler import FileDataHandler, FilterList
15
- from sapiopycommons.general.custom_report_util import CustomReportUtil
16
13
  from sapiopycommons.general.time_util import TimeUtil
17
14
 
18
15
 
@@ -483,71 +480,3 @@ class ContainsSubstringFromCellRule(RowRule):
483
480
 
484
481
  def validate(self, row: dict[str, Any]) -> bool:
485
482
  return row.get(self.second) in row.get(self.first)
486
-
487
-
488
- class UniqueSystemValueRule(ColumnRule):
489
- """
490
- Requires that every cell in the column has a value that is not already in use in the system for a given data type
491
- and field name.
492
- """
493
- user: SapioUser
494
- data_type_name: str
495
- data_field_name: str
496
-
497
- def __init__(self, context: SapioWebhookContext | SapioUser, header: str, data_type_name: str,
498
- data_field_name: str):
499
- """
500
- :param context: The current webhook context or a user object to send requests from.
501
- :param header: The header that this rule acts upon.
502
- :param data_type_name: The data type name to search on.
503
- :param data_field_name: The data field name to search on. This is expected to be a string field.
504
- """
505
- self.user = context.user if isinstance(context, SapioWebhookContext) else context
506
- self.data_type_name = data_type_name
507
- self.data_field_name = data_field_name
508
- super().__init__(header, f"This value already exists in the system.")
509
-
510
- def validate(self, rows: list[dict[str, Any]]) -> list[int]:
511
- file_handler = FileDataHandler(rows)
512
- values: list[str] = file_handler.get_values_list(self.header)
513
-
514
- # Run a quick report for all records of this type that match these field values.
515
- term = RawReportTerm(self.data_type_name, self.data_field_name, RawTermOperation.EQUAL_TO_OPERATOR,
516
- "{" + ",".join(values) + "}")
517
- results: list[dict[str, Any]] = CustomReportUtil.run_quick_report(self.user, term)
518
- existing_values: list[Any] = [x.get(self.data_field_name) for x in results]
519
- return file_handler.get_in_list(self.header, existing_values)
520
-
521
-
522
- class ExistingSystemValueRule(ColumnRule):
523
- """
524
- Requires that every cell in the column has a value that is already in use in the system for a given data type
525
- and field name.
526
- """
527
- user: SapioUser
528
- data_type_name: str
529
- data_field_name: str
530
-
531
- def __init__(self, context: SapioWebhookContext | SapioUser, header: str, data_type_name: str,
532
- data_field_name: str):
533
- """
534
- :param context: The current webhook context or a user object to send requests from.
535
- :param header: The header that this rule acts upon.
536
- :param data_type_name: The data type name to search on.
537
- :param data_field_name: The data field name to search on. This is expected to be a string field.
538
- """
539
- self.user = context.user if isinstance(context, SapioWebhookContext) else context
540
- self.data_type_name = data_type_name
541
- self.data_field_name = data_field_name
542
- super().__init__(header, f"This value doesn't exist in the system.")
543
-
544
- def validate(self, rows: list[dict[str, Any]]) -> list[int]:
545
- file_handler = FileDataHandler(rows)
546
- values: list[str] = file_handler.get_values_list(self.header)
547
-
548
- # Run a quick report for all records of this type that match these field values.
549
- term = RawReportTerm(self.data_type_name, self.data_field_name, RawTermOperation.EQUAL_TO_OPERATOR,
550
- "{" + ",".join(values) + "}")
551
- results: list[dict[str, Any]] = CustomReportUtil.run_quick_report(self.user, term)
552
- existing_values: list[Any] = [x.get(self.data_field_name) for x in results]
553
- return file_handler.get_not_in_list(self.header, existing_values)
@@ -3,7 +3,7 @@ from typing import Any
3
3
 
4
4
  from sapiopylib.rest.DataMgmtService import DataMgmtServer
5
5
  from sapiopylib.rest.User import SapioUser
6
- from sapiopylib.rest.pojo.CustomReport import ReportColumn, CustomReport, CustomReportCriteria, RawReportTerm
6
+ from sapiopylib.rest.pojo.CustomReport import ReportColumn, CustomReport
7
7
  from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
8
8
 
9
9
 
@@ -13,9 +13,7 @@ class CustomReportUtil:
13
13
  def run_system_report(context: SapioWebhookContext | SapioUser,
14
14
  report_name: str,
15
15
  filters: dict[str, Iterable[Any]] | None = None,
16
- page_limit: int | None = None,
17
- page_size: int | None = None,
18
- page_number: int | None = None) -> list[dict[str, Any]]:
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,94 +27,26 @@ 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
30
  :return: The results of the report listed row by row, mapping each cell to the header it is under. The header
35
31
  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
32
  """
41
- results: tuple = CustomReportUtil.__exhaust_system_report(context, report_name, page_limit,
42
- page_size, page_number)
33
+ results = CustomReportUtil.__exhaust_system_report(context, report_name, page_limit)
43
34
  columns: list[ReportColumn] = results[0]
44
35
  rows: list[list[Any]] = results[1]
45
- return CustomReportUtil.__process_results(rows, columns, filters)
46
36
 
47
- @staticmethod
48
- def run_custom_report(context: SapioWebhookContext | SapioUser,
49
- report_criteria: CustomReportCriteria,
50
- filters: dict[str, Iterable[Any]] | None = None,
51
- page_limit: int | None = None,
52
- page_size: int | None = None,
53
- page_number: int | None = None) -> list[dict[str, Any]]:
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
- :return: The results of the report listed row by row, mapping each cell to the header it is under. The header
76
- 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
- """
82
- results: tuple = CustomReportUtil.__exhaust_custom_report(context, report_criteria, page_limit,
83
- page_size, page_number)
84
- columns: list[ReportColumn] = results[0]
85
- rows: list[list[Any]] = results[1]
86
- return CustomReportUtil.__process_results(rows, columns, filters)
87
-
88
- @staticmethod
89
- def run_quick_report(context: SapioWebhookContext | SapioUser,
90
- report_term: RawReportTerm,
91
- filters: dict[str, Iterable[Any]] | None = None,
92
- page_limit: int | None = None,
93
- page_size: int | None = None,
94
- page_number: int | None = None) -> list[dict[str, Any]]:
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.
98
-
99
- Quick reports are helpful for cases where you need to query record field values in a more complex manner than
100
- the data record manager allows, but still simpler than a full-blown custom report. The columns that are returned
101
- in a quick search are every visible field from the data type that corresponds to the given report term. (Fields
102
- which are not marked as visible in the data designer will be excluded.)
103
-
104
- :param context: The current webhook context or a user object to send requests from.
105
- :param report_term: The raw report term to use for the quick report.
106
- :param filters: If provided, filter the results of the report using the given mapping of headers to values to
107
- filter on. Only those headers that both the filters and the custom report share will take effect. That is,
108
- any filters that have a header name that isn't in the custom report will be ignored.
109
- :param page_limit: The maximum number of pages to query. If None, exhausts all possible pages.
110
- :param page_size: The size of each page of results in the search. If None, the page size is set by the server.
111
- :param page_number: The page number to start the search from, If None, starts on the first page.
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[Any]] = 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
52
  def get_system_report_criteria(context: SapioWebhookContext | SapioUser, report_name: str) -> CustomReport:
@@ -139,124 +69,22 @@ class CustomReportUtil:
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: SapioWebhookContext | SapioUser,
143
- report_name: str,
144
- page_limit: int | None,
145
- page_size: int | None,
146
- page_number: int | None) \
72
+ def __exhaust_system_report(context: SapioWebhookContext | SapioUser, report_name: str, page_limit: int | None = None) \
147
73
  -> tuple[list[ReportColumn], list[list[Any]]]:
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
74
  user: SapioUser = context if isinstance(context, SapioUser) else context.user
153
75
  report_man = DataMgmtServer.get_custom_report_manager(user)
154
76
 
155
- result = None
77
+ report = None
78
+ page_size: int | None = None
79
+ page_number: int | None = None
156
80
  has_next_page: bool = True
157
81
  rows: list[list[Any]] = []
158
82
  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)
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)
165
89
  cur_page += 1
166
- return result.column_list, rows
167
-
168
- @staticmethod
169
- def __exhaust_custom_report(context: SapioWebhookContext | SapioUser,
170
- report: CustomReportCriteria,
171
- page_limit: int | None,
172
- page_size: int | None,
173
- page_number: int | None) \
174
- -> tuple[list[ReportColumn], list[list[Any]]]:
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 = context if isinstance(context, SapioUser) else context.user
180
- report_man = DataMgmtServer.get_custom_report_manager(user)
181
-
182
- result = None
183
- if page_size is not None:
184
- report.page_size = page_size
185
- if page_number is not None:
186
- report.page_number = page_number
187
- has_next_page: bool = True
188
- rows: list[list[Any]] = []
189
- cur_page: int = 1
190
- while has_next_page and (not page_limit or cur_page <= page_limit):
191
- result = report_man.run_custom_report(report)
192
- report.page_size = result.page_size
193
- report.page_number = result.page_number
194
- has_next_page = result.has_next_page
195
- rows.extend(result.result_table)
196
- cur_page += 1
197
- return result.column_list, rows
198
-
199
- @staticmethod
200
- def __exhaust_quick_report(context: SapioWebhookContext | SapioUser,
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[Any]]]:
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 = context if isinstance(context, SapioUser) else context.user
211
- report_man = DataMgmtServer.get_custom_report_manager(user)
212
-
213
- result = None
214
- has_next_page: bool = True
215
- rows: list[list[Any]] = []
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[Any]], columns: list[ReportColumn],
228
- filters: dict[str, Iterable[Any]] | None) -> list[dict[str, Any]]:
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
- ret: list[dict[str, Any]] = []
247
- for row in rows:
248
- row_data: dict[str, Any] = {}
249
- filter_row: bool = False
250
- for value, column in zip(row, columns):
251
- header: str = column.data_field_name
252
- # If two columns share the same data field name, prepend the data type name of the column to the
253
- # data field name.
254
- if header in prepend_dt:
255
- header = column.data_type_name + "." + header
256
- if filters is not None and header in filters and value not in filters.get(header):
257
- filter_row = True
258
- break
259
- row_data.update({header: value})
260
- if filter_row is False:
261
- ret.append(row_data)
262
- return ret
90
+ return report.column_list, rows