sapiopycommons 2025.2.25a450__py3-none-any.whl → 2025.3.6a453__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.

@@ -70,56 +70,66 @@ class RecordHandler:
70
70
  self.rel_man = self.rec_man.relationship_manager
71
71
  self.an_man = RecordModelAncestorManager(self.rec_man)
72
72
 
73
- def wrap_model(self, record: DataRecord, wrapper_type: type[WrappedType]) -> WrappedType:
73
+ def wrap_model(self, record: DataRecord, wrapper_type: type[WrappedType] | None = None) \
74
+ -> WrappedType | PyRecordModel:
74
75
  """
75
76
  Shorthand for adding a single data record as a record model.
76
77
 
77
78
  :param record: The data record to wrap.
78
- :param wrapper_type: The record model wrapper to use.
79
+ :param wrapper_type: The record model wrapper to use. If not provided, the record is returned as a
80
+ PyRecordModel instead of WrappedRecordModels.
79
81
  :return: The record model for the input.
80
82
  """
81
- self.__verify_data_type([record], wrapper_type)
82
- return self.inst_man.add_existing_record_of_type(record, wrapper_type)
83
+ if wrapper_type is not None:
84
+ self.__verify_data_type([record], wrapper_type)
85
+ return self.inst_man.add_existing_record_of_type(record, wrapper_type)
86
+ return self.inst_man.add_existing_record(record)
83
87
 
84
- def wrap_models(self, records: Iterable[DataRecord], wrapper_type: type[WrappedType]) -> list[WrappedType]:
88
+ def wrap_models(self, records: Iterable[DataRecord], wrapper_type: type[WrappedType] | None = None) \
89
+ -> list[WrappedType] | list[PyRecordModel]:
85
90
  """
86
91
  Shorthand for adding a list of data records as record models.
87
92
 
88
93
  :param records: The data records to wrap.
89
- :param wrapper_type: The record model wrapper to use.
94
+ :param wrapper_type: The record model wrapper to use. If not provided, the records are returned as
95
+ PyRecordModels instead of WrappedRecordModels.
90
96
  :return: The record models for the input.
91
97
  """
92
- self.__verify_data_type(records, wrapper_type)
93
- return self.inst_man.add_existing_records_of_type(list(records), wrapper_type)
98
+ if wrapper_type is not None:
99
+ self.__verify_data_type(records, wrapper_type)
100
+ return self.inst_man.add_existing_records_of_type(list(records), wrapper_type)
101
+ return self.inst_man.add_existing_records(list(records))
94
102
 
95
- def query_models(self, wrapper_type: type[WrappedType], field: FieldIdentifier, value_list: Iterable[FieldValue],
96
- page_limit: int | None = None, page_size: int | None = None) -> list[WrappedType]:
103
+ def query_models(self, wrapper_type: type[WrappedType] | str, field: FieldIdentifier,
104
+ value_list: Iterable[FieldValue], page_limit: int | None = None, page_size: int | None = None) \
105
+ -> list[WrappedType] | list[PyRecordModel]:
97
106
  """
98
107
  Shorthand for using the data record manager to query for a list of data records by field value
99
108
  and then converting the results into a list of record models.
100
109
 
101
- :param wrapper_type: The record model wrapper to use.
110
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
102
111
  :param field: The field to query on.
103
112
  :param value_list: The values of the field to query on.
104
113
  :param page_limit: The maximum number of pages to query. If None, exhausts all possible pages. This parameter
105
114
  only functions if you set a page size or the platform enforces a page size.
106
115
  :param page_size: The size of the pages to query. If None, the page size may be limited by the platform.
107
- :return: The record models for the queried records.
116
+ :return: The record models for the queried records. If a data type name was used instead of a model wrapper,
117
+ then the returned records will be PyRecordModels instead of WrappedRecordModels.
108
118
  """
109
119
  criteria: DataRecordPojoPageCriteria | None = None
110
120
  if page_size is not None:
111
121
  criteria = DataRecordPojoPageCriteria(page_size=page_size)
112
122
  return self.query_models_with_criteria(wrapper_type, field, value_list, criteria, page_limit)[0]
113
123
 
