sapiopycommons 2025.2.25a449__py3-none-any.whl → 2025.3.6a451__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,29 +162,32 @@ 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
192
  dt: str = wrapper_type.get_wrapper_data_type_name()
178
193
  field: str = AliasUtil.to_data_field_name(field)
@@ -180,104 +195,111 @@ class RecordHandler:
180
195
  pager.max_page = page_limit
181
196
  return self.wrap_models(pager.get_all_at_once(), wrapper_type), pager.next_page_criteria
182
197
 
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]:
198
+ def query_models_by_id(self, wrapper_type: type[WrappedType] | str, ids: Iterable[int],
199
+ page_limit: int | None = None, page_size: int | None = None) \
200
+ -> list[WrappedType] | list[PyRecordModel]:
185
201
  """
186
202
  Shorthand for using the data record manager to query for a list of data records by record ID
187
203
  and then converting the results into a list of record models.
188
204
 
189
- :param wrapper_type: The record model wrapper to use.
205
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
190
206
  :param ids: The list of record IDs to query.
191
207
  :param page_limit: The maximum number of pages to query. If None, exhausts all possible pages. This parameter
192
208
  only functions if you set a page size or the platform enforces a page size.
193
209
  :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.
210
+ :return: The record models for the queried records. If a data type name was used instead of a model wrapper,
211
+ then the returned records will be PyRecordModels instead of WrappedRecordModels.
195
212
  """
196
213
  criteria: DataRecordPojoPageCriteria | None = None
197
214
  if page_size is not None:
198
215
  criteria = DataRecordPojoPageCriteria(page_size=page_size)
199
216
  return self.query_models_by_id_with_criteria(wrapper_type, ids, criteria, page_limit)[0]
200
217
 
