sapiopycommons 2025.5.13a523__py3-none-any.whl → 2025.5.14a527__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 (54) hide show
  1. sapiopycommons/ai/tool_of_tools.py +809 -0
  2. sapiopycommons/callbacks/callback_util.py +116 -64
  3. sapiopycommons/callbacks/field_builder.py +2 -0
  4. sapiopycommons/customreport/auto_pagers.py +2 -1
  5. sapiopycommons/customreport/term_builder.py +1 -1
  6. sapiopycommons/datatype/pseudo_data_types.py +349 -326
  7. sapiopycommons/eln/experiment_cache.py +188 -0
  8. sapiopycommons/eln/experiment_handler.py +336 -719
  9. sapiopycommons/eln/experiment_step_factory.py +476 -0
  10. sapiopycommons/eln/plate_designer.py +7 -2
  11. sapiopycommons/eln/step_creation.py +236 -0
  12. sapiopycommons/files/file_util.py +4 -4
  13. sapiopycommons/general/accession_service.py +2 -2
  14. sapiopycommons/general/aliases.py +4 -1
  15. sapiopycommons/general/data_structure_util.py +115 -0
  16. sapiopycommons/general/sapio_links.py +4 -12
  17. sapiopycommons/processtracking/custom_workflow_handler.py +2 -1
  18. sapiopycommons/recordmodel/record_handler.py +357 -27
  19. sapiopycommons/rules/eln_rule_handler.py +8 -1
  20. sapiopycommons/rules/on_save_rule_handler.py +8 -1
  21. sapiopycommons/webhook/webhook_handlers.py +3 -0
  22. sapiopycommons/webhook/webservice_handlers.py +2 -2
  23. {sapiopycommons-2025.5.13a523.dist-info → sapiopycommons-2025.5.14a527.dist-info}/METADATA +2 -2
  24. sapiopycommons-2025.5.14a527.dist-info/RECORD +69 -0
  25. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.py +0 -43
  26. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.pyi +0 -31
  27. sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2_grpc.py +0 -24
  28. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.py +0 -123
  29. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.pyi +0 -598
  30. sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2_grpc.py +0 -24
  31. sapiopycommons/ai/api/plan/proto/step_output_pb2.py +0 -45
  32. sapiopycommons/ai/api/plan/proto/step_output_pb2.pyi +0 -42
  33. sapiopycommons/ai/api/plan/proto/step_output_pb2_grpc.py +0 -24
  34. sapiopycommons/ai/api/plan/proto/step_pb2.py +0 -43
  35. sapiopycommons/ai/api/plan/proto/step_pb2.pyi +0 -43
  36. sapiopycommons/ai/api/plan/proto/step_pb2_grpc.py +0 -24
  37. sapiopycommons/ai/api/plan/script/proto/script_pb2.py +0 -53
  38. sapiopycommons/ai/api/plan/script/proto/script_pb2.pyi +0 -99
  39. sapiopycommons/ai/api/plan/script/proto/script_pb2_grpc.py +0 -153
  40. sapiopycommons/ai/api/plan/tool/proto/entry_pb2.py +0 -57
  41. sapiopycommons/ai/api/plan/tool/proto/entry_pb2.pyi +0 -96
  42. sapiopycommons/ai/api/plan/tool/proto/entry_pb2_grpc.py +0 -24
  43. sapiopycommons/ai/api/plan/tool/proto/tool_pb2.py +0 -67
  44. sapiopycommons/ai/api/plan/tool/proto/tool_pb2.pyi +0 -220
  45. sapiopycommons/ai/api/plan/tool/proto/tool_pb2_grpc.py +0 -154
  46. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.py +0 -39
  47. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.pyi +0 -32
  48. sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2_grpc.py +0 -24
  49. sapiopycommons/ai/protobuf_utils.py +0 -454
  50. sapiopycommons/ai/tool_service_base.py +0 -787
  51. sapiopycommons/general/html_formatter.py +0 -456
  52. sapiopycommons-2025.5.13a523.dist-info/RECORD +0 -91
  53. {sapiopycommons-2025.5.13a523.dist-info → sapiopycommons-2025.5.14a527.dist-info}/WHEEL +0 -0
  54. {sapiopycommons-2025.5.13a523.dist-info → sapiopycommons-2025.5.14a527.dist-info}/licenses/LICENSE +0 -0
