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.
- sapiopycommons/eln/experiment_report_util.py +214 -0
- {sapiopycommons-2024.7.2a279.dist-info → sapiopycommons-2024.7.3a280.dist-info}/METADATA +1 -1
- {sapiopycommons-2024.7.2a279.dist-info → sapiopycommons-2024.7.3a280.dist-info}/RECORD +5 -4
- {sapiopycommons-2024.7.2a279.dist-info → sapiopycommons-2024.7.3a280.dist-info}/WHEEL +0 -0
- {sapiopycommons-2024.7.2a279.dist-info → sapiopycommons-2024.7.3a280.dist-info}/licenses/LICENSE +0 -0
|
@@ -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.
|
|
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.
|
|
40
|
-
sapiopycommons-2024.7.
|
|
41
|
-
sapiopycommons-2024.7.
|
|
42
|
-
sapiopycommons-2024.7.
|
|
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,,
|
|
File without changes
|
{sapiopycommons-2024.7.2a279.dist-info → sapiopycommons-2024.7.3a280.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|