sapiopycommons 2025.4.3a469__py3-none-any.whl → 2025.4.8a473__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,235 @@
1
+ from typing import Iterable
2
+
3
+ from sapiopycommons.general.aliases import DataTypeIdentifier, FieldIdentifier, ExperimentEntryIdentifier
4
+ from sapiopylib.rest.pojo.TableColumn import TableColumn
5
+ from sapiopylib.rest.pojo.datatype.FieldDefinition import AbstractVeloxFieldDefinition
6
+ from sapiopylib.rest.pojo.eln.SapioELNEnums import ExperimentEntryStatus, ElnEntryType
7
+ from sapiopylib.rest.pojo.eln.field_set import ElnFieldSetInfo
8
+
9
+
10
+ # CR-47564: Created these classes to streamline entry creation using the ExperimentEntryFactory.
11
+ class StepCreation:
12
+ """
13
+ An object that contains the criteria for creating a new entry in the experiment.
14
+ """
15
+ _entry_type: ElnEntryType
16
+ """The type of the entry to be created."""
17
+ is_shown_in_template: bool | None
18
+ """Whether the entry will appear in the template if the experiment this entry is in is saved to a new template."""
19
+ is_removable: bool | None
20
+ """Whether the entry can be removed by users."""
21
+ is_renamable: bool | None
22
+ """Whether the entry can be renamed by users."""
23
+ is_static_view: bool | None
24
+ """Whether the entry's attachment is static. For attachment entries only. Static attachment entries will store
25
+ their attachment data in the template."""
26
+ related_entry_set: Iterable[ExperimentEntryIdentifier | str] | None
27
+ """The IDs of the entries this entry is implicitly dependent on. If any of the entries are deleted then this entry
28
+ is also deleted."""
29
+ dependency_set: Iterable[ExperimentEntryIdentifier | str] | None
30
+ """The IDs of the entries this entry is dependent on. Requires the entries to be completed before this entry will
31
+ be enabled."""
32
+ requires_grabber_plugin: bool
33
+ """Whether to run a grabber plugin when this entry is initialized."""
34
+ entry_singleton_id: str | None
35
+ """When this field is present (i.e. not null or blank) it will enforce that only one entry with this singleton
36
+ value is present in the experiment. If you attempt to create an entry with the singletonId of an entry already
37
+ present in the experiment it will return the existing entry instead of creating a new one. If an entry isn't
38
+ present in the Notebook Experiment with a matching singletonId it will create a new entry like normal."""
39
+ is_hidden: bool | None
40
+ """Whether the user is able to visibly see this entry within the experiment."""
41
+ entry_height: int | None
42
+ """The height of this entry in pixels. Setting the height to 0 will cause the entry to auto-size to its contents."""
43
+ description: str | None
44
+ """The description of the entry."""
45
+ is_initialization_required: bool | None
46
+ """Whether the user must manually initialize this entry by clicking on it."""
47
+ collapse_entry: bool | None
48
+ """Whether the entry should be collapsed by default."""
49
+ entry_status: ExperimentEntryStatus | None
50
+ """The current status of the entry."""
51
+ template_item_fulfilled_timestamp: int | None
52
+ """The time in milliseconds since the epoch that this entry became initialized."""
53
+ entry_options: dict[str, str] | None
54
+ """The entry options of the entry."""
55
+
56
+ def __init__(self, entry_type: ElnEntryType):
57
+ self._entry_type = entry_type
58
+ self.is_shown_in_template = None
59
+ self.is_removable = None
60
+ self.is_renamable = None
61
+ self.is_static_view = None
62
+ self._related_entry_set = None
63
+ self._dependency_set = None
64
+ self.requires_grabber_plugin = False
65
+ self.entry_singleton_id = None
66
+ self.is_hidden = None
67
+ self.entry_height = None
68
+ self.description = None
69
+ self.is_initialization_required = None
70
+ self.collapse_entry = None
71
+ self.entry_status = None
72
+ self.template_item_fulfilled_timestamp = None
73
+ self.entry_options = None
74
+
75
+ @property
76
+ def entry_type(self) -> ElnEntryType:
77
+ return self._entry_type
78
+
79
+ class AttachmentStepCreation(StepCreation):
80
+ """
81
+ An object that contains criteria for creating a new attachment entry in an experiment.
82
+ """
83
+ def __init__(self):
84
+ super().__init__(ElnEntryType.Attachment)
85
+
86
+
87
+ class DashboardStepCreation(StepCreation):
88
+ """
89
+ An object that contains criteria for creating a new dashboard entry in an experiment.
90
+ """
91
+ source_entry: ExperimentEntryIdentifier | str | None
92
+ """The entry that contains the source data for this entry's dashboard(s)."""
93
+ dashboard_guids: Iterable[str] | None
94
+ """The GUIDs of the dashboards to display in this entry."""
95
+
96
+ def __init__(self):
97
+ super().__init__(ElnEntryType.Dashboard)
98
+ self.source_entry = None
99
+ self.dashboard_guids = None
100
+
101
+
102
+ class GlobalDtFormStepCreation(StepCreation):
103
+ """
104
+ An object that contains criteria for creating a new global data type form entry in an experiment.
105
+ """
106
+ layout_name: str | None
107
+ """The name of the data type layout to be displayed in this form. The layout must be for the data type for this
108
+ entry."""
109
+ form_names: Iterable[str] | None
110
+ """The names of the components in the chosen data type layout to display in this form."""
111
+ extension_types: Iterable[DataTypeIdentifier] | None
112
+ """The names of the extension data types to display fields from within the form."""
113
+ field_names: Iterable[FieldIdentifier] | None
114
+ """A list of data field names for the fields to be displayed in the form."""
115
+
116
+ def __init__(self):
117
+ super().__init__(ElnEntryType.Form)
118
+ self.form_names = None
119
+ self.layout_name = None
120
+ self.extension_types = None
121
+ self.field_names = None
122
+
123
+
124
+ class ELnDtFormStepCreation(StepCreation):
125
+ """
126
+ An object that contains criteria for creating a new ELN data type form entry in an experiment.
127
+ """
128
+ is_field_addable: bool | None
129
+ """Whether new fields can be added to the entry by users."""
130
+ is_existing_field_removable: bool | None
131
+ """Whether existing fields on the entry can be removed by users."""
132
+ field_sets: Iterable[int | str | ElnFieldSetInfo] | None
133
+ """The predefined field sets to display in this form."""
134
+ field_definitions: Iterable[AbstractVeloxFieldDefinition] | None
135
+ """New field definitions to be created for this entry."""
136
+ predefined_field_names: Iterable[str] | None
137
+ """The names of the predefined fields to display in this form."""
138
+
139
+ def __init__(self):
140
+ super().__init__(ElnEntryType.Form)
141
+ self.is_field_addable = None
142
+ self.is_existing_field_removable = None
143
+ self.field_sets = None
144
+ self.field_definitions = None
145
+ self.predefined_field_names = None
146
+ self.table_columns = None
147
+
148
+
149
+ class PluginStepCreation(StepCreation):
150
+ """
151
+ An object that contains criteria for creating a new plugin entry in an experiment.
152
+ """
153
+ plugin_name: str | None
154
+ """The client side plugin name to render this entry with."""
155
+ using_template_data: bool | None
156
+ """Whether this entry will use the data from the template."""
157
+ provides_template_data: bool | None
158
+ """Whether this entry can provide data to copy into a new template."""
159
+
160
+ def __init__(self):
161
+ super().__init__(ElnEntryType.Plugin)
162
+ self.plugin_name = None
163
+ self.using_template_data = None
164
+ self.provides_template_data = None
165
+
166
+
167
+ class GlobalDtTableStepCreation(StepCreation):
168
+ """
169
+ An object that contains criteria for creating a new global data type table entry in an experiment.
170
+ """
171
+ layout_name: str | None
172
+ """The name of the data type layout to display in this table."""
173
+ extension_types: Iterable[str] | None
174
+ """The names of the extension data types to display fields from within the table."""
175
+ table_columns: Iterable[TableColumn] | None
176
+ """The columns to display in the table. This can be used to change the sort order and direction of columns."""
177
+ field_names: Iterable[FieldIdentifier] | None
178
+ """A list of data field names for the fields to be displayed in the table. These will be added as TableColumns and
179
+ placed after any of the existing columns specified in the table_columns parameter without any sorting."""
180
+ show_key_fields: bool | None
181
+ """Whether the key fields of the data type should be shown in the entry."""
182
+
183
+ def __init__(self):
184
+ super().__init__(ElnEntryType.Table)
185
+ self.layout_name = None
186
+ self.extension_types = None
187
+ self.table_columns = None
188
+ self.show_key_fields = None
189
+
190
+
191
+ class ELnDtTableStepCreation(StepCreation):
192
+ """
193
+ An object that contains criteria for creating a new ELN data type table entry in an experiment.
194
+ """
195
+ is_field_addable: bool | None
196
+ """Whether new fields can be added to the entry by users."""
197
+ is_existing_field_removable: bool | None
198
+ """Whether existing fields on the entry can be removed by users."""
199
+ field_sets: Iterable[int | str | ElnFieldSetInfo] | None
200
+ """The predefined field sets to display in this form."""
201
+ field_definitions: Iterable[AbstractVeloxFieldDefinition] | None
202
+ """New field definitions to be created for this entry."""
203
+ predefined_field_names: Iterable[str] | None
204
+ """The names of the predefined fields to display in this form."""
205
+ table_columns: Iterable[TableColumn] | None
206
+ """The columns to display in the table."""
207
+
208
+ def __init__(self):
209
+ super().__init__(ElnEntryType.Table)
210
+ self.is_field_addable = None
211
+ self.is_existing_field_removable = None
212
+ self.field_sets = None
213
+ self.field_definitions = None
214
+ self.predefined_field_names = None
215
+ self.table_columns = None
216
+
217
+
218
+ class TempDataStepCreation(StepCreation):
219
+ """
220
+ An object that contains criteria for creating a new temp data entry in an experiment.
221
+ """
222
+ plugin_path: str | None
223
+ """The temp data plugin path to run to populate the entry."""
224
+
225
+ def __init__(self):
226
+ super().__init__(ElnEntryType.TempData)
227
+ self.plugin_path = None
228
+
229
+
230
+ class TextStepCreation(StepCreation):
231
+ """
232
+ An object that contains criteria for creating a new text entry in an experiment.
233
+ """
234
+ def __init__(self):
235
+ super().__init__(ElnEntryType.Text)
@@ -7,6 +7,7 @@ from sapiopylib.rest.pojo.datatype.FieldDefinition import FieldType, AbstractVel
7
7
  from sapiopylib.rest.pojo.eln.ElnExperiment import ElnExperiment
