sapiopycommons 2025.3.10a455__py3-none-any.whl → 2025.3.21a458__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.

Files changed (29) hide show
  1. sapiopycommons/callbacks/callback_util.py +1220 -366
  2. sapiopycommons/chem/Molecules.py +0 -2
  3. sapiopycommons/customreport/auto_pagers.py +270 -0
  4. sapiopycommons/datatype/data_fields.py +1 -1
  5. sapiopycommons/eln/experiment_handler.py +2 -1
  6. sapiopycommons/eln/experiment_report_util.py +7 -7
  7. sapiopycommons/files/file_bridge.py +76 -0
  8. sapiopycommons/files/file_bridge_handler.py +325 -110
  9. sapiopycommons/files/file_data_handler.py +2 -2
  10. sapiopycommons/files/file_util.py +36 -11
  11. sapiopycommons/files/file_validator.py +6 -5
  12. sapiopycommons/files/file_writer.py +1 -1
  13. sapiopycommons/flowcyto/flow_cyto.py +1 -1
  14. sapiopycommons/general/accession_service.py +1 -1
  15. sapiopycommons/general/aliases.py +48 -28
  16. sapiopycommons/general/audit_log.py +2 -2
  17. sapiopycommons/general/custom_report_util.py +24 -1
  18. sapiopycommons/general/directive_util.py +86 -0
  19. sapiopycommons/general/exceptions.py +41 -2
  20. sapiopycommons/general/popup_util.py +2 -2
  21. sapiopycommons/multimodal/multimodal.py +1 -0
  22. sapiopycommons/processtracking/custom_workflow_handler.py +3 -3
  23. sapiopycommons/recordmodel/record_handler.py +5 -3
  24. sapiopycommons/samples/aliquot.py +48 -0
  25. sapiopycommons/webhook/webhook_handlers.py +445 -55
  26. {sapiopycommons-2025.3.10a455.dist-info → sapiopycommons-2025.3.21a458.dist-info}/METADATA +1 -1
  27. {sapiopycommons-2025.3.10a455.dist-info → sapiopycommons-2025.3.21a458.dist-info}/RECORD +29 -26
  28. {sapiopycommons-2025.3.10a455.dist-info → sapiopycommons-2025.3.21a458.dist-info}/WHEEL +0 -0
  29. {sapiopycommons-2025.3.10a455.dist-info → sapiopycommons-2025.3.21a458.dist-info}/licenses/LICENSE +0 -0
@@ -5,10 +5,10 @@ from sapiopylib.rest.pojo.CustomReport import CustomReportCriteria
5
5
  from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
6
6
  from sapiopylib.rest.utils.recordmodel.RecordModelWrapper import WrappedType
7
7
 
8
+ from sapiopycommons.customreport.auto_pagers import CustomReportDictAutoPager, CustomReportRecordAutoPager
8
9
  from sapiopycommons.customreport.custom_report_builder import CustomReportBuilder
9
10
  from sapiopycommons.datatype.data_fields import ProcessQueueItemFields, SystemFields, ProcessWorkflowTrackingFields
10
11
  from sapiopycommons.general.aliases import UserIdentifier, AliasUtil, SapioRecord
11
- from sapiopycommons.general.custom_report_util import CustomReportUtil
12
12
  from sapiopycommons.general.exceptions import SapioException
13
13
  from sapiopycommons.general.time_util import TimeUtil
14
14
  from sapiopycommons.recordmodel.record_handler import RecordHandler
@@ -185,7 +185,7 @@ class QueueItemHandler:
185
185
  :return: A list of every queue item in the system that matches the search criteria.
186
186
  """
187
187
  report = self.build_queue_item_report(criteria)
188
- return self.rec_handler.query_models_by_report(wrapper, report)
188
+ return CustomReportRecordAutoPager(self.user, report, wrapper).get_all_at_once()
189
189
 
190
190
  def get_records_from_item_report(self, wrapper: type[WrappedType],
191
191
  criteria: QueueItemReportCriteria = QueueItemReportCriteria()) -> list[WrappedType]:
@@ -203,7 +203,7 @@ class QueueItemHandler:
203
203
  criteria.not_data_type_names = None
204
204
  report = self.build_queue_item_report(criteria)
205
205
  record_ids: list[int] = [x[ProcessQueueItemFields.DATA_RECORD_ID__FIELD.field_name]
206
- for x in CustomReportUtil.run_custom_report(self.user, report)]
206
+ for x in CustomReportDictAutoPager(self.user, report)]
207
207
  return self.rec_handler.query_models_by_id(wrapper, record_ids)
208
208
 
209
209
  def get_queue_items_for_records(self, records: Iterable[SapioRecord], wrapper: type[WrappedType],
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import warnings
3
4
  from collections.abc import Iterable
4
5
  from weakref import WeakValueDictionary
5
6
 
@@ -232,7 +233,7 @@ class RecordHandler:
232
233
  :param page_size: The size of the pages to query. If None, the page size may be limited by the platform.
233
234
  :return: The record models for the queried records mapped in a dictionary by their record ID.
234
235
  """
235
- return {x.record_id: x for x in self.query_models_by_id(wrapper_type, ids, page_limit, page_size)}
236
+ return {AliasUtil.to_record_id(x): x for x in self.query_models_by_id(wrapper_type, ids, page_limit, page_size)}
236
237
 