114
- def query_and_map_models(self, wrapper_type: type[WrappedType], field: FieldIdentifier,
124
+ def query_and_map_models(self, wrapper_type: type[WrappedType] | str, field: FieldIdentifier,
115
125
  value_list: Iterable[FieldValue], page_limit: int | None = None,
116
126
  page_size: int | None = None, *, mapping_field: FieldIdentifier | None = None) \
117
- -> dict[FieldValue, list[WrappedType]]:
127
+ -> dict[FieldValue, list[WrappedType] | list[PyRecordModel]]:
118
128
  """
119
129
  Shorthand for using query_models to search for records given values on a specific field and then using
120
130
  map_by_field to turn the returned list into a dictionary mapping field values to records.
121
131
 
122
- :param wrapper_type: The record model wrapper to use.
132
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
123
133
  :param field: The field to query and map on.
124
134
  :param value_list: The values of the field to query on.
125
135
  :param page_limit: The maximum number of pages to query. If None, exhausts all possible pages. This parameter
@@ -127,22 +137,24 @@ class RecordHandler:
127
137
  :param page_size: The size of the pages to query. If None, the page size may be limited by the platform.
128
138
  :param mapping_field: If provided, use this field to map against instead of the field that was queried on.
129
139
  :return: The record models for the queried records mapped by field values to the records with that value.
140
+ If a data type name was used instead of a model wrapper, then the returned records will be PyRecordModels
141
+ instead of WrappedRecordModels.
130
142
  """
131
143
  if mapping_field is None:
132
144
  mapping_field = field
133
145
  return self.map_by_field(self.query_models(wrapper_type, field, value_list, page_limit, page_size),
134
146
  mapping_field)
135
147
 
136
- def query_and_unique_map_models(self, wrapper_type: type[WrappedType], field: FieldIdentifier,
148
+ def query_and_unique_map_models(self, wrapper_type: type[WrappedType] | str, field: FieldIdentifier,
137
149
  value_list: Iterable[FieldValue], page_limit: int | None = None,
138
150
  page_size: int | None = None, *, mapping_field: FieldIdentifier | None = None) \
139
- -> dict[FieldValue, WrappedType]:
151
+ -> dict[FieldValue, WrappedType | PyRecordModel]:
140
152
  """
141
153
  Shorthand for using query_models to search for records given values on a specific field and then using
142
154
  map_by_unique_field to turn the returned list into a dictionary mapping field values to records.
143
155
  If any two records share the same field value, throws an exception.
144
156
 
145
- :param wrapper_type: The record model wrapper to use.
157
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
146
158
  :param field: The field to query and map on.
147
159
  :param value_list: The values of the field to query on.
148
160
  :param page_limit: The maximum number of pages to query. If None, exhausts all possible pages. This parameter
@@ -150,134 +162,150 @@ class RecordHandler:
150
162
  :param page_size: The size of the pages to query. If None, the page size may be limited by the platform.
151
163
  :param mapping_field: If provided, use this field to map against instead of the field that was queried on.
152
164
  :return: The record models for the queried records mapped by field values to the record with that value.
165
+ If a data type name was used instead of a model wrapper, then the returned records will be PyRecordModels
166
+ instead of WrappedRecordModels.
153
167
  """
154
168
  if mapping_field is None:
155
169
  mapping_field = field
156
170
  return self.map_by_unique_field(self.query_models(wrapper_type, field, value_list, page_limit, page_size),
157
171
  mapping_field)
158
172
 
159
- def query_models_with_criteria(self, wrapper_type: type[WrappedType], field: FieldIdentifier,
173
+ def query_models_with_criteria(self, wrapper_type: type[WrappedType] | str, field: FieldIdentifier,
160
174
  value_list: Iterable[FieldValue],
161
175
  paging_criteria: DataRecordPojoPageCriteria | None = None,
162
176
  page_limit: int | None = None) \
163
- -> tuple[list[WrappedType], DataRecordPojoPageCriteria]:
177
+ -> tuple[list[WrappedType] | list[PyRecordModel], DataRecordPojoPageCriteria]:
164
178
  """
165
179
  Shorthand for using the data record manager to query for a list of data records by field value
166
180
  and then converting the results into a list of record models.
167
181
 
168
- :param wrapper_type: The record model wrapper to use.
182
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
169
183
  :param field: The field to query on.
170
184
  :param value_list: The values of the field to query on.
171
185
  :param paging_criteria: The paging criteria to start the query with.
172
186
  :param page_limit: The maximum number of pages to query from the starting criteria. If None, exhausts all
173
187
  possible pages. This parameter only functions if you set a page size in the paging criteria or the platform
174
188
  enforces a page size.
175
- :return: The record models for the queried records and the final paging criteria.
189
+ :return: The record models for the queried records and the final paging criteria. If a data type name was used
190
+ instead of a model wrapper, then the returned records will be PyRecordModels instead of WrappedRecordModels.
176
191
  """
177
- dt: str = wrapper_type.get_wrapper_data_type_name()
192
+ dt: str = AliasUtil.to_data_type_name(wrapper_type)
193
+ if isinstance(wrapper_type, str):
194
+ wrapper_type = None
178
195
  field: str = AliasUtil.to_data_field_name(field)
179
196
  pager = QueryDataRecordsAutoPager(dt, field, list(value_list), self.user, paging_criteria)
180
197
  pager.max_page = page_limit
181
198
  return self.wrap_models(pager.get_all_at_once(), wrapper_type), pager.next_page_criteria
182
199
 
183
- def query_models_by_id(self, wrapper_type: type[WrappedType], ids: Iterable[int],
184
- page_limit: int | None = None, page_size: int | None = None) -> list[WrappedType]:
200
+ def query_models_by_id(self, wrapper_type: type[WrappedType] | str, ids: Iterable[int],
201
+ page_limit: int | None = None, page_size: int | None = None) \
202
+ -> list[WrappedType] | list[PyRecordModel]:
185
203
  """
186
204
  Shorthand for using the data record manager to query for a list of data records by record ID
187
205
  and then converting the results into a list of record models.
188
206
 
189
- :param wrapper_type: The record model wrapper to use.
207
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
190
208
  :param ids: The list of record IDs to query.
191
209
  :param page_limit: The maximum number of pages to query. If None, exhausts all possible pages. This parameter
192
210
  only functions if you set a page size or the platform enforces a page size.
193
211
  :param page_size: The size of the pages to query. If None, the page size may be limited by the platform.
194
- :return: The record models for the queried records.
212
+ :return: The record models for the queried records. If a data type name was used instead of a model wrapper,
213
+ then the returned records will be PyRecordModels instead of WrappedRecordModels.
195
214
  """
196
215
  criteria: DataRecordPojoPageCriteria | None = None
197
216
  if page_size is not None:
198
217
  criteria = DataRecordPojoPageCriteria(page_size=page_size)
199
218
  return self.query_models_by_id_with_criteria(wrapper_type, ids, criteria, page_limit)[0]
200
219
 
201
- def query_models_by_id_with_criteria(self, wrapper_type: type[WrappedType], ids: Iterable[int],
220
+ def query_models_by_id_with_criteria(self, wrapper_type: type[WrappedType] | str, ids: Iterable[int],
202
221
  paging_criteria: DataRecordPojoPageCriteria | None = None,
203
222
  page_limit: int | None = None) \
204
- -> tuple[list[WrappedType], DataRecordPojoPageCriteria]:
223
+ -> tuple[list[WrappedType] | list[PyRecordModel], DataRecordPojoPageCriteria]:
205
224
  """
206
225
  Shorthand for using the data record manager to query for a list of data records by record ID
207
226
  and then converting the results into a list of record models.
208
227
 
209
- :param wrapper_type: The record model wrapper to use.
228
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
210
229
  :param ids: The list of record IDs to query.
211
230
  :param paging_criteria: The paging criteria to start the query with.
212
231
  :param page_limit: The maximum number of pages to query from the starting criteria. If None, exhausts all
213
232
  possible pages. This parameter only functions if you set a page size in the paging criteria or the platform
214
233
  enforces a page size.
215
- :return: The record models for the queried records and the final paging criteria.
234
+ :return: The record models for the queried records and the final paging criteria. If a data type name was used
235
+ instead of a model wrapper, then the returned records will be PyRecordModels instead of WrappedRecordModels.
216
236
  """
217
- dt: str = wrapper_type.get_wrapper_data_type_name()
237
+ dt: str = AliasUtil.to_data_type_name(wrapper_type)
238
+ if isinstance(wrapper_type, str):
239
+ wrapper_type = None
218
240
  pager = QueryDataRecordByIdListAutoPager(dt, list(ids), self.user, paging_criteria)
219
241
  pager.max_page = page_limit
220
242
  return self.wrap_models(pager.get_all_at_once(), wrapper_type), pager.next_page_criteria
221
243
 
222
- def query_models_by_id_and_map(self, wrapper_type: type[WrappedType], ids: Iterable[int],
244
+ def query_models_by_id_and_map(self, wrapper_type: type[WrappedType] | str, ids: Iterable[int],
223
245
  page_limit: int | None = None, page_size: int | None = None) \
224
- -> dict[int, WrappedType]:
246
+ -> dict[int, WrappedType | PyRecordModel]:
225
247
  """
226
248
  Shorthand for using the data record manager to query for a list of data records by record ID
227
249
  and then converting the results into a dictionary of record ID to the record model for that ID.
228
250
 
229
- :param wrapper_type: The record model wrapper to use.
251
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
230
252
  :param ids: The list of record IDs to query.
231
253
  :param page_limit: The maximum number of pages to query. If None, exhausts all possible pages. This parameter
232
254
  only functions if you set a page size or the platform enforces a page size.
233
255
  :param page_size: The size of the pages to query. If None, the page size may be limited by the platform.
234
256
  :return: The record models for the queried records mapped in a dictionary by their record ID.
257
+ If a data type name was used instead of a model wrapper, then the returned records will be PyRecordModels
258
+ instead of WrappedRecordModels.
235
259
  """
236
260
  return {AliasUtil.to_record_id(x): x for x in self.query_models_by_id(wrapper_type, ids, page_limit, page_size)}
237
261
 
238
- def query_all_models(self, wrapper_type: type[WrappedType], page_limit: int | None = None,
239
- page_size: int | None = None) -> list[WrappedType]:
262
+ def query_all_models(self, wrapper_type: type[WrappedType] | str, page_limit: int | None = None,
263
+ page_size: int | None = None) -> list[WrappedType] | list[PyRecordModel]:
240
264
  """
241
265
  Shorthand for using the data record manager to query for all data records of a given type
242
266
  and then converting the results into a list of record models.
243
267
 
244
- :param wrapper_type: The record model wrapper to use.
268
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
245
269
  :param page_limit: The maximum number of pages to query. If None, exhausts all possible pages. This parameter
246
270
  only functions if you set a page size or the platform enforces a page size.
247
271
  :param page_size: The size of the pages to query. If None, the page size may be limited by the platform.
248
- :return: The record models for the queried records.
272
+ :return: The record models for the queried records. If a data type name was used instead of a model wrapper,
273
+ then the returned records will be PyRecordModels instead of WrappedRecordModels.
249
274
  """
250
275
  criteria: DataRecordPojoPageCriteria | None = None
251
276
  if page_size is not None:
252
277
  criteria = DataRecordPojoPageCriteria(page_size=page_size)
253
278
  return self.query_all_models_with_criteria(wrapper_type, criteria, page_limit)[0]
254
279
 
255
- def query_all_models_with_criteria(self, wrapper_type: type[WrappedType],
280
+ def query_all_models_with_criteria(self, wrapper_type: type[WrappedType] | str,
256
281
  paging_criteria: DataRecordPojoPageCriteria | None = None,
257
282
  page_limit: int | None = None) \
258
- -> tuple[list[WrappedType], DataRecordPojoPageCriteria]:
283
+ -> tuple[list[WrappedType] | list[PyRecordModel], DataRecordPojoPageCriteria]:
259
284
  """
260
285
  Shorthand for using the data record manager to query for all data records of a given type
261
286
  and then converting the results into a list of record models.
262
287
 
263
- :param wrapper_type: The record model wrapper to use.
288
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
264
289
  :param paging_criteria: The paging criteria to start the query with.
265
290
  :param page_limit: The maximum number of pages to query from the starting criteria. If None, exhausts all
266
291
  possible pages. This parameter only functions if you set a page size in the paging criteria or the platform
267
292
  enforces a page size.
268
- :return: The record models for the queried records and the final paging criteria.
293
+ :return: The record models for the queried records and the final paging criteria. If a data type name was used
294
+ instead of a model wrapper, then the returned records will be PyRecordModels instead of WrappedRecordModels.
269
295
  """
270
- dt: str = wrapper_type.get_wrapper_data_type_name()
296
+ dt: str = AliasUtil.to_data_type_name(wrapper_type)
297
+ if isinstance(wrapper_type, str):
298
+ wrapper_type = None
271
299
  pager = QueryAllRecordsOfTypeAutoPager(dt, self.user, paging_criteria)
272
300
  pager.max_page = page_limit
273
301
  return self.wrap_models(pager.get_all_at_once(), wrapper_type), pager.next_page_criteria
274
302
 
275
- def query_models_by_report(self, wrapper_type: type[WrappedType],
303
+ def query_models_by_report(self, wrapper_type: type[WrappedType] | str,
276
304
  report_name: str | RawReportTerm | CustomReportCriteria,
277
305
  filters: dict[FieldIdentifierKey, Iterable[FieldValue]] | None = None,
278
306
  page_limit: int | None = None,
279
307
  page_size: int | None = None,
280
- page_number: int | None = None) -> list[WrappedType]:
308
+ page_number: int | None = None) -> list[WrappedType] | list[PyRecordModel]:
281
309
  """
282
310
  Run a report and use the results of that report to query for and return the records in the report results.
283
311
  First runs the report, then runs a data record manager query on the results of the custom report.
@@ -287,7 +315,7 @@ class RecordHandler:
287
315
 
288
316
  Any given custom report criteria should only have columns from a single data type.
289
317
 
290
- :param wrapper_type: The record model wrapper to use.
318
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
291
319
  :param report_name: The name of a system report, or a raw report term for a quick report, or custom report
292
320
  criteria for a custom report.
293
321
  :param filters: If provided, filter the results of the report using the given mapping of headers to values to
@@ -299,7 +327,8 @@ class RecordHandler:
299
327
  :param page_number: The page number to start the search from, If None, starts on the first page.
300
328
  If the input report is a custom report criteria, uses the value from the criteria, unless this value is
301
329
  not None, in which case it overwrites the given report's value. Note that the number of the first page is 0.
302
- :return: The record models for the queried records that matched the given report.
330
+ :return: The record models for the queried records that matched the given report. If a data type name was used
331
+ instead of a model wrapper, then the returned records will be PyRecordModels instead of WrappedRecordModels.
303
332
  """
304
333
  warnings.warn("Deprecated in favor of the [System/Custom/Quick]ReportRecordAutoPager classes.", DeprecationWarning)
305
334
  if isinstance(report_name, str):
@@ -309,7 +338,7 @@ class RecordHandler:
309
338
  results: list[dict[str, FieldValue]] = CustomReportUtil.run_quick_report(self.user, report_name, filters,
310
339
  page_limit, page_size, page_number)
311
340
  elif isinstance(report_name, CustomReportCriteria):
312
- dt: str = wrapper_type.get_wrapper_data_type_name()
341
+ dt: str = AliasUtil.to_data_type_name(wrapper_type)
313
342
  # Ensure that the root data type is the one we're looking for.
314
343
  report_name.root_data_type = dt
315
344
  # Raise an exception if any column in the report doesn't match the given data type.
@@ -329,35 +358,38 @@ class RecordHandler:
329
358
  ids: list[int] = [row["RecordId"] for row in results]
330
359
  return self.query_models_by_id(wrapper_type, ids)
331
360
 
332
- def add_model(self, wrapper_type: type[WrappedType]) -> WrappedType:
361
+ def add_model(self, wrapper_type: type[WrappedType] | str) -> WrappedType | PyRecordModel:
333
362
  """
334
363
  Shorthand for using the instance manager to add a new record model of the given type.
335
364
 
336
- :param wrapper_type: The record model wrapper to use.
337
- :return: The newly added record model.
365
+ :param wrapper_type: The record model wrapper to use, or the data type name of the record.
366
+ :return: The newly added record model. If a data type name was used instead of a model wrapper, then the
367
+ returned record will be a PyRecordModel instead of a WrappedRecordModel.
338
368
  """
339
369
  return self.inst_man.add_new_record_of_type(wrapper_type)
340
370
 
341
- def add_models(self, wrapper_type: type[WrappedType], num: int) -> list[WrappedType]:
371
+ def add_models(self, wrapper_type: type[WrappedType] | str, num: int) -> list[WrappedType] | list[PyRecordModel]:
342
372
  """
343
373
  Shorthand for using the instance manager to add new record models of the given type.
344
374
 
345
- :param wrapper_type: The record model wrapper to use.
375
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
346
376
  :param num: The number of models to create.
347
- :return: The newly added record models.
377
+ :return: The newly added record models. If a data type name was used instead of a model wrapper, then the
378
+ returned records will be PyRecordModels instead of WrappedRecordModels.
348
379
  """
349
380
  return self.inst_man.add_new_records_of_type(num, wrapper_type)
350
381
 
351
- def add_models_with_data(self, wrapper_type: type[WrappedType], fields: list[FieldIdentifierMap]) \
352
- -> list[WrappedType]:
382
+ def add_models_with_data(self, wrapper_type: type[WrappedType] | str, fields: list[FieldIdentifierMap]) \
383
+ -> list[WrappedType] | list[PyRecordModel]:
353
384
  """
354
385
  Shorthand for using the instance manager to add new models of the given type, and then initializing all those
355
386
  models with the given fields.
356
387
 
357
- :param wrapper_type: The record model wrapper to use.
388
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
358
389
  :param fields: A list of field maps to initialize the record models with.
359
390
  :return: The newly added record models with the provided fields set. The records will be in the same order as
360
- the fields in the fields list.
391
+ the fields in the fields list. If a data type name was used instead of a model wrapper, then the returned
392
+ records will be PyRecordModels instead of WrappedRecordModels.
361
393
  """
362
394
  fields: list[FieldMap] = AliasUtil.to_data_field_names_list_dict(fields)
363
395
  models: list[WrappedType] = self.add_models(wrapper_type, len(fields))
@@ -365,8 +397,9 @@ class RecordHandler:
365
397
  model.set_field_values(field_list)
366
398
  return models
367
399
 
368
- def find_or_add_model(self, wrapper_type: type[WrappedType], primary_identifier: FieldIdentifier,
369
- id_value: FieldValue, secondary_identifiers: FieldIdentifierMap | None = None) -> WrappedType:
400
+ def find_or_add_model(self, wrapper_type: type[WrappedType] | str, primary_identifier: FieldIdentifier,
401
+ id_value: FieldValue, secondary_identifiers: FieldIdentifierMap | None = None) \
402
+ -> WrappedType | PyRecordModel:
370
403
  """
371
404
  Find a unique record that matches the given field values. If no such records exist, add a record model to the
372
405
  cache with the identifying fields set to the desired values. This record will be created in the system when
@@ -377,12 +410,14 @@ class RecordHandler:
377
410
 
378
411
  Makes a webservice call to query for the existing record.
379
412
 
380
- :param wrapper_type: The record model wrapper to use.
413
+ :param wrapper_type: The record model wrapper to use, or the data type name of the record.
381
414
  :param primary_identifier: The data field name of the field to search on.
382
415
  :param id_value: The value of the identifying field to search for.
383
416
  :param secondary_identifiers: Optional fields used to filter the records that are returned after searching on
384
417
  the primary identifier.
385
418
  :return: The record model with the identifying field value, either pulled from the system or newly created.
419
+ If a data type name was used instead of a model wrapper, then the returned record will be a PyRecordModel
420
+ instead of a WrappedRecordModel.
386
421
  """
387
422
  # PR-46335: Initialize the secondary identifiers parameter if None is provided to avoid an exception.
388
423
  # If no secondary identifiers were provided, use an empty dictionary.
@@ -403,22 +438,25 @@ class RecordHandler:
403
438
  secondary_identifiers.update({primary_identifier: id_value})
404
439
  return self.add_models_with_data(wrapper_type, [secondary_identifiers])[0]
405
440
 
406
- def create_models(self, wrapper_type: type[WrappedType], num: int) -> list[WrappedType]:
441
+ def create_models(self, wrapper_type: type[WrappedType] | str, num: int) -> list[WrappedType] | list[PyRecordModel]:
407
442
  """
408
443
  Shorthand for creating new records via the data record manager and then returning them as wrapped
409
444
  record models. Useful in cases where your record model needs to have a valid record ID.
410
445
 
411
446
  Makes a webservice call to create the data records.
412
447
 
413
- :param wrapper_type: The record model wrapper to use.
448
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
414
449
  :param num: The number of new records to create.
415
- :return: The newly created record models.
450
+ :return: The newly created record models. If a data type name was used instead of a model wrapper, then the
451
+ returned records will be PyRecordModels instead of WrappedRecordModels.
416
452
  """
417
- dt: str = wrapper_type.get_wrapper_data_type_name()
453
+ dt: str = AliasUtil.to_data_type_name(wrapper_type)
454
+ if isinstance(wrapper_type, str):
455
+ wrapper_type = None
418
456
  return self.wrap_models(self.dr_man.add_data_records(dt, num), wrapper_type)
419
457
 
420
- def create_models_with_data(self, wrapper_type: type[WrappedType], fields: list[FieldIdentifierMap]) \
421
- -> list[WrappedType]:
458
+ def create_models_with_data(self, wrapper_type: type[WrappedType] | str, fields: list[FieldIdentifierMap]) \
459
+ -> list[WrappedType] | list[PyRecordModel]:
422
460
  """
423
461
  Shorthand for creating new records via the data record manager with field data to initialize the records with
424
462
  and then returning them as wrapped record models. Useful in cases where your record model needs to have a valid
@@ -426,17 +464,20 @@ class RecordHandler:
426
464
 
427
465
  Makes a webservice call to create the data records.
428
466
 
429
- :param wrapper_type: The record model wrapper to use.
467
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
430
468
  :param fields: The field map list to initialize the new data records with.
431
- :return: The newly created record models.
469
+ :return: The newly created record models. If a data type name was used instead of a model wrapper, then the
470
+ returned records will be PyRecordModels instead of WrappedRecordModels.
432
471
  """
433
- dt: str = wrapper_type.get_wrapper_data_type_name()
472
+ dt: str = AliasUtil.to_data_type_name(wrapper_type)
473
+ if isinstance(wrapper_type, str):
474
+ wrapper_type = None
434
475
  fields: list[FieldMap] = AliasUtil.to_data_field_names_list_dict(fields)
435
476
  return self.wrap_models(self.dr_man.add_data_records_with_data(dt, fields), wrapper_type)
436
477
 
437
- def find_or_create_model(self, wrapper_type: type[WrappedType], primary_identifier: FieldIdentifier,
478
+ def find_or_create_model(self, wrapper_type: type[WrappedType] | str, primary_identifier: FieldIdentifier,
438
479
  id_value: FieldValue, secondary_identifiers: FieldIdentifierMap | None = None) \
439
- -> WrappedType:
480
+ -> WrappedType | PyRecordModel:
440
481
  """
441
482
  Find a unique record that matches the given field values. If no such records exist, create one with the
442
483
  identifying fields set to the desired values. If more than one record with the identifying values exists,
@@ -448,12 +489,14 @@ class RecordHandler:
448
489
  Makes a webservice call to query for the existing record. Makes an additional webservice call if the record
449
490
  needs to be created.
450
491
 
451
- :param wrapper_type: The record model wrapper to use.
492
+ :param wrapper_type: The record model wrapper to use, or the data type name of the record.
452
493
  :param primary_identifier: The data field name of the field to search on.
453
494
  :param id_value: The value of the identifying field to search for.
454
495
  :param secondary_identifiers: Optional fields used to filter the records that are returned after searching on
455
496
  the primary identifier.
456
497
  :return: The record model with the identifying field value, either pulled from the system or newly created.
498
+ If a data type name was used instead of a model wrapper, then the returned record will be a PyRecordModel
499
+ instead of a WrappedRecordModel.
457
500
  """
458
501
  # PR-46335: Initialize the secondary identifiers parameter if None is provided to avoid an exception.
459
502
  # If no secondary identifiers were provided, use an empty dictionary.
@@ -475,7 +518,8 @@ class RecordHandler:
475
518
  return self.create_models_with_data(wrapper_type, [secondary_identifiers])[0]
476
519
 
477
520
  @staticmethod
478
- def map_to_parent(models: Iterable[RecordModel], parent_type: type[WrappedType]) -> dict[RecordModel, WrappedType]:
521
+ def map_to_parent(models: Iterable[WrappedRecordModel], parent_type: type[WrappedType])\
522
+ -> dict[WrappedRecordModel, WrappedType]:
479
523
  """
480
524
  Map a list of record models to a single parent of a given type. The parents must already be loaded.
481
525
 
@@ -484,14 +528,14 @@ class RecordHandler:
484
528
  :return: A dict[ModelType, ParentType]. If an input model doesn't have a parent of the given parent type, then
485
529
  it will map to None.
486
530
  """
487
- return_dict: dict[RecordModel, WrappedType] = {}
531
+ return_dict: dict[WrappedRecordModel, WrappedType] = {}
488
532
  for model in models:
489
533
  return_dict[model] = model.get_parent_of_type(parent_type)
490
534
  return return_dict
491
535
 
492
536
  @staticmethod
493
- def map_to_parents(models: Iterable[RecordModel], parent_type: type[WrappedType]) \
494
- -> dict[RecordModel, list[WrappedType]]:
537
+ def map_to_parents(models: Iterable[WrappedRecordModel], parent_type: type[WrappedType]) \
538
+ -> dict[WrappedRecordModel, list[WrappedType]]:
495
539
  """
496
540
  Map a list of record models to a list parents of a given type. The parents must already be loaded.
497
541
 
@@ -500,14 +544,14 @@ class RecordHandler:
500
544
  :return: A dict[ModelType, list[ParentType]]. If an input model doesn't have a parent of the given parent type,
501
545
  then it will map to an empty list.
502
546
  """
503
- return_dict: dict[RecordModel, list[WrappedType]] = {}
547
+ return_dict: dict[WrappedRecordModel, list[WrappedType]] = {}
504
548
  for model in models:
505
549
  return_dict[model] = model.get_parents_of_type(parent_type)
506
550
  return return_dict
507
551
 
508
552
  @staticmethod
509
- def map_by_parent(models: Iterable[RecordModel], parent_type: type[WrappedType]) \
510
- -> dict[WrappedType, RecordModel]:
553
+ def map_by_parent(models: Iterable[WrappedRecordModel], parent_type: type[WrappedType]) \
554
+ -> dict[WrappedType, WrappedRecordModel]:
511
555
  """
512
556
  Take a list of record models and map them by their parent. Essentially an inversion of map_to_parent.
513
557
  If two records share the same parent, an exception will be thrown. The parents must already be loaded.
@@ -517,8 +561,8 @@ class RecordHandler:
517
561
  :return: A dict[ParentType, ModelType]. If an input model doesn't have a parent of the given parent type,
518
562
  then it will not be in the resulting dictionary.
519
563
  """
520
- to_parent: dict[RecordModel, WrappedType] = RecordHandler.map_to_parent(models, parent_type)
521
- by_parent: dict[WrappedType, RecordModel] = {}
564
+ to_parent: dict[WrappedRecordModel, WrappedType] = RecordHandler.map_to_parent(models, parent_type)
565
+ by_parent: dict[WrappedType, WrappedRecordModel] = {}
522
566
  for record, parent in to_parent.items():
523
567
  if parent is None:
524
568
  continue
@@ -529,8 +573,8 @@ class RecordHandler:
529
573
  return by_parent
530
574
 
531
575
  @staticmethod
532
- def map_by_parents(models: Iterable[RecordModel], parent_type: type[WrappedType]) \
533
- -> dict[WrappedType, list[RecordModel]]:
576
+ def map_by_parents(models: Iterable[WrappedRecordModel], parent_type: type[WrappedType]) \
577
+ -> dict[WrappedType, list[WrappedRecordModel]]:
534
578
  """
535
579
  Take a list of record models and map them by their parents. Essentially an inversion of map_to_parents. Input
536
580
  models that share a parent will end up in the same list. The parents must already be loaded.
@@ -540,15 +584,16 @@ class RecordHandler:
540
584
  :return: A dict[ParentType, list[ModelType]]. If an input model doesn't have a parent of the given parent type,
541
585
  then it will not be in the resulting dictionary.
542
586
  """
543
- to_parents: dict[RecordModel, list[WrappedType]] = RecordHandler.map_to_parents(models, parent_type)
544
- by_parents: dict[WrappedType, list[RecordModel]] = {}
587
+ to_parents: dict[WrappedRecordModel, list[WrappedType]] = RecordHandler.map_to_parents(models, parent_type)
588
+ by_parents: dict[WrappedType, list[WrappedRecordModel]] = {}
545
589
  for record, parents in to_parents.items():
546
590
  for parent in parents:
547
591
  by_parents.setdefault(parent, []).append(record)
548
592
  return by_parents
549
593
 
550
594
  @staticmethod
551
- def map_to_child(models: Iterable[RecordModel], child_type: type[WrappedType]) -> dict[RecordModel, WrappedType]:
595
+ def map_to_child(models: Iterable[WrappedRecordModel], child_type: type[WrappedType])\
596
+ -> dict[WrappedRecordModel, WrappedType]:
552
597
  """
553
598
  Map a list of record models to a single child of a given type. The children must already be loaded.
554
599
 
@@ -557,14 +602,14 @@ class RecordHandler:
557
602
  :return: A dict[ModelType, ChildType]. If an input model doesn't have a child of the given child type, then
558
603
  it will map to None.
559
604
  """
560
- return_dict: dict[RecordModel, WrappedType] = {}
605
+ return_dict: dict[WrappedRecordModel, WrappedType] = {}
561
606
  for model in models:
562
607
  return_dict[model] = model.get_child_of_type(child_type)
563
608
  return return_dict
564
609
 
565
610
  @staticmethod
566
- def map_to_children(models: Iterable[RecordModel], child_type: type[WrappedType]) \
567
- -> dict[RecordModel, list[WrappedType]]:
611
+ def map_to_children(models: Iterable[WrappedRecordModel], child_type: type[WrappedType]) \
612
+ -> dict[WrappedRecordModel, list[WrappedType]]:
568
613
  """
569
614
  Map a list of record models to a list children of a given type. The children must already be loaded.
570
615
 
@@ -573,14 +618,14 @@ class RecordHandler:
573
618
  :return: A dict[ModelType, list[ChildType]]. If an input model doesn't have children of the given child type,
574
619
  then it will map to an empty list.
575
620
  """
576
- return_dict: dict[RecordModel, list[WrappedType]] = {}
621
+ return_dict: dict[WrappedRecordModel, list[WrappedType]] = {}
577
622
  for model in models:
578
623
  return_dict[model] = model.get_children_of_type(child_type)
579
624
  return return_dict
580
625
 
581
626
  @staticmethod
582
- def map_by_child(models: Iterable[RecordModel], child_type: type[WrappedType]) \
583
- -> dict[WrappedType, RecordModel]:
627
+ def map_by_child(models: Iterable[WrappedRecordModel], child_type: type[WrappedType]) \
628
+ -> dict[WrappedType, WrappedRecordModel]:
584
629
  """
585
630
  Take a list of record models and map them by their children. Essentially an inversion of map_to_child.
586
631
  If two records share the same child, an exception will be thrown. The children must already be loaded.
@@ -590,8 +635,8 @@ class RecordHandler:
590
635
  :return: A dict[ChildType, ModelType]. If an input model doesn't have a child of the given child type,
591
636
  then it will not be in the resulting dictionary.
592
637
  """
593
- to_child: dict[RecordModel, WrappedType] = RecordHandler.map_to_child(models, child_type)
594
- by_child: dict[WrappedType, RecordModel] = {}
638
+ to_child: dict[WrappedRecordModel, WrappedType] = RecordHandler.map_to_child(models, child_type)
639
+ by_child: dict[WrappedType, WrappedRecordModel] = {}
595
640
  for record, child in to_child.items():
596
641
  if child is None:
597
642
  continue
@@ -602,8 +647,8 @@ class RecordHandler:
602
647
  return by_child
603
648
 
604
649
  @staticmethod
605
- def map_by_children(models: Iterable[RecordModel], child_type: type[WrappedType]) \
606
- -> dict[WrappedType, list[RecordModel]]:
650
+ def map_by_children(models: Iterable[WrappedRecordModel], child_type: type[WrappedType]) \
651
+ -> dict[WrappedType, list[WrappedRecordModel]]:
607
652
  """
608
653
  Take a list of record models and map them by their children. Essentially an inversion of map_to_children. Input
609
654
  models that share a child will end up in the same list. The children must already be loaded.
@@ -613,8 +658,8 @@ class RecordHandler:
613
658
  :return: A dict[ChildType, list[ModelType]]. If an input model doesn't have children of the given child type,
614
659
  then it will not be in the resulting dictionary.
615
660
  """
616
- to_children: dict[RecordModel, list[WrappedType]] = RecordHandler.map_to_children(models, child_type)
617
- by_children: dict[WrappedType, list[RecordModel]] = {}
661
+ to_children: dict[WrappedRecordModel, list[WrappedType]] = RecordHandler.map_to_children(models, child_type)
662
+ by_children: dict[WrappedType, list[WrappedRecordModel]] = {}
618
663
  for record, children in to_children.items():
619
664
  for child in children:
620
665
  by_children.setdefault(child, []).append(record)
@@ -1072,18 +1117,19 @@ class RecordHandler:
1072
1117
  ret_dict.update({model: self.inst_man.wrap(current[0], wrapper_type) if current else None})
1073
1118
  return ret_dict
1074
1119
 
1075
- def __find_model(self, wrapper_type: type[WrappedType], primary_identifier: str, id_value: FieldValue,
1076
- secondary_identifiers: FieldIdentifierMap | None = None) -> WrappedType | None:
1120
+ def __find_model(self, wrapper_type: type[WrappedType] | str, primary_identifier: str, id_value: FieldValue,
1121
+ secondary_identifiers: FieldIdentifierMap | None = None) -> WrappedType | PyRecordModel | None:
1077
1122
  """
1078
1123
  Find a record from the system that matches the given field values. The primary identifier and value is used
1079
1124
  to query for the record, then the secondary identifiers may be optionally provided to further filter the
1080
1125
  returned results. If no record is found with these filters, returns None.
1081
1126
  """
1082
1127
  # Query for all records that match the primary identifier.
1083
- results: list[WrappedType] = self.query_models(wrapper_type, primary_identifier, [id_value])
1128
+ results: list[WrappedType] | list[PyRecordModel] = self.query_models(wrapper_type, primary_identifier,
1129
+ [id_value])
1084
1130
 
1085
1131
  # Find the one record, if any, that matches the secondary identifiers.
1086
- unique_record: WrappedType | None = None
1132
+ unique_record: WrappedType | PyRecordModel | None = None
1087
1133
  for result in results:
1088
1134
  matches_all: bool = True
1089
1135
  for field, value in secondary_identifiers.items():
@@ -1093,7 +1139,7 @@ class RecordHandler:
1093
1139
  if matches_all:
1094
1140
  # If a previous record in the results already matched all identifiers, then throw an exception.
1095
1141
  if unique_record is not None:
1096
- raise SapioException(f"More than one record of type {wrapper_type.get_wrapper_data_type_name()} "
1142
+ raise SapioException(f"More than one record of type {AliasUtil.to_data_type_name(wrapper_type)} "
1097
1143
  f"encountered in system that matches all provided identifiers.")
1098
1144
  unique_record = result
1099
1145
  return unique_record