8
8
  from sapiopylib.rest.pojo.eln.ExperimentEntry import ExperimentEntry
9
9
  from sapiopylib.rest.pojo.eln.SapioELNEnums import ElnBaseDataType
10
+ from sapiopylib.rest.pojo.eln.eln_headings import ElnExperimentTab
10
11
  from sapiopylib.rest.pojo.webhook.WebhookContext import SapioWebhookContext
11
12
  from sapiopylib.rest.utils.Protocols import ElnExperimentProtocol, ElnEntryStep
12
13
  from sapiopylib.rest.utils.recordmodel.PyRecordModel import PyRecordModel, AbstractRecordModel
@@ -37,6 +38,8 @@ ExperimentIdentifier: TypeAlias = ElnExperimentProtocol | ElnExperiment | int
37
38
  ID."""
38
39
  ExperimentEntryIdentifier: TypeAlias = ElnEntryStep | ExperimentEntry | int
39
40
  """An ExperimentEntryIdentifier is either an ELN entry step, experiment entry, or an integer for the entry's ID."""
41
+ TabIdentifier: TypeAlias = int | ElnExperimentTab
42
+ """A TabIdentifier is either an integer for the tab's ID or an ElnExperimentTab object."""
40
43
  FieldMap: TypeAlias = dict[str, FieldValue]
