sapiopycommons 2025.2.5a412__py3-none-any.whl → 2025.2.5a415__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.

@@ -10,7 +10,8 @@ from sapiopylib.rest.pojo.chartdata.DashboardEnums import ChartGroupingType, Cha
10
10
  from sapiopylib.rest.pojo.chartdata.DashboardSeries import GaugeChartSeries
11
11
  from sapiopylib.rest.pojo.eln.ElnExperiment import ElnExperiment
12
12
  from sapiopylib.rest.pojo.eln.ExperimentEntry import ExperimentEntry
13
- from sapiopylib.rest.pojo.eln.ExperimentEntryCriteria import ElnEntryCriteria, ElnFormEntryUpdateCriteria
13
+ from sapiopylib.rest.pojo.eln.ExperimentEntryCriteria import ElnEntryCriteria, ElnFormEntryUpdateCriteria, \
14
+ ElnDashboardEntryUpdateCriteria, ElnTextEntryUpdateCriteria, AbstractElnEntryUpdateCriteria
14
15
  from sapiopylib.rest.pojo.eln.SapioELNEnums import ElnEntryType, ElnBaseDataType
15
16
  from sapiopylib.rest.pojo.eln.eln_headings import ElnExperimentTabAddCriteria, ElnExperimentTab
16
17
  from sapiopylib.rest.pojo.eln.field_set import ElnFieldSetInfo
@@ -18,6 +19,7 @@ from sapiopylib.rest.utils.ProtocolUtils import ELNStepFactory
18
19
  from sapiopylib.rest.utils.Protocols import ElnEntryStep, ElnExperimentProtocol
19
20
 
20
21
  from sapiopycommons.general.exceptions import SapioException
22
+ from sapiopycommons.general.time_util import TimeUtil
21
23
 
22
24
  CREDENTIALS_HEADER: Final[str] = "SAPIO_APP_API_KEY"
23
25
  API_URL_HEADER: Final[str] = "SAPIO_APP_API_URL"
@@ -101,13 +103,15 @@ class ToolOfToolsHelper:
101
103
  """Whether a tab for this tool has been initialized."""
102
104
  tab: ElnExperimentTab
103
105
  """The tab that contains the tool's entries."""
104
- description_entry: ElnEntryStep
106
+ description_entry: ElnEntryStep | None
105
107
  """The text entry that displays the description of the tool."""
106
- progress_entry: ElnEntryStep
108
+ description_record: DataRecord | None
109
+ """The record that stores the description of the tool."""
110
+ progress_entry: ElnEntryStep | None
107
111
  """A hidden entry for tracking the progress of the tool."""
108
- progress_record: DataRecord
112
+ progress_record: DataRecord | None
109
113
  """The record that stores the progress of the tool."""
110
- progress_gauge_entry: ElnEntryStep
114
+ progress_gauge_entry: ElnEntryStep | None
111
115
  """A chart entry that displays the progress of the tool using the hidden progress entry."""
112
116
  results_entry: ElnEntryStep | None
113
117
  """An entry for displaying the results of the tool. If None, the tool does not produce result records."""
@@ -154,7 +158,7 @@ class ToolOfToolsHelper:
154
158
  if entry.eln_entry.notebook_experiment_tab_id != tab.tab_id:
155
159
  continue
156
160
 
157
- dt: str = entry.get_data_type_names()[0]
161
+ dt: str = entry.get_data_type_names()[0] if entry.get_data_type_names() else None
158
162
  if (entry.eln_entry.entry_type == ElnEntryType.Form
159
163
  and ElnBaseDataType.get_base_type(dt) == ElnBaseDataType.EXPERIMENT_DETAIL
160
164
  and not hasattr(self, "progress_entry")):
@@ -166,18 +170,21 @@ class ToolOfToolsHelper:
166
170
  elif (entry.eln_entry.entry_type == ElnEntryType.Text
167
171
  and not hasattr(self, "description_entry")):
168
172
  self.description_entry = entry
173
+ self.description_record = entry.get_records()[0]
169
174
  elif (entry.eln_entry.entry_type == ElnEntryType.Table
170
175
  and dt == self.results_data_type
171
- and not hasattr(self, "result_entry")):
176
+ and not hasattr(self, "results_entry")):
172
177
  self.results_entry = entry
173
178
 
174
179
  if not hasattr(self, "progress_entry"):
175
- self.results_entry = None
180
+ self.progress_entry = None
181
+ self.progress_record = None
176
182
  if not hasattr(self, "progress_gauge_entry"):
