sapiopycommons 2025.7.15a611__py3-none-any.whl → 2025.7.18a614__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 (60) hide show
  1. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.py +43 -0
  2. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.pyi +31 -0
  3. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2_grpc.py +24 -0
  4. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.py +123 -0
  5. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.pyi +598 -0
  6. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2_grpc.py +24 -0
  7. sapiopycommons/ai/api/plan/proto/step_output_pb2.py +45 -0
  8. sapiopycommons/ai/api/plan/proto/step_output_pb2.pyi +42 -0
  9. sapiopycommons/ai/api/plan/proto/step_output_pb2_grpc.py +24 -0
  10. sapiopycommons/ai/api/plan/proto/step_pb2.py +43 -0
  11. sapiopycommons/ai/api/plan/proto/step_pb2.pyi +43 -0
  12. sapiopycommons/ai/api/plan/proto/step_pb2_grpc.py +24 -0
  13. sapiopycommons/ai/api/plan/script/proto/script_pb2.py +55 -0
  14. sapiopycommons/ai/api/plan/script/proto/script_pb2.pyi +115 -0
  15. sapiopycommons/ai/api/plan/script/proto/script_pb2_grpc.py +153 -0
  16. sapiopycommons/ai/api/plan/tool/proto/entry_pb2.py +57 -0
  17. sapiopycommons/ai/api/plan/tool/proto/entry_pb2.pyi +96 -0
  18. sapiopycommons/ai/api/plan/tool/proto/entry_pb2_grpc.py +24 -0
  19. sapiopycommons/ai/api/plan/tool/proto/tool_pb2.py +69 -0
  20. sapiopycommons/ai/api/plan/tool/proto/tool_pb2.pyi +232 -0
  21. sapiopycommons/ai/api/plan/tool/proto/tool_pb2_grpc.py +154 -0
  22. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.py +39 -0
  23. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.pyi +32 -0
  24. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2_grpc.py +24 -0
  25. sapiopycommons/ai/protobuf_utils.py +508 -0
  26. sapiopycommons/ai/test_client.py +251 -0
  27. sapiopycommons/ai/tool_service_base.py +826 -0
  28. sapiopycommons/callbacks/callback_util.py +343 -683
  29. sapiopycommons/callbacks/field_builder.py +0 -2
  30. sapiopycommons/chem/IndigoMolecules.py +1 -29
  31. sapiopycommons/chem/Molecules.py +3 -3
  32. sapiopycommons/customreport/auto_pagers.py +1 -26
  33. sapiopycommons/customreport/term_builder.py +1 -1
  34. sapiopycommons/datatype/pseudo_data_types.py +326 -349
  35. sapiopycommons/eln/experiment_handler.py +767 -408
  36. sapiopycommons/eln/experiment_report_util.py +6 -11
  37. sapiopycommons/eln/plate_designer.py +2 -7
  38. sapiopycommons/files/file_util.py +5 -7
  39. sapiopycommons/general/accession_service.py +2 -2
  40. sapiopycommons/general/aliases.py +1 -3
  41. sapiopycommons/general/audit_log.py +0 -7
  42. sapiopycommons/general/custom_report_util.py +0 -12
  43. sapiopycommons/processtracking/custom_workflow_handler.py +1 -11
  44. sapiopycommons/processtracking/endpoints.py +0 -27
  45. sapiopycommons/recordmodel/record_handler.py +391 -785
  46. sapiopycommons/rules/eln_rule_handler.py +1 -8
  47. sapiopycommons/rules/on_save_rule_handler.py +1 -8
  48. sapiopycommons/webhook/webhook_handlers.py +4 -9
  49. sapiopycommons/webhook/webservice_handlers.py +2 -2
  50. {sapiopycommons-2025.7.15a611.dist-info → sapiopycommons-2025.7.18a614.dist-info}/METADATA +2 -2
  51. sapiopycommons-2025.7.18a614.dist-info/RECORD +92 -0
  52. sapiopycommons/ai/tool_of_tools.py +0 -917
  53. sapiopycommons/eln/experiment_cache.py +0 -188
  54. sapiopycommons/eln/experiment_step_factory.py +0 -476
  55. sapiopycommons/eln/step_creation.py +0 -236
  56. sapiopycommons/files/file_text_converter.py +0 -207
  57. sapiopycommons/general/data_structure_util.py +0 -115
  58. sapiopycommons-2025.7.15a611.dist-info/RECORD +0 -71
  59. {sapiopycommons-2025.7.15a611.dist-info → sapiopycommons-2025.7.18a614.dist-info}/WHEEL +0 -0
  60. {sapiopycommons-2025.7.15a611.dist-info → sapiopycommons-2025.7.18a614.dist-info}/licenses/LICENSE +0 -0
