sapiopycommons 2025.8.14a703__py3-none-any.whl → 2026.1.22a847__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.
Files changed (57) hide show
  1. sapiopycommons/ai/agent_service_base.py +2051 -0
  2. sapiopycommons/ai/converter_service_base.py +163 -0
  3. sapiopycommons/ai/external_credentials.py +131 -0
  4. sapiopycommons/ai/protoapi/agent/agent_pb2.py +87 -0
  5. sapiopycommons/ai/protoapi/agent/agent_pb2.pyi +282 -0
  6. sapiopycommons/ai/protoapi/agent/agent_pb2_grpc.py +154 -0
  7. sapiopycommons/ai/protoapi/agent/entry_pb2.py +49 -0
  8. sapiopycommons/ai/protoapi/agent/entry_pb2.pyi +40 -0
  9. sapiopycommons/ai/protoapi/agent/entry_pb2_grpc.py +24 -0
  10. sapiopycommons/ai/protoapi/agent/item/item_container_pb2.py +61 -0
  11. sapiopycommons/ai/protoapi/agent/item/item_container_pb2.pyi +181 -0
  12. sapiopycommons/ai/protoapi/agent/item/item_container_pb2_grpc.py +24 -0
  13. sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2.py +41 -0
  14. sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2.pyi +36 -0
  15. sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2_grpc.py +24 -0
  16. sapiopycommons/ai/protoapi/fielddefinitions/fields_pb2.py +51 -0
  17. sapiopycommons/ai/protoapi/fielddefinitions/fields_pb2.pyi +59 -0
  18. sapiopycommons/ai/protoapi/fielddefinitions/fields_pb2_grpc.py +24 -0
  19. sapiopycommons/ai/protoapi/fielddefinitions/velox_field_def_pb2.py +123 -0
  20. sapiopycommons/ai/protoapi/fielddefinitions/velox_field_def_pb2.pyi +599 -0
  21. sapiopycommons/ai/protoapi/fielddefinitions/velox_field_def_pb2_grpc.py +24 -0
  22. sapiopycommons/ai/protoapi/pipeline/converter/converter_pb2.py +59 -0
  23. sapiopycommons/ai/protoapi/pipeline/converter/converter_pb2.pyi +68 -0
  24. sapiopycommons/ai/protoapi/pipeline/converter/converter_pb2_grpc.py +149 -0
  25. sapiopycommons/ai/protoapi/pipeline/script/script_pb2.py +69 -0
  26. sapiopycommons/ai/protoapi/pipeline/script/script_pb2.pyi +109 -0
  27. sapiopycommons/ai/protoapi/pipeline/script/script_pb2_grpc.py +153 -0
  28. sapiopycommons/ai/protoapi/pipeline/step_output_pb2.py +49 -0
  29. sapiopycommons/ai/protoapi/pipeline/step_output_pb2.pyi +56 -0
  30. sapiopycommons/ai/protoapi/pipeline/step_output_pb2_grpc.py +24 -0
  31. sapiopycommons/ai/protoapi/pipeline/step_pb2.py +43 -0
  32. sapiopycommons/ai/protoapi/pipeline/step_pb2.pyi +44 -0
  33. sapiopycommons/ai/protoapi/pipeline/step_pb2_grpc.py +24 -0
  34. sapiopycommons/ai/protoapi/session/sapio_conn_info_pb2.py +39 -0
  35. sapiopycommons/ai/protoapi/session/sapio_conn_info_pb2.pyi +33 -0
  36. sapiopycommons/ai/protoapi/session/sapio_conn_info_pb2_grpc.py +24 -0
  37. sapiopycommons/ai/protobuf_utils.py +583 -0
  38. sapiopycommons/ai/request_validation.py +561 -0
  39. sapiopycommons/ai/server.py +152 -0
  40. sapiopycommons/ai/test_client.py +534 -0
  41. sapiopycommons/callbacks/callback_util.py +26 -7
  42. sapiopycommons/eln/experiment_handler.py +12 -5
  43. sapiopycommons/files/file_util.py +128 -1
  44. sapiopycommons/files/temp_files.py +82 -0
  45. sapiopycommons/general/aliases.py +4 -1
  46. sapiopycommons/general/macros.py +172 -0
  47. sapiopycommons/general/time_util.py +199 -4
  48. sapiopycommons/recordmodel/record_handler.py +47 -12
  49. sapiopycommons/rules/eln_rule_handler.py +3 -0
  50. sapiopycommons/rules/on_save_rule_handler.py +3 -0
  51. sapiopycommons/webhook/webservice_handlers.py +1 -1
  52. {sapiopycommons-2025.8.14a703.dist-info → sapiopycommons-2026.1.22a847.dist-info}/METADATA +2 -2
  53. sapiopycommons-2026.1.22a847.dist-info/RECORD +113 -0
  54. sapiopycommons/ai/tool_of_tools.py +0 -917
  55. sapiopycommons-2025.8.14a703.dist-info/RECORD +0 -72
  56. {sapiopycommons-2025.8.14a703.dist-info → sapiopycommons-2026.1.22a847.dist-info}/WHEEL +0 -0
  57. {sapiopycommons-2025.8.14a703.dist-info → sapiopycommons-2026.1.22a847.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,583 @@
1
+ from typing import Mapping
2
+
3
+ from sapiopylib.rest.pojo.DataRecord import DataRecord
4
+ from sapiopylib.rest.pojo.Sort import SortDirection
5
+ from sapiopylib.rest.pojo.datatype.FieldDefinition import AbstractVeloxFieldDefinition, FieldType, \
6
+ VeloxBooleanFieldDefinition, VeloxDateFieldDefinition, VeloxAccessionFieldDefinition, VeloxActionFieldDefinition, \
7
+ VeloxChildLinkFieldDefinition, VeloxDateRangeFieldDefinition, VeloxDoubleFieldDefinition, \
8
+ VeloxEnumFieldDefinition, VeloxIdentifierFieldDefinition, VeloxIntegerFieldDefinition, \
9
+ VeloxLongFieldDefinition, VeloxMultiParentFieldDefinition, VeloxParentFieldDefinition, \
10
+ VeloxPickListFieldDefinition, VeloxSelectionFieldDefinition, VeloxShortFieldDefinition, \
11
+ VeloxStringFieldDefinition, VeloxSideLinkFieldDefinition, VeloxActionStringFieldDefinition, FieldValidator, \
12
+ ListMode, SapioDoubleFormat, SapioStringFormat
13
+
14
+ from sapiopycommons.ai.protoapi.fielddefinitions.fields_pb2 import FieldValuePbo, DataRecordPbo
15
+ from sapiopycommons.ai.protoapi.fielddefinitions.velox_field_def_pb2 import FieldTypePbo, SortDirectionPbo, \
16
+ DoubleFormatPbo, StringFormatPbo, FieldValidatorPbo, VeloxFieldDefPbo, BooleanPropertiesPbo, DatePropertiesPbo, \
17
+ DoublePropertiesPbo, IntegerPropertiesPbo, LongPropertiesPbo, SelectionPropertiesPbo, StringPropertiesPbo, \
18
+ SideLinkPropertiesPbo, ShortPropertiesPbo, PickListPropertiesPbo, ParentLinkPropertiesPbo, MultiParentPropertiesPbo, \
19
+ IdentifierPropertiesPbo, FileBlobPropertiesPbo, EnumPropertiesPbo, DateRangePropertiesPbo, ChildLinkPropertiesPbo, \
20
+ ActionStringPropertiesPbo, ActionPropertiesPbo, AccessionPropertiesPbo, SelectionDependentFieldEntryPbo, \
21
+ EnumDependentFieldEntryPbo, BooleanDependentFieldEntryPbo
22
+ from sapiopycommons.general.aliases import FieldValue
23
+
24
+
25
+ # FR-47422: Created class.
26
+ class ProtobufUtils:
27
+ @staticmethod
28
+ def field_type_to_pbo(field_type: FieldType) -> FieldTypePbo:
29
+ """
30
+ Convert a FieldType enum to its corresponding FieldTypePbo.
31
+
32
+ :param field_type: The FieldType enum value.
33
+ :return: The corresponding FieldTypePbo.
34
+ """
35
+ match field_type:
36
+ case FieldType.ACTION:
37
+ return FieldTypePbo.ACTION
38
+ case FieldType.ACTION_STRING:
39
+ return FieldTypePbo.ACTION_STRING
40
+ case FieldType.AUTO_ACCESSION:
41
+ return FieldTypePbo.AUTO_ACCESSION
42
+ case FieldType.BOOLEAN:
43
+ return FieldTypePbo.BOOLEAN
44
+ case FieldType.CHILDLINK:
45
+ return FieldTypePbo.CHILDLINK
46
+ case FieldType.DATE:
47
+ return FieldTypePbo.DATE
48
+ case FieldType.DATE_RANGE:
49
+ return FieldTypePbo.DATE_RANGE
50
+ case FieldType.DOUBLE:
51
+ return FieldTypePbo.DOUBLE
52
+ case FieldType.ENUM:
53
+ return FieldTypePbo.ENUM
54
+ # case FieldType.FILE_BLOB:
55
+ # return FieldTypePbo.FILE_BLOB
56
+ case FieldType.IDENTIFIER:
57
+ return FieldTypePbo.IDENTIFIER
58
+ case FieldType.INTEGER:
59
+ return FieldTypePbo.INTEGER
60
+ case FieldType.LINK:
61
+ return FieldTypePbo.LINK
62
+ case FieldType.LONG:
63
+ return FieldTypePbo.LONG
64
+ case FieldType.MULTIPARENTLINK:
65
+ return FieldTypePbo.MULTIPARENTLINK
66
+ case FieldType.PARENTLINK:
67
+ return FieldTypePbo.PARENTLINK
68
+ case FieldType.PICKLIST:
69
+ return FieldTypePbo.PICKLIST
70
+ case FieldType.SELECTION:
71
+ return FieldTypePbo.SELECTION
72
+ case FieldType.SHORT:
73
+ return FieldTypePbo.SHORT
74
+ case FieldType.SIDE_LINK:
75
+ return FieldTypePbo.SIDE_LINK
76
+ case FieldType.STRING:
77
+ return FieldTypePbo.STRING
78
+ case _:
79
+ return FieldTypePbo.FIELD_TYPE_UNSPECIFIED
80
+
81
+ @staticmethod
82
+ def sort_direction_to_pbo(sort_direction: SortDirection | None) -> SortDirectionPbo:
83
+ """
84
+ Convert a SortDirection enum to its corresponding SortDirectionPbo.
85
+
86
+ :param sort_direction: The SortDirection enum value.
87
+ :return: The corresponding SortDirectionPbo.
88
+ """
89
+ if sort_direction is None or sort_direction == SortDirection.NONE:
90
+ return SortDirectionPbo.SORT_DIRECTION_NONE
91
+ elif sort_direction == SortDirection.ASCENDING:
92
+ return SortDirectionPbo.SORT_DIRECTION_ASCENDING
93
+ elif sort_direction == SortDirection.DESCENDING:
94
+ return SortDirectionPbo.SORT_DIRECTION_DESCENDING
95
+ else:
96
+ return SortDirectionPbo.SORT_DIRECTION_UNSPECIFIED
97
+
98
+ @staticmethod
99
+ def double_format_to_pbo(double_format: SapioDoubleFormat | None) -> DoubleFormatPbo:
100
+ """
101
+ Convert a SapioDoubleFormat enum to its corresponding DoubleFormatPbo.
102
+
103
+ :param double_format: The SapioDoubleFormat enum value.
104
+ :return: The corresponding DoubleFormatPbo.
105
+ """
106
+ if double_format is None:
107
+ return DoubleFormatPbo.DOUBLE_FORMAT_UNSPECIFIED
108
+ elif double_format == SapioDoubleFormat.CURRENCY:
109
+ return DoubleFormatPbo.DOUBLE_FORMAT_CURRENCY
110
+ elif double_format == SapioDoubleFormat.PERCENTAGE:
111
+ return DoubleFormatPbo.DOUBLE_FORMAT_PERCENTAGE
112
+ else:
113
+ return DoubleFormatPbo.DOUBLE_FORMAT_UNSPECIFIED
114
+
115
+ @staticmethod
116
+ def string_format_to_pbo(string_format: SapioStringFormat | None) -> StringFormatPbo:
117
+ """
118
+ Convert a SapioStringFormat enum to its corresponding StringFormatPbo.
119
+
120
+ :param string_format: The SapioStringFormat enum value.
121
+ :return: The corresponding StringFormatPbo.
122
+ """
123
+ if string_format is None:
124
+ return StringFormatPbo.STRING_FORMAT_UNSPECIFIED
125
+ elif string_format == SapioStringFormat.EMAIL:
126
+ return StringFormatPbo.STRING_FORMAT_EMAIL
127
+ elif string_format == SapioStringFormat.PHONE:
128
+ return StringFormatPbo.STRING_FORMAT_PHONE
129
+ else:
130
+ return StringFormatPbo.STRING_FORMAT_UNSPECIFIED
131
+
132
+ @staticmethod
133
+ def field_validator_to_pbo(validator: FieldValidator | None) -> FieldValidatorPbo | None:
134
+ """
135
+ Convert a FieldValidator object to its corresponding FieldValidatorPbo.
136
+
137
+ :param validator: The FieldValidator object.
138
+ :return: The corresponding FieldValidatorPbo or None if validator is None.
139
+ """
140
+ if validator is None:
141
+ return None
142
+ return FieldValidatorPbo(
143
+ validation_regex=validator.validation_regex,
144
+ error_message=validator.error_message
145
+ )
146
+
147
+ @staticmethod
148
+ def field_validator_pbo(regex: str | None, error: str | None) -> FieldValidatorPbo | None:
149
+ """
150
+ Create a FieldValidatorPbo object with the provided regex and error message. Returns None if the regex is None.
151
+ """
152
+ if not regex:
153
+ return None
154
+ return FieldValidatorPbo(
155
+ validation_regex=regex,
156
+ error_message=error
157
+ )
158
+
159
+ @staticmethod
160
+ def list_mode_to_str(list_mode: ListMode, field: VeloxSelectionFieldDefinition) -> str | None:
161
+ """
162
+ Convert a ListMode enum to its string representation.
163
+
164
+ :param list_mode: The ListMode enum value.
165
+ :param field: The VeloxSelectionFieldDefinition object.
166
+ :return: The string representation of the ListMode or None if list_mode is None.
167
+ """
168
+ if list_mode is None:
169
+ return None
170
+ list_mode_str = list_mode.list_mode_name
171
+ if list_mode == ListMode.LIST:
172
+ list_mode_str += field.pick_list_name or ""
173
+ elif list_mode == ListMode.PLUGIN:
174
+ list_mode_str += field.plugin_name or ""
175
+ elif list_mode == ListMode.REPORT:
176
+ list_mode_str += field.custom_report_name or ""
177
+ return list_mode_str
178
+
179
+ @staticmethod
180
+ def field_def_to_pbo(field: AbstractVeloxFieldDefinition) -> VeloxFieldDefPbo:
181
+ """
182
+ Convert a AbstractVeloxFieldDefinition object to its corresponding VeloxFieldDefPbo.
183
+
184
+ :param field: The AbstractVeloxFieldDefinition object.
185
+ :return: The corresponding VeloxFieldDefPbo.
186
+ """
187
+ accession_properties: AccessionPropertiesPbo | None = None
188
+ action_properties: ActionPropertiesPbo | None = None
189
+ action_string_properties: ActionStringPropertiesPbo | None = None
190
+ boolean_properties: BooleanPropertiesPbo | None = None
191
+ child_link_properties: ChildLinkPropertiesPbo | None = None
192
+ date_properties: DatePropertiesPbo | None = None
193
+ date_range_properties: DateRangePropertiesPbo | None = None
194
+ double_properties: DoublePropertiesPbo | None = None
195
+ enum_properties: EnumPropertiesPbo | None = None
196
+ file_blob_properties: FileBlobPropertiesPbo | None = None
197
+ identifier_properties: IdentifierPropertiesPbo | None = None
198
+ integer_properties: IntegerPropertiesPbo | None = None
199
+ long_properties: LongPropertiesPbo | None = None
200
+ multi_parent_properties: MultiParentPropertiesPbo | None = None
201
+ parent_link_properties: ParentLinkPropertiesPbo | None = None
202
+ picklist_properties: PickListPropertiesPbo | None = None
203
+ selection_properties: SelectionPropertiesPbo | None = None
204
+ short_properties: ShortPropertiesPbo | None = None
205
+ side_link_properties: SideLinkPropertiesPbo | None = None
206
+ string_properties: StringPropertiesPbo | None = None
207
+
208
+ if isinstance(field, VeloxAccessionFieldDefinition):
209
+ accession_properties = AccessionPropertiesPbo(
210
+ unique_value=field.unique_value,
211
+ # index_for_search # Missing in FieldDefinition.py
212
+ link_out=field.link_out,
213
+ link_out_url=field.link_out_url,
214
+ sequence_key=field.sequence_key,
215
+ prefix=field.prefix,
216
+ suffix=field.suffix,
217
+ number_of_digits=field.number_of_digits,
218
+ starting_value=field.starting_value
219
+ )
220
+ elif isinstance(field, VeloxActionFieldDefinition):
221
+ action_properties = ActionPropertiesPbo(
222
+ # icon_name # Missing in FieldDefinition.py
223
+ # icon_color # Missing in FieldDefinition.py
224
+ # background_color # Missing in FieldDefinition.py
225
+ # font_color # Missing in FieldDefinition.py
226
+ # action_plugin_path # Missing in FieldDefinition.py
227
+ )
228
+ elif isinstance(field, VeloxActionStringFieldDefinition):
229
+ action_string_properties = ActionStringPropertiesPbo(
230
+ default_value=field.default_value,
231
+ max_length=field.max_length,
232
+ unique_value=field.unique_value,
233
+ icon_name=field.icon_name,
234
+ action_plugin_path=field.action_plugin_path,
235
+ field_validator=ProtobufUtils.field_validator_to_pbo(field.field_validator),
236
+ direct_edit=field.direct_edit
237
+ )
238
+ elif isinstance(field, VeloxBooleanFieldDefinition):
239
+ boolean_properties = BooleanPropertiesPbo(
240
+ default_value=field.default_value,
241
+ is_process_todo_item=field.process_todo_item,
242
+ dependent_fields=[BooleanDependentFieldEntryPbo(key=k, dependent_field_names=v)
243
+ for k, v in field.get_dependent_field_map().items()],
244
+ is_hide_disabled_fields=field.hide_disabled_fields
245
+ )
246
+ elif isinstance(field, VeloxChildLinkFieldDefinition):
247
+ child_link_properties = ChildLinkPropertiesPbo(
248
+ # default_value # Missing in FieldDefinition.py
249
+ )
250
+ elif isinstance(field, VeloxDateFieldDefinition):
251
+ date_properties = DatePropertiesPbo(
252
+ default_value=field.default_value,
253
+ static_date=field.static_date,
254
+ date_time_format=field.date_time_format
255
+ )
256
+ elif isinstance(field, VeloxDateRangeFieldDefinition):
257
+ date_range_properties = DateRangePropertiesPbo(
258
+ default_value=field.default_value,
259
+ is_static=field.static_date,
260
+ date_time_format=field.date_time_format
261
+ )
262
+ elif isinstance(field, VeloxDoubleFieldDefinition):
263
+ double_properties = DoublePropertiesPbo(
264
+ min_value=field.min_value,
265
+ max_value=field.max_value,
266
+ default_value=field.default_value,
267
+ precision=field.precision,
268
+ double_format=ProtobufUtils.double_format_to_pbo(field.double_format),
269
+ # color_ranges # Missing in FieldDefinition.py
270
+ )
271
+ # elif isinstance(field, VeloxFileBlobFieldDefinition):
272
+ # file_blob_properties = FileBlobPropertiesPbo()
273
+ elif isinstance(field, VeloxEnumFieldDefinition):
274
+ enum_properties = EnumPropertiesPbo(
275
+ default_value=field.default_value,
276
+ values=field.values if field.values is not None else [],
277
+ # color_mapping # Missing in FieldDefinition.py
278
+ # auto_clear_field_list # Missing in FieldDefinition.py
279
+ dependent_fields=[EnumDependentFieldEntryPbo(key=k, dependent_field_names=v)
280
+ for k,v in field.get_dependent_field_map().items()],
281
+ is_hide_disabled_fields=field.hide_disabled_fields
282
+ )
283
+ elif isinstance(field, VeloxIdentifierFieldDefinition):
284
+ identifier_properties = IdentifierPropertiesPbo(
285
+ # default_value # Missing in FieldDefinition.py
286
+ )
287
+ elif isinstance(field, VeloxIntegerFieldDefinition):
288
+ integer_properties = IntegerPropertiesPbo(
289
+ min_value=field.min_value,
290
+ max_value=field.max_value,
291
+ default_value=field.default_value,
292
+ unique_value=field.unique_value,
293
+ # color_ranges # Missing in FieldDefinition.py
294
+ )
295
+ elif isinstance(field, VeloxLongFieldDefinition):
296
+ long_properties = LongPropertiesPbo(
297
+ min_value=field.min_value,
298
+ max_value=field.max_value,
299
+ default_value=field.default_value,
300
+ unique_value=field.unique_value,
301
+ # color_ranges # Missing in FieldDefinition.py
302
+ )
303
+ elif isinstance(field, VeloxMultiParentFieldDefinition):
304
+ multi_parent_properties = MultiParentPropertiesPbo()
305
+ elif isinstance(field, VeloxParentFieldDefinition):
306
+ parent_link_properties = ParentLinkPropertiesPbo(
307
+ # default_value # Missing in FieldDefinition.py
308
+ )
309
+ elif isinstance(field, VeloxPickListFieldDefinition):
310
+ picklist_properties = PickListPropertiesPbo(
311
+ default_value=field.default_value,
312
+ pick_list_name=field.pick_list_name,
313
+ direct_edit=field.direct_edit,
314
+ # link_out # Missing in FieldDefinition.py
315
+ # link_out_url # Missing in FieldDefinition.py
316
+ # index_for_search # Missing in FieldDefinition.py
317
+ # field_validator # Missing in FieldDefinition.py
318
+ # color_mapping # Missing in FieldDefinition.py
319
+ # auto_clear_field_list # Missing in FieldDefinition.py
320
+ # process_detail_map # Missing in FieldDefinition.py
321
+ dependent_fields=[SelectionDependentFieldEntryPbo(key=k, dependent_field_names=v)
322
+ for k,v in field.get_dependent_field_map().items()],
323
+ is_hide_disabled_fields=field.hide_disabled_fields
324
+ )
325
+ elif isinstance(field, VeloxSelectionFieldDefinition):
326
+ list_mode_str = ProtobufUtils.list_mode_to_str(field.list_mode, field)
327
+ selection_properties = SelectionPropertiesPbo(
328
+ default_value=field.default_value,
329
+ list_mode=list_mode_str,
330
+ # auto_sort # Missing in FieldDefinition.py
331
+ direct_edit=field.direct_edit,
332
+ unique_value=field.unique_value,
333
+ # link_out # Missing in FieldDefinition.py
334
+ # link_out_url # Missing in FieldDefinition.py
335
+ multi_select=field.multi_select,
336
+ # index_for_search # Missing in FieldDefinition.py
337
+ # is_auto_size # Missing in FieldDefinition.py
338
+ # field_validator # Missing in FieldDefinition.py
339
+ static_list_values=field.static_list_values if field.static_list_values is not None else [],
340
+ # color_mapping # Missing in FieldDefinition.py
341
+ # auto_clear_field_list # Missing in FieldDefinition.py
342
+ # process_detail_map # Missing in FieldDefinition.py
343
+ dependent_fields=[SelectionDependentFieldEntryPbo(key=k, dependent_field_names=v)
344
+ for k,v in field.get_dependent_field_map().items()],
345
+ is_hide_disabled_fields=field.hide_disabled_fields
346
+ )
347
+ elif isinstance(field, VeloxShortFieldDefinition):
348
+ short_properties = ShortPropertiesPbo(
349
+ min_value=field.min_value,
350
+ max_value=field.max_value,
351
+ default_value=field.default_value,
352
+ unique_value=field.unique_value,
353
+ # color_ranges # Missing in FieldDefinition.py
354
+ )
355
+ elif isinstance(field, VeloxSideLinkFieldDefinition):
356
+ side_link_properties = SideLinkPropertiesPbo(
357
+ linked_data_type_name=field.linked_data_type_name,
358
+ default_value=field.default_value,
359
+ # show_in_knowledge_graph # Missing in FieldDefinition.py
360
+ # knowledge_graph_display_name # Missing in FieldDefinition.py
361
+ )
362
+ elif isinstance(field, VeloxStringFieldDefinition):
363
+ string_properties = StringPropertiesPbo(
364
+ default_value=field.default_value,
365
+ max_length=field.max_length,
366
+ num_lines=field.num_lines,
367
+ unique_value=field.unique_value,
368
+ # index_for_search # Missing in FieldDefinition.py
369
+ html_editor=field.html_editor,
370
+ link_out=field.link_out,
371
+ link_out_url=field.link_out_url,
372
+ string_format=ProtobufUtils.string_format_to_pbo(field.string_format),
373
+ is_auto_size=field.auto_size,
374
+ field_validator=ProtobufUtils.field_validator_to_pbo(field.field_validator),
375
+ # preserve_padding # Missing in FieldDefinition.py
376
+ )
377
+ else:
378
+ print(f"Warning: Unhandled field type for properties mapping: {type(field)}")
379
+
380
+ return VeloxFieldDefPbo(
381
+ data_field_type=ProtobufUtils.field_type_to_pbo(field.data_field_type),
382
+ data_field_name=field.data_field_name,
383
+ display_name=field.display_name,
384
+ description=field.description,
385
+ required=field.required,
386
+ editable=field.editable,
387
+ visible=field.visible,
388
+ identifier=field.identifier,
389
+ identifier_order=field.identifier_order,
390
+ sort_direction=ProtobufUtils.sort_direction_to_pbo(field.sort_direction),
391
+ sort_order=field.sort_order,
392
+ tag=field.tag,
393
+ # approve_edit # Missing in FieldDefinition.py
394
+ # workflow_only_editing # Missing in FieldDefinition.py
395
+ # font_size # Missing in FieldDefinition.py
396
+ # bold_font # Missing in FieldDefinition.py
397
+ # italic_font # Missing in FieldDefinition.py
398
+ # text_decoration # Missing in FieldDefinition.py
399
+ is_key_field=field.key_field,
400
+ key_field_order=field.key_field_order,
401
+ # is_removable # Missing in FieldDefinition.py
402
+ is_system_field=field.system_field,
403
+ # is_restricted # Missing in FieldDefinition.py
404
+ is_audit_logged=field.audit_logged,
405
+ # is_active # Missing in FieldDefinition.py
406
+ # is_for_plugin_use_only # Missing in FieldDefinition.py
407
+ default_table_column_width=field.default_table_column_width,
408
+
409
+ accession_properties=accession_properties,
410
+ action_properties=action_properties,
411
+ action_string_properties=action_string_properties,
412
+ boolean_properties=boolean_properties,
413
+ child_link_properties=child_link_properties,
414
+ date_properties=date_properties,
415
+ date_range_properties=date_range_properties,
416
+ double_properties=double_properties,
417
+ enum_properties=enum_properties,
418
+ file_blob_properties=file_blob_properties,
419
+ identifier_properties=identifier_properties,
420
+ integer_properties=integer_properties,
421
+ long_properties=long_properties,
422
+ multi_parent_properties=multi_parent_properties,
423
+ parent_link_properties=parent_link_properties,
424
+ picklist_properties=picklist_properties,
425
+ selection_properties=selection_properties,
426
+ short_properties=short_properties,
427
+ side_link_properties=side_link_properties,
428
+ string_properties=string_properties,
429
+ )
430
+
431
+ @staticmethod
432
+ def value_to_field_pbo(value: FieldValue) -> FieldValuePbo:
433
+ """
434
+ Convert a Python value to its corresponding FieldValuePbo.
435
+
436
+ :param value: The Python value (str, int, float, bool).
437
+ :return: The corresponding FieldValuePbo object.
438
+ """
439
+ field_value = FieldValuePbo()
440
+ if isinstance(value, str):
441
+ field_value.string_value = value
442
+ elif isinstance(value, int):
443
+ field_value.int_value = value
444
+ elif isinstance(value, float):
445
+ field_value.double_value = value
446
+ elif isinstance(value, bool):
447
+ field_value.bool_value = value
448
+ elif value is not None:
449
+ raise ValueError(f"Unsupported value type: {type(value)}")
450
+ return field_value
451
+
452
+ @staticmethod
453
+ def field_map_to_pbo(field_map: dict[str, FieldValue]) -> dict[str, FieldValuePbo]:
454
+ """
455
+ Convert a field map from a record into a field map that uses FieldValuePbo objects.
456
+
457
+ :param field_map: A mapping from field names to field values.
458
+ :return: The corresponding mapping from field names to FieldValuePbo.
459
+ """
460
+ fields: dict[str, FieldValuePbo] = {}
461
+ for field, value in field_map.items():
462
+ fields[field] = ProtobufUtils.value_to_field_pbo(value)
463
+ return fields
464
+
465
+ @staticmethod
466
+ def pbo_to_field_map(field_map: Mapping[str, FieldValuePbo]) -> dict[str, FieldValue]:
467
+ """
468
+ Convert a field map from a DataRecordPbo to a field map that uses normal field value objects.
469
+
470
+ :param field_map: A mapping from field names to FieldValuePbo.
471
+ :return: The corresponding mapping from field names to field values.
472
+ """
473
+ fields: dict[str, FieldValue] = {}
474
+ for field, value in field_map.items():
475
+ fields[field] = ProtobufUtils.field_pbo_to_value(value)
476
+ return fields
477
+
478
+ @staticmethod
479
+ def field_pbo_to_value(value: FieldValuePbo) -> FieldValue:
480
+ """
481
+ Convert a FieldValuePbo to its corresponding Python value.
482
+
483
+ :param value: The FieldValuePbo object.
484
+ :return: The corresponding Python value.
485
+ """
486
+ if value.HasField("string_value"):
487
+ return value.string_value
488
+ elif value.HasField("int_value"):
489
+ return value.int_value
490
+ elif value.HasField("double_value"):
491
+ return value.double_value
492
+ elif value.HasField("bool_value"):
493
+ return value.bool_value
494
+ else:
495
+ return None
496
+
497
+ @staticmethod
498
+ def pbo_to_data_record(value: DataRecordPbo) -> DataRecord:
499
+ return DataRecord(
500
+ data_type_name=value.data_type_name,
501
+ record_id=value.record_id if value.HasField("record_id") else None,
502
+ fields=ProtobufUtils.pbo_to_field_map(value.fields),
503
+ )
504
+
505
+ @staticmethod
506
+ def field_def_pbo_to_default_value(field_def: VeloxFieldDefPbo) -> FieldValue:
507
+ """
508
+ Get the default value of a VeloxFieldDefPbo.
509
+
510
+ :param field_def: The VeloxFieldDefPbo object.
511
+ :return: The default value for the field definition.
512
+ """
513
+ match field_def.data_field_type:
514
+ case FieldTypePbo.ACTION:
515
+ return None
516
+ case FieldTypePbo.ACTION_STRING:
517
+ if not field_def.action_string_properties.HasField("default_value"):
518
+ return None
519
+ return field_def.action_string_properties.default_value
520
+ case FieldTypePbo.AUTO_ACCESSION:
521
+ return None
522
+ case FieldTypePbo.BOOLEAN:
523
+ if not field_def.boolean_properties.HasField("default_value"):
524
+ return None
525
+ return field_def.boolean_properties.default_value
526
+ case FieldTypePbo.CHILDLINK:
527
+ return None
528
+ case FieldTypePbo.DATE:
529
+ if not field_def.date_properties.HasField("default_value"):
530
+ return None
531
+ return field_def.date_properties.default_value
532
+ case FieldTypePbo.DATE_RANGE:
533
+ if not field_def.date_range_properties.HasField("default_value"):
534
+ return None
535
+ return field_def.date_range_properties.default_value
536
+ case FieldTypePbo.DOUBLE:
537
+ if not field_def.double_properties.HasField("default_value"):
538
+ return None
539
+ return field_def.double_properties.default_value
540
+ case FieldTypePbo.ENUM:
541
+ if not field_def.enum_properties.HasField("default_value"):
542
+ return None
543
+ return field_def.enum_properties.default_value
544
+ # case FieldTypePbo.FILE_BLOB:
545
+ # return None
546
+ case FieldTypePbo.IDENTIFIER:
547
+ return None
548
+ case FieldTypePbo.INTEGER:
549
+ if not field_def.integer_properties.HasField("default_value"):
550
+ return None
551
+ return field_def.integer_properties.default_value
552
+ case FieldTypePbo.LINK:
553
+ return None
554
+ case FieldTypePbo.LONG:
555
+ if not field_def.long_properties.HasField("default_value"):
556
+ return None
557
+ return field_def.long_properties.default_value
558
+ case FieldTypePbo.MULTIPARENTLINK:
559
+ return None
560
+ case FieldTypePbo.PARENTLINK:
561
+ return None
562
+ case FieldTypePbo.PICKLIST:
563
+ if not field_def.picklist_properties.HasField("default_value"):
564
+ return None
565
+ return field_def.picklist_properties.default_value
566
+ case FieldTypePbo.SELECTION:
567
+ if not field_def.selection_properties.HasField("default_value"):
568
+ return None
569
+ return field_def.selection_properties.default_value
570
+ case FieldTypePbo.SHORT:
571
+ if not field_def.short_properties.HasField("default_value"):
572
+ return None
573
+ return field_def.short_properties.default_value
574
+ case FieldTypePbo.SIDE_LINK:
575
+ if not field_def.side_link_properties.HasField("default_value"):
576
+ return None
577
+ return field_def.side_link_properties.default_value
578
+ case FieldTypePbo.STRING:
579
+ if not field_def.string_properties.HasField("default_value"):
580
+ return None
581
+ return field_def.string_properties.default_value
582
+ case _:
583
+ raise Exception(f"Unexpected field type: {field_def.data_field_type}")