sapiopycommons 2024.8.19a305__py3-none-any.whl → 2024.8.20a306__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.

@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import io
4
- from typing import Any
5
4
  from weakref import WeakValueDictionary
6
5
 
7
6
  from sapiopylib.rest.ClientCallbackService import ClientCallback
@@ -18,7 +17,6 @@ from sapiopylib.rest.pojo.webhook.ClientCallbackRequest import OptionDialogReque
18
17
  DataRecordDialogRequest, InputSelectionRequest, FilePromptRequest, MultiFilePromptRequest, \
19
18
  TempTableSelectionRequest, DisplayPopupRequest, PopupType
20
19
  from sapiopylib.rest.pojo.webhook.ClientCallbackResult import ESigningResponsePojo
21
- from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
22
20
  from sapiopylib.rest.pojo.webhook.WebhookEnums import FormAccessLevel, ScanToSelectCriteria, SearchType
23
21
  from sapiopylib.rest.utils.DataTypeCacheManager import DataTypeCacheManager
24
22
  from sapiopylib.rest.utils.FormBuilder import FormBuilder
@@ -26,7 +24,8 @@ from sapiopylib.rest.utils.recorddatasinks import InMemoryRecordDataSink
26
24
  from sapiopylib.rest.utils.recordmodel.RecordModelWrapper import WrappedType
27
25
 
28
26
  from sapiopycommons.files.file_util import FileUtil
29
- from sapiopycommons.general.aliases import FieldMap, SapioRecord, AliasUtil, RecordIdentifier
27
+ from sapiopycommons.general.aliases import FieldMap, SapioRecord, AliasUtil, RecordIdentifier, FieldValue, \
28
+ UserIdentifier
30
29
  from sapiopycommons.general.custom_report_util import CustomReportUtil
31
30
  from sapiopycommons.general.exceptions import SapioUserCancelledException, SapioException, SapioUserErrorException
32
31
  from sapiopycommons.recordmodel.record_handler import RecordHandler
@@ -42,11 +41,11 @@ class CallbackUtil:
42
41
  __instances: WeakValueDictionary[SapioUser, CallbackUtil] = WeakValueDictionary()
43
42
  __initialized: bool
44
43
 
45
- def __new__(cls, context: SapioWebhookContext | SapioUser):
44
+ def __new__(cls, context: UserIdentifier):
46
45
  """
47
46
  :param context: The current webhook context or a user object to send requests from.
48
47
  """
49
- user = context if isinstance(context, SapioUser) else context.user
48
+ user = AliasUtil.to_sapio_user(context)
50
49
  obj = cls.__instances.get(user)
51
50
  if not obj:
52
51
  obj = object.__new__(cls)
@@ -54,7 +53,7 @@ class CallbackUtil:
54
53
  cls.__instances[user] = obj
55
54
  return obj
56
55
 
57
- def __init__(self, context: SapioWebhookContext | SapioUser):
56
+ def __init__(self, context: UserIdentifier):
58
57
  """
59
58
  :param context: The current webhook context or a user object to send requests from.
60
59
  """
@@ -62,7 +61,7 @@ class CallbackUtil:
62
61
  return
63
62
  self.__initialized = True
64
63
 
65
- self.user = context if isinstance(context, SapioUser) else context.user
64
+ self.user = AliasUtil.to_sapio_user(context)
66
65
  self.callback = DataMgmtServer.get_client_callback(self.user)
67
66
  self.dt_cache = DataTypeCacheManager(self.user)
68
67
  self.width_pixels = None
@@ -281,7 +280,7 @@ class CallbackUtil:
281
280
  modifier = FieldModifier(visible=True, editable=editable)
282
281
 
283
282
  # Build the form using only those fields that are desired.
284
- values: dict[str, Any] = {}
283
+ values: dict[str, FieldValue] = {}
285
284
  builder = FormBuilder(data_type, type_def.display_name, type_def.plural_display_name)
286
285
  for field_name in fields:
287
286
  field_def = field_defs.get(field_name)
@@ -303,7 +302,7 @@ class CallbackUtil:
303
302
  raise SapioUserCancelledException()
304
303
  return response
305
304
 
306
- def input_dialog(self, title: str, msg: str, field: AbstractVeloxFieldDefinition) -> Any:
305
+ def input_dialog(self, title: str, msg: str, field: AbstractVeloxFieldDefinition) -> FieldValue:
307
306
  """
308
307
  Create an input dialog where the user must input data for a singular field.
309
308
 
@@ -314,7 +313,7 @@ class CallbackUtil:
314
313
  """