@@ -1,188 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from weakref import WeakValueDictionary
4
-
5
- from sapiopylib.rest.ELNService import ElnManager
6
- from sapiopylib.rest.User import SapioUser
7
- from sapiopylib.rest.pojo.datatype.FieldDefinition import AbstractVeloxFieldDefinition
8
- from sapiopylib.rest.pojo.eln.ElnExperiment import ElnTemplate, TemplateExperimentQuery
9
- from sapiopylib.rest.pojo.eln.SapioELNEnums import ElnBaseDataType
10
- from sapiopylib.rest.pojo.eln.field_set import ElnFieldSetInfo
11
- from sapiopylib.rest.pojo.eln.protocol_template import ProtocolTemplateInfo, ProtocolTemplateQuery
12
-
13
- from sapiopycommons.general.aliases import UserIdentifier, AliasUtil
14
- from sapiopycommons.general.exceptions import SapioException
15
-
16
-
17
- # FR-47530: Created a class that caches experiment template and predefined field information.
18
- class ExperimentCacheManager:
19
- """
20
- A class to manage the caching of experiment-related information.
21
- """
22
- user: SapioUser
23
- eln_man: ElnManager
24
-
25
- _templates: list[ElnTemplate]
26
- """A list of experiment templates. Only cached when first accessed."""
27
- _protocols: list[ProtocolTemplateInfo]
28
- """A list of protocol templates. Only cached when first accessed."""
29
- _field_sets: dict[str, ElnFieldSetInfo]
30
- """A dictionary of field set name to field set. Only cached when first accessed."""
31
- _field_set_fields: dict[int, list[AbstractVeloxFieldDefinition]]
32
- """A dictionary of field set ID to field definitions. Only cached when first accessed."""
33
- _predefined_fields: dict[str, dict[str, AbstractVeloxFieldDefinition]]
34
- """A dictionary of ELN data type name to predefined field definitions. Only cached when first accessed."""
35
-
36
- __instances: WeakValueDictionary[SapioUser, ExperimentCacheManager] = WeakValueDictionary()
37
- __initialized: bool
38
-
39
- def __new__(cls, context: UserIdentifier):
40
- """
41
- :param context: The current webhook context or a user object to send requests from.
42
- """
43
- user = AliasUtil.to_sapio_user(context)
44
- obj = cls.__instances.get(user)
45
- if not obj:
46
- obj = object.__new__(cls)
47
- obj.__initialized = False
48
- cls.__instances[user] = obj
49
- return obj
50
-
51
- def __init__(self, context: UserIdentifier):
52
- """
53
- :param context: The current webhook context or a user object to send requests from.
54
- """
55
- if self.__initialized:
56
- return
57
- self.__initialized = True
58
-
59
- self.user = AliasUtil.to_sapio_user(context)
60
- self.eln_man = ElnManager(self.user)
61
-
62
- self._field_set_fields = {}
63
- self._predefined_fields = {}
64
-
65
- def get_experiment_template(self, name: str, active: bool = True, version: int | None = None,
66
- first_match: bool = False, public: bool | None = True) -> ElnTemplate:
67
- """
68
- Get the experiment template with the given information.
69
-
70
- :param name: The name of the template.
71
- :param active: Whether the template is marked as active.
72
- :param version: The version of the template to get. If None, the latest version will be returned.
73
- :param first_match: If true, returns the first match found. If false, raises an exception.
74
- :param public: Whether the template is public. If true, only pubic templates will be queried. If false, only
75
- private templates will be queried. If None, both public and private templates will be queried. Non-public
76
- templates do not have a version number, so this will always fail if public is false and a version number is
77
- provided.
78
- :return: The experiment template with the given information.
79
- """
80
- if not hasattr(self, "_templates"):
81
- query = TemplateExperimentQuery()
82
- query.active_templates_only = False
83
- query.latest_version_only = False
84
- self._templates = self.eln_man.get_template_experiment_list(query)
85
- return self._find_template(self._templates, name, active, version, first_match, public)
86
-
87
-
88
- def get_protocol_template(self, name: str, active: bool = True, version: int | None = None,
89
- first_match: bool = False, public: bool | None = True) -> ProtocolTemplateInfo:
90
- """
91
- Get the protocol template with the given information. Will throw an exception if multiple templates match
92
- the given information.
93
-
94
- :param name: The name of the template.
95
- :param active: Whether the template is marked as active.
96
- :param version: The version of the template to get. If None, the latest version will be returned.
97
- :param first_match: If true, returns the first match found. If false, raises an exception.
98
- :param public: Whether the template is public. If true, only pubic templates will be queried. If false, only
99
- private templates will be queried. If None, both public and private templates will be queried. Non-public
100
- templates do not have a version number, so this will always fail if public is false and a version number is
101
- provided.
102
- :return: The protocol template with the given information.
103
- """
104
- if not hasattr(self, "_protocols"):
105
- query = ProtocolTemplateQuery()
106
- query.active_templates_only = False
107
- query.latest_version_only = False
108
- self._protocols = self.eln_man.get_protocol_template_info_list(query)
109
- return self._find_template(self._protocols, name, active, version, first_match, public)
110
-
111
- @staticmethod
112
- def _find_template(templates: list[ElnTemplate] | list[ProtocolTemplateInfo], name: str, active: bool,
113
- version: int, first_match: bool, public: bool | None) -> ElnTemplate | ProtocolTemplateInfo:
114
- """
115
- Find the experiment or protocol template with the given information.
116
- """
117
- matches = []
118
- for template in templates:
119
- if template.template_name != name:
120
- continue
121
- if template.active != active:
122
- continue
123
- if version is not None and template.template_version != version:
124
- continue
125
- if public is True and template.template_version is None:
126
- continue
127
- if public is False and template.template_version is not None:
128
- continue
129
- matches.append(template)
130
- if not matches:
131
- raise SapioException(f"No template with the name \"{name}\"" +
132
- ("" if version is None else f" and the version {version}") +
133
- f" found.")
134
- # Only filter for the max version number if any of the matches actually have a version number.
135
- versioned_matches = [x for x in matches if x.template_version is not None]
136
- if version is None and versioned_matches:
137
- return max(versioned_matches, key=lambda x: x.template_version)
138
- if len(matches) > 1 and not first_match:
139
- raise SapioException(f"Multiple templates with the name \"{name}\" found. Consider setting first_match to "
140
- f"true, or restrict your search criteria further.")
141
- return matches[0]
142
-
143
- def get_predefined_field(self, field_name: str, data_type: ElnBaseDataType) -> AbstractVeloxFieldDefinition:
144
- """
145
- Get the predefined field of the given name for the given ELN data type.
146
-
147
- :param field_name: The name of the field.
148
- :param data_type: The ELN data type of the field.
149
- :return: The predefined field of the given name for the given ELN data type.
150
- """
151
- return self.get_predefined_fields(data_type)[field_name]
152
-
153
- def get_predefined_fields(self, data_type: ElnBaseDataType) -> dict[str, AbstractVeloxFieldDefinition]:
154
- """
155
- Get the predefined fields for the given ELN data type.
156
-
157
- :param data_type: The ELN data type to get the predefined fields for.
158
- :return: A dictionary of field name to field definition for the given ELN data type.
159
- """
160
- if data_type.data_type_name not in self._predefined_fields:
161
- fields: list[AbstractVeloxFieldDefinition] = self.eln_man.get_predefined_fields(data_type)
162
- self._predefined_fields[data_type.data_type_name] = {x.data_field_name: x for x in fields}
163
- return self._predefined_fields[data_type.data_type_name]
164
-
165
- def get_field_set(self, name: str) -> ElnFieldSetInfo:
166
- """
167
- Get the field set with the given name.
168
-
169
- :param name: The name of the field set.
170
- :return: The field set with the given name.
171
- """
172
- if not hasattr(self, "_field_sets"):
173
- self._field_sets = {x.field_set_name: x for x in self.eln_man.get_field_set_info_list()}
174
- return self._field_sets[name]
175
-
176
- def get_field_set_fields(self, field_set: ElnFieldSetInfo | int) -> list[AbstractVeloxFieldDefinition]:
177
- """
178
- Get the fields of the given field set.
179
-
180
- :param field_set: The field set to get the fields from. Can be either an ElnFieldSetInfo object or an integer
181
- for the set ID.
182
- :return: The fields of the given field set.
183
- """
184
- field_set: int = field_set if isinstance(field_set, int) else field_set.field_set_id
185
- if field_set in self._field_set_fields:
186
- return self._field_set_fields[field_set]
187
- self._field_set_fields[field_set] = self.eln_man.get_predefined_fields_from_field_set_id(field_set)
188
- return self._field_set_fields[field_set]
@@ -1,476 +0,0 @@
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
- if criteria.field_definitions:
202
- entry_criteria.field_definition_list = list(criteria.field_definitions)
203
- if criteria.predefined_field_names:
204
- if entry_criteria.field_definition_list is None:
205
- entry_criteria.field_definition_list = []
206
- for field_name in criteria.predefined_field_names:
207
- entry_criteria.field_definition_list.append(self._exp_cache.get_predefined_field(field_name, dt))
208
-
209
- step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
210
- return step
211
-
212
- def create_plugin_step(self, entry_name: str,
213
- data_type: DataTypeIdentifier,
214
- criteria: PluginStepCreation | None,
215
- position: ElnEntryPosition | None = None) -> ElnEntryStep:
216
- """
217
- Create a new plugin entry in the experiment.
218
-
219
- :param entry_name: The name of the entry.
220
- :param data_type: The data type of the entry.
221
- :param criteria: Additional criteria for creating the entry, such as plugin name and whether it provides
222
- :param position: Information about where to place the entry in the experiment.
223
- :return: The newly created plugin entry.
224
- """
225
- entry_criteria = cast(ElnPluginEntryCriteria,
226
- self._create_step_criteria(entry_name, data_type, criteria, position))
227
-
228
- if criteria:
229
- entry_criteria.csp_plugin_name = criteria.plugin_name
230
- entry_criteria.using_template_data = criteria.using_template_data
231
- entry_criteria.provides_template_data = criteria.provides_template_data
232
-
233
- step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
234
- return step
235
-
236
- def create_table_step(self, entry_name: str, data_type: DataTypeIdentifier,
237
- records: list[SapioRecord] | None = None,
238
- criteria: GlobalDtTableStepCreation = GlobalDtTableStepCreation(),
239
- position: ElnEntryPosition | None = None) -> ElnEntryStep:
240
- """
241
- Create a new table entry in the experiment.
242
-
243
- :param entry_name: The name of the entry.
244
- :param data_type: The data type of the entry.
245
- :param criteria: Additional criteria for creating the entry.
246
- :param position: Information about where to place the entry in the experiment.
247
- :param records: The list of records to initially populate the entry with.
248
- :return: The newly created table entry.
249
- """
250
- entry_criteria = cast(ElnTableEntryCriteria,
251
- self._create_step_criteria(entry_name, data_type, criteria, position))
252
- if criteria:
253
- entry_criteria.data_type_layout_name = criteria.layout_name
254
- entry_criteria.show_key_fields = criteria.show_key_fields
255
- if criteria.extension_types:
256
- entry_criteria.extension_type_list = list(criteria.extension_types)
257
- if criteria.table_columns:
258
- entry_criteria.table_column_list = list(criteria.table_columns)
259
- if criteria.field_names:
260
- if entry_criteria.table_column_list is None:
261
- entry_criteria.table_column_list = []
262
- for field in AliasUtil.to_data_field_names(criteria.field_names):
263
- entry_criteria.table_column_list.append(TableColumn(data_type, field))
264
-
265
- step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
266
- if records:
267
- self._exp_handler.set_step_records(step, records)
268
- return step
269
-
270
- def create_experiment_detail_table_step(self, entry_name: str,
271
- field_maps: list[FieldMap] | None = None,
272
- criteria: ELnDtTableStepCreation = ELnDtTableStepCreation(),
273
- position: ElnEntryPosition | None = None) -> ElnEntryStep:
274
- """
275
- Create a new ELN experiment details table entry in the experiment.
276
-
277
- :param entry_name: The name of the entry.
278
- :param field_maps: A field maps list that will be used to populate the entry. The data field names in
279
- the maps must match the field names of the provided field definitions.
280
- :param criteria: Additional criteria for creating the entry.
281
- :param position: Information about where to place the entry in the experiment.
282
- :return: The newly created table entry.
283
- """
284
- dt = ElnBaseDataType.EXPERIMENT_DETAIL
285
- return self._create_eln_dt_table_step(entry_name, dt, field_maps, criteria, position)
286
-
287
- def create_sample_detail_table_step(self, entry_name: str,
288
- field_maps: list[FieldMap] | None = None,
289
- criteria: ELnDtTableStepCreation = ELnDtTableStepCreation(),
290
- position: ElnEntryPosition | None = None) -> ElnEntryStep:
291
- """
292
- Create a new ELN sample details table entry in the experiment.
293
-
294
- :param entry_name: The name of the entry.
295
- :param field_maps: A field maps list that will be used to populate the entry. The data field names in
296
- the maps must match the field names of the provided field definitions.
297
- :param criteria: Additional criteria for creating the entry.
298
- :param position: Information about where to place the entry in the experiment.
299
- :return: The newly created table entry.
300
- """
301
- dt = ElnBaseDataType.SAMPLE_DETAIL
302
- return self._create_eln_dt_table_step(entry_name, dt, field_maps, criteria, position)
303
-
304
- def _create_eln_dt_table_step(self, entry_name: str,
305
- dt: ElnBaseDataType,
306
- field_maps: list[FieldMap] | None = None,
307
- criteria: ELnDtTableStepCreation = ELnDtTableStepCreation(),
308
- position: ElnEntryPosition | None = None) -> ElnEntryStep:
309
- entry_criteria = cast(ElnTableEntryCriteria,
310
- self._create_step_criteria(entry_name, dt.data_type_name, criteria, position))
311
-
312
- if field_maps:
313
- entry_criteria.field_map_list = field_maps
314
- if criteria:
315
- entry_criteria.is_field_addable = criteria.is_field_addable
316
- entry_criteria.is_existing_field_removable = criteria.is_existing_field_removable
317
- if criteria.field_sets:
318
- field_sets: set[int] = set()
319
- for field_set in criteria.field_sets:
320
- if isinstance(field_set, int):
321
- field_sets.add(field_set)
322
- elif isinstance(field_set, ElnFieldSetInfo):
323
- field_sets.add(field_set.field_set_id)
324
- elif isinstance(field_set, str):
325
- field_sets.add(self._exp_cache.get_field_set(field_set).field_set_id)
326
- entry_criteria.field_set_id_list = list(field_sets)
327
- if criteria.field_definitions:
328
- entry_criteria.field_definition_list = list(criteria.field_definitions)
329
- if criteria.predefined_field_names:
330
- if entry_criteria.field_definition_list is None:
331
- entry_criteria.field_definition_list = []
332
- for field_name in criteria.predefined_field_names:
333
- entry_criteria.field_definition_list.append(self._exp_cache.get_predefined_field(field_name, dt))
334
- if criteria.table_columns:
335
- entry_criteria.table_column_list = list(criteria.table_columns)
336
-
337
- step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
338
- return step
339
-
340
- def create_temp_data_step(self, entry_name: str,
341
- data_type: DataTypeIdentifier,
342
- criteria: TempDataStepCreation = TempDataStepCreation(),
343
- position: ElnEntryPosition | None = None) -> ElnEntryStep:
344
- """
345
- Create a new temp data entry in the experiment.
346
-
347
- :param entry_name: The name of the entry.
348
- :param data_type: The data type of the entry.
349
- :param criteria: Additional criteria for creating the entry.
350
- :param position: Information about where to place the entry in the experiment.
351
- :return: The newly created temp data entry.
352
- """
353
- entry_criteria = cast(ElnTempDataEntryCriteria,
354
- self._create_step_criteria(entry_name, data_type, criteria, position))
355
-
356
- if criteria:
357
- entry_criteria.temp_data_plugin_path = criteria.plugin_path
358
-
359
- step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
360
- return step
361
-
362
- def create_text_step(self, entry_name: str,
363
- text: str | None = None,
364
- criteria: TextStepCreation = TextStepCreation(),
365
- position: ElnEntryPosition | None = None) -> ElnEntryStep:
366
- """
367
- Create a new text entry in the experiment.
368
-
369
- :param entry_name: The name of the entry.
370
- :param text: The text to populate the entry with.
371
- :param criteria: Additional criteria for creating the entry.
372
- :param position: Information about where to place the entry in the experiment.
373
- :return: The newly created text entry.
374
- """
375
- dt = ElnBaseDataType.TEXT_ENTRY_DETAIL.data_type_name
376
- entry_criteria = cast(ElnTextEntryCriteria,
377
- self._create_step_criteria(entry_name, dt, criteria, position))
378
-
379
- step = self._exp_handler.add_entry_to_caches(self._eln_man.add_experiment_entry(self._exp_id, entry_criteria))
380
-
381
- if text:
382
- text_record: DataRecord = step.get_records()[0]
383
- text_record.set_field_value(ElnBaseDataType.get_text_entry_data_field_name(), text)
384
- DataRecordManager(self.user).commit_data_records([text_record])
385
-
386
- return step
387
-
388
- def create_plate_designer_step(self, entry_name: str,
389
- source_entry: Step | None = None,
390
- criteria: PluginStepCreation = PluginStepCreation(),
391
- position: ElnEntryPosition | None = None) -> ElnEntryStep:
392
- """
393
- Create a new 3D plate designer entry in the experiment.
394
-
395
- :param entry_name: The name of the entry.
396
- :param source_entry: The entry that the plate designer will source its samples from.
397
- :param criteria: Additional criteria for creating the entry.
398
- :param position: Information about where to place the entry in the experiment.
399
- :return: The newly created plate designer entry.
400
- """
401
- criteria.plugin_name = PLATE_DESIGNER_PLUGIN
402
- if criteria.entry_height is None:
403
- criteria.entry_height = 600
404
- if source_entry is not None:
405
- criteria.related_entry_set = [source_entry]
406
- default_layer = MultiLayerPlateLayer(
407
- MultiLayerDataTypeConfig("Sample"),
408
- PlatingOrder.FillBy.BY_COLUMN,
409
- MultiLayerReplicateConfig(),
410
- MultiLayerDilutionConfig()
411
- )
412
- initial_step_options: dict[str, str] = {
413
- "MultiLayerPlating_Plate_RecordIdList": "",
414
- "MultiLayerPlating_Entry_Prefs": MultiLayerPlatingManager.get_entry_prefs_json([default_layer]),
415
- "MultiLayerPlating_Entry_PrePlating_Prefs": MultiLayerPlatingManager.get_plate_configs_json(MultiLayerPlateConfig())
416
- }
417
- if criteria.entry_options is None:
418
- criteria.entry_options = initial_step_options
419
- else:
420
- criteria.entry_options.update(initial_step_options)
421
- return self.create_plugin_step(entry_name, "Sample", criteria, position)
422
-
423
- def _create_step_criteria(self, name: str, dt: DataTypeIdentifier,
424
- criteria: StepCreation, position: ElnEntryPosition | None) \
425
- -> AbstractElnEntryCriteria:
426
- """
427
- Create the criteria for a new entry in the experiment of the given type.
428
- """
429
- if position is not None:
430
- order: int = position.order
431
- tab_id: int = position.tab_id
432
- column_order: int = position.column_order
433
- column_span: int = position.column_span
434
- else:
435
- last_tab: ElnExperimentTab = self._exp_handler.get_last_tab()
436
- order: int = self._exp_handler.get_next_entry_order_in_tab(last_tab)
437
- tab_id: int = last_tab.tab_id
438
- column_order: int = 0
439
- column_span: int = last_tab.max_number_of_columns
440
-
441
- dt: str = AliasUtil.to_data_type_name(dt)
442
- et = criteria.entry_type
443
- entry_criteria = ExperimentEntryCriteriaUtil.get_entry_creation_criteria(et, name, dt, order)
444
- entry_criteria.notebook_experiment_tab_id = tab_id
445
- entry_criteria.column_order = column_order
446
- entry_criteria.column_span = column_span
447
- if criteria:
448
- entry_criteria.is_shown_in_template = criteria.is_shown_in_template
449
- entry_criteria.is_removable = criteria.is_removable
450
- entry_criteria.is_renamable = criteria.is_renamable
451
- entry_criteria.is_static_view = criteria.is_static_view
452
- if criteria.related_entry_set:
453
- entry_criteria.related_entry_set = self.__to_entry_ids(criteria.related_entry_set)
454
- if criteria.dependency_set:
455
- entry_criteria.dependency_set = self.__to_entry_ids(criteria.dependency_set)
456
- entry_criteria.requires_grabber_plugin = criteria.requires_grabber_plugin
457
- entry_criteria.entry_singleton_id = criteria.entry_singleton_id
458
- entry_criteria.is_hidden = criteria.is_hidden
459
- entry_criteria.entry_height = criteria.entry_height
460
- entry_criteria.description = criteria.description
461
- entry_criteria.is_initialization_required = criteria.is_initialization_required
462
- entry_criteria.collapse_entry = criteria.collapse_entry
463
- entry_criteria.entry_status = criteria.entry_status
464
- entry_criteria.template_item_fulfilled_timestamp = criteria.template_item_fulfilled_timestamp
465
- entry_criteria.entry_options = criteria.entry_options
466
-
467
- return entry_criteria
468
-
469
- def __to_entry_ids(self, entries: Iterable[ExperimentEntryIdentifier | str]) -> list[int] | None:
470
- entry_ids: set[int] = set()
471
- for entry in entries:
472
- if isinstance(entry, str):
473
- entry_ids.add(self._exp_handler.get_step(entry).get_id())
474
- else:
475
- entry_ids.add(AliasUtil.to_entry_id(entry))
476
- return list(entry_ids)