177
- self.results_entry = None
183
+ self.progress_gauge_entry = None
178
184
  if not hasattr(self, "description_entry"):
179
- self.results_entry = None
180
- if not hasattr(self, "result_entry"):
185
+ self.description_entry = None
186
+ self.description_record = None
187
+ if not hasattr(self, "results_entry"):
181
188
  self.results_entry = None
182
189
 
183
190
  self.tab = tab
@@ -204,18 +211,39 @@ class ToolOfToolsHelper:
204
211
  self.progress_record = progress_entry.get_records()[0]
205
212
 
206
213
  # Hide the progress entry.
207
- update_crit = ElnFormEntryUpdateCriteria()
208
- update_crit.is_hidden = True
209
- self.eln_man.update_experiment_entry(self.exp_id, progress_entry.get_id(), update_crit)
214
+ form_update_crit = ElnFormEntryUpdateCriteria()
215
+ form_update_crit.is_hidden = True
216
+
217
+ # Create the text entry that displays the description of the tool. Include the timestamp of when the
218
+ # tool started and format the description so that the text isn't too small to read.
219
+ # TODO: Get the UTC offset in seconds from the header once that's being sent.
220
+ now: str = TimeUtil.now_in_format("%Y-%m-%d %H:%M:%S UTC", "UTC")
221
+ description: str = f"""<p><span style="color: rgb(35, 111, 161); font-size: 12pt; font-weight:500;">{now}</span>
222
+ <br><span style="font-size: 15pt;">{self.description}</span></p>"""
223
+ text_entry: ElnEntryStep = ELNStepFactory.create_text_entry(self._protocol, description)
224
+ self.description_entry = text_entry
225
+ self.description_record = text_entry.get_records()[0]
226
+
227
+ # Shrink the text entry by one column.
228
+ text_update_crit = _ElnTextEntryUpdateCriteria()
229
+ text_update_crit.column_span = 2
210
230
 
211
231
  # Create a gauge entry to display the progress.
212
232
  gauge_entry: ElnEntryStep = self._create_gauge_chart(self._protocol, progress_entry,
213
233
  f"{self.name} Progress", "Progress", "StatusMsg")
214
234
  self.progress_gauge_entry = gauge_entry
215
235
 
216
- # Create the text entry that displays the description of the tool.
217
- text_entry: ElnEntryStep = ELNStepFactory.create_text_entry(self._protocol, self.description)
218
- self.description_entry = text_entry
236
+ # Make sure the gauge entry isn't too big and stick it to the right of the text entry.
237
+ dash_update_crit = ElnDashboardEntryUpdateCriteria()
238
+ dash_update_crit.entry_height = 250
239
+ dash_update_crit.column_span = 2
240
+ dash_update_crit.column_order = 2
241
+
242
+ self.eln_man.update_experiment_entries(self.exp_id, {
243
+ self.progress_entry.get_id(): form_update_crit,
244
+ self.progress_gauge_entry.get_id(): dash_update_crit,
245
+ self.description_entry.get_id(): text_update_crit
246
+ })
219
247
 
220
248
  # Create a results entry if this tool produces result records.
221
249
  if self.results_data_type:
@@ -227,6 +255,20 @@ class ToolOfToolsHelper:
227
255
 
228
256
  return tab
229
257
 
258
+ def add_to_description(self, description: str) -> None:
259
+ """
260
+ Add to the description entry of the tool.
261
+
262
+ :param description: The text to add to the description.
263
+ """
264
+ if not self._initialized:
265
+ raise SapioException("The tab for this tool has not been initialized.")
266
+ field: str = ElnBaseDataType.get_text_entry_data_field_name()
267
+ update: str = self.description_record.get_field_value(field)
268
+ update += f"""<p style="padding-top: 10px;"><span style="font-size: 15pt;">{description}</span></p>"""
269
+ self.description_record.set_field_value(field, update)
270
+ self.dr_man.commit_data_records([self.description_record])
271
+
230
272
  def update_progress(self, progress: float, status_msg: str | None = None) -> None:
231
273
  """
232
274
  Updates the progress of the tool.
@@ -240,6 +282,21 @@ class ToolOfToolsHelper:
240
282
  self.progress_record.set_field_value("StatusMsg", status_msg)
241
283
  self.dr_man.commit_data_records([self.progress_record])
242
284
 
285
+ def add_results_bar_chart(self, x_axis: str, y_axis: str) -> ExperimentEntry:
286
+ """
287
+ Create a bar chart entry for the results of the tool.
288
+
289
+ :param x_axis: The data field to use for the x-axis of the chart.
290
+ :param y_axis: The data field to use for the y-axis of the chart.
291
+ :return: The newly created chart entry.
292
+ """
293
+ if not self._initialized:
294
+ raise SapioException("The tab for this tool has not been initialized.")
295
+ if not self.results_entry:
296
+ raise SapioException("This tool does not produce result records.")
297
+ return ELNStepFactory.create_bar_chart_step(self._protocol, self.results_entry, f"{self.name} Results Chart",
298
+ x_axis, y_axis)[0].eln_entry
299
+
243
300
  def add_attachment_entry(self, file_name: str, file_data: str | bytes, entry_name: str,
244
301
  tab: ElnExperimentTab | None = None) -> ExperimentEntry:
245
302
  """
@@ -338,3 +395,18 @@ class _GaugeChartDefinition(GaugeChartDefinition):
338
395
  "dataFieldName": self.status_field
339
396
  }
340
397
  return result
398
+
399
+
400
+ # TODO: Remove once the ElnTextEntryUpdateCriteria is fixed.
401
+ class _ElnTextEntryUpdateCriteria(AbstractElnEntryUpdateCriteria):
402
+ """
403
+ Text Entry Update Data Payload
404
+ Create this payload object and set the attributes you want to update before sending the request.
405
+ """
406
+
407
+ def __init__(self):
408
+ super().__init__(ElnEntryType.Text)
409
+
410
+ def to_json(self) -> dict[str, Any]:
411
+ ret = super().to_json()
412
+ return ret
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sapiopycommons
3
- Version: 2025.2.5a412
3
+ Version: 2025.2.5a415
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>
@@ -15,7 +15,7 @@ sapiopycommons/datatype/attachment_util.py,sha256=_l2swuP8noIGAl4bwzBUEhr6YlN_OV
15
15
  sapiopycommons/datatype/data_fields.py,sha256=C6HpqtEuF0KsxhlBUprfyv1XguaXql3EYWVbh8y-IFU,4064
16
16
  sapiopycommons/datatype/pseudo_data_types.py,sha256=6TG7aJxgmUZ8FQkWBcgmbK5oy7AFFNtKOPpi1w1OOYA,27657
17
17
  sapiopycommons/elain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- sapiopycommons/elain/tool_of_tools.py,sha256=nSVxZ7ILmtJpe_yMcuHl2qgACLYPSZ6i4VLr_JfQG98,16871
18
+ sapiopycommons/elain/tool_of_tools.py,sha256=ernAtZMlFtEulnk4hVO3ZM9Yehaf7AzPicjXjVjc-8g,20455
19
19
  sapiopycommons/eln/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  sapiopycommons/eln/experiment_handler.py,sha256=8hmR7sawDo9K6iBwB44QSoxlH1M91inor7dfuXQ4LKs,69323
21
21
  sapiopycommons/eln/experiment_report_util.py,sha256=EA2Iq8gW17bSEI6lPoHYQQ-fDvG4O28RWOoTPXpOlUw,36640
@@ -57,7 +57,7 @@ sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
57
57
  sapiopycommons/webhook/webhook_context.py,sha256=D793uLsb1691SalaPnBUk3rOSxn_hYLhdvkaIxjNXss,1909
58
58
  sapiopycommons/webhook/webhook_handlers.py,sha256=M5PMt-j7PpnzUQMUQDTvqwJUyJNxuFtC9wdnk5VRNpI,39703
59
59
  sapiopycommons/webhook/webservice_handlers.py,sha256=Y5dHx_UFWFuSqaoPL6Re-fsKYRuxvCWZ8bj6KSZ3jfM,14285
60
- sapiopycommons-2025.2.5a412.dist-info/METADATA,sha256=dqBuaqHjWkuMQBsUpph31ZGWuANOIzYjWT242mOKbXk,3142
61
- sapiopycommons-2025.2.5a412.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
62
- sapiopycommons-2025.2.5a412.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
63
- sapiopycommons-2025.2.5a412.dist-info/RECORD,,
60
+ sapiopycommons-2025.2.5a415.dist-info/METADATA,sha256=KIywfrDTUc15xKeX4-YwuiMiZZSrb4sRjxqzxXKYh80,3142
61
+ sapiopycommons-2025.2.5a415.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
62
+ sapiopycommons-2025.2.5a415.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
63
+ sapiopycommons-2025.2.5a415.dist-info/RECORD,,