201
- def query_models_by_id_with_criteria(self, wrapper_type: type[WrappedType], ids: Iterable[int],
218
+ def query_models_by_id_with_criteria(self, wrapper_type: type[WrappedType] | str, ids: Iterable[int],
202
219
  paging_criteria: DataRecordPojoPageCriteria | None = None,
203
220
  page_limit: int | None = None) \
204
- -> tuple[list[WrappedType], DataRecordPojoPageCriteria]:
221
+ -> tuple[list[WrappedType] | list[PyRecordModel], DataRecordPojoPageCriteria]:
205
222
  """
206
223
  Shorthand for using the data record manager to query for a list of data records by record ID
207
224
  and then converting the results into a list of record models.
208
225
 
209
- :param wrapper_type: The record model wrapper to use.
226
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
210
227
  :param ids: The list of record IDs to query.
211
228
  :param paging_criteria: The paging criteria to start the query with.
212
229
  :param page_limit: The maximum number of pages to query from the starting criteria. If None, exhausts all
213
230
  possible pages. This parameter only functions if you set a page size in the paging criteria or the platform
214
231
  enforces a page size.
215
- :return: The record models for the queried records and the final paging criteria.
232
+ :return: The record models for the queried records and the final paging criteria. If a data type name was used
233
+ instead of a model wrapper, then the returned records will be PyRecordModels instead of WrappedRecordModels.
216
234
  """
217
- dt: str = wrapper_type.get_wrapper_data_type_name()
235
+ dt: str = AliasUtil.to_data_type_name(wrapper_type)
218
236
  pager = QueryDataRecordByIdListAutoPager(dt, list(ids), self.user, paging_criteria)
219
237
  pager.max_page = page_limit
220
238
  return self.wrap_models(pager.get_all_at_once(), wrapper_type), pager.next_page_criteria
221
239
 
222
- def query_models_by_id_and_map(self, wrapper_type: type[WrappedType], ids: Iterable[int],
240
+ def query_models_by_id_and_map(self, wrapper_type: type[WrappedType] | str, ids: Iterable[int],
223
241
  page_limit: int | None = None, page_size: int | None = None) \
224
- -> dict[int, WrappedType]:
242
+ -> dict[int, WrappedType | PyRecordModel]:
225
243
  """
226
244
  Shorthand for using the data record manager to query for a list of data records by record ID
227
245
  and then converting the results into a dictionary of record ID to the record model for that ID.
228
246
 
229
- :param wrapper_type: The record model wrapper to use.
247
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
230
248
  :param ids: The list of record IDs to query.
231
249
  :param page_limit: The maximum number of pages to query. If None, exhausts all possible pages. This parameter
232
250
  only functions if you set a page size or the platform enforces a page size.
233
251
  :param page_size: The size of the pages to query. If None, the page size may be limited by the platform.
234
252
  :return: The record models for the queried records mapped in a dictionary by their record ID.
253
+ If a data type name was used instead of a model wrapper, then the returned records will be PyRecordModels
254
+ instead of WrappedRecordModels.
235
255
  """
236
256
  return {AliasUtil.to_record_id(x): x for x in self.query_models_by_id(wrapper_type, ids, page_limit, page_size)}
237
257
 
238
- def query_all_models(self, wrapper_type: type[WrappedType], page_limit: int | None = None,
239
- page_size: int | None = None) -> list[WrappedType]:
258
+ def query_all_models(self, wrapper_type: type[WrappedType] | str, page_limit: int | None = None,
259
+ page_size: int | None = None) -> list[WrappedType] | list[PyRecordModel]:
240
260
  """
241
261
  Shorthand for using the data record manager to query for all data records of a given type
242
262
  and then converting the results into a list of record models.
243
263
 
244
- :param wrapper_type: The record model wrapper to use.
264
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
245
265
  :param page_limit: The maximum number of pages to query. If None, exhausts all possible pages. This parameter
246
266
  only functions if you set a page size or the platform enforces a page size.
247
267
  :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.
268
+ :return: The record models for the queried records. If a data type name was used instead of a model wrapper,
269
+ then the returned records will be PyRecordModels instead of WrappedRecordModels.
249
270
  """
250
271
  criteria: DataRecordPojoPageCriteria | None = None
251
272
  if page_size is not None:
252
273
  criteria = DataRecordPojoPageCriteria(page_size=page_size)
253
274
  return self.query_all_models_with_criteria(wrapper_type, criteria, page_limit)[0]
254
275
 
255
- def query_all_models_with_criteria(self, wrapper_type: type[WrappedType],
276
+ def query_all_models_with_criteria(self, wrapper_type: type[WrappedType] | str,
256
277
  paging_criteria: DataRecordPojoPageCriteria | None = None,
257
278
  page_limit: int | None = None) \
258
- -> tuple[list[WrappedType], DataRecordPojoPageCriteria]:
279
+ -> tuple[list[WrappedType] | list[PyRecordModel], DataRecordPojoPageCriteria]:
259
280
  """
260
281
  Shorthand for using the data record manager to query for all data records of a given type
261
282
  and then converting the results into a list of record models.
262
283
 
263
- :param wrapper_type: The record model wrapper to use.
284
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
264
285
  :param paging_criteria: The paging criteria to start the query with.
265
286
  :param page_limit: The maximum number of pages to query from the starting criteria. If None, exhausts all
266
287
  possible pages. This parameter only functions if you set a page size in the paging criteria or the platform
267
288
  enforces a page size.
268
- :return: The record models for the queried records and the final paging criteria.
289
+ :return: The record models for the queried records and the final paging criteria. If a data type name was used
290
+ instead of a model wrapper, then the returned records will be PyRecordModels instead of WrappedRecordModels.
269
291
  """
270
292
  dt: str = wrapper_type.get_wrapper_data_type_name()
271
293
  pager = QueryAllRecordsOfTypeAutoPager(dt, self.user, paging_criteria)
272
294
  pager.max_page = page_limit
273
295
  return self.wrap_models(pager.get_all_at_once(), wrapper_type), pager.next_page_criteria
274
296
 
275
- def query_models_by_report(self, wrapper_type: type[WrappedType],
297
+ def query_models_by_report(self, wrapper_type: type[WrappedType] | str,
276
298
  report_name: str | RawReportTerm | CustomReportCriteria,
277
299
  filters: dict[FieldIdentifierKey, Iterable[FieldValue]] | None = None,
278
300
  page_limit: int | None = None,
279
301
  page_size: int | None = None,
280
- page_number: int | None = None) -> list[WrappedType]:
302
+ page_number: int | None = None) -> list[WrappedType] | list[PyRecordModel]:
281
303
  """
282
304
  Run a report and use the results of that report to query for and return the records in the report results.
283
305
  First runs the report, then runs a data record manager query on the results of the custom report.
@@ -287,7 +309,7 @@ class RecordHandler:
287
309
 
288
310
  Any given custom report criteria should only have columns from a single data type.
289
311
 
290
- :param wrapper_type: The record model wrapper to use.
312
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
291
313
  :param report_name: The name of a system report, or a raw report term for a quick report, or custom report
292
314
  criteria for a custom report.
293
315
  :param filters: If provided, filter the results of the report using the given mapping of headers to values to
@@ -299,7 +321,8 @@ class RecordHandler:
299
321
  :param page_number: The page number to start the search from, If None, starts on the first page.
300
322
  If the input report is a custom report criteria, uses the value from the criteria, unless this value is
301
323
  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.
324
+ :return: The record models for the queried records that matched the given report. If a data type name was used
325
+ instead of a model wrapper, then the returned records will be PyRecordModels instead of WrappedRecordModels.
303
326
  """
304
327
  warnings.warn("Deprecated in favor of the [System/Custom/Quick]ReportRecordAutoPager classes.", DeprecationWarning)
305
328
  if isinstance(report_name, str):
@@ -309,7 +332,7 @@ class RecordHandler:
309
332
  results: list[dict[str, FieldValue]] = CustomReportUtil.run_quick_report(self.user, report_name, filters,
310
333
  page_limit, page_size, page_number)
311
334
  elif isinstance(report_name, CustomReportCriteria):
312
- dt: str = wrapper_type.get_wrapper_data_type_name()
335
+ dt: str = AliasUtil.to_data_type_name(wrapper_type)
313
336
  # Ensure that the root data type is the one we're looking for.
314
337
  report_name.root_data_type = dt
315
338
  # Raise an exception if any column in the report doesn't match the given data type.
@@ -329,35 +352,38 @@ class RecordHandler:
329
352
  ids: list[int] = [row["RecordId"] for row in results]
330
353
  return self.query_models_by_id(wrapper_type, ids)
331
354
 
332
- def add_model(self, wrapper_type: type[WrappedType]) -> WrappedType:
355
+ def add_model(self, wrapper_type: type[WrappedType] | str) -> WrappedType | PyRecordModel:
333
356
  """
334
357
  Shorthand for using the instance manager to add a new record model of the given type.
335
358
 
336
- :param wrapper_type: The record model wrapper to use.
337
- :return: The newly added record model.
359
+ :param wrapper_type: The record model wrapper to use, or the data type name of the record.
360
+ :return: The newly added record model. If a data type name was used instead of a model wrapper, then the
361
+ returned record will be a PyRecordModel instead of a WrappedRecordModel.
338
362
  """
339
363
  return self.inst_man.add_new_record_of_type(wrapper_type)
340
364
 
341
- def add_models(self, wrapper_type: type[WrappedType], num: int) -> list[WrappedType]:
365
+ def add_models(self, wrapper_type: type[WrappedType] | str, num: int) -> list[WrappedType] | list[PyRecordModel]:
342
366
  """
343
367
  Shorthand for using the instance manager to add new record models of the given type.
344
368
 
345
- :param wrapper_type: The record model wrapper to use.
369
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
346
370
  :param num: The number of models to create.
347
- :return: The newly added record models.
371
+ :return: The newly added record models. If a data type name was used instead of a model wrapper, then the
372
+ returned records will be PyRecordModels instead of WrappedRecordModels.
348
373
  """
349
374
  return self.inst_man.add_new_records_of_type(num, wrapper_type)
350
375
 
351
- def add_models_with_data(self, wrapper_type: type[WrappedType], fields: list[FieldIdentifierMap]) \
352
- -> list[WrappedType]:
376
+ def add_models_with_data(self, wrapper_type: type[WrappedType] | str, fields: list[FieldIdentifierMap]) \
377
+ -> list[WrappedType] | list[PyRecordModel]:
353
378
  """
354
379
  Shorthand for using the instance manager to add new models of the given type, and then initializing all those
355
380
  models with the given fields.
356
381
 
357
- :param wrapper_type: The record model wrapper to use.
382
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
358
383
  :param fields: A list of field maps to initialize the record models with.
359
384
  :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.
385
+ the fields in the fields list. If a data type name was used instead of a model wrapper, then the returned
386
+ records will be PyRecordModels instead of WrappedRecordModels.
361
387
  """
362
388
  fields: list[FieldMap] = AliasUtil.to_data_field_names_list_dict(fields)
363
389
  models: list[WrappedType] = self.add_models(wrapper_type, len(fields))
@@ -365,8 +391,9 @@ class RecordHandler:
365
391
  model.set_field_values(field_list)
366
392
  return models
367
393
 
368
- def find_or_add_model(self, wrapper_type: type[WrappedType], primary_identifier: FieldIdentifier,
369
- id_value: FieldValue, secondary_identifiers: FieldIdentifierMap | None = None) -> WrappedType:
394
+ def find_or_add_model(self, wrapper_type: type[WrappedType] | str, primary_identifier: FieldIdentifier,
395
+ id_value: FieldValue, secondary_identifiers: FieldIdentifierMap | None = None) \
396
+ -> WrappedType | PyRecordModel:
370
397
  """
371
398
  Find a unique record that matches the given field values. If no such records exist, add a record model to the
372
399
  cache with the identifying fields set to the desired values. This record will be created in the system when
@@ -377,12 +404,14 @@ class RecordHandler:
377
404
 
378
405
  Makes a webservice call to query for the existing record.
379
406
 
380
- :param wrapper_type: The record model wrapper to use.
407
+ :param wrapper_type: The record model wrapper to use, or the data type name of the record.
381
408
  :param primary_identifier: The data field name of the field to search on.
382
409
  :param id_value: The value of the identifying field to search for.
383
410
  :param secondary_identifiers: Optional fields used to filter the records that are returned after searching on
384
411
  the primary identifier.
385
412
  :return: The record model with the identifying field value, either pulled from the system or newly created.
413
+ If a data type name was used instead of a model wrapper, then the returned record will be a PyRecordModel
414
+ instead of a WrappedRecordModel.
386
415
  """
387
416
  # PR-46335: Initialize the secondary identifiers parameter if None is provided to avoid an exception.
388
417
  # If no secondary identifiers were provided, use an empty dictionary.
@@ -403,22 +432,23 @@ class RecordHandler:
403
432
  secondary_identifiers.update({primary_identifier: id_value})
404
433
  return self.add_models_with_data(wrapper_type, [secondary_identifiers])[0]
405
434
 
406
- def create_models(self, wrapper_type: type[WrappedType], num: int) -> list[WrappedType]:
435
+ def create_models(self, wrapper_type: type[WrappedType] | str, num: int) -> list[WrappedType] | list[PyRecordModel]:
407
436
  """
408
437
  Shorthand for creating new records via the data record manager and then returning them as wrapped
409
438
  record models. Useful in cases where your record model needs to have a valid record ID.
410
439
 
411
440
  Makes a webservice call to create the data records.
412
441
 
413
- :param wrapper_type: The record model wrapper to use.
442
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
414
443
  :param num: The number of new records to create.
415
- :return: The newly created record models.
444
+ :return: The newly created record models. If a data type name was used instead of a model wrapper, then the
445
+ returned records will be PyRecordModels instead of WrappedRecordModels.
416
446
  """
417
447
  dt: str = wrapper_type.get_wrapper_data_type_name()
418
448
  return self.wrap_models(self.dr_man.add_data_records(dt, num), wrapper_type)
419
449
 
420
- def create_models_with_data(self, wrapper_type: type[WrappedType], fields: list[FieldIdentifierMap]) \
421
- -> list[WrappedType]:
450
+ def create_models_with_data(self, wrapper_type: type[WrappedType] | str, fields: list[FieldIdentifierMap]) \
451
+ -> list[WrappedType] | list[PyRecordModel]:
422
452
  """
423
453
  Shorthand for creating new records via the data record manager with field data to initialize the records with
424
454
  and then returning them as wrapped record models. Useful in cases where your record model needs to have a valid
@@ -426,17 +456,18 @@ class RecordHandler:
426
456
 
427
457
  Makes a webservice call to create the data records.
428
458
 
429
- :param wrapper_type: The record model wrapper to use.
459
+ :param wrapper_type: The record model wrapper to use, or the data type name of the records.
430
460
  :param fields: The field map list to initialize the new data records with.
431
- :return: The newly created record models.
461
+ :return: The newly created record models. If a data type name was used instead of a model wrapper, then the
462
+ returned records will be PyRecordModels instead of WrappedRecordModels.
432
463
  """
433
464
  dt: str = wrapper_type.get_wrapper_data_type_name()
434
465
  fields: list[FieldMap] = AliasUtil.to_data_field_names_list_dict(fields)
435
466
  return self.wrap_models(self.dr_man.add_data_records_with_data(dt, fields), wrapper_type)
436
467
 
437
- def find_or_create_model(self, wrapper_type: type[WrappedType], primary_identifier: FieldIdentifier,
468
+ def find_or_create_model(self, wrapper_type: type[WrappedType] | str, primary_identifier: FieldIdentifier,
438
469
  id_value: FieldValue, secondary_identifiers: FieldIdentifierMap | None = None) \
439
- -> WrappedType:
470
+ -> WrappedType | PyRecordModel:
440
471
  """
441
472
  Find a unique record that matches the given field values. If no such records exist, create one with the
442
473
  identifying fields set to the desired values. If more than one record with the identifying values exists,
@@ -448,12 +479,14 @@ class RecordHandler:
448
479
  Makes a webservice call to query for the existing record. Makes an additional webservice call if the record
449
480
  needs to be created.
450
481
 
451
- :param wrapper_type: The record model wrapper to use.
482
+ :param wrapper_type: The record model wrapper to use, or the data type name of the record.
452
483
  :param primary_identifier: The data field name of the field to search on.
453
484
  :param id_value: The value of the identifying field to search for.
454
485
  :param secondary_identifiers: Optional fields used to filter the records that are returned after searching on
455
486
  the primary identifier.
456
487
  :return: The record model with the identifying field value, either pulled from the system or newly created.
488
+ If a data type name was used instead of a model wrapper, then the returned record will be a PyRecordModel
489
+ instead of a WrappedRecordModel.
457
490
  """
458
491
  # PR-46335: Initialize the secondary identifiers parameter if None is provided to avoid an exception.
459
492
  # If no secondary identifiers were provided, use an empty dictionary.
@@ -475,7 +508,8 @@ class RecordHandler:
475
508
  return self.create_models_with_data(wrapper_type, [secondary_identifiers])[0]
476
509
 
477
510
  @staticmethod
478
- def map_to_parent(models: Iterable[RecordModel], parent_type: type[WrappedType]) -> dict[RecordModel, WrappedType]:
511
+ def map_to_parent(models: Iterable[WrappedRecordModel], parent_type: type[WrappedType])\
512
+ -> dict[WrappedRecordModel, WrappedType]:
479
513
  """
480
514
  Map a list of record models to a single parent of a given type. The parents must already be loaded.
481
515
 
@@ -484,14 +518,14 @@ class RecordHandler:
484
518
  :return: A dict[ModelType, ParentType]. If an input model doesn't have a parent of the given parent type, then
485
519
  it will map to None.
486
520
  """
487
- return_dict: dict[RecordModel, WrappedType] = {}
521
+ return_dict: dict[WrappedRecordModel, WrappedType] = {}
488
522
  for model in models:
489
523
  return_dict[model] = model.get_parent_of_type(parent_type)
490
524
  return return_dict
491
525
 
492
526
  @staticmethod
493
- def map_to_parents(models: Iterable[RecordModel], parent_type: type[WrappedType]) \
494
- -> dict[RecordModel, list[WrappedType]]:
527
+ def map_to_parents(models: Iterable[WrappedRecordModel], parent_type: type[WrappedType]) \
528
+ -> dict[WrappedRecordModel, list[WrappedType]]:
495
529
  """
496
530
  Map a list of record models to a list parents of a given type. The parents must already be loaded.
497
531
 
@@ -500,14 +534,14 @@ class RecordHandler:
500
534
  :return: A dict[ModelType, list[ParentType]]. If an input model doesn't have a parent of the given parent type,
501
535
  then it will map to an empty list.
502
536
  """
503
- return_dict: dict[RecordModel, list[WrappedType]] = {}
537
+ return_dict: dict[WrappedRecordModel, list[WrappedType]] = {}
504
538
  for model in models:
505
539
  return_dict[model] = model.get_parents_of_type(parent_type)
506
540
  return return_dict
507
541
 
508
542
  @staticmethod
509
- def map_by_parent(models: Iterable[RecordModel], parent_type: type[WrappedType]) \
510
- -> dict[WrappedType, RecordModel]:
543
+ def map_by_parent(models: Iterable[WrappedRecordModel], parent_type: type[WrappedType]) \
544
+ -> dict[WrappedType, WrappedRecordModel]:
511
545
  """
512
546
  Take a list of record models and map them by their parent. Essentially an inversion of map_to_parent.
513
547
  If two records share the same parent, an exception will be thrown. The parents must already be loaded.
@@ -517,8 +551,8 @@ class RecordHandler:
517
551
  :return: A dict[ParentType, ModelType]. If an input model doesn't have a parent of the given parent type,
518
552
  then it will not be in the resulting dictionary.
519
553
  """
520
- to_parent: dict[RecordModel, WrappedType] = RecordHandler.map_to_parent(models, parent_type)
521
- by_parent: dict[WrappedType, RecordModel] = {}
554
+ to_parent: dict[WrappedRecordModel, WrappedType] = RecordHandler.map_to_parent(models, parent_type)
555
+ by_parent: dict[WrappedType, WrappedRecordModel] = {}
522
556
  for record, parent in to_parent.items():
523
557
  if parent is None:
524
558
  continue
@@ -529,8 +563,8 @@ class RecordHandler:
529
563
  return by_parent
530
564
 
531
565
  @staticmethod
532
- def map_by_parents(models: Iterable[RecordModel], parent_type: type[WrappedType]) \
533
- -> dict[WrappedType, list[RecordModel]]:
566
+ def map_by_parents(models: Iterable[WrappedRecordModel], parent_type: type[WrappedType]) \
567
+ -> dict[WrappedType, list[WrappedRecordModel]]:
534
568
  """
535
569
  Take a list of record models and map them by their parents. Essentially an inversion of map_to_parents. Input
536
570
  models that share a parent will end up in the same list. The parents must already be loaded.
@@ -540,15 +574,16 @@ class RecordHandler:
540
574
  :return: A dict[ParentType, list[ModelType]]. If an input model doesn't have a parent of the given parent type,
541
575
  then it will not be in the resulting dictionary.
542
576
  """
543
- to_parents: dict[RecordModel, list[WrappedType]] = RecordHandler.map_to_parents(models, parent_type)
544
- by_parents: dict[WrappedType, list[RecordModel]] = {}
577
+ to_parents: dict[WrappedRecordModel, list[WrappedType]] = RecordHandler.map_to_parents(models, parent_type)
578
+ by_parents: dict[WrappedType, list[WrappedRecordModel]] = {}
545
579
  for record, parents in to_parents.items():
546
580
  for parent in parents:
547
581
  by_parents.setdefault(parent, []).append(record)
548
582
  return by_parents
549
583
 
550
584
  @staticmethod
551
- def map_to_child(models: Iterable[RecordModel], child_type: type[WrappedType]) -> dict[RecordModel, WrappedType]:
585
+ def map_to_child(models: Iterable[WrappedRecordModel], child_type: type[WrappedType])\
586
+ -> dict[WrappedRecordModel, WrappedType]:
552
587
  """
553
588
  Map a list of record models to a single child of a given type. The children must already be loaded.
554
589
 
@@ -557,14 +592,14 @@ class RecordHandler:
557
592
  :return: A dict[ModelType, ChildType]. If an input model doesn't have a child of the given child type, then
558
593
  it will map to None.
559
594
  """
560
- return_dict: dict[RecordModel, WrappedType] = {}
595
+ return_dict: dict[WrappedRecordModel, WrappedType] = {}
561
596
  for model in models:
562
597
  return_dict[model] = model.get_child_of_type(child_type)
563
598
  return return_dict
564
599
 
565
600
  @staticmethod
566
- def map_to_children(models: Iterable[RecordModel], child_type: type[WrappedType]) \
567
- -> dict[RecordModel, list[WrappedType]]:
601
+ def map_to_children(models: Iterable[WrappedRecordModel], child_type: type[WrappedType]) \
602
+ -> dict[WrappedRecordModel, list[WrappedType]]:
568
603
  """
569
604
  Map a list of record models to a list children of a given type. The children must already be loaded.
570
605
 
@@ -573,14 +608,14 @@ class RecordHandler:
573
608
  :return: A dict[ModelType, list[ChildType]]. If an input model doesn't have children of the given child type,
574
609
  then it will map to an empty list.
575
610
  """
576
- return_dict: dict[RecordModel, list[WrappedType]] = {}
611
+ return_dict: dict[WrappedRecordModel, list[WrappedType]] = {}
577
612
  for model in models:
578
613
  return_dict[model] = model.get_children_of_type(child_type)
579
614
  return return_dict
580
615
 
581
616
  @staticmethod
582
- def map_by_child(models: Iterable[RecordModel], child_type: type[WrappedType]) \
583
- -> dict[WrappedType, RecordModel]:
617
+ def map_by_child(models: Iterable[WrappedRecordModel], child_type: type[WrappedType]) \
618
+ -> dict[WrappedType, WrappedRecordModel]:
584
619
  """
585
620
  Take a list of record models and map them by their children. Essentially an inversion of map_to_child.
586
621
  If two records share the same child, an exception will be thrown. The children must already be loaded.
@@ -590,8 +625,8 @@ class RecordHandler:
590
625
  :return: A dict[ChildType, ModelType]. If an input model doesn't have a child of the given child type,
591
626
  then it will not be in the resulting dictionary.
592
627
  """
593
- to_child: dict[RecordModel, WrappedType] = RecordHandler.map_to_child(models, child_type)
594
- by_child: dict[WrappedType, RecordModel] = {}
628
+ to_child: dict[WrappedRecordModel, WrappedType] = RecordHandler.map_to_child(models, child_type)
629
+ by_child: dict[WrappedType, WrappedRecordModel] = {}
595
630
  for record, child in to_child.items():
596
631
  if child is None:
597
632
  continue
@@ -602,8 +637,8 @@ class RecordHandler:
602
637
  return by_child
603
638
 
604
639
  @staticmethod
605
- def map_by_children(models: Iterable[RecordModel], child_type: type[WrappedType]) \
606
- -> dict[WrappedType, list[RecordModel]]:
640
+ def map_by_children(models: Iterable[WrappedRecordModel], child_type: type[WrappedType]) \
641
+ -> dict[WrappedType, list[WrappedRecordModel]]:
607
642
  """
608
643
  Take a list of record models and map them by their children. Essentially an inversion of map_to_children. Input
609
644
  models that share a child will end up in the same list. The children must already be loaded.
@@ -613,8 +648,8 @@ class RecordHandler:
613
648
  :return: A dict[ChildType, list[ModelType]]. If an input model doesn't have children of the given child type,
614
649
  then it will not be in the resulting dictionary.
615
650
  """
616
- to_children: dict[RecordModel, list[WrappedType]] = RecordHandler.map_to_children(models, child_type)
617
- by_children: dict[WrappedType, list[RecordModel]] = {}
651
+ to_children: dict[WrappedRecordModel, list[WrappedType]] = RecordHandler.map_to_children(models, child_type)
652
+ by_children: dict[WrappedType, list[WrappedRecordModel]] = {}
618
653
  for record, children in to_children.items():
619
654
  for child in children:
620
655
  by_children.setdefault(child, []).append(record)
@@ -1072,18 +1107,19 @@ class RecordHandler:
1072
1107
  ret_dict.update({model: self.inst_man.wrap(current[0], wrapper_type) if current else None})
1073
1108
  return ret_dict
1074
1109
 
1075
- def __find_model(self, wrapper_type: type[WrappedType], primary_identifier: str, id_value: FieldValue,
1076
- secondary_identifiers: FieldIdentifierMap | None = None) -> WrappedType | None:
1110
+ def __find_model(self, wrapper_type: type[WrappedType] | str, primary_identifier: str, id_value: FieldValue,
1111
+ secondary_identifiers: FieldIdentifierMap | None = None) -> WrappedType | PyRecordModel | None:
1077
1112
  """
1078
1113
  Find a record from the system that matches the given field values. The primary identifier and value is used
1079
1114
  to query for the record, then the secondary identifiers may be optionally provided to further filter the
1080
1115
  returned results. If no record is found with these filters, returns None.
1081
1116
  """
1082
1117
  # Query for all records that match the primary identifier.
1083
- results: list[WrappedType] = self.query_models(wrapper_type, primary_identifier, [id_value])
1118
+ results: list[WrappedType] | list[PyRecordModel] = self.query_models(wrapper_type, primary_identifier,
1119
+ [id_value])
1084
1120
 
1085
1121
  # Find the one record, if any, that matches the secondary identifiers.
1086
- unique_record: WrappedType | None = None
1122
+ unique_record: WrappedType | PyRecordModel | None = None
1087
1123
  for result in results:
1088
1124
  matches_all: bool = True
1089
1125
  for field, value in secondary_identifiers.items():
@@ -1093,7 +1129,7 @@ class RecordHandler:
1093
1129
  if matches_all:
1094
1130
  # If a previous record in the results already matched all identifiers, then throw an exception.
1095
1131
  if unique_record is not None:
1096
- raise SapioException(f"More than one record of type {wrapper_type.get_wrapper_data_type_name()} "
1132
+ raise SapioException(f"More than one record of type {AliasUtil.to_data_type_name(wrapper_type)} "
1097
1133
  f"encountered in system that matches all provided identifiers.")
1098
1134
  unique_record = result
1099
1135
  return unique_record