sapiopycommons 2025.4.9a150__py3-none-any.whl → 2025.4.9a476__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/callbacks/callback_util.py +1262 -392
- sapiopycommons/callbacks/field_builder.py +2 -0
- sapiopycommons/chem/Molecules.py +0 -2
- sapiopycommons/customreport/auto_pagers.py +281 -0
- sapiopycommons/customreport/term_builder.py +1 -1
- sapiopycommons/datatype/attachment_util.py +4 -2
- sapiopycommons/datatype/data_fields.py +23 -1
- sapiopycommons/eln/experiment_cache.py +173 -0
- sapiopycommons/eln/experiment_handler.py +933 -279
- sapiopycommons/eln/experiment_report_util.py +15 -10
- sapiopycommons/eln/experiment_step_factory.py +474 -0
- sapiopycommons/eln/experiment_tags.py +7 -0
- sapiopycommons/eln/plate_designer.py +159 -59
- sapiopycommons/eln/step_creation.py +235 -0
- sapiopycommons/files/file_bridge.py +76 -0
- sapiopycommons/files/file_bridge_handler.py +325 -110
- sapiopycommons/files/file_data_handler.py +2 -2
- sapiopycommons/files/file_util.py +40 -15
- sapiopycommons/files/file_validator.py +6 -5
- sapiopycommons/files/file_writer.py +1 -1
- sapiopycommons/flowcyto/flow_cyto.py +1 -1
- sapiopycommons/general/accession_service.py +3 -3
- sapiopycommons/general/aliases.py +51 -28
- sapiopycommons/general/audit_log.py +2 -2
- sapiopycommons/general/custom_report_util.py +24 -1
- sapiopycommons/general/data_structure_util.py +115 -0
- sapiopycommons/general/directive_util.py +86 -0
- sapiopycommons/general/exceptions.py +41 -2
- sapiopycommons/general/popup_util.py +2 -2
- sapiopycommons/multimodal/multimodal.py +1 -0
- sapiopycommons/processtracking/custom_workflow_handler.py +46 -30
- sapiopycommons/recordmodel/record_handler.py +547 -159
- sapiopycommons/rules/eln_rule_handler.py +41 -30
- sapiopycommons/rules/on_save_rule_handler.py +41 -30
- sapiopycommons/samples/aliquot.py +48 -0
- sapiopycommons/webhook/webhook_handlers.py +448 -55
- sapiopycommons/webhook/webservice_handlers.py +2 -2
- {sapiopycommons-2025.4.9a150.dist-info → sapiopycommons-2025.4.9a476.dist-info}/METADATA +1 -1
- sapiopycommons-2025.4.9a476.dist-info/RECORD +67 -0
- sapiopycommons-2025.4.9a150.dist-info/RECORD +0 -59
- {sapiopycommons-2025.4.9a150.dist-info → sapiopycommons-2025.4.9a476.dist-info}/WHEEL +0 -0
- {sapiopycommons-2025.4.9a150.dist-info → sapiopycommons-2025.4.9a476.dist-info}/licenses/LICENSE +0 -0
|
@@ -4,15 +4,16 @@ from sapiopylib.rest.pojo.CustomReport import CustomReportCriteria, AbstractRepo
|
|
|
4
4
|
from sapiopylib.rest.pojo.datatype.FieldDefinition import FieldType
|
|
5
5
|
from sapiopylib.rest.pojo.eln.ElnExperiment import ElnExperiment, ElnExperimentQueryCriteria
|
|
6
6
|
from sapiopylib.rest.pojo.eln.SapioELNEnums import ElnExperimentStatus, ElnBaseDataType
|
|
7
|
+
from sapiopylib.rest.utils.recordmodel.PyRecordModel import PyRecordModel
|
|
7
8
|
from sapiopylib.rest.utils.recordmodel.RecordModelWrapper import WrappedType
|
|
8
9
|
|
|
10
|
+
from sapiopycommons.customreport.auto_pagers import CustomReportDictAutoPager
|
|
9
11
|
from sapiopycommons.customreport.custom_report_builder import CustomReportBuilder
|
|
10
12
|
from sapiopycommons.customreport.term_builder import TermBuilder
|
|
11
13
|
from sapiopycommons.datatype.pseudo_data_types import EnbEntryOptionsPseudoDef, NotebookExperimentOptionPseudoDef, \
|
|
12
14
|
NotebookExperimentPseudoDef, ExperimentEntryRecordPseudoDef, EnbEntryPseudoDef
|
|
13
15
|
from sapiopycommons.general.aliases import SapioRecord, UserIdentifier, AliasUtil, FieldValue, \
|
|
14
16
|
ExperimentEntryIdentifier, ExperimentIdentifier
|
|
15
|
-
from sapiopycommons.general.custom_report_util import CustomReportUtil
|
|
16
17
|
from sapiopycommons.general.exceptions import SapioException
|
|
17
18
|
from sapiopycommons.recordmodel.record_handler import RecordHandler
|
|
18
19
|
|
|
@@ -201,7 +202,7 @@ class ExperimentReportUtil:
|
|
|
201
202
|
criteria = report_builder.build_report_criteria()
|
|
202
203
|
|
|
203
204
|
ret_val: dict[SapioRecord, int] = {}
|
|
204
|
-
rows: list[dict[str, FieldValue]] =
|
|
205
|
+
rows: list[dict[str, FieldValue]] = CustomReportDictAutoPager(context, criteria).get_all_at_once()
|
|
205
206
|
for row in rows:
|
|
206
207
|
dt: str = row[EnbEntryPseudoDef.DATA_TYPE_NAME__FIELD_NAME.field_name]
|
|
207
208
|
exp_id: int = row[EnbEntryPseudoDef.EXPERIMENT_ID__FIELD_NAME.field_name]
|
|
@@ -209,16 +210,20 @@ class ExperimentReportUtil:
|
|
|
209
210
|
ret_val[record] = exp_id
|
|
210
211
|
return ret_val
|
|
211
212
|
|
|
213
|
+
# CR-47491: Support providing a data type name string to receive PyRecordModels instead of requiring a WrapperType.
|
|
212
214
|
@staticmethod
|
|
213
215
|
def map_experiments_to_records_of_type(context: UserIdentifier, exp_ids: list[ExperimentIdentifier],
|
|
214
|
-
wrapper_type: type[WrappedType]
|
|
216
|
+
wrapper_type: type[WrappedType] | str) \
|
|
217
|
+
-> dict[int, list[WrappedType] | list[PyRecordModel]]:
|
|
215
218
|
"""
|
|
216
219
|
Return a dictionary mapping each experiment id to a list of records of the given type that were used in each
|
|
217
220
|
experiment. If an experiment didn't use any records of the given type then it will be mapped to an empty list.
|
|
218
221
|
|
|
219
222
|
:param context: The current webhook context or a user object to send requests from.
|
|
220
223
|
:param exp_ids: A list of experiment identifiers.
|
|
221
|
-
:param wrapper_type: The record model wrapper to use, corresponds to which data type we will
|
|
224
|
+
:param wrapper_type: The record model wrapper or data type name to use, corresponds to which data type we will
|
|
225
|
+
query for. If a data type name is provided, the returned records will be PyRecordModels instead of
|
|
226
|
+
WrappedRecordModels.
|
|
222
227
|
:return: A dictionary mapping each experiment id to a list of records of the given type that were used in that
|
|
223
228
|
experiment.
|
|
224
229
|
"""
|
|
@@ -227,7 +232,7 @@ class ExperimentReportUtil:
|
|
|
227
232
|
|
|
228
233
|
user = AliasUtil.to_sapio_user(context)
|
|
229
234
|
record_handler = RecordHandler(user)
|
|
230
|
-
data_type_name: str =
|
|
235
|
+
data_type_name: str = AliasUtil.to_data_type_name(wrapper_type)
|
|
231
236
|
|
|
232
237
|
exp_ids: list[int] = AliasUtil.to_notebook_ids(exp_ids)
|
|
233
238
|
rows = ExperimentReportUtil.__get_record_experiment_relation_rows(user, data_type_name, exp_ids=exp_ids)
|
|
@@ -268,7 +273,7 @@ class ExperimentReportUtil:
|
|
|
268
273
|
|
|
269
274
|
# Ensure that each experiment appears in the dictionary, even if it has no experiment options.
|
|
270
275
|
options: dict[int, dict[str, str]] = {x: {} for x in exp_ids}
|
|
271
|
-
results: list[dict[str, FieldValue]] =
|
|
276
|
+
results: list[dict[str, FieldValue]] = CustomReportDictAutoPager(context, report).get_all_at_once()
|
|
272
277
|
for row in results:
|
|
273
278
|
exp_id: int = row[NotebookExperimentOptionPseudoDef.EXPERIMENT_ID__FIELD_NAME.field_name]
|
|
274
279
|
key: str = row[NotebookExperimentOptionPseudoDef.OPTION_KEY__FIELD_NAME.field_name]
|
|
@@ -299,7 +304,7 @@ class ExperimentReportUtil:
|
|
|
299
304
|
|
|
300
305
|
# Ensure that each entry appears in the dictionary, even if it has no entry options.
|
|
301
306
|
options: dict[int, dict[str, str]] = {x: {} for x in entries}
|
|
302
|
-
results: list[dict[str, FieldValue]] =
|
|
307
|
+
results: list[dict[str, FieldValue]] = CustomReportDictAutoPager(context, report).get_all_at_once()
|
|
303
308
|
for row in results:
|
|
304
309
|
entry_id: int = row[EnbEntryOptionsPseudoDef.ENTRY_ID__FIELD_NAME.field_name]
|
|
305
310
|
key: str = row[EnbEntryOptionsPseudoDef.ENTRY_OPTION_KEY__FIELD_NAME.field_name]
|
|
@@ -332,7 +337,7 @@ class ExperimentReportUtil:
|
|
|
332
337
|
report = report_builder.build_report_criteria()
|
|
333
338
|
|
|
334
339
|
ret_val: dict[int, str] = {}
|
|
335
|
-
results: list[dict[str, FieldValue]] =
|
|
340
|
+
results: list[dict[str, FieldValue]] = CustomReportDictAutoPager(context, report).get_all_at_once()
|
|
336
341
|
for row in results:
|
|
337
342
|
exp_id: int = row[NotebookExperimentPseudoDef.EXPERIMENT_ID__FIELD_NAME.field_name]
|
|
338
343
|
name: str = row["TemplateExperimentName"]
|
|
@@ -581,7 +586,7 @@ class ExperimentReportUtil:
|
|
|
581
586
|
"""
|
|
582
587
|
user = AliasUtil.to_sapio_user(context)
|
|
583
588
|
exp_ids: list[int] = []
|
|
584
|
-
for row in
|
|
589
|
+
for row in CustomReportDictAutoPager(user, report):
|
|
585
590
|
exp_ids.append(row[NotebookExperimentPseudoDef.EXPERIMENT_ID__FIELD_NAME.field_name])
|
|
586
591
|
if not exp_ids:
|
|
587
592
|
return []
|
|
@@ -646,4 +651,4 @@ class ExperimentReportUtil:
|
|
|
646
651
|
report_builder.add_join(records_entry_join, ExperimentEntryRecordPseudoDef.DATA_TYPE_NAME)
|
|
647
652
|
report_builder.add_join(experiment_entry_enb_entry_join, EnbEntryPseudoDef.DATA_TYPE_NAME)
|
|
648
653
|
report_builder.add_join(enb_entry_experiment_join, NotebookExperimentPseudoDef.DATA_TYPE_NAME)
|
|
649
|
-
return
|
|
654
|
+
return CustomReportDictAutoPager(user, report_builder.build_report_criteria()).get_all_at_once()
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
from typing import cast
|
|
5
|
+
|
|
6
|
+
from sapiopycommons.datatype.data_fields import SystemFields
|
|
7
|
+
from sapiopycommons.eln.step_creation import StepCreation, AttachmentStepCreation, GlobalDtFormStepCreation, \
|
|
8
|
+
ELnDtFormStepCreation, PluginStepCreation, TextStepCreation, TempDataStepCreation, ELnDtTableStepCreation, \
|
|
9
|
+
GlobalDtTableStepCreation, DashboardStepCreation
|
|
10
|
+
from sapiopycommons.eln.experiment_cache import ExperimentCacheManager
|
|
11
|
+
from sapiopycommons.eln.experiment_handler import ExperimentHandler, Step
|
|
12
|
+
from sapiopycommons.eln.experiment_tags import PLATE_DESIGNER_PLUGIN
|
|
13
|
+
from sapiopycommons.general.aliases import AliasUtil, SapioRecord, DataTypeIdentifier, FieldMap, \
|
|
14
|
+
ExperimentEntryIdentifier
|
|
15
|
+
from sapiopycommons.general.exceptions import SapioException
|
|
16
|
+
from sapiopylib.rest.DataRecordManagerService import DataRecordManager
|
|
17
|
+
from sapiopylib.rest.ELNService import ElnManager
|
|
18
|
+
from sapiopylib.rest.User import SapioUser
|
|
19
|
+
from sapiopylib.rest.pojo.DataRecord import DataRecord
|
|
20
|
+
from sapiopylib.rest.pojo.TableColumn import TableColumn
|
|
21
|
+
from sapiopylib.rest.pojo.eln.ElnEntryPosition import ElnEntryPosition
|
|
22
|
+
from sapiopylib.rest.pojo.eln.ExperimentEntry import EntryAttachment, EntryRecordAttachment
|
|
23
|
+
from sapiopylib.rest.pojo.eln.ExperimentEntryCriteria import ExperimentEntryCriteriaUtil, AbstractElnEntryCriteria, \
|
|
24
|
+
ElnAttachmentEntryCriteria, \
|
|
25
|
+
ElnFormEntryCriteria, ElnPluginEntryCriteria, ElnTextEntryCriteria, ElnTempDataEntryCriteria, ElnTableEntryCriteria, \
|
|
26
|
+
ElnDashboardEntryCriteria
|
|
27
|
+
from sapiopylib.rest.pojo.eln.SapioELNEnums import ElnBaseDataType
|
|
28
|
+
from sapiopylib.rest.pojo.eln.eln_headings import ElnExperimentTab
|
|
29
|
+
from sapiopylib.rest.pojo.eln.field_set import ElnFieldSetInfo
|
|
30
|
+
from sapiopylib.rest.utils.Protocols import ElnEntryStep
|
|
31
|
+
from sapiopylib.rest.utils.plates.MultiLayerPlating import MultiLayerPlateConfig, MultiLayerPlateLayer, \
|
|
32
|
+
MultiLayerDataTypeConfig, MultiLayerReplicateConfig, MultiLayerDilutionConfig
|
|
33
|
+
from sapiopylib.rest.utils.plates.MultiLayerPlatingUtils import MultiLayerPlatingManager
|
|
34
|
+
from sapiopylib.rest.utils.plates.PlatingUtils import PlatingOrder
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# CR-47564: Moved the entry creation functions to their own class.
|
|
38
|
+
class ExperimentStepFactory:
|
|
39
|
+
user: SapioUser
|
|
40
|
+
_exp_handler: ExperimentHandler
|
|
41
|
+
|
|
42
|
+
_exp_id: int
|
|
43
|
+
|
|
44
|
+
_eln_man: ElnManager
|
|
45
|
+
_exp_cache: ExperimentCacheManager
|
|
46
|
+
|
|
47
|
+
def __init__(self, exp_handler: ExperimentHandler):
|
|
48
|
+
self.user = exp_handler.user
|
|
49
|
+
self._exp_handler = exp_handler
|
|
50
|
+
self._exp_id = exp_handler.protocol.get_id()
|
|
51
|
+
self._eln_man = ElnManager(self.user)
|
|
52
|
+
self._exp_cache = ExperimentCacheManager(self.user)
|
|
53
|
+
|
|
54
|
+
# FR-47468: Add functions for creating new entries in the experiment.
|
|
55
|
+
def create_attachment_step(self, entry_name: str, data_type: DataTypeIdentifier,
|
|
56
|
+
attachments: Iterable[EntryAttachment] | Iterable[SapioRecord] | None = None,
|
|
57
|
+
criteria: AttachmentStepCreation = AttachmentStepCreation(),
|
|
58
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
59
|
+
"""
|
|
60
|
+
Create a new attachment entry in the experiment.
|
|
61
|
+
|
|
62
|
+
:param entry_name: The name of the entry.
|
|
63
|
+
:param data_type: The data type of the entry.
|
|
64
|
+
:param attachments: The list of attachments to initially populate the entry with.
|
|
65
|
+
:param criteria: Additional criteria for creating the entry.
|
|
66
|
+
:param position: Information about where to place the entry in the experiment.
|
|
67
|
+
:return: The newly created attachment entry.
|
|
68
|
+
"""
|
|
69
|
+
entry_criteria = cast(ElnAttachmentEntryCriteria,
|
|
70
|
+
self._create_step_criteria(entry_name, data_type, criteria, position))
|
|
71
|
+
|
|
72
|
+
if attachments:
|
|
73
|
+
entry_attachments: list[EntryAttachment] = []
|
|
74
|
+
for entry in attachments:
|
|
75
|
+
if isinstance(entry, EntryAttachment):
|
|
76
|
+
entry_attachments.append(entry)
|
|
77
|
+
elif isinstance(entry, SapioRecord):
|
|
78
|
+
entry: SapioRecord
|
|
79
|
+
file_name: str = entry.get_field_value("FilePath")
|
|
80
|
+
if not file_name:
|
|
81
|
+
file_name = entry.get_field_value(SystemFields.DATA_RECORD_NAME__FIELD.field_name)
|
|
82
|
+
rec_id: int = AliasUtil.to_record_id(entry)
|
|
83
|
+
entry_attachments.append(EntryRecordAttachment(file_name, rec_id))
|
|
84
|
+
else:
|
|
85
|
+
raise SapioException("Attachments must be of type EntryAttachment or SapioRecord.")
|
|
86
|
+
entry_criteria.entry_attachment_list = entry_attachments
|
|
87
|
+
|
|
88
|
+
step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
|
|
89
|
+
return step
|
|
90
|
+
|
|
91
|
+
def create_dashboard_step(self, entry_name, data_type: DataTypeIdentifier,
|
|
92
|
+
criteria: DashboardStepCreation = DashboardStepCreation(),
|
|
93
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
94
|
+
entry_criteria = cast(ElnDashboardEntryCriteria,
|
|
95
|
+
self._create_step_criteria(entry_name, data_type, criteria, position))
|
|
96
|
+
|
|
97
|
+
if criteria:
|
|
98
|
+
if entry_criteria.source_entry_id:
|
|
99
|
+
entry_criteria.source_entry_id = self.__to_entry_ids([criteria.source_entry])[0]
|
|
100
|
+
if criteria.dashboard_guids:
|
|
101
|
+
entry_criteria.dashboard_guid_list = list(criteria.dashboard_guids)
|
|
102
|
+
|
|
103
|
+
step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
|
|
104
|
+
return step
|
|
105
|
+
|
|
106
|
+
def create_form_step(self, entry_name: str,
|
|
107
|
+
data_type: DataTypeIdentifier,
|
|
108
|
+
record: SapioRecord | None = None,
|
|
109
|
+
criteria: GlobalDtFormStepCreation = GlobalDtFormStepCreation(),
|
|
110
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
111
|
+
"""
|
|
112
|
+
Create a new form entry in the experiment.
|
|
113
|
+
|
|
114
|
+
:param entry_name: The name of the entry.
|
|
115
|
+
:param data_type: The data type of the entry.
|
|
116
|
+
:param record: The record to initially populate the entry with.
|
|
117
|
+
:param criteria: Additional criteria for creating the entry.
|
|
118
|
+
:param position: Information about where to place the entry in the experiment.
|
|
119
|
+
:return: The newly created form entry.
|
|
120
|
+
"""
|
|
121
|
+
if record:
|
|
122
|
+
rdt: str = AliasUtil.to_data_type_name(record)
|
|
123
|
+
sdt: str = AliasUtil.to_data_type_name(data_type)
|
|
124
|
+
if rdt != sdt:
|
|
125
|
+
raise SapioException(f"Cannot set {rdt} records for entry {entry_name} of type "
|
|
126
|
+
f"{sdt}.")
|
|
127
|
+
|
|
128
|
+
entry_criteria = cast(ElnFormEntryCriteria,
|
|
129
|
+
self._create_step_criteria(entry_name, data_type, criteria, position))
|
|
130
|
+
if record:
|
|
131
|
+
entry_criteria.record_id = AliasUtil.to_record_id(record)
|
|
132
|
+
if criteria:
|
|
133
|
+
entry_criteria.data_type_layout_name = criteria.layout_name
|
|
134
|
+
if entry_criteria.form_name_list:
|
|
135
|
+
entry_criteria.form_name_list = list(criteria.form_names)
|
|
136
|
+
if criteria.extension_types:
|
|
137
|
+
entry_criteria.extension_type_list = AliasUtil.to_data_type_names(criteria.extension_types)
|
|
138
|
+
if criteria.field_names:
|
|
139
|
+
entry_criteria.data_field_name_list = AliasUtil.to_data_field_names(criteria.field_names)
|
|
140
|
+
|
|
141
|
+
step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
|
|
142
|
+
return step
|
|
143
|
+
|
|
144
|
+
def create_experiment_detail_form_step(self, entry_name: str,
|
|
145
|
+
field_map: FieldMap | None = None,
|
|
146
|
+
criteria: ELnDtFormStepCreation = ELnDtFormStepCreation(),
|
|
147
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
148
|
+
"""
|
|
149
|
+
Create a new ELN experiment details form entry in the experiment.
|
|
150
|
+
|
|
151
|
+
:param entry_name: The name of the entry.
|
|
152
|
+
:param field_map: A field map that will be used to populate the entry. The data field names in
|
|
153
|
+
the map must match the field names of the provided field definitions.
|
|
154
|
+
:param criteria: Additional criteria for creating the entry.
|
|
155
|
+
:param position: Information about where to place the entry in the experiment.
|
|
156
|
+
:return: The newly created form entry.
|
|
157
|
+
"""
|
|
158
|
+
dt = ElnBaseDataType.EXPERIMENT_DETAIL
|
|
159
|
+
return self._create_eln_dt_form_step(entry_name, dt, field_map, criteria, position)
|
|
160
|
+
|
|
161
|
+
def create_sample_detail_form_step(self, entry_name: str,
|
|
162
|
+
field_map: FieldMap | None = None,
|
|
163
|
+
criteria: ELnDtFormStepCreation = ELnDtFormStepCreation(),
|
|
164
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
165
|
+
"""
|
|
166
|
+
Create a new ELN sample details form entry in the experiment.
|
|
167
|
+
|
|
168
|
+
:param entry_name: The name of the entry.
|
|
169
|
+
:param field_map: A field map that will be used to populate the entry. The data field names in
|
|
170
|
+
the map must match the field names of the provided field definitions.
|
|
171
|
+
:param criteria: Additional criteria for creating the entry.
|
|
172
|
+
:param position: Information about where to place the entry in the experiment.
|
|
173
|
+
:return: The newly created form entry.
|
|
174
|
+
"""
|
|
175
|
+
dt = ElnBaseDataType.SAMPLE_DETAIL
|
|
176
|
+
return self._create_eln_dt_form_step(entry_name, dt, field_map, criteria, position)
|
|
177
|
+
|
|
178
|
+
def _create_eln_dt_form_step(self, entry_name: str,
|
|
179
|
+
dt: ElnBaseDataType,
|
|
180
|
+
field_map: FieldMap | None = None,
|
|
181
|
+
criteria: ELnDtFormStepCreation = ELnDtFormStepCreation(),
|
|
182
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
183
|
+
entry_criteria = cast(ElnFormEntryCriteria,
|
|
184
|
+
self._create_step_criteria(entry_name, dt.data_type_name, criteria, position))
|
|
185
|
+
|
|
186
|
+
if field_map:
|
|
187
|
+
entry_criteria.field_map = field_map
|
|
188
|
+
if criteria:
|
|
189
|
+
entry_criteria.is_field_addable = criteria.is_field_addable
|
|
190
|
+
entry_criteria.is_existing_field_removable = criteria.is_existing_field_removable
|
|
191
|
+
if criteria.field_sets:
|
|
192
|
+
field_sets: set[int] = set()
|
|
193
|
+
for field_set in criteria.field_sets:
|
|
194
|
+
if isinstance(field_set, int):
|
|
195
|
+
field_sets.add(field_set)
|
|
196
|
+
elif isinstance(field_set, ElnFieldSetInfo):
|
|
197
|
+
field_sets.add(field_set.field_set_id)
|
|
198
|
+
elif isinstance(field_set, str):
|
|
199
|
+
field_sets.add(self._exp_cache.get_field_set(field_set).field_set_id)
|
|
200
|
+
entry_criteria.field_set_id_list = list(field_sets)
|
|
201
|
+
entry_criteria.field_definition_list = criteria.field_definitions
|
|
202
|
+
if criteria.predefined_field_names:
|
|
203
|
+
if entry_criteria.field_definition_list is None:
|
|
204
|
+
entry_criteria.field_definition_list = []
|
|
205
|
+
for field_name in criteria.predefined_field_names:
|
|
206
|
+
entry_criteria.field_definition_list.append(self._exp_cache.get_predefined_field(field_name, dt))
|
|
207
|
+
|
|
208
|
+
step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
|
|
209
|
+
return step
|
|
210
|
+
|
|
211
|
+
def create_plugin_step(self, entry_name: str,
|
|
212
|
+
data_type: DataTypeIdentifier,
|
|
213
|
+
criteria: PluginStepCreation | None,
|
|
214
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
215
|
+
"""
|
|
216
|
+
Create a new plugin entry in the experiment.
|
|
217
|
+
|
|
218
|
+
:param entry_name: The name of the entry.
|
|
219
|
+
:param data_type: The data type of the entry.
|
|
220
|
+
:param criteria: Additional criteria for creating the entry, such as plugin name and whether it provides
|
|
221
|
+
:param position: Information about where to place the entry in the experiment.
|
|
222
|
+
:return: The newly created plugin entry.
|
|
223
|
+
"""
|
|
224
|
+
entry_criteria = cast(ElnPluginEntryCriteria,
|
|
225
|
+
self._create_step_criteria(entry_name, data_type, criteria, position))
|
|
226
|
+
|
|
227
|
+
if criteria:
|
|
228
|
+
entry_criteria.csp_plugin_name = criteria.plugin_name
|
|
229
|
+
entry_criteria.using_template_data = criteria.using_template_data
|
|
230
|
+
entry_criteria.provides_template_data = criteria.provides_template_data
|
|
231
|
+
|
|
232
|
+
step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
|
|
233
|
+
return step
|
|
234
|
+
|
|
235
|
+
def create_table_step(self, entry_name: str, data_type: DataTypeIdentifier,
|
|
236
|
+
records: list[SapioRecord] | None = None,
|
|
237
|
+
criteria: GlobalDtTableStepCreation = GlobalDtTableStepCreation(),
|
|
238
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
239
|
+
"""
|
|
240
|
+
Create a new table entry in the experiment.
|
|
241
|
+
|
|
242
|
+
:param entry_name: The name of the entry.
|
|
243
|
+
:param data_type: The data type of the entry.
|
|
244
|
+
:param criteria: Additional criteria for creating the entry.
|
|
245
|
+
:param position: Information about where to place the entry in the experiment.
|
|
246
|
+
:param records: The list of records to initially populate the entry with.
|
|
247
|
+
:return: The newly created table entry.
|
|
248
|
+
"""
|
|
249
|
+
entry_criteria = cast(ElnTableEntryCriteria,
|
|
250
|
+
self._create_step_criteria(entry_name, data_type, criteria, position))
|
|
251
|
+
if criteria:
|
|
252
|
+
entry_criteria.data_type_layout_name = criteria.layout_name
|
|
253
|
+
entry_criteria.show_key_fields = criteria.show_key_fields
|
|
254
|
+
if criteria.extension_types:
|
|
255
|
+
entry_criteria.extension_type_list = list(criteria.extension_types)
|
|
256
|
+
if criteria.table_columns:
|
|
257
|
+
entry_criteria.table_column_list = list(criteria.table_columns)
|
|
258
|
+
if criteria.field_names:
|
|
259
|
+
if entry_criteria.table_column_list is None:
|
|
260
|
+
entry_criteria.table_column_list = []
|
|
261
|
+
for field in AliasUtil.to_data_field_names(criteria.field_names):
|
|
262
|
+
entry_criteria.table_column_list.append(TableColumn(data_type, field))
|
|
263
|
+
|
|
264
|
+
step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
|
|
265
|
+
if records:
|
|
266
|
+
self._exp_handler.set_step_records(step, records)
|
|
267
|
+
return step
|
|
268
|
+
|
|
269
|
+
def create_experiment_detail_table_step(self, entry_name: str,
|
|
270
|
+
field_maps: list[FieldMap] | None = None,
|
|
271
|
+
criteria: ELnDtTableStepCreation = ELnDtTableStepCreation(),
|
|
272
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
273
|
+
"""
|
|
274
|
+
Create a new ELN experiment details table entry in the experiment.
|
|
275
|
+
|
|
276
|
+
:param entry_name: The name of the entry.
|
|
277
|
+
:param field_maps: A field maps list that will be used to populate the entry. The data field names in
|
|
278
|
+
the maps must match the field names of the provided field definitions.
|
|
279
|
+
:param criteria: Additional criteria for creating the entry.
|
|
280
|
+
:param position: Information about where to place the entry in the experiment.
|
|
281
|
+
:return: The newly created table entry.
|
|
282
|
+
"""
|
|
283
|
+
dt = ElnBaseDataType.EXPERIMENT_DETAIL
|
|
284
|
+
return self._create_eln_dt_table_step(entry_name, dt, field_maps, criteria, position)
|
|
285
|
+
|
|
286
|
+
def create_sample_detail_table_step(self, entry_name: str,
|
|
287
|
+
field_maps: list[FieldMap] | None = None,
|
|
288
|
+
criteria: ELnDtTableStepCreation = ELnDtTableStepCreation(),
|
|
289
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
290
|
+
"""
|
|
291
|
+
Create a new ELN sample details table entry in the experiment.
|
|
292
|
+
|
|
293
|
+
:param entry_name: The name of the entry.
|
|
294
|
+
:param field_maps: A field maps list that will be used to populate the entry. The data field names in
|
|
295
|
+
the maps must match the field names of the provided field definitions.
|
|
296
|
+
:param criteria: Additional criteria for creating the entry.
|
|
297
|
+
:param position: Information about where to place the entry in the experiment.
|
|
298
|
+
:return: The newly created table entry.
|
|
299
|
+
"""
|
|
300
|
+
dt = ElnBaseDataType.SAMPLE_DETAIL
|
|
301
|
+
return self._create_eln_dt_table_step(entry_name, dt, field_maps, criteria, position)
|
|
302
|
+
|
|
303
|
+
def _create_eln_dt_table_step(self, entry_name: str,
|
|
304
|
+
dt: ElnBaseDataType,
|
|
305
|
+
field_maps: list[FieldMap] | None = None,
|
|
306
|
+
criteria: ELnDtTableStepCreation = ELnDtTableStepCreation(),
|
|
307
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
308
|
+
entry_criteria = cast(ElnTableEntryCriteria,
|
|
309
|
+
self._create_step_criteria(entry_name, dt.data_type_name, criteria, position))
|
|
310
|
+
|
|
311
|
+
if field_maps:
|
|
312
|
+
entry_criteria.field_map_list = field_maps
|
|
313
|
+
if criteria:
|
|
314
|
+
entry_criteria.is_field_addable = criteria.is_field_addable
|
|
315
|
+
entry_criteria.is_existing_field_removable = criteria.is_existing_field_removable
|
|
316
|
+
if criteria.field_sets:
|
|
317
|
+
field_sets: set[int] = set()
|
|
318
|
+
for field_set in criteria.field_sets:
|
|
319
|
+
if isinstance(field_set, int):
|
|
320
|
+
field_sets.add(field_set)
|
|
321
|
+
elif isinstance(field_set, ElnFieldSetInfo):
|
|
322
|
+
field_sets.add(field_set.field_set_id)
|
|
323
|
+
elif isinstance(field_set, str):
|
|
324
|
+
field_sets.add(self._exp_cache.get_field_set(field_set).field_set_id)
|
|
325
|
+
entry_criteria.field_set_id_list = list(field_sets)
|
|
326
|
+
entry_criteria.field_definition_list = list(criteria.field_definitions)
|
|
327
|
+
if criteria.predefined_field_names:
|
|
328
|
+
if entry_criteria.field_definition_list is None:
|
|
329
|
+
entry_criteria.field_definition_list = []
|
|
330
|
+
for field_name in criteria.predefined_field_names:
|
|
331
|
+
entry_criteria.field_definition_list.append(self._exp_cache.get_predefined_field(field_name, dt))
|
|
332
|
+
if criteria.table_columns:
|
|
333
|
+
entry_criteria.table_column_list = list(criteria.table_columns)
|
|
334
|
+
|
|
335
|
+
step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
|
|
336
|
+
return step
|
|
337
|
+
|
|
338
|
+
def create_temp_data_step(self, entry_name: str,
|
|
339
|
+
data_type: DataTypeIdentifier,
|
|
340
|
+
criteria: TempDataStepCreation = TempDataStepCreation(),
|
|
341
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
342
|
+
"""
|
|
343
|
+
Create a new temp data entry in the experiment.
|
|
344
|
+
|
|
345
|
+
:param entry_name: The name of the entry.
|
|
346
|
+
:param data_type: The data type of the entry.
|
|
347
|
+
:param criteria: Additional criteria for creating the entry.
|
|
348
|
+
:param position: Information about where to place the entry in the experiment.
|
|
349
|
+
:return: The newly created temp data entry.
|
|
350
|
+
"""
|
|
351
|
+
entry_criteria = cast(ElnTempDataEntryCriteria,
|
|
352
|
+
self._create_step_criteria(entry_name, data_type, criteria, position))
|
|
353
|
+
|
|
354
|
+
if criteria:
|
|
355
|
+
entry_criteria.temp_data_plugin_path = criteria.plugin_path
|
|
356
|
+
|
|
357
|
+
step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
|
|
358
|
+
return step
|
|
359
|
+
|
|
360
|
+
def create_text_step(self, entry_name: str,
|
|
361
|
+
text: str | None = None,
|
|
362
|
+
criteria: TextStepCreation = TextStepCreation(),
|
|
363
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
364
|
+
"""
|
|
365
|
+
Create a new text entry in the experiment.
|
|
366
|
+
|
|
367
|
+
:param entry_name: The name of the entry.
|
|
368
|
+
:param text: The text to populate the entry with.
|
|
369
|
+
:param criteria: Additional criteria for creating the entry.
|
|
370
|
+
:param position: Information about where to place the entry in the experiment.
|
|
371
|
+
:return: The newly created text entry.
|
|
372
|
+
"""
|
|
373
|
+
dt = ElnBaseDataType.TEXT_ENTRY_DETAIL.data_type_name
|
|
374
|
+
entry_criteria = cast(ElnTextEntryCriteria,
|
|
375
|
+
self._create_step_criteria(entry_name, dt, criteria, position))
|
|
376
|
+
|
|
377
|
+
step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
|
|
378
|
+
|
|
379
|
+
if text:
|
|
380
|
+
text_record: DataRecord = step.get_records()[0]
|
|
381
|
+
text_record.set_field_value(ElnBaseDataType.get_text_entry_data_field_name(), text)
|
|
382
|
+
DataRecordManager(self.user).commit_data_records([text_record])
|
|
383
|
+
|
|
384
|
+
return step
|
|
385
|
+
|
|
386
|
+
def create_plate_designer_step(self, entry_name: str,
|
|
387
|
+
source_entry: Step | None = None,
|
|
388
|
+
criteria: PluginStepCreation = PluginStepCreation(),
|
|
389
|
+
position: ElnEntryPosition | None = None) -> ElnEntryStep:
|
|
390
|
+
"""
|
|
391
|
+
Create a new 3D plate designer entry in the experiment.
|
|
392
|
+
|
|
393
|
+
:param entry_name: The name of the entry.
|
|
394
|
+
:param source_entry: The entry that the plate designer will source its samples from.
|
|
395
|
+
:param criteria: Additional criteria for creating the entry.
|
|
396
|
+
:param position: Information about where to place the entry in the experiment.
|
|
397
|
+
:return: The newly created plate designer entry.
|
|
398
|
+
"""
|
|
399
|
+
criteria.plugin_name = PLATE_DESIGNER_PLUGIN
|
|
400
|
+
if criteria.entry_height is None:
|
|
401
|
+
criteria.entry_height = 600
|
|
402
|
+
if source_entry is not None:
|
|
403
|
+
criteria.related_entry_set = [source_entry]
|
|
404
|
+
default_layer = MultiLayerPlateLayer(
|
|
405
|
+
MultiLayerDataTypeConfig("Sample"),
|
|
406
|
+
PlatingOrder.FillBy.BY_COLUMN,
|
|
407
|
+
MultiLayerReplicateConfig(),
|
|
408
|
+
MultiLayerDilutionConfig()
|
|
409
|
+
)
|
|
410
|
+
initial_step_options: dict[str, str] = {
|
|
411
|
+
"MultiLayerPlating_Plate_RecordIdList": "",
|
|
412
|
+
"MultiLayerPlating_Entry_Prefs": MultiLayerPlatingManager.get_entry_prefs_json([default_layer]),
|
|
413
|
+
"MultiLayerPlating_Entry_PrePlating_Prefs": MultiLayerPlatingManager.get_plate_configs_json(MultiLayerPlateConfig())
|
|
414
|
+
}
|
|
415
|
+
if criteria.entry_options is None:
|
|
416
|
+
criteria.entry_options = initial_step_options
|
|
417
|
+
else:
|
|
418
|
+
criteria.entry_options.update(initial_step_options)
|
|
419
|
+
return self.create_plugin_step(entry_name, "Sample", criteria, position)
|
|
420
|
+
|
|
421
|
+
def _create_step_criteria(self, name: str, dt: DataTypeIdentifier,
|
|
422
|
+
criteria: StepCreation, position: ElnEntryPosition | None) \
|
|
423
|
+
-> AbstractElnEntryCriteria:
|
|
424
|
+
"""
|
|
425
|
+
Create the criteria for a new entry in the experiment of the given type.
|
|
426
|
+
"""
|
|
427
|
+
if position is not None:
|
|
428
|
+
order: int = position.order
|
|
429
|
+
tab_id: int = position.tab_id
|
|
430
|
+
column_order: int = position.column_order
|
|
431
|
+
column_span: int = position.column_span
|
|
432
|
+
else:
|
|
433
|
+
last_tab: ElnExperimentTab = self._exp_handler.get_last_tab()
|
|
434
|
+
order: int = self._exp_handler.get_next_entry_order_in_tab(last_tab)
|
|
435
|
+
tab_id: int = last_tab.tab_id
|
|
436
|
+
column_order: int = 0
|
|
437
|
+
column_span: int = last_tab.max_number_of_columns
|
|
438
|
+
|
|
439
|
+
dt: str = AliasUtil.to_data_type_name(dt)
|
|
440
|
+
et = criteria.entry_type
|
|
441
|
+
entry_criteria = ExperimentEntryCriteriaUtil.get_entry_creation_criteria(et, name, dt, order)
|
|
442
|
+
entry_criteria.notebook_experiment_tab_id = tab_id
|
|
443
|
+
entry_criteria.column_order = column_order
|
|
444
|
+
entry_criteria.column_span = column_span
|
|
445
|
+
if criteria:
|
|
446
|
+
entry_criteria.is_shown_in_template = criteria.is_shown_in_template
|
|
447
|
+
entry_criteria.is_removable = criteria.is_removable
|
|
448
|
+
entry_criteria.is_renamable = criteria.is_renamable
|
|
449
|
+
entry_criteria.is_static_view = criteria.is_static_view
|
|
450
|
+
if criteria.related_entry_set:
|
|
451
|
+
entry_criteria.related_entry_set = self.__to_entry_ids(criteria.related_entry_set)
|
|
452
|
+
if criteria.dependency_set:
|
|
453
|
+
entry_criteria.dependency_set = self.__to_entry_ids(criteria.dependency_set)
|
|
454
|
+
entry_criteria.requires_grabber_plugin = criteria.requires_grabber_plugin
|
|
455
|
+
entry_criteria.entry_singleton_id = criteria.entry_singleton_id
|
|
456
|
+
entry_criteria.is_hidden = criteria.is_hidden
|
|
457
|
+
entry_criteria.entry_height = criteria.entry_height
|
|
458
|
+
entry_criteria.description = criteria.description
|
|
459
|
+
entry_criteria.is_initialization_required = criteria.is_initialization_required
|
|
460
|
+
entry_criteria.collapse_entry = criteria.collapse_entry
|
|
461
|
+
entry_criteria.entry_status = criteria.entry_status
|
|
462
|
+
entry_criteria.template_item_fulfilled_timestamp = criteria.template_item_fulfilled_timestamp
|
|
463
|
+
entry_criteria.entry_options = criteria.entry_options
|
|
464
|
+
|
|
465
|
+
return entry_criteria
|
|
466
|
+
|
|
467
|
+
def __to_entry_ids(self, entries: Iterable[ExperimentEntryIdentifier | str]) -> list[int] | None:
|
|
468
|
+
entry_ids: set[int] = set()
|
|
469
|
+
for entry in entries:
|
|
470
|
+
if isinstance(entry, str):
|
|
471
|
+
entry_ids.add(self._exp_handler.get_step(entry).get_id())
|
|
472
|
+
else:
|
|
473
|
+
entry_ids.add(AliasUtil.to_entry_id(entry))
|
|
474
|
+
return list(entry_ids)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# CSP paths:
|
|
2
|
+
PLATE_DESIGNER_PLUGIN: str = "com.velox.gwt.client.plugins.multilayerplating.core.ElnMultiLayerPlatingClientPlugin"
|
|
3
|
+
|
|
4
|
+
# 3D Plate Designer entry tags:
|
|
5
|
+
PLATE_IDS_TAG: str = "MultiLayerPlating_Plate_RecordIdList"
|
|
6
|
+
PLATE_CONFIG_PREFS_TAG: str = "MultiLayerPlating_Entry_PrePlating_Prefs"
|
|
7
|
+
PLATE_LAYER_PREFS_TAG: str = "MultiLayerPlating_Entry_Prefs"
|