315
314
  request = InputDialogCriteria(title, msg, field,
316
315
  width_in_pixels=self.width_pixels, width_percentage=self.width_percent)
317
- response: Any | None = self.callback.show_input_dialog(request)
316
+ response: FieldValue | None = self.callback.show_input_dialog(request)
318
317
  if response is None:
319
318
  raise SapioUserCancelledException()
320
319
  return response
@@ -606,10 +605,10 @@ class CallbackUtil:
606
605
  field_names.append(name)
607
606
 
608
607
  # Get the values for each row.
609
- values: list[dict[str, Any]] = []
608
+ values: list[dict[str, FieldValue]] = []
610
609
  for row in row_contents:
611
610
  # The final values for this row:
612
- row_values: dict[str, Any] = {}
611
+ row_values: dict[str, FieldValue] = {}
613
612
 
614
613
  # Map the records for this row by their data type. If a field map is provided, its data type is Default.
615
614
  row_records: dict[str, SapioRecord | FieldMap] = {}
@@ -18,7 +18,7 @@ AND = CompositeTermOperation.AND_OPERATOR
18
18
  OR = CompositeTermOperation.OR_OPERATOR
19
19
 
20
20
  # Forms that field term values can take.
21
- TermValue = str | int | float | bool | Iterable
21
+ TermValue = str | int | float | bool | Iterable | None
22
22
 
23
23
 
24
24
  class TermBuilder:
@@ -281,9 +281,12 @@ class TermBuilder:
281
281
  """
282
282
  # If the given value is already a string, then nothing needs to be done with it.
283
283
  if not isinstance(value, str):
284
+ # If the given value is None, then use an empty string for the search instead.
285
+ if value is None:
286
+ value = ""
284
287
  # If the given value is an iterable object, then the return value is the contents of that iterable
285
288
  # in a comma separated list surrounded by curly braces.
286
- if isinstance(value, Iterable):
289
+ elif isinstance(value, Iterable):
287
290
  # When converting a list of values to a string, values in the list which are already strings should be
288
291
  # put in quotation marks so that strings that contain commas do not get split up. All other value
289
292
  # types can be simply converted to a string, though.
@@ -1,11 +1,9 @@
1
1
  import io
2
2
 
3
3
  from sapiopylib.rest.DataMgmtService import DataMgmtServer
4
- from sapiopylib.rest.User import SapioUser
5
- from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
6
4
  from sapiopylib.rest.utils.recordmodel.RecordModelWrapper import WrappedType
7
5
 
8
- from sapiopycommons.general.aliases import AliasUtil, SapioRecord
6
+ from sapiopycommons.general.aliases import AliasUtil, SapioRecord, UserIdentifier
9
7
  from sapiopycommons.general.exceptions import SapioException
10
8
  from sapiopycommons.recordmodel.record_handler import RecordHandler
11
9
 
@@ -13,7 +11,7 @@ from sapiopycommons.recordmodel.record_handler import RecordHandler
13
11
  # FR-46064 - Initial port of PyWebhookUtils to sapiopycommons.
14
12
  class AttachmentUtil:
15
13
  @staticmethod
16
- def get_attachment_bytes(context: SapioWebhookContext | SapioUser, attachment: SapioRecord) -> bytes:
14
+ def get_attachment_bytes(context: UserIdentifier, attachment: SapioRecord) -> bytes:
17
15
  """
18
16
  Get the data bytes for the given attachment record. Makes a webservice call to retrieve the data.
19
17
 
@@ -22,10 +20,7 @@ class AttachmentUtil:
22
20
  :return: The bytes for the attachment's file data.
23
21
  """
24
22
  attachment = AliasUtil.to_data_record(attachment)
25
- if isinstance(context, SapioWebhookContext):
26
- dr_man = context.data_record_manager
27
- else:
28
- dr_man = DataMgmtServer.get_data_record_manager(context)
23
+ dr_man = DataMgmtServer.get_data_record_manager(AliasUtil.to_sapio_user(context))
29
24
  with io.BytesIO() as data_sink:
30
25
  def consume_data(chunk: bytes):
31
26
  data_sink.write(chunk)
@@ -36,7 +31,7 @@ class AttachmentUtil:
36
31
  return file_bytes
37
32
 
38
33
  @staticmethod
39
- def set_attachment_bytes(context: SapioWebhookContext | SapioUser, attachment: SapioRecord,
34
+ def set_attachment_bytes(context: UserIdentifier, attachment: SapioRecord,
40
35
  file_name: str, file_bytes: bytes) -> None:
41
36
  """