41
44
  """A field map is simply a dict of data field names to values. The purpose of aliasing this is to help distinguish
42
45
  any random dict in a webhook from one which is explicitly used for record fields."""
@@ -105,7 +105,8 @@ class QueueItemHandler:
105
105
  """
106
106
  self.user = AliasUtil.to_sapio_user(context)
107
107
  self.rec_handler = RecordHandler(self.user)
108
- if isinstance(context, SapioWebhookContext):
108
+ # PR-47565: Only initialize a ProcessQueueContext if the given context object has context_data.
109
+ if isinstance(context, SapioWebhookContext) and context.context_data:
109
110
  self.context = ProcessQueueContext(context)
110
111
  else:
111
112
  self.context = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sapiopycommons
3
- Version: 2025.4.3a469
3
+ Version: 2025.4.8a473
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>
@@ -13,13 +13,15 @@ sapiopycommons/customreport/term_builder.py,sha256=1_PGjxNUy5YWim8WJ_HJfiTq6i0D3
13
13
  sapiopycommons/datatype/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  sapiopycommons/datatype/attachment_util.py,sha256=N-nhsJ0oxa_Ft6Y6VWeNFYLzfuQqsjhHA6_-yIt2wVw,3596
15
15
  sapiopycommons/datatype/data_fields.py,sha256=pczUlEcE0TeHEDU0Gkvu7voacSLPXCB7l9UbI1Tb6V0,5656
16
- sapiopycommons/datatype/experiment_cache.py,sha256=kiYZBZEAuQpv-rFviv8_6g7uvXdzH9BMUEprvAHT0Ds,8181
17
16
  sapiopycommons/datatype/pseudo_data_types.py,sha256=6TG7aJxgmUZ8FQkWBcgmbK5oy7AFFNtKOPpi1w1OOYA,27657
18
17
  sapiopycommons/eln/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- sapiopycommons/eln/experiment_handler.py,sha256=GQxvCFRd8Oa_w5Jxdyn1fU34vg78rO-IUZB_Genre1E,127393
18
+ sapiopycommons/eln/experiment_cache.py,sha256=kiYZBZEAuQpv-rFviv8_6g7uvXdzH9BMUEprvAHT0Ds,8181
19
+ sapiopycommons/eln/experiment_handler.py,sha256=7vYRlYAW_xT5LcZ5nLqL9dxEHGRAPEuUxX8d8TElWV8,105742
20
20
  sapiopycommons/eln/experiment_report_util.py,sha256=NNNNPVD3_2ZAjoOqCMOnlnmPD0SCjDcgYi453ATSJBs,37027
21
+ sapiopycommons/eln/experiment_step_factory.py,sha256=6mUv2JXN5-MCM_aUblcv95v4NMTp9i1W42AqJ8sdUkM,26007
21
22
  sapiopycommons/eln/experiment_tags.py,sha256=7-fpOiSqrjbXmWIJhEhaxMgLsVCPAtKqH8xRzpDVKoE,356
22
23
  sapiopycommons/eln/plate_designer.py,sha256=ix2cflz13PAHyu4deS3d5Qd3kQXk0C7IQxBQ2Dm9fEM,13692
24
+ sapiopycommons/eln/step_creation.py,sha256=DiniCKef2Nkpa2QeDiRvh_Q_QBu6J7o7vNlU28TaYRI,10141
23
25
  sapiopycommons/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
26
  sapiopycommons/files/complex_data_loader.py,sha256=T39veNhvYl6j_uZjIIJ8Mk5Aa7otR5RB-g8XlAdkksA,1421
25
27
  sapiopycommons/files/file_bridge.py,sha256=vKbqxPexi15epr_-_qLrEfYoxNxB031mXN92iVtOMqE,9511
@@ -32,7 +34,7 @@ sapiopycommons/flowcyto/flow_cyto.py,sha256=vs9WhXXKz3urpjL8QKSk56B-NSmQR3O3x_WF
32
34
  sapiopycommons/flowcyto/flowcyto_data.py,sha256=mYKFuLbtpJ-EsQxLGtu4tNHVlygTxKixgJxJqD68F58,2596
33
35
  sapiopycommons/general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
36
  sapiopycommons/general/accession_service.py,sha256=3e__bVs7CYZ1CduLlGA9plnK7nCtdy7GXjCrNObPFgo,13484
35
- sapiopycommons/general/aliases.py,sha256=alc2R5TOSKbZif3pcGZ706y23Y9F4HQPC-Kj4xJZ_Us,14503
37
+ sapiopycommons/general/aliases.py,sha256=wDNg0HSZm13O4lS8L8DT5mMBZ5GDwSbSHpDDwSFcZpc,14711
36
38
  sapiopycommons/general/audit_log.py,sha256=KQq0PsvukUoE3l6TQb3-vpu5-MbSINpWlnQ9e7jojPg,8743
37
39
  sapiopycommons/general/custom_report_util.py,sha256=NwwmejSQLwSbrndEk1gPyFNYk9GZoS7Wrp9ab9moFgw,18014
38
40
  sapiopycommons/general/data_structure_util.py,sha256=fbQR_Fh4Scg67IpFPbQW9wVLw1oxlYxqp4LjBRTpjgU,4702
@@ -45,7 +47,7 @@ sapiopycommons/general/time_util.py,sha256=jU1urPoZRv6evNucR0-288EyT4PrsDpCr-H1-
45
47
  sapiopycommons/multimodal/multimodal.py,sha256=PFaGJPbKvW__tnxb8KkgkJZOKjQdgxF_kGfD5chet1s,6779
46
48
  sapiopycommons/multimodal/multimodal_data.py,sha256=0BeVPr9HaC0hNTF1v1phTIKGruvNnwerHsD994qJKBg,15099
47
49
  sapiopycommons/processtracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- sapiopycommons/processtracking/custom_workflow_handler.py,sha256=QZVRDUXpHfYIKD9LtaOcOt0Sr3RGDaeGQb-LZYAgkCc,25117
50
+ sapiopycommons/processtracking/custom_workflow_handler.py,sha256=wsDmJvl6pgrKEhxpTdh41B0CXAUCMli5JBkVDj-jbWw,25246
49
51
  sapiopycommons/processtracking/endpoints.py,sha256=w5bziI2xC7450M95rCF8JpRwkoni1kEDibyAux9B12Q,10848
50
52
  sapiopycommons/recordmodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
53
  sapiopycommons/recordmodel/record_handler.py,sha256=jN158FR1fMYrwrcptcLkzxdKU40qrC-JMdTjgVoDrtE,90126
@@ -59,7 +61,7 @@ sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
59
61
  sapiopycommons/webhook/webhook_context.py,sha256=D793uLsb1691SalaPnBUk3rOSxn_hYLhdvkaIxjNXss,1909
60
62
  sapiopycommons/webhook/webhook_handlers.py,sha256=tUVNCw05CDGu1gFDm2g558hX_O203WVm_n__ojjoRRM,39841
61
63
  sapiopycommons/webhook/webservice_handlers.py,sha256=tyaYGG1-v_JJrJHZ6cy5mGCxX9z1foLw7pM4MDJlFxs,14297
62
- sapiopycommons-2025.4.3a469.dist-info/METADATA,sha256=yMKudOSZVmxq9MJjCW_tRHpnQGWLUwkKcV7rATvxZA4,3142
63
- sapiopycommons-2025.4.3a469.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
64
- sapiopycommons-2025.4.3a469.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
65
- sapiopycommons-2025.4.3a469.dist-info/RECORD,,
64
+ sapiopycommons-2025.4.8a473.dist-info/METADATA,sha256=j7dB9Oy9qtcyLF6QYmAzL3yIQc5NYGaLRvgudYh0pxg,3142
65
+ sapiopycommons-2025.4.8a473.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
66
+ sapiopycommons-2025.4.8a473.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
67
+ sapiopycommons-2025.4.8a473.dist-info/RECORD,,
File without changes