237
238
  def query_all_models(self, wrapper_type: type[WrappedType], page_limit: int | None = None,
238
239
  page_size: int | None = None) -> list[WrappedType]:
@@ -300,6 +301,7 @@ class RecordHandler:
300
301
  not None, in which case it overwrites the given report's value. Note that the number of the first page is 0.
301
302
  :return: The record models for the queried records that matched the given report.
302
303
  """
304
+ warnings.warn("Deprecated in favor of the [System/Custom/Quick]ReportRecordAutoPager classes.", DeprecationWarning)
303
305
  if isinstance(report_name, str):
304
306
  results: list[dict[str, FieldValue]] = CustomReportUtil.run_system_report(self.user, report_name, filters,
305
307
  page_limit, page_size, page_number)
@@ -893,14 +895,14 @@ class RecordHandler:
893
895
 
894
896
  @staticmethod
895
897
  def values_to_field_maps(field_name: FieldIdentifier, values: Iterable[FieldValue],
896
- existing_fields: list[FieldIdentifier] | None = None) -> list[FieldMap]:
898
+ existing_fields: list[FieldMap] | None = None) -> list[FieldMap]:
897
899
  """
898
900
  Add a list of values for a specific field to a list of dictionaries pairing each value to that field name.
899
901
 
900
902
  :param field_name: The name of the field that the values are from.
901
903
  :param values: A list of field values.
902
904
  :param existing_fields: An optional existing fields map list to add the new values to. Values are added in the
903
- list in the same order that they appear. If no existing fields are provided, returns a new fields map list.
905
+ list in the same order that they appear. If no existing fields are provided, returns a new fields map list.
904
906
  :return: A fields map list that contains the given values mapped by the given field name.
905
907
  """
906
908
  # Update the existing fields map list if one is given.
@@ -0,0 +1,48 @@
1
+ from sapiopycommons.general.aliases import SapioRecord
2
+ from sapiopylib.rest.User import SapioUser
3
+ from sapiopylib.rest.utils.MultiMap import SetMultimap
4
+
5
+ # FR-47421 Added module
6
+
7
+ def create_aliquot_for_samples(parent_sample_to_num_aliquots_map: dict[SapioRecord, int], user: SapioUser) -> SetMultimap[SapioRecord, int]:
8
+ """"
9
+ Ask server to create aliquot records for provided sample parent records.
10
+ :param parent_sample_to_num_aliquots_map: The dictionary containing (parent sample record) -> (number of aliquots to create) mapping.
11
+ :return: The dictionary containing (parent sample record) -> (list of new aliquot record ids) mapping.
12
+ """
13
+ # throw error if at least one record id is blank
14
+ has_negative_record_ids = any([record.record_id < 0 for record in parent_sample_to_num_aliquots_map.keys()])
15
+ if has_negative_record_ids:
16
+ raise ValueError("At least one record requested for aliquot has a negative record ID. "
17
+ "You should have stored record model changes first.")
18
+ has_blank_record_ids = any([record.record_id is None for record in parent_sample_to_num_aliquots_map.keys()])
19
+ if has_blank_record_ids:
20
+ raise ValueError("At least one record requested for aliquot does not currently have a record ID.")
21
+ record_id_to_sapio_record_map = {record.record_id: record for record in parent_sample_to_num_aliquots_map.keys()}
22
+ parent_record_id_to_num_aliquots_map = {record.record_id: num_aliquots for record, num_aliquots in parent_sample_to_num_aliquots_map.items()}
23
+ aliquot_result: SetMultimap[int, int] = create_aliquot_for_samples_record_ids(parent_record_id_to_num_aliquots_map, user)
24
+ ret: SetMultimap[SapioRecord, int] = SetMultimap()
25
+ for parent_record_id in aliquot_result.keys():
26
+ parent_record = record_id_to_sapio_record_map[parent_record_id]
27
+ for aliquot_record_id in aliquot_result.get(parent_record_id):
28
+ ret.put(parent_record, aliquot_record_id)
29
+ return ret
30
+
31
+
32
+ def create_aliquot_for_samples_record_ids(parent_record_id_to_num_aliquots_map: dict[int, int], user: SapioUser) -> SetMultimap[int, int]:
33
+ """
34
+ Ask the server to create aliquot records for the provided sample record IDs.
35
+ :param sample_record_id_list: The dictionary containing (parent sample record id) -> (number of aliquots to create) mapping.
36
+ :return: The dictionary containing (parent sample record id) -> (list of new aliquot record ids) mapping.
37
+ """
38
+ if not parent_record_id_to_num_aliquots_map:
39
+ return SetMultimap()
40
+ endpoint_path = 'sample/aliquot'
41
+ response = user.plugin_put(endpoint_path, payload=parent_record_id_to_num_aliquots_map)
42
+ user.raise_for_status(response)
43
+ response_map: dict[int, list[int]] = response.json()
44
+ ret: SetMultimap[int, int] = SetMultimap()
45
+ for parent_record_id, aliquot_record_ids in response_map.items():
46
+ for aliquot_record_id in aliquot_record_ids:
47
+ ret.put(int(parent_record_id), int(aliquot_record_id))
48
+ return ret