sapiopycommons 2024.7.2a279__py3-none-any.whl → 2024.7.3a280__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.

@@ -0,0 +1,214 @@
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
+ from sapiopylib.rest.pojo.datatype.FieldDefinition import FieldType
13
+ from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
14
+ from sapiopylib.rest.utils.recordmodel.RecordModelWrapper import WrappedType
15
+
16
+ from sapiopycommons.general.aliases import SapioRecord
17
+ from sapiopycommons.general.custom_report_util import CustomReportUtil
18
+ from sapiopycommons.recordmodel.record_handler import RecordHandler
19
+
20
+ _NOTEBOOK_ID = "EXPERIMENTID"
21
+ _RECORD_ID = "RECORDID"
22
+
23
+
24
+ # FR-46908 - Provide a utility class that holds experiment related custom reports e.g. getting all the experiments
25
+ # that given records were used in or getting all records of a datatype used in given experiments.
26
+ class ExperimentReportUtil:
27
+ @staticmethod
28
+ def map_records_to_experiment_ids(
29
+ context: SapioWebhookContext | SapioUser,
30
+ records: list[SapioRecord],
31
+ ) -> dict[SapioRecord, list[int]]:
32
+ """
33
+ Return a dictionary mapping each record to a list of ids of experiments that they were used in.
34
+ If a record wasn't used in any experiments then it will be mapped to an empty list.
35
+
36
+ :param context: The current webhook context or a user object to send requests from.
37
+ :param records: a list of records of the same data type.
38
+ :return: a dictionary mapping each record to a list of ids of each experiment it was used in.
39
+ """
40
+ if not records:
41
+ return {}
42
+
43
+ user: SapioUser = context if isinstance(context, SapioUser) else context.user
44
+
45
+ data_type_name = records[0].data_type_name
46
+
47
+ 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
+ )
52
+
53
+ 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
+
59
+ for row in rows:
60
+ record_id: int = row[_RECORD_ID]
61
+ exp_id: int = row[_NOTEBOOK_ID]
62
+
63
+ record = id_to_record[record_id]
64
+
65
+ record_to_exps[record].add(exp_id)
66
+
67
+ return {record: list(exps) for record, exps in record_to_exps.items()}
68
+
69
+ @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]]:
75
+ """
76
+ Return a dictionary mapping each experiment id to a list of records of the given type that were used in each experiment.
77
+ If an experiment didn't use any records of the given type then it will be mapped to an empty list.
78
+
79
+ :param context: The current webhook context or a user object to send requests from.
80
+ :param exp_ids: a list of experiment ids. These are specifically the Notebook Experiment ids which can be found in the title of the experiment.
81
+ :param wrapper_type: The record model wrapper to use, corresponds to which data type we will query for.
82
+ :return: a dictionary mapping each experiment id to a list of records of the given type that were used in that experiment.
83
+ """
84
+ if not exp_ids:
85
+ return {}
86
+
87
+ user = context if isinstance(context, SapioUser) else context.user
88
+
89
+ record_handler = RecordHandler(user)
90
+
91
+ data_type_name: str = wrapper_type.get_wrapper_data_type_name()
92
+
93
+ rows = ExperimentReportUtil.__get_record_experiment_relation_rows(
94
+ user, data_type_name, exp_ids=exp_ids
95
+ )
96
+
97
+ record_ids: set[int] = {row[_RECORD_ID] for row in rows}
98
+
99
+ records = record_handler.query_models_by_id(wrapper_type, record_ids)
100
+
101
+ id_to_record: dict[int, WrappedType] = RecordHandler.map_by_id(records)
102
+
103
+ exp_to_records: dict[int, set[SapioRecord]] = {exp: set() for exp in exp_ids}
104
+
105
+ for row in rows:
106
+ record_id: int = row[_RECORD_ID]
107
+ exp_id: int = row[_NOTEBOOK_ID]
108
+
109
+ record = id_to_record[record_id]
110
+
111
+ exp_to_records[exp_id].add(record)
112
+
113
+ return {exp: list(records) for exp, records in exp_to_records.items()}
114
+
115
+ @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]]:
122
+ """
123
+ Return a list of dicts mapping \"RECORDID\" to the record id and \"EXPERIMENTID\" to the experiment id.
124
+ At least one of record_ids and exp_ids should be provided.
125
+ """
126
+ assert (record_ids or exp_ids)
127
+
128
+ 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
+
137
+ else:
138
+ # 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
+ )
145
+
146
+ 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
+
158
+ else:
159
+ # 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
+ ]
176
+
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
+ )
185
+
186
+ # 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
+
195
+ # 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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sapiopycommons
3
- Version: 2024.7.2a279
3
+ Version: 2024.7.3a280
4
4
  Summary: Official Sapio Python API Utilities Package
5
5
  Project-URL: Homepage, https://github.com/sapiosciences
6
6
  Author-email: Jonathan Steck <jsteck@sapiosciences.com>, Yechen Qiao <yqiao@sapiosciences.com>
@@ -8,6 +8,7 @@ sapiopycommons/datatype/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
8
8
  sapiopycommons/datatype/attachment_util.py,sha256=YlnMprj5IGBbAZDLG2khS1P7JIYTw_NYfpJAfRZfP3M,3219
9
9
  sapiopycommons/eln/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  sapiopycommons/eln/experiment_handler.py,sha256=v1pG4qtZb8OSNWfKtFo6NjnEkReqnu5R9i_hqWh_xxg,57198
11
+ sapiopycommons/eln/experiment_report_util.py,sha256=FTLw-6SLAMeoWTOO-qhGROE9g54pZdyoQJIhiIzlwGw,7848
11
12
  sapiopycommons/eln/plate_designer.py,sha256=FYJfhhNq8hdfuXgDYOYHy6g0m2zNwQXZWF_MTPzElDg,7184
12
13
  sapiopycommons/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
14
  sapiopycommons/files/complex_data_loader.py,sha256=XSJOl676mIklJo78v07-70u1b015a5DI4sqZPI3C-Tw,1475
@@ -36,7 +37,7 @@ sapiopycommons/rules/eln_rule_handler.py,sha256=qfkBZtck0KK1i9s9Xe2UZqkzQOgPCzDx
36
37
  sapiopycommons/rules/on_save_rule_handler.py,sha256=JY9F30IcHwFVdgPAMQtTYuRastV1jeezhVktyrzNASU,10763
37
38
  sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
39
  sapiopycommons/webhook/webhook_handlers.py,sha256=ibpBY3Sk3Eij919bIdW0awzlogYoQSWYDDOg--NwsQE,13431
39
- sapiopycommons-2024.7.2a279.dist-info/METADATA,sha256=HqvQb86znDDaqgF0QLCt6WtNtxF70JgGOiOES7iiXXU,3175
40
- sapiopycommons-2024.7.2a279.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
41
- sapiopycommons-2024.7.2a279.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
42
- sapiopycommons-2024.7.2a279.dist-info/RECORD,,
40
+ sapiopycommons-2024.7.3a280.dist-info/METADATA,sha256=bdT3mlji7J-b8ayWJrDCel9qHdQUA2qAx3oO4xMFq5k,3175
41
+ sapiopycommons-2024.7.3a280.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
42
+ sapiopycommons-2024.7.3a280.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
43
+ sapiopycommons-2024.7.3a280.dist-info/RECORD,,