42
37
  Set the attachment data for a given attachment record. Makes a webservice call to set the data.
@@ -50,15 +45,12 @@ class AttachmentUtil:
50
45
  raise SapioException("Provided record cannot have its attachment data set, as it does not exist in the "
51
46
  "system yet.")
52
47
  attachment = AliasUtil.to_data_record(attachment)
53
- if isinstance(context, SapioWebhookContext):
54
- dr_man = context.data_record_manager
55
- else:
56
- dr_man = DataMgmtServer.get_data_record_manager(context)
48
+ dr_man = DataMgmtServer.get_data_record_manager(AliasUtil.to_sapio_user(context))
57
49
  with io.BytesIO(file_bytes) as stream:
58
50
  dr_man.set_attachment_data(attachment, file_name, stream)
59
51
 
60
52
  @staticmethod
61
- def create_attachment(context: SapioWebhookContext | SapioUser, file_name: str, file_bytes: bytes,
53
+ def create_attachment(context: UserIdentifier, file_name: str, file_bytes: bytes,
62
54
  wrapper_type: type[WrappedType]) -> WrappedType:
63
55
  """
64
56
  Create an attachment data type and initialize its attachment bytes at the same time.
@@ -23,7 +23,8 @@ from sapiopylib.rest.utils.recordmodel.RecordModelManager import RecordModelInst
23
23
  from sapiopylib.rest.utils.recordmodel.RecordModelWrapper import WrappedType
24
24
  from sapiopylib.rest.utils.recordmodel.properties import Child
25
25
 
26
- from sapiopycommons.general.aliases import AliasUtil, SapioRecord, ExperimentIdentifier, RecordModel
26
+ from sapiopycommons.general.aliases import AliasUtil, SapioRecord, ExperimentIdentifier, UserIdentifier, \
27
+ DataTypeIdentifier, RecordModel
27
28
  from sapiopycommons.general.exceptions import SapioException
28
29
 
29
30
  Step = str | ElnEntryStep
@@ -87,8 +88,7 @@ class ExperimentHandler:
87
88
  __instances: WeakValueDictionary[str, ExperimentHandler] = WeakValueDictionary()
88
89
  __initialized: bool
89
90
 
90
- def __new__(cls, context: SapioWebhookContext | SapioUser,
91
- experiment: ExperimentIdentifier | SapioRecord | None = None):
91
+ def __new__(cls, context: UserIdentifier, experiment: ExperimentIdentifier | SapioRecord | None = None):
92
92
  """
93
93
  :param context: The current webhook context or a user object to send requests from.
94
94
  :param experiment: If an experiment is provided that is separate from the experiment that is in the context,
@@ -106,8 +106,7 @@ class ExperimentHandler:
106
106
  cls.__instances[key] = obj
107
107
  return obj
108
108
 
109
- def __init__(self, context: SapioWebhookContext | SapioUser,
110
- experiment: ExperimentIdentifier | SapioRecord | None = None):
109
+ def __init__(self, context: UserIdentifier, experiment: ExperimentIdentifier | SapioRecord | None = None):
111
110
  """
112
111
  Initialization will throw an exception if there is no ELN Experiment in the provided context and no experiment
113
112
  is provided.
@@ -146,8 +145,7 @@ class ExperimentHandler:
146
145
  self.__steps.update({entry.entry_name: ElnEntryStep(self.__protocol, entry)})
147
146
 
148
147
  @staticmethod
149
- def __parse_params(context: SapioWebhookContext | SapioUser,
150
- experiment: ExperimentIdentifier | SapioRecord | None = None) \
148
+ def __parse_params(context: UserIdentifier, experiment: ExperimentIdentifier | SapioRecord | None = None) \
151
149
  -> tuple[SapioUser, SapioWebhookContext | None, ElnExperiment]:
152
150
  if isinstance(context, SapioWebhookContext):
153
151
  user = context.user
@@ -536,7 +534,7 @@ class ExperimentHandler:
536
534
  ret_list.append(step)
537
535
  return ret_list
538
536
 
539
- def get_all_steps(self, data_type: str | type[WrappedType] | None = None) -> list[ElnEntryStep]:
537
+ def get_all_steps(self, data_type: DataTypeIdentifier | None = None) -> list[ElnEntryStep]:
540
538
  """
541
539
  Get a list of every entry in the experiment. Optionally filter the returned entries by a data type.
542
540
 
@@ -552,8 +550,7 @@ class ExperimentHandler:
552
550
  all_steps: list[ElnEntryStep] = self.__protocol.get_sorted_step_list()
553
551
  if data_type is None:
554
552
  return all_steps
555
- if not isinstance(data_type, str):
556
- data_type: str = data_type.get_wrapper_data_type_name()
553
+ data_type: str = AliasUtil.to_data_type_name(data_type)
557
554
  return [x for x in all_steps if data_type in x.get_data_type_names()]
558
555
 
559
556
  def get_step_records(self, step: Step) -> list[DataRecord]:
@@ -605,6 +602,10 @@ class ExperimentHandler:
605
602
  The records may be provided as either DataRecords, PyRecordModels, or WrappedRecordModels.
606
603
  """
607
604
  step = self.__to_eln_step(step)
605
+ dt: str = AliasUtil.to_singular_data_type_name(records)
606
+ if dt != step.get_data_type_names()[0]:
607
+ raise SapioException(f"Cannot add {dt} records to entry {step.get_name()} of type "
608
+ f"{step.get_data_type_names()[0]}.")
608
609
  step.add_records(AliasUtil.to_data_records(records))
609
610
 
610
611
  def remove_step_records(self, step: Step, records: Iterable[SapioRecord]) -> None:
@@ -623,6 +624,10 @@ class ExperimentHandler:
623
624
  The records may be provided as either DataRecords, PyRecordModels, or WrappedRecordModels.
624
625
  """
625
626
  step = self.__to_eln_step(step)
627
+ dt: str = AliasUtil.to_singular_data_type_name(records)
628
+ if dt != step.get_data_type_names()[0]:
629
+ raise SapioException(f"Cannot remove {dt} records from entry {step.get_name()} of type "
630
+ f"{step.get_data_type_names()[0]}.")
626
631
  step.remove_records(AliasUtil.to_data_records(records))
627
632
 
628
633
  def set_step_records(self, step: Step, records: Iterable[SapioRecord]) -> None:
@@ -646,6 +651,10 @@ class ExperimentHandler:
646
651
  The records may be provided as either DataRecords, PyRecordModels, or WrappedRecordModels.
647
652
  """
648
653
  step = self.__to_eln_step(step)
654
+ dt: str = AliasUtil.to_singular_data_type_name(records)
655
+ if dt != step.get_data_type_names()[0]:
656
+ raise SapioException(f"Cannot set {dt} records for entry {step.get_name()} of type "
657
+ f"{step.get_data_type_names()[0]}.")
649
658
  step.set_records(AliasUtil.to_data_records(records))
650
659
 
651
660
  # FR-46496 - Provide alias of set_step_records for use with form entries.
@@ -733,8 +742,10 @@ class ExperimentHandler:
733
742
  dt: str = step.get_data_type_names()[0]
734
743
  if not ElnBaseDataType.is_eln_type(dt):
735
744
  raise SapioException("The provided step is not an ELN data type entry.")
736
- if any([x.data_type_name != dt for x in records]):
737
- raise SapioException("Not all of the provided records match the data type of the step.")
745
+ record_dt: str = AliasUtil.to_singular_data_type_name(records)
746
+ if record_dt != dt:
747
+ raise SapioException(f"Cannot remove {dt} records from entry {step.get_name()} of type "
748
+ f"{step.get_data_type_names()[0]}.")
738
749
  # If any rows were provided as data records, turn them into record models before deleting them, as otherwise
739
750
  # this function would need to make a webservice call to do the deletion.
740
751
  data_records: list[DataRecord] = []
@@ -1,19 +1,10 @@
1
1
  from sapiopylib.rest.User import SapioUser
2
- from sapiopylib.rest.pojo.CustomReport import (
3
- CompositeReportTerm,
4
- CompositeTermOperation,
5
- CustomReportCriteria,
6
- ExplicitJoinDefinition,
7
- FieldCompareReportTerm,
8
- RawReportTerm,
9
- RawTermOperation,
10
- ReportColumn,
11
- )
12
2
  from sapiopylib.rest.pojo.datatype.FieldDefinition import FieldType
13
- from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
14
3
  from sapiopylib.rest.utils.recordmodel.RecordModelWrapper import WrappedType
15
4
 
16
- from sapiopycommons.general.aliases import SapioRecord
5
+ from sapiopycommons.customreport.custom_report_builder import CustomReportBuilder
6
+ from sapiopycommons.customreport.term_builder import TermBuilder
7
+ from sapiopycommons.general.aliases import SapioRecord, UserIdentifier, AliasUtil
17
8
  from sapiopycommons.general.custom_report_util import CustomReportUtil
18
9
  from sapiopycommons.recordmodel.record_handler import RecordHandler
19
10
 
@@ -25,10 +16,8 @@ _RECORD_ID = "RECORDID"
25
16
  # that given records were used in or getting all records of a datatype used in given experiments.
26
17
  class ExperimentReportUtil:
27
18
  @staticmethod
28
- def map_records_to_experiment_ids(
29
- context: SapioWebhookContext | SapioUser,
30
- records: list[SapioRecord],
31
- ) -> dict[SapioRecord, list[int]]:
19
+ def map_records_to_experiment_ids(context: UserIdentifier, records: list[SapioRecord]) \
20
+ -> dict[SapioRecord, list[int]]:
32
21
  """
33
22
  Return a dictionary mapping each record to a list of ids of experiments that they were used in.
34
23
  If a record wasn't used in any experiments then it will be mapped to an empty list.
@@ -40,38 +29,25 @@ class ExperimentReportUtil:
40
29
  if not records:
41
30
  return {}
42
31
 
43
- user: SapioUser = context if isinstance(context, SapioUser) else context.user
44
-
45
- data_type_name = records[0].data_type_name
32
+ user: SapioUser = AliasUtil.to_sapio_user(context)
33
+ data_type_name: str = AliasUtil.to_singular_data_type_name(records)
46
34
 
47
35
  record_ids = [record.record_id for record in records]
48
-
49
- rows = ExperimentReportUtil.__get_record_experiment_relation_rows(
50
- user, data_type_name, record_ids=record_ids
51
- )
36
+ rows = ExperimentReportUtil.__get_record_experiment_relation_rows(user, data_type_name, record_ids=record_ids)
52
37
 
53
38
  id_to_record: dict[int, SapioRecord] = RecordHandler.map_by_id(records)
54
-
55
- record_to_exps: dict[SapioRecord, set[int]] = {
56
- record: set() for record in records
57
- }
58
-
39
+ record_to_exps: dict[SapioRecord, set[int]] = {record: set() for record in records}
59
40
  for row in rows:
60
41
  record_id: int = row[_RECORD_ID]
61
42
  exp_id: int = row[_NOTEBOOK_ID]
62
-
63
43
  record = id_to_record[record_id]
64
-
65
44
  record_to_exps[record].add(exp_id)
66
45
 
67
46
  return {record: list(exps) for record, exps in record_to_exps.items()}
68
47
 
69
48
  @staticmethod
70
- def map_experiments_to_records_of_type(
71
- context: SapioWebhookContext | SapioUser,
72
- exp_ids: list[int],
73
- wrapper_type: type[WrappedType],
74
- ) -> dict[int, list[WrappedType]]:
49
+ def map_experiments_to_records_of_type(context: UserIdentifier, exp_ids: list[int],
50
+ wrapper_type: type[WrappedType]) -> dict[int, list[WrappedType]]:
75
51
  """
76
52
  Return a dictionary mapping each experiment id to a list of records of the given type that were used in each experiment.
77
53
  If an experiment didn't use any records of the given type then it will be mapped to an empty list.
@@ -84,41 +60,27 @@ class ExperimentReportUtil:
84
60
  if not exp_ids:
85
61
  return {}
86
62
 
87
- user = context if isinstance(context, SapioUser) else context.user
88
-
63
+ user = AliasUtil.to_sapio_user(context)
89
64
  record_handler = RecordHandler(user)
90
-
91
65
  data_type_name: str = wrapper_type.get_wrapper_data_type_name()
92
66
 
93
- rows = ExperimentReportUtil.__get_record_experiment_relation_rows(
94
- user, data_type_name, exp_ids=exp_ids
95
- )
96
-
67
+ rows = ExperimentReportUtil.__get_record_experiment_relation_rows(user, data_type_name, exp_ids=exp_ids)
97
68
  record_ids: set[int] = {row[_RECORD_ID] for row in rows}
98
-
99
69
  records = record_handler.query_models_by_id(wrapper_type, record_ids)
100
70
 
101
71
  id_to_record: dict[int, WrappedType] = RecordHandler.map_by_id(records)
102
-
103
72
  exp_to_records: dict[int, set[SapioRecord]] = {exp: set() for exp in exp_ids}
104
-
105
73
  for row in rows:
106
74
  record_id: int = row[_RECORD_ID]
107
75
  exp_id: int = row[_NOTEBOOK_ID]
108
-
109
76
  record = id_to_record[record_id]
110
-
111
77
  exp_to_records[exp_id].add(record)
112
78
 
113
79
  return {exp: list(records) for exp, records in exp_to_records.items()}
114
80
 
115
81
  @staticmethod
116
- def __get_record_experiment_relation_rows(
117
- user: SapioUser,
118
- data_type_name: str,
119
- record_ids: list[int] | None = None,
120
- exp_ids: list[int] | None = None,
121
- ) -> list[dict[str, int]]:
82
+ def __get_record_experiment_relation_rows(user: SapioUser, data_type_name: str, record_ids: list[int] | None = None,
83
+ exp_ids: list[int] | None = None) -> list[dict[str, int]]:
122
84
  """
123
85
  Return a list of dicts mapping \"RECORDID\" to the record id and \"EXPERIMENTID\" to the experiment id.
124
86
  At least one of record_ids and exp_ids should be provided.
@@ -126,89 +88,31 @@ class ExperimentReportUtil:
126
88
  assert (record_ids or exp_ids)
127
89
 
128
90
  if record_ids:
129
- rec_ids = [str(record_id) for record_id in record_ids]
130
-
131
- ids_str = "{" + ", ".join(rec_ids) + "}"
132
-
133
- records_term = RawReportTerm(
134
- data_type_name, "RECORDID", RawTermOperation.EQUAL_TO_OPERATOR, ids_str
135
- )
136
-
91
+ records_term = TermBuilder.is_term(data_type_name, "RECORDID", record_ids)
137
92
  else:
138
93
  # Get all records of the given type
139
- records_term = RawReportTerm(
140
- data_type_name,
141
- "RECORDID",
142
- RawTermOperation.GREATER_THAN_OR_EQUAL_OPERATOR,
143
- "0",
144
- )
94
+ records_term = TermBuilder.all_records_term(data_type_name)
145
95
 
146
96
  if exp_ids:
147
- exp_ids = [str(exp_id) for exp_id in exp_ids]
148
-
149
- ids_str = "{" + ", ".join(exp_ids) + "}"
150
-
151
- exp_term = RawReportTerm(
152
- "NOTEBOOKEXPERIMENT",
153
- "EXPERIMENTID",
154
- RawTermOperation.EQUAL_TO_OPERATOR,
155
- ids_str,
156
- )
157
-
97
+ exp_term = TermBuilder.is_term("NOTEBOOKEXPERIMENT", "EXPERIMENTID", exp_ids)
158
98
  else:
159
99
  # Get all experiments
160
- exp_term = RawReportTerm(
161
- "NOTEBOOKEXPERIMENT",
162
- "EXPERIMENTID",
163
- RawTermOperation.GREATER_THAN_OR_EQUAL_OPERATOR,
164
- "0",
165
- )
166
-
167
- root_term = CompositeReportTerm(
168
- records_term, CompositeTermOperation.AND_OPERATOR, exp_term
169
- )
170
-
171
- # The columns the resulting dataframe will have
172
- column_list = [
173
- ReportColumn(data_type_name, "RECORDID", FieldType.LONG),
174
- ReportColumn("NOTEBOOKEXPERIMENT", "EXPERIMENTID", FieldType.LONG),
175
- ]
100
+ exp_term = TermBuilder.gte_term("NOTEBOOKEXPERIMENT", "EXPERIMENTID", "0")
176
101
 
177
- # Join records on the experiment entry records that correspond to them.
178
- records_entry_join = FieldCompareReportTerm(
179
- data_type_name,
180
- "RECORDID",
181
- RawTermOperation.EQUAL_TO_OPERATOR,
182
- "EXPERIMENTENTRYRECORD",
183
- "RECORDID",
184
- )
102
+ root_term = TermBuilder.and_terms(records_term, exp_term)
185
103
 
104
+ # Join records on the experiment entry records that correspond to them.
105
+ records_entry_join = TermBuilder.compare_is_term("EXPERIMENTENTRYRECORD", "RECORDID", data_type_name, "RECORDID")
186
106
  # Join entry records on the experiment entries they are in.
187
- experiment_entry_enb_entry_join = FieldCompareReportTerm(
188
- "EXPERIMENTENTRYRECORD",
189
- "ENTRYID",
190
- RawTermOperation.EQUAL_TO_OPERATOR,
191
- "ENBENTRY",
192
- "ENTRYID",
193
- )
194
-
107
+ experiment_entry_enb_entry_join = TermBuilder.compare_is_term("ENBENTRY", "ENTRYID", "EXPERIMENTENTRYRECORD", "ENTRYID")
195
108
  # Join entries on the experiments they are in.
196
- enb_entry_experiment_join = FieldCompareReportTerm(
197
- "ENBENTRY",
198
- "EXPERIMENTID",
199
- RawTermOperation.EQUAL_TO_OPERATOR,
200
- "NOTEBOOKEXPERIMENT",
201
- "EXPERIMENTID",
202
- )
203
-
204
- report_criteria = CustomReportCriteria(
205
- column_list,
206
- root_term,
207
- join_list=[
208
- ExplicitJoinDefinition("EXPERIMENTENTRYRECORD", records_entry_join),
209
- ExplicitJoinDefinition("ENBENTRY", experiment_entry_enb_entry_join),
210
- ExplicitJoinDefinition("NOTEBOOKEXPERIMENT", enb_entry_experiment_join),
211
- ],
212
- )
213
-
214
- return CustomReportUtil.run_custom_report(user, report_criteria)
109
+ enb_entry_experiment_join = TermBuilder.compare_is_term("NOTEBOOKEXPERIMENT", "EXPERIMENTID", "ENBENTRY", "EXPERIMENTID")
110
+
111
+ report_builder = CustomReportBuilder(data_type_name)
112
+ report_builder.set_root_term(root_term)
113
+ report_builder.add_column("RECORDID", FieldType.LONG, data_type=data_type_name)
114
+ report_builder.add_column("EXPERIMENTID", FieldType.LONG, data_type="NOTEBOOKEXPERIMENT")
115
+ report_builder.add_join(records_entry_join)
116
+ report_builder.add_join(experiment_entry_enb_entry_join)
117
+ report_builder.add_join(enb_entry_experiment_join)
118
+ return CustomReportUtil.run_custom_report(user, report_builder.build_report_criteria())
@@ -1,12 +1,13 @@
1
1
  import io
2
2
 
3
3
  from sapiopylib.rest.User import SapioUser
4
- from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
4
+
5
+ from sapiopycommons.general.aliases import UserIdentifier, AliasUtil
5
6
 
6
7
 
7
8
  class CDL:
8
9
  @staticmethod
9
- def load_cdl(context: SapioWebhookContext | SapioUser, config_name: str, file_name: str, file_data: bytes | str) \
10
+ def load_cdl(context: UserIdentifier, config_name: str, file_name: str, file_data: bytes | str) \
10
11
  -> list[int]:
11
12
  """
12
13
  Create data records from a file using one of the complex data loader (CDL) configurations in the system.
@@ -22,7 +23,7 @@ class CDL:
22
23
  "configName": config_name,
23
24
  "fileName": file_name
24
25
  }
25
- user: SapioUser = context if isinstance(context, SapioUser) else context.user
26
+ user: SapioUser = AliasUtil.to_sapio_user(context)
26
27
  with io.BytesIO(file_data.encode() if isinstance(file_data, str) else file_data) as data_stream:
27
28
  response = user.post_data_stream(sub_path, params=params, data_stream=data_stream)
28
29
  user.raise_for_status(response)
@@ -4,13 +4,14 @@ import urllib.parse
4
4
 
5
5
  from requests import Response
6
6
  from sapiopylib.rest.User import SapioUser
7
- from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
7
+
8
+ from sapiopycommons.general.aliases import UserIdentifier, AliasUtil
8
9
 
9
10
 
10
11
  # FR-46064 - Initial port of PyWebhookUtils to sapiopycommons.
11
12
  class FileBridge:
12
13
  @staticmethod
13
- def read_file(context: SapioWebhookContext | SapioUser, bridge_name: str, file_path: str,
14
+ def read_file(context: UserIdentifier, bridge_name: str, file_path: str,
14
15
  base64_decode: bool = True) -> bytes:
15
16
  """
16
17
  Read a file from FileBridge.
@@ -27,7 +28,7 @@ class FileBridge:
27
28
  params = {
28
29
  'Filepath': f"bridge://{bridge_name}/{file_path}"
29
30
  }
30
- user: SapioUser = context if isinstance(context, SapioUser) else context.user
31
+ user: SapioUser = AliasUtil.to_sapio_user(context)
31
32
  response = user.get(sub_path, params)
32
33
  user.raise_for_status(response)
33
34
 
@@ -37,7 +38,7 @@ class FileBridge:
37
38
  return ret_val
38
39
 
39
40
  @staticmethod
40
- def write_file(context: SapioWebhookContext | SapioUser, bridge_name: str, file_path: str,
41
+ def write_file(context: UserIdentifier, bridge_name: str, file_path: str,
41
42
  file_data: bytes | str) -> None:
42
43
  """
43
44
  Write a file to FileBridge.
@@ -53,13 +54,13 @@ class FileBridge:
53
54
  params = {
54
55
  'Filepath': f"bridge://{bridge_name}/{file_path}"
55
56
  }
56
- user: SapioUser = context if isinstance(context, SapioUser) else context.user
57
+ user: SapioUser = AliasUtil.to_sapio_user(context)
57
58
  with io.BytesIO(file_data.encode() if isinstance(file_data, str) else file_data) as data_stream:
58
59
  response = user.post_data_stream(sub_path, params=params, data_stream=data_stream)
59
60
  user.raise_for_status(response)
60
61
 
61
62
  @staticmethod
62
- def list_directory(context: SapioWebhookContext | SapioUser, bridge_name: str,
63
+ def list_directory(context: UserIdentifier, bridge_name: str,
63
64
  file_path: str | None = "") -> list[str]:
64
65
  """
65
66
  List the contents of a FileBridge directory.
@@ -74,7 +75,7 @@ class FileBridge:
74
75
  params = {
75
76
  'Filepath': f"bridge://{bridge_name}/{file_path}"
76
77
  }
77
- user: SapioUser = context if isinstance(context, SapioUser) else context.user
78
+ user: SapioUser = AliasUtil.to_sapio_user(context)
78
79
  response: Response = user.get(sub_path, params=params)
79
80
  user.raise_for_status(response)
80
81
 
@@ -83,7 +84,7 @@ class FileBridge:
83
84
  return [urllib.parse.unquote(value)[path_length:] for value in response_body]
84
85
 
85
86
  @staticmethod
86
- def create_directory(context: SapioWebhookContext | SapioUser, bridge_name: str, file_path: str) -> None:
87
+ def create_directory(context: UserIdentifier, bridge_name: str, file_path: str) -> None:
87
88
  """
88
89
  Create a new directory in FileBridge.
89
90
 
@@ -97,12 +98,12 @@ class FileBridge:
97
98
  params = {
98
99
  'Filepath': f"bridge://{bridge_name}/{file_path}"
99
100
  }
100
- user: SapioUser = context if isinstance(context, SapioUser) else context.user
101
+ user: SapioUser = AliasUtil.to_sapio_user(context)
101
102
  response = user.post(sub_path, params=params)
102
103
  user.raise_for_status(response)
103
104
 
104
105
  @staticmethod
105
- def delete_file(context: SapioWebhookContext | SapioUser, bridge_name: str, file_path: str) -> None:
106
+ def delete_file(context: UserIdentifier, bridge_name: str, file_path: str) -> None:
106
107
  """
107
108
  Delete an existing file in FileBridge.
108
109
 
@@ -115,12 +116,12 @@ class FileBridge:
115
116
  params = {
116
117
  'Filepath': f"bridge://{bridge_name}/{file_path}"
117
118
  }
118
- user: SapioUser = context if isinstance(context, SapioUser) else context.user
119
+ user: SapioUser = AliasUtil.to_sapio_user(context)
119
120
  response = user.delete(sub_path, params=params)
120
121
  user.raise_for_status(response)
121
122
 
122
123
  @staticmethod
123
- def delete_directory(context: SapioWebhookContext | SapioUser, bridge_name: str, file_path: str) -> None:
124
+ def delete_directory(context: UserIdentifier, bridge_name: str, file_path: str) -> None:
124
125
  """
125
126
  Delete an existing directory in FileBridge.
126
127
 
@@ -133,6 +134,6 @@ class FileBridge:
133
134
  params = {
134
135
  'Filepath': f"bridge://{bridge_name}/{file_path}"
135
136
  }
136
- user: SapioUser = context if isinstance(context, SapioUser) else context.user
137
+ user: SapioUser = AliasUtil.to_sapio_user(context)
137
138
  response = user.delete(sub_path, params=params)
138
139
  user.raise_for_status(response)