@@ -1,456 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import re
4
- from typing import Final
5
-
6
-
7
- class HtmlFormatter:
8
- """
9
- A class for formatting text in HTML with tag classes supported by the client.
10
- """
11
- TIMESTAMP_TEXT__CSS_CLASS_NAME: Final[str] = "timestamp-text"
12
- HEADER_1_TEXT__CSS_CLASS_NAME: Final[str] = "header1-text"
13
- HEADER_2_TEXT__CSS_CLASS_NAME: Final[str] = "header2-text"
14
- HEADER_3_TEXT__CSS_CLASS_NAME: Final[str] = "header3-text"
15
- BODY_TEXT__CSS_CLASS_NAME: Final[str] = "body-text"
16
- CAPTION_TEXT__CSS_CLASS_NAME: Final[str] = "caption-text"
17
-
18
- @staticmethod
19
- def timestamp(text: str) -> str:
20
- """
21
- Given a text string, return that same text string HTML formatted using the timestamp CSS class.
22
-
23
- :param text: The text to format.
24
- :return: The HTML formatted text.
25
- """
26
- return f'<span class="{HtmlFormatter.TIMESTAMP_TEXT__CSS_CLASS_NAME}">{text}</span>'
27
-
28
- @staticmethod
29
- def header_1(text: str) -> str:
30
- """
31
- Given a text string, return that same text string HTML formatted using the header 1 CSS class.
32
-
33
- :param text: The text to format.
34
- :return: The HTML formatted text.
35
- """
36
- return f'<span class="{HtmlFormatter.HEADER_1_TEXT__CSS_CLASS_NAME}">{text}</span>'
37
-
38
- @staticmethod
39
- def header_2(text: str) -> str:
40
- """
41
- Given a text string, return that same text string HTML formatted using the header 2 CSS class.
42
-
43
- :param text: The text to format.
44
- :return: The HTML formatted text.
45
- """
46
- return f'<span class="{HtmlFormatter.HEADER_2_TEXT__CSS_CLASS_NAME}">{text}</span>'
47
-
48
- @staticmethod
49
- def header_3(text: str) -> str:
50
- """
51
- Given a text string, return that same text string HTML formatted using the header 3 CSS class.
52
-
53
- :param text: The text to format.
54
- :return: The HTML formatted text.
55
- """
56
- return f'<span class="{HtmlFormatter.HEADER_3_TEXT__CSS_CLASS_NAME}">{text}</span>'
57
-
58
- @staticmethod
59
- def body(text: str) -> str:
60
- """
61
- Given a text string, return that same text string HTML formatted using the body text CSS class.
62
-
63
- :param text: The text to format.
64
- :return: The HTML formatted text.
65
- """
66
- return f'<span class="{HtmlFormatter.BODY_TEXT__CSS_CLASS_NAME}">{text}</span>'
67
-
68
- @staticmethod
69
- def caption(text: str) -> str:
70
- """
71
- Given a text string, return that same text string HTML formatted using the caption text CSS class.
72
-
73
- :param text: The text to format.
74
- :return: The HTML formatted text.
75
- """
76
- return f'<span class="{HtmlFormatter.CAPTION_TEXT__CSS_CLASS_NAME}">{text}</span>'
77
-
78
- @staticmethod
79
- def replace_newlines(text: str) -> str:
80
- """
81
- Given a text string, return that same text string HTML formatted with newlines replaced by HTML line breaks.
82
-
83
- :param text: The text to format.
84
- :return: The HTML formatted text.
85
- """
86
- return re.sub("\r?\n", "<br>", text)
87
-
88
- @staticmethod
89
- def scrub_html(text: str) -> str:
90
- """
91
- Given a string that contains HTML, return that same string with all HTML removed.
92
-
93
- :param text: The HTML string to scrub.
94
- :return: The scrubbed text.
95
- """
96
- if not text:
97
- return ""
98
-
99
- from bs4 import BeautifulSoup
100
- return BeautifulSoup(text, "html.parser").get_text()
101
-
102
- @staticmethod
103
- def scrub_markdown(text: str) -> str:
104
- """
105
- Given a string that contains markdown, return that same string with all markdown removed.
106
-
107
- :param text: The markdown string to scrub.
108
- :return: The scrubbed text.
109
- """
110
- if not text:
111
- return ""
112
-
113
- # --- Remove Headers ---
114
- # Level 1-6 headers (# to ######)
115
- text = re.sub(r"^#{1,6}\s*(.*)$", r"\1", text, flags=re.MULTILINE).strip()
116
-
117
- # --- Remove Emphasis ---
118
- # Bold (**text** or __text__)
119
- text = re.sub(r"\*\*(.*?)\*\*", r"\1", text)
120
- text = re.sub(r"__(.*?)__", r"\1", text)
121
-
122
- # Italic (*text* or _text_)
123
- text = re.sub(r"\*(.*?)\*", r"\1", text)
124
- text = re.sub(r"_(.*?)_", r"\1", text)
125
-
126
- # --- Remove Strikethrough ---
127
- # Strikethrough (~~text~~)
128
- text = re.sub(r"~~(.*?)~~", r"\1", text)
129
-
130
- # --- Remove Links ---
131
- # Links ([text](url))
132
- text = re.sub(r"\[(.*?)]\((.*?)\)", r"\1", text)
133
-
134
- # --- Remove Images ---
135
- # Images (![alt text](url))
136
- text = re.sub(r"!\\[(.*?)\\]\\((.*?)\\)", "", text) # remove the entire image tag
137
-
138
- # --- Remove Code ---
139
- # Inline code (`code`)
140
- text = re.sub(r"`(.*?)`", r"\1", text)
141
-
142
- # Code blocks (```code```)
143
- text = re.sub(r"```.*?```", "", text, flags=re.DOTALL) # multiline code blocks
144
-
145
- # --- Remove Lists ---
146
- # Unordered lists (* item, - item, + item)
147
- text = re.sub(r"(?m)^[*\-+]\s+", "", text)
148
-
149
- # Ordered lists (1. item)
150
- text = re.sub(r"(?m)^\d+\.\s+", "", text)
151
-
152
- # --- Remove Blockquotes ---
153
- # Blockquotes (> text)
154
- text = re.sub(r"(?m)^>\s+", "", text)
155
-
156
- # --- Remove Horizontal Rules ---
157
- # Horizontal rules (---, ***, ___)
158
- text = re.sub(r"(?m)^[-_*]{3,}\s*$", "", text) # Remove horizontal rules
159
-
160
- # --- Remove HTML tags (basic)---
161
- # This is a very simple HTML tag removal, it does not handle nested tags or attributes properly.
162
- text = re.sub(r"<[^>]*>", "", text)
163
-
164
- # --- Remove escaped characters ---
165
- text = re.sub(r"\\([!\"#$%&'()*+,./:;<=>?@\\[]^_`{|}~-])", r"\1", text)
166
-
167
- return text
168
-
169
- @staticmethod
170
- def convert_markdown_to_html(text: str) -> str:
171
- """
172
- Given a markdown string, convert it to HTML and return the HTML string.
173
-
174
- :param text: The markdown string to convert.
175
- :return: The HTML string.
176
- """
177
- if not text:
178
- return ""
179
-
180
- # Replace newlines with break tags and tabs with em spaces.
181
- text = text.replace("\r\n", "<br>").replace("\n", "<br>").replace("\t", "&emsp;")
182
-
183
- # Format code blocks to maintain indentation.
184
- text = HtmlFormatter.format_code_blocks(text, "<br>")
185
-
186
- # Convert any other markdown to HTML.
187
- text = HtmlFormatter._convert_markdown_by_line(text)
188
-
189
- return text
190
-
191
- @staticmethod
192
- def format_code_blocks(text: str, newline: str = "\n") -> str:
193
- """
194
- Locate each markdown code block in the given text and format it with HTML code and preformatting tags
195
- to maintain indentation and add language-specific syntax highlighting.
196
-
197
- :param text: The text to format.
198
- :param newline: The newline character to expect in the input text.
199
- :return: The formatted text.
200
- """
201
- # Extract all the code blocks from the text
202
- code_blocks = HtmlFormatter.extract_code_blocks(text, newline)
203
- if not code_blocks:
204
- return text
205
-
206
- # Iterate through the code blocks, adding them to the text with the <pre><code> </code></pre>
207
- # so that indentation is preserved.
208
- current_index = 0
209
- formatted = []
210
- for code_block in code_blocks:
211
- formatted.append(text[current_index:code_block.start_index])
212
- formatted.append(code_block.to_html())
213
- current_index = code_block.end_index
214
- # Append the rest of the text after the last code block.
215
- formatted.append(text[current_index:])
216
- return "".join(formatted)
217
-
218
- @staticmethod
219
- def sanitize_code_blocks(text: str, newline: str = "\n") -> str:
220
- """
221
- Given the input text, remove all code blocks while leaving all other text unchanged.
222
- For use in any location where we don't want to display code (because it's scary).
223
-
224
- :param text: The text to sanitize.
225
- :param newline: The newline character to expect in the input text.
226
- :return: The sanitized text.
227
- """
228
- code_blocks = HtmlFormatter.extract_code_blocks(text, newline)
229
-
230
- if not code_blocks:
231
- return text
232
-
233
- current_index = 0
234
- formatted_text = []
235
-
236
- for block in code_blocks:
237
- formatted_text.append(text[current_index: block.start_index])
238
- current_index = block.end_index
239
-
240
- formatted_text.append(text[current_index:])
241
-
242
- return "".join(formatted_text)
243
-
244
- @staticmethod
245
- def extract_code_blocks(text: str, newline: str = "\n") -> list[CodeBlock]:
246
- """
247
- Extract all code blocks from the given response.
248
-
249
- :param text: The text to extract the code blocks from.
250
- :param newline: The newline character to expect in the input text.
251
- :return: A list of code blocks.
252
- """
253
- code: list[CodeBlock] = []
254
- current_index = 0
255
- while current_index < len(text):
256
- code_block = HtmlFormatter.next_code_block(text, current_index, newline)
257
- if code_block is None:
258
- break
259
- code.append(code_block)
260
- current_index = code_block.end_index
261
- return code
262
-
263
- @staticmethod
264
- def next_code_block(text: str, start_index: int, newline: str = "\n") -> CodeBlock | None:
265
- """
266
- Extract the next code block from the given response, starting at the given index.
267
-
268
- :param text: The text to extract the code block from.
269
- :param start_index: The index to start searching for the code block at.
270
- :param newline: The newline character to expect in the input text.
271
- :return: The extracted code block. Null if no code block is found after the start index.
272
- """
273
- # Find the start of the next code block.
274
- start_tag = text.find("```", start_index)
275
- if start_tag == -1:
276
- return None
277
-
278
- # Extract the language from the starting tag of the code block.
279
- first_line = text.find(newline, start_tag)
280
- if first_line == -1:
281
- return None
282
- language = text[start_tag + 3:first_line].strip()
283
- first_line += len(newline)
284
-
285
- # Find the end of the code block.
286
- code: str
287
- end_tag = text.find("```", first_line)
288
- # If there is no end to the code block, just return the rest of the text as a code block.
289
- if end_tag == -1:
290
- end_tag = len(text)
291
- code = text[first_line:end_tag]
292
- else:
293
- code = text[first_line:end_tag]
294
- end_tag += 3
295
- return CodeBlock(code, language, start_tag, end_tag)
296
-
297
- @staticmethod
298
- def _convert_markdown_by_line(text: str) -> str:
299
- """
300
- Convert markdown to HTML for each line in the given markdown text. Line breaks are expected to be represented
301
- by break tags already.
302
-
303
- :param text: The markdown text to convert.
304
- :return: The HTML text.
305
- """
306
- html = []
307
- lines = text.split("<br>")
308
-
309
- in_unordered_list = False
310
- in_ordered_list = False
311
-
312
- for line in lines:
313
- # Skip code blocks, as these have already been formatted.
314
- # Also skip empty lines.
315
- if "</code></pre>" in line or not line.strip():
316
- html.append(line + "<br>")
317
- continue
318
- processed_line = HtmlFormatter._process_line(line.strip())
319
-
320
- # Handle headings
321
- if processed_line.startswith("# "):
322
- HtmlFormatter._close_lists(html, in_unordered_list, in_ordered_list)
323
- in_unordered_list = False
324
- in_ordered_list = False
325
- html.append(HtmlFormatter.header_1(processed_line[2:].strip()) + "<br>")
326
- elif processed_line.startswith("## "):
327
- HtmlFormatter._close_lists(html, in_unordered_list, in_ordered_list)
328
- in_unordered_list = False
329
- in_ordered_list = False
330
- html.append(HtmlFormatter.header_2(processed_line[3:].strip()) + "<br>")
331
- elif processed_line.startswith("### "):
332
- HtmlFormatter._close_lists(html, in_unordered_list, in_ordered_list)
333
- in_unordered_list = False
334
- in_ordered_list = False
335
- html.append(HtmlFormatter.header_3(processed_line[4:].strip()) + "<br>")
336
- # Handle unordered lists
337
- elif processed_line.startswith("* "):
338
- if not in_unordered_list:
339
- HtmlFormatter._close_lists(html, False, in_ordered_list) # Close any previous ordered list.
340
- in_ordered_list = False
341
- html.append("<ul>")
342
- in_unordered_list = True
343
- html.append("<li>" + HtmlFormatter.body(processed_line[2:].strip()) + "</li>")
344
- # Handle ordered lists
345
- elif re.match(r"^\d+\. .*", processed_line): # Matches "1. text"
346
- if not in_ordered_list:
347
- HtmlFormatter._close_lists(html, in_unordered_list, False) # Close any previous unordered list.
348
- in_unordered_list = False
349
- html.append("<ol>")
350
- in_ordered_list = True
351
- html.append(
352
- "<li>" + HtmlFormatter.body(processed_line[processed_line.find('.') + 2:].strip()) + "</li>")
353
-
354
- # Handle regular paragraphs
355
- else:
356
- HtmlFormatter._close_lists(html, in_unordered_list, in_ordered_list)
357
- in_unordered_list = False
358
- in_ordered_list = False
359
- html.append(HtmlFormatter.body(processed_line.strip()) + "<br>")
360
-
361
- # Close any open lists at the end
362
- HtmlFormatter._close_lists(html, in_unordered_list, in_ordered_list)
363
-
364
- return "".join(html)
365
-
366
- @staticmethod
367
- def _close_lists(text: list, in_unordered_list: bool, in_ordered_list: bool):
368
- """
369
- Close any open unordered or ordered lists in the given HTML string.
370
-
371
- :param text: The HTML string to append to.
372
- :param in_unordered_list: Whether an unordered list is currently open.
373
- :param in_ordered_list: Whether an ordered list is currently open.
374
- """
375
- if in_unordered_list:
376
- text.append("</ul>")
377
- if in_ordered_list:
378
- text.append("</ol>")
379
-
380
- @staticmethod
381
- def _process_line(line: str) -> str:
382
- """
383
- Process a single line of markdown text and convert it to HTML.
384
-
385
- :param line: The line of markdown text to process.
386
- :return: The HTML formatted line.
387
- """
388
- # Bold: **text**
389
- line = re.sub(r"\*\*(.*?)\*\*", r"<strong>\1</strong>", line)
390
-
391
- # Italic: *text*
392
- line = re.sub(r"\*(.*?)\*", r"<em>\1</em>", line)
393
-
394
- # Code: `text`
395
- line = re.sub(r"`(.*?)`", r"<code>\1</code>", line)
396
-
397
- return line
398
-
399
-
400
- class CodeBlock:
401
- """
402
- A class representing a code block extracted from a response.
403
- """
404
- def __init__(self, code: str, language: str, start_index: int, end_index: int):
405
- """
406
- :param code: The text of the code block.
407
- :param language: The language of the code block.
408
- :param start_index: The index of the first character of the code block in the original response.
409
- :param end_index: The index after the last character of the code block in the original response.
410
- """
411
- if code is None:
412
- raise ValueError("Code cannot be None")
413
- if language is None:
414
- language = ""
415
- if start_index < 0 or end_index < 0 or start_index > end_index:
416
- raise ValueError("Invalid start or end index")
417
-
418
- # Replace em spaces within code blocks with quadruple spaces and break tags with newlines.
419
- # Code editors that the code is copy/pasted into might not recognize em spaces as valid indentation,
420
- # and the library that adds the language-specific syntax highlighting expects newlines instead of break
421
- # tags.
422
- if "<br>" in code:
423
- code = code.replace("<br>", "\n")
424
- if "&emsp;" in code:
425
- code = code.replace("&emsp;", " ")
426
- # We don't want mixed whitespace, so replace all tabs with quad spaces.
427
- if "\t" in code:
428
- code = code.replace("\t", " ")
429
-
430
- self.code = code
431
- self.language = language.strip()
432
- self.start_index = start_index
433
- self.end_index = end_index
434
-
435
- def to_html(self) -> str:
436
- """
437
- :return: The HTML representation of this code block.
438
- """
439
- start_tag: str
440
- if self.language:
441
- lang_class = f'class="language-{self.language}"'
442
- start_tag = f"<pre {lang_class}><code {lang_class}>"
443
- else:
444
- start_tag = "<pre><code>"
445
- end_tag = "</code></pre>"
446
-
447
- return start_tag + self.code + end_tag
448
-
449
- def to_markdown(self) -> str:
450
- """
451
- :return: The markdown representation of this code block.
452
- """
453
- start_tag = f"```{self.language}\n"
454
- end_tag = "```" if self.code.endswith("\n") else "\n```"
455
-
456
- return start_tag + self.code + end_tag
@@ -1,91 +0,0 @@
1
- sapiopycommons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- sapiopycommons/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- sapiopycommons/ai/protobuf_utils.py,sha256=aKmZtNLrrzUe_LFsdW0zYpG4VI-ZGgukyXVDFtIqfes,22656
4
- sapiopycommons/ai/tool_service_base.py,sha256=adsC1kesRZJGdUmvcp1KrXgQ1RuLE7OMnPwRUsaP8DM,34578
5
- sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.py,sha256=YcZjb_YM-XeLErM8hEC_S7vGMVGvcXAMGs2b-u5zvOE,2377
6
- sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.pyi,sha256=FwtXmNAf7iYGEFm4kbqb04v77jNHbZg18ZmEDhle_bU,1444
7
- sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2_grpc.py,sha256=wPImJPdCUZNVEVoUWzsba9kGIXjEKPdUkawP5SnVyiU,932
8
- sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.py,sha256=nWC91vR2pMgMUyNOZRZ0YiuL1-8ntnjXLqt1daxsD34,20869
9
- sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.pyi,sha256=U5zXrbBxsWilLTsRWJd1TqjdjLKFsr3enF9OJ8GfyWw,34028
10
- sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2_grpc.py,sha256=4vD4jWanaJ4uclSkFmS7JIz_lwYXDWBE3DomuPjUyII,941
11
- sapiopycommons/ai/api/plan/proto/step_output_pb2.py,sha256=JpBZSyoYyPTEaaXjW664PeJNK0zxV1mly_kp5re42z4,2661
12
- sapiopycommons/ai/api/plan/proto/step_output_pb2.pyi,sha256=yuxOYnDZ9DRuu-TLzaKOW_B4LUiYxTrNc2AbssXg4kE,2022
13
- sapiopycommons/ai/api/plan/proto/step_output_pb2_grpc.py,sha256=vDRY_pIIshQ4UpdW-ra1F5zBmntdsW2scySkMAA-zfc,925
14
- sapiopycommons/ai/api/plan/proto/step_pb2.py,sha256=nL976oTFdX4ih4gg7_J-8eFoGB69tFvERB2gT3L2-6s,2439
15
- sapiopycommons/ai/api/plan/proto/step_pb2.pyi,sha256=QPIcsjcUvEGQkdZMUMiVzFFNDl8yOUe_qJtf5XEp5Ck,2062
16
- sapiopycommons/ai/api/plan/proto/step_pb2_grpc.py,sha256=DgiBYFvTNiDG_2a9Tpt5iel2fRUfePZWP41fZTC-KWk,918
17
- sapiopycommons/ai/api/plan/script/proto/script_pb2.py,sha256=5tmf7Wmxt42XA8g_2Qv-sxnA7AuK-A0kCT3-4i1Y2Vk,4221
18
- sapiopycommons/ai/api/plan/script/proto/script_pb2.pyi,sha256=mJ-JXUMUyIjPvv-glNn8FRlDfG1yGivtY0mp6dXVSjA,6061
19
- sapiopycommons/ai/api/plan/script/proto/script_pb2_grpc.py,sha256=RkShHpe_d5EJHk3qp-or1JpvSEqShb7cCiaXnJ2YSww,6931
20
- sapiopycommons/ai/api/plan/tool/proto/entry_pb2.py,sha256=A-ufAWwbJ0odVXBZBQKvke6LYPijPl2dpb2IFRaXmPE,4124
21
- sapiopycommons/ai/api/plan/tool/proto/entry_pb2.pyi,sha256=NNBrdHz5PzAuUEXuGgTU4THy9rx8Sr9iGTb65QtVH4Q,4589
22
- sapiopycommons/ai/api/plan/tool/proto/entry_pb2_grpc.py,sha256=YKkX2kexERUx4asLCShufSnZhgf339Zk8Xw1FAgLfHQ,924
23
- sapiopycommons/ai/api/plan/tool/proto/tool_pb2.py,sha256=jrSgsSx8mGPWuxYPxOom7l925bavWaX4NEQAkC9niJo,6854
24
- sapiopycommons/ai/api/plan/tool/proto/tool_pb2.pyi,sha256=KzOmH-ic0anjRta4jhScMRCOI1OtO5rSZrQDr_W3eZ0,15992
25
- sapiopycommons/ai/api/plan/tool/proto/tool_pb2_grpc.py,sha256=68u5E1ZKha5frP5GuY8Ad-c0c79vBhtfnj5Q4u-8xOY,6982
26
- sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.py,sha256=WKzNi-d5dqeJbmEXUVE5qJ4Qm34HmsqRXRtXih382g8,2100
27
- sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.pyi,sha256=vLYA8Tkzq2AwgVadoUp5vAg4HgGlgga0kzeS3e_XkCQ,1621
28
- sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2_grpc.py,sha256=2W0YzT4SfnGTLq98AdvkyNM0n75Tkl8DervPS1ryGao,932
29
- sapiopycommons/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- sapiopycommons/callbacks/callback_util.py,sha256=sz76LzD9sVLPMcoOpmzPe1aILGXcpHfyZ-qex8oR11c,130849
31
- sapiopycommons/callbacks/field_builder.py,sha256=p2XacN99MuKk3ite8GAqstUMpixqugul2CsC4gB83-o,38620
32
- sapiopycommons/chem/IndigoMolecules.py,sha256=slM2y39zZFHc468c366EqR8T-GYJ24UnM9HWAqWFEwQ,3900
33
- sapiopycommons/chem/Molecules.py,sha256=5PzRyE1s-Z3nfwh3Y4dCNdQOIJGhog08wyZvgTkKwyU,12384
34
- sapiopycommons/chem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- sapiopycommons/customreport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- sapiopycommons/customreport/auto_pagers.py,sha256=3-XXWrP7r41a_Y-8YLPnfm0s65m4qEEUqu4azX47oPI,14828
37
- sapiopycommons/customreport/column_builder.py,sha256=0RO53e9rKPZ07C--KcepN6_tpRw_FxF3O9vdG0ilKG8,3014
38
- sapiopycommons/customreport/custom_report_builder.py,sha256=BlTxZ4t1sfZA2Ciur1EfYvkZxHxJ7ADwYNAe2zwiN0c,7176
39
- sapiopycommons/customreport/term_builder.py,sha256=PNp71NF1vFxidk5v6uQNi9oQR9KJIk8WfhyntvvZN-U,18573
40
- sapiopycommons/datatype/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- sapiopycommons/datatype/attachment_util.py,sha256=N-nhsJ0oxa_Ft6Y6VWeNFYLzfuQqsjhHA6_-yIt2wVw,3596
42
- sapiopycommons/datatype/data_fields.py,sha256=pczUlEcE0TeHEDU0Gkvu7voacSLPXCB7l9UbI1Tb6V0,5656
43
- sapiopycommons/datatype/pseudo_data_types.py,sha256=6TG7aJxgmUZ8FQkWBcgmbK5oy7AFFNtKOPpi1w1OOYA,27657
44
- sapiopycommons/eln/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- sapiopycommons/eln/experiment_handler.py,sha256=FeqmjnxN5WyDDstN3_AMSo9r7nQi-5zou4m-3K5JsYM,123363
46
- sapiopycommons/eln/experiment_report_util.py,sha256=NNNNPVD3_2ZAjoOqCMOnlnmPD0SCjDcgYi453ATSJBs,37027
47
- sapiopycommons/eln/experiment_tags.py,sha256=7-fpOiSqrjbXmWIJhEhaxMgLsVCPAtKqH8xRzpDVKoE,356
48
- sapiopycommons/eln/plate_designer.py,sha256=ix2cflz13PAHyu4deS3d5Qd3kQXk0C7IQxBQ2Dm9fEM,13692
49
- sapiopycommons/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- sapiopycommons/files/complex_data_loader.py,sha256=T39veNhvYl6j_uZjIIJ8Mk5Aa7otR5RB-g8XlAdkksA,1421
51
- sapiopycommons/files/file_bridge.py,sha256=vKbqxPexi15epr_-_qLrEfYoxNxB031mXN92iVtOMqE,9511
52
- sapiopycommons/files/file_bridge_handler.py,sha256=SEYDIQhSCmjI6qyLdDJE8JVKSd0WYvF7JvAq_Ahp9Do,25503
53
- sapiopycommons/files/file_data_handler.py,sha256=f96MlkMuQhUCi4oLnzJK5AiuElCp5jLI8_sJkZVwpws,36779
54
- sapiopycommons/files/file_util.py,sha256=w4Q7zYJb9YaPxrecmT4RT_OOibKMRP0NI1CyoOLfAP4,31747
55
- sapiopycommons/files/file_validator.py,sha256=ryg22-93csmRO_Pv0ZpWphNkB74xWZnHyJ23K56qLj0,28761
56
- sapiopycommons/files/file_writer.py,sha256=hACVl0duCjP28gJ1NPljkjagNCLod0ygUlPbvUmRDNM,17605
57
- sapiopycommons/flowcyto/flow_cyto.py,sha256=vs9WhXXKz3urpjL8QKSk56B-NSmQR3O3x_WFBKoeO10,3227
58
- sapiopycommons/flowcyto/flowcyto_data.py,sha256=mYKFuLbtpJ-EsQxLGtu4tNHVlygTxKixgJxJqD68F58,2596
59
- sapiopycommons/general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
- sapiopycommons/general/accession_service.py,sha256=QeNGd78Zr08ezWpThTuAkxO4bXusEcp5x9jJRZRwliA,13483
61
- sapiopycommons/general/aliases.py,sha256=alc2R5TOSKbZif3pcGZ706y23Y9F4HQPC-Kj4xJZ_Us,14503
62
- sapiopycommons/general/audit_log.py,sha256=KQq0PsvukUoE3l6TQb3-vpu5-MbSINpWlnQ9e7jojPg,8743
63
- sapiopycommons/general/custom_report_util.py,sha256=NwwmejSQLwSbrndEk1gPyFNYk9GZoS7Wrp9ab9moFgw,18014
64
- sapiopycommons/general/directive_util.py,sha256=7SeQrd2Ye5JHlXZtJZaVGgtaSLdq_Vm9EObuxf44Pz8,3905
65
- sapiopycommons/general/exceptions.py,sha256=aPlzK1cvxeMU5UsokYlLrIBGltUfJZ7LH8zvLh9DxpI,3233
66
- sapiopycommons/general/html_formatter.py,sha256=HE3OeGgwOw6x53zGSc4-UzP4-JoOmQIz3pX-DzNVg94,17138
67
- sapiopycommons/general/popup_util.py,sha256=HKILegU1uCL_6abNlNL0Wn3xgX2JNa_kJeq7e5CZu6Q,31923
68
- sapiopycommons/general/sapio_links.py,sha256=YkcVKNLrSGoM7tCCXBAsIbIxylctwdcEyhePrRMODe0,2859
69
- sapiopycommons/general/storage_util.py,sha256=ovmK_jN7v09BoX07XxwShpBUC5WYQOM7dbKV_VeLXJU,8892
70
- sapiopycommons/general/time_util.py,sha256=jU1urPoZRv6evNucR0-288EyT4PrsDpCr-H1-7BKq9A,12363
71
- sapiopycommons/multimodal/multimodal.py,sha256=PFaGJPbKvW__tnxb8KkgkJZOKjQdgxF_kGfD5chet1s,6779
72
- sapiopycommons/multimodal/multimodal_data.py,sha256=0BeVPr9HaC0hNTF1v1phTIKGruvNnwerHsD994qJKBg,15099
73
- sapiopycommons/processtracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
- sapiopycommons/processtracking/custom_workflow_handler.py,sha256=QZVRDUXpHfYIKD9LtaOcOt0Sr3RGDaeGQb-LZYAgkCc,25117
75
- sapiopycommons/processtracking/endpoints.py,sha256=w5bziI2xC7450M95rCF8JpRwkoni1kEDibyAux9B12Q,10848
76
- sapiopycommons/recordmodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
- sapiopycommons/recordmodel/record_handler.py,sha256=aPbR3OS0RlsKOGztY-LZaOmkXKUB8ZTw3qqdJKXwd6U,70872
78
- sapiopycommons/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
- sapiopycommons/rules/eln_rule_handler.py,sha256=1aC88brATcjL1O0Hd2hQ0XNguKsKh8xELXComotk3mQ,10772
80
- sapiopycommons/rules/on_save_rule_handler.py,sha256=J1YKjOGA1KUTwpnZMa7oIi5QU_4mBJrPygSHNDsMIIA,10539
81
- sapiopycommons/samples/aliquot.py,sha256=mWOJUqaQh0t3HklNuGdmuV7D5zzXs6fpLwtDdM6_XTo,3018
82
- sapiopycommons/sftpconnect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
- sapiopycommons/sftpconnect/sftp_builder.py,sha256=lFK3FeXk-sFLefW0hqY8WGUQDeYiGaT6yDACzT_zFgQ,3015
84
- sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
- sapiopycommons/webhook/webhook_context.py,sha256=D793uLsb1691SalaPnBUk3rOSxn_hYLhdvkaIxjNXss,1909
86
- sapiopycommons/webhook/webhook_handlers.py,sha256=L0HetSm43NvA5KyW3xbLpGFh2DbAaeZJVtXIEl2fvV8,39689
87
- sapiopycommons/webhook/webservice_handlers.py,sha256=Y5dHx_UFWFuSqaoPL6Re-fsKYRuxvCWZ8bj6KSZ3jfM,14285
88
- sapiopycommons-2025.5.13a523.dist-info/METADATA,sha256=QqPGY0nDOqra3OvNj_CbyA5SNwYfSzf8DOZm1HbjPfo,3143
89
- sapiopycommons-2025.5.13a523.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
90
- sapiopycommons-2025.5.13a523.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
91
- sapiopycommons-2025.5.13a523.dist-info/RECORD,,