holado 0.2.3__py3-none-any.whl → 0.2.5__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 holado might be problematic. Click here for more details.

Files changed (30) hide show
  1. holado/__init__.py +61 -23
  2. holado/common/context/service_manager.py +10 -2
  3. holado/common/context/session_context.py +43 -12
  4. holado/common/handlers/object.py +12 -4
  5. holado/holado_config.py +1 -0
  6. {holado-0.2.3.dist-info → holado-0.2.5.dist-info}/METADATA +1 -1
  7. {holado-0.2.3.dist-info → holado-0.2.5.dist-info}/RECORD +30 -30
  8. holado_ais/ais/ais_messages.py +140 -139
  9. holado_core/common/tools/path_manager.py +8 -4
  10. holado_grpc/api/rpc/grpc_client.py +122 -118
  11. holado_helper/docker/logging.conf +3 -1
  12. holado_helper/docker/run_holado_test_nonreg_in_docker.sh +28 -28
  13. holado_helper/docker/run_terminal_in_docker-with_docker_control.sh +27 -27
  14. holado_helper/docker/run_terminal_in_docker.sh +26 -26
  15. holado_helper/script/initialize_script.py +5 -5
  16. holado_logging/__init__.py +7 -9
  17. holado_logging/common/logging/holado_logger.py +2 -2
  18. holado_logging/common/logging/log_config.py +152 -127
  19. holado_logging/common/logging/log_manager.py +20 -19
  20. holado_multitask/multitasking/multitask_manager.py +1 -1
  21. holado_multitask/multithreading/thread.py +8 -4
  22. holado_protobuf/__init__.py +1 -1
  23. holado_protobuf/ipc/protobuf/protobuf_messages.py +821 -818
  24. holado_rabbitmq/tools/rabbitmq/rabbitmq_client.py +1 -2
  25. holado_test/behave/independant_runner.py +3 -5
  26. holado_test/scenario/step_tools.py +2 -0
  27. test_holado/environment.py +1 -1
  28. test_holado/logging.conf +3 -1
  29. {holado-0.2.3.dist-info → holado-0.2.5.dist-info}/WHEEL +0 -0
  30. {holado-0.2.3.dist-info → holado-0.2.5.dist-info}/licenses/LICENSE +0 -0
@@ -25,18 +25,19 @@ from holado_value.common.tools.value_types import ValueTypes
25
25
  import inspect
26
26
  from typing import NamedTuple
27
27
  from holado_core.common.exceptions.holado_exception import HAException
28
- from google.protobuf.descriptor import FieldDescriptor
29
28
  from holado_python.standard_library.typing import Typing
30
29
  from holado.common.handlers.undefined import undefined_argument, undefined_value
31
- from holado_protobuf.ipc.protobuf.protobuf_converter import SortOrder
32
30
 
33
31
  logger = logging.getLogger(__name__)
34
32
 
35
33
  try:
36
34
  import google.protobuf.message
37
35
  import google.protobuf.descriptor
36
+ from google.protobuf.descriptor import FieldDescriptor
38
37
  # import google.protobuf.pyext
39
38
  from google.protobuf.internal import api_implementation
39
+ from holado_protobuf.ipc.protobuf.protobuf_converter import SortOrder
40
+
40
41
  # logger.info(f"Protobuf internal API implementation is of type '{api_implementation.Type()}'")
41
42
  if api_implementation.Type() == 'cpp':
42
43
  # from google.protobuf.pyext.cpp_message import GeneratedProtocolMessageType
@@ -65,901 +66,903 @@ class ProtobufMessages(object):
65
66
  def is_available(cls):
66
67
  return with_protobuf
67
68
 
68
- @classmethod
69
- def is_descriptor_enum(cls, obj):
70
- return isinstance(obj, google.protobuf.descriptor.EnumDescriptor)
71
-
72
- @classmethod
73
- def is_descriptor_message(cls, obj):
74
- return isinstance(obj, google.protobuf.descriptor.Descriptor)
75
-
76
- @classmethod
77
- def is_object_message(cls, obj):
78
- return isinstance(obj, google.protobuf.message.Message)
79
-
80
- @classmethod
81
- def is_object_enum(cls, obj):
82
- class_name = type(obj).__name__.lower()
83
- return "enum" in class_name
84
-
85
- @classmethod
86
- def is_object_repeated(cls, obj):
87
- class_name = type(obj).__name__.lower()
88
- return "repeated" in class_name
89
-
90
- @classmethod
91
- def is_object_map(cls, obj):
92
- class_name = type(obj).__name__.lower()
93
- return "map" in class_name and hasattr(obj, 'items') and callable(obj.items)
94
- # return isinstance(obj, ScalarMap) or isinstance(obj, MessageMap)
95
-
96
- def is_message_field_set(self, obj, field_name):
97
- return self.__is_message_field_set(obj, field_name)
98
-
99
- def __init__(self):
100
- self.__message_types_by_fullname = {}
101
- self.__enum_types_by_fullname = {}
102
- self.__enum_data_by_fullname = {}
103
- self.__regex_attribute_fullname = re.compile(r'^(.*?)(?:\[(.+)\])?$')
69
+ if with_protobuf:
104
70
 
105
- self.__registered_types = []
71
+ @classmethod
72
+ def is_descriptor_enum(cls, obj):
73
+ return isinstance(obj, google.protobuf.descriptor.EnumDescriptor)
74
+
75
+ @classmethod
76
+ def is_descriptor_message(cls, obj):
77
+ return isinstance(obj, google.protobuf.descriptor.Descriptor)
78
+
79
+ @classmethod
80
+ def is_object_message(cls, obj):
81
+ return isinstance(obj, google.protobuf.message.Message)
106
82
 
107
- def initialize(self):
108
- self._register_types()
83
+ @classmethod
84
+ def is_object_enum(cls, obj):
85
+ class_name = type(obj).__name__.lower()
86
+ return "enum" in class_name
87
+
88
+ @classmethod
89
+ def is_object_repeated(cls, obj):
90
+ class_name = type(obj).__name__.lower()
91
+ return "repeated" in class_name
92
+
93
+ @classmethod
94
+ def is_object_map(cls, obj):
95
+ class_name = type(obj).__name__.lower()
96
+ return "map" in class_name and hasattr(obj, 'items') and callable(obj.items)
97
+ # return isinstance(obj, ScalarMap) or isinstance(obj, MessageMap)
98
+
99
+ def is_message_field_set(self, obj, field_name):
100
+ return self.__is_message_field_set(obj, field_name)
109
101
 
110
- def import_all_compiled_proto(self, compiled_proto_path, package_name=None, raise_if_not_exist=True):
111
- """Register a folder path containing compiled proto files. Usually it corresponds to the parameter '--python_out' passed to proto compiler."""
112
- if Tools.do_log(logger, logging.DEBUG):
113
- logger.debug(f"[ProtobufMessages] Importing all compiled proto in '{compiled_proto_path}'...")
102
+ def __init__(self):
103
+ self.__message_types_by_fullname = {}
104
+ self.__enum_types_by_fullname = {}
105
+ self.__enum_data_by_fullname = {}
106
+ self.__regex_attribute_fullname = re.compile(r'^(.*?)(?:\[(.+)\])?$')
107
+
108
+ self.__registered_types = []
114
109
 
115
- if package_name is None:
116
- package_name = ""
110
+ def initialize(self):
111
+ self._register_types()
112
+
113
+ def import_all_compiled_proto(self, compiled_proto_path, package_name=None, raise_if_not_exist=True):
114
+ """Register a folder path containing compiled proto files. Usually it corresponds to the parameter '--python_out' passed to proto compiler."""
115
+ if Tools.do_log(logger, logging.DEBUG):
116
+ logger.debug(f"[ProtobufMessages] Importing all compiled proto in '{compiled_proto_path}'...")
117
+
118
+ if package_name is None:
119
+ package_name = ""
120
+
121
+ if os.path.exists(compiled_proto_path):
122
+ if os.path.isfile(compiled_proto_path):
123
+ proto_path = os.path.dirname(compiled_proto_path)
124
+ sys.path.append(proto_path)
125
+ self.__import_compiled_proto(compiled_proto_path, package_name)
126
+ elif os.path.isdir(compiled_proto_path):
127
+ sys.path.append(compiled_proto_path)
128
+ self.__import_all_compiled_proto(compiled_proto_path, package_name)
129
+ else:
130
+ raise TechnicalException(f"Unmanaged path '{compiled_proto_path}'")
131
+ else:
132
+ msg = f"Path '{compiled_proto_path}' doesn't exist"
133
+ if raise_if_not_exist:
134
+ raise TechnicalException(msg)
135
+ else:
136
+ logger.warning(msg)
117
137
 
118
- if os.path.exists(compiled_proto_path):
119
- if os.path.isfile(compiled_proto_path):
120
- proto_path = os.path.dirname(compiled_proto_path)
121
- sys.path.append(proto_path)
122
- self.__import_compiled_proto(compiled_proto_path, package_name)
123
- elif os.path.isdir(compiled_proto_path):
124
- sys.path.append(compiled_proto_path)
125
- self.__import_all_compiled_proto(compiled_proto_path, package_name)
138
+ def __import_all_compiled_proto(self, compiled_proto_path, package_name):
139
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
140
+ logger.trace(f"[ProtobufMessages] Importing all compiled proto in '{compiled_proto_path}' (package: '{package_name}')...")
141
+ if os.path.isdir(compiled_proto_path):
142
+ lp = os.listdir(compiled_proto_path)
143
+ for cp in lp:
144
+ if not cp.startswith((".", "_")):
145
+ cur_proto_path = os.path.join(compiled_proto_path, cp)
146
+
147
+ if os.path.isfile(cur_proto_path):
148
+ self.__import_compiled_proto(cur_proto_path, package_name)
149
+ elif os.path.isdir(cur_proto_path):
150
+ cur_package_name = f"{package_name}.{cp}" if package_name is not None and len(package_name) > 0 else cp
151
+ self.__import_all_compiled_proto(cur_proto_path, cur_package_name)
152
+ else:
153
+ raise TechnicalException(f"Unmanaged path '{cur_proto_path}'")
126
154
  else:
127
155
  raise TechnicalException(f"Unmanaged path '{compiled_proto_path}'")
128
- else:
129
- msg = f"Path '{compiled_proto_path}' doesn't exist"
130
- if raise_if_not_exist:
131
- raise TechnicalException(msg)
132
- else:
133
- logger.warning(msg)
134
-
135
- def __import_all_compiled_proto(self, compiled_proto_path, package_name):
136
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
137
- logger.trace(f"[ProtobufMessages] Importing all compiled proto in '{compiled_proto_path}' (package: '{package_name}')...")
138
- if os.path.isdir(compiled_proto_path):
139
- lp = os.listdir(compiled_proto_path)
140
- for cp in lp:
141
- if not cp.startswith((".", "_")):
142
- cur_proto_path = os.path.join(compiled_proto_path, cp)
143
-
144
- if os.path.isfile(cur_proto_path):
145
- self.__import_compiled_proto(cur_proto_path, package_name)
146
- elif os.path.isdir(cur_proto_path):
147
- cur_package_name = f"{package_name}.{cp}" if package_name is not None and len(package_name) > 0 else cp
148
- self.__import_all_compiled_proto(cur_proto_path, cur_package_name)
149
- else:
150
- raise TechnicalException(f"Unmanaged path '{cur_proto_path}'")
151
- else:
152
- raise TechnicalException(f"Unmanaged path '{compiled_proto_path}'")
153
-
154
- def __import_compiled_proto(self, compiled_proto_file_path, package_name):
155
- if not os.path.isfile(compiled_proto_file_path):
156
- raise TechnicalException(f"Compiled proto path '{compiled_proto_file_path}' is not a file")
157
- if not compiled_proto_file_path.endswith("_pb2.py"):
158
- return
159
-
160
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
161
-
162
- logger.trace(f"[ProtobufMessages] Importing compiled proto file '{compiled_proto_file_path}' (package: '{package_name}')...")
163
-
164
- filename = os.path.splitext(os.path.basename(compiled_proto_file_path))[0]
165
- module_name = f"{package_name}.{filename}" if package_name is not None and len(package_name) > 0 else filename
166
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
167
- logger.trace(f"[ProtobufMessages] Importing module '{module_name}'")
168
- module = importlib.import_module(module_name)
169
156
 
170
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
171
-
172
- logger.trace(f"[ProtobufMessages] DESCRIPTOR of module '{module_name}': {self.__represent_descriptor(module.DESCRIPTOR)}")
173
- module_package = module.DESCRIPTOR.package if hasattr(module.DESCRIPTOR, 'package') else package_name
174
- self.__import_compiled_proto_object(module, module_package)
175
-
176
- def __import_compiled_proto_object(self, module_or_object, module_or_object_fullname):
177
- # Import message types
178
- if hasattr(module_or_object.DESCRIPTOR, 'message_types_by_name'):
179
- for mt_name in module_or_object.DESCRIPTOR.message_types_by_name:
180
- self.__import_compiled_proto_message(module_or_object, module_or_object_fullname, mt_name)
181
-
182
- # Import enum types
183
- if hasattr(module_or_object.DESCRIPTOR, 'enum_types_by_name'):
184
- for et_name in module_or_object.DESCRIPTOR.enum_types_by_name:
185
- self.__import_compiled_proto_enum(module_or_object, module_or_object_fullname, et_name)
157
+ def __import_compiled_proto(self, compiled_proto_file_path, package_name):
158
+ if not os.path.isfile(compiled_proto_file_path):
159
+ raise TechnicalException(f"Compiled proto path '{compiled_proto_file_path}' is not a file")
160
+ if not compiled_proto_file_path.endswith("_pb2.py"):
161
+ return
162
+
163
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
164
+
165
+ logger.trace(f"[ProtobufMessages] Importing compiled proto file '{compiled_proto_file_path}' (package: '{package_name}')...")
186
166
 
187
- # Import nested types
188
- if hasattr(module_or_object.DESCRIPTOR, 'nested_types_by_name'):
189
- for nt_name in module_or_object.DESCRIPTOR.nested_types_by_name:
190
- nt = module_or_object.DESCRIPTOR.nested_types_by_name[nt_name]
191
- if self.is_descriptor_message(nt):
192
- self.__import_compiled_proto_message(module_or_object, module_or_object_fullname, nt_name)
193
- elif self.is_descriptor_enum(nt):
194
- self.__import_compiled_proto_enum(module_or_object, module_or_object_fullname, nt_name)
195
- else:
196
- raise TechnicalException(f"Unmanaged nested type '{nt_name}' having descriptor: {self.__represent_descriptor(nt)}")
197
-
198
- def __import_compiled_proto_message(self, module_or_object, module_or_object_fullname, message_type_name):
199
- if hasattr(module_or_object, message_type_name):
200
- mt = getattr(module_or_object, message_type_name)
201
- mt_fullname = f"{module_or_object_fullname}.{message_type_name}" if module_or_object_fullname is not None and len(module_or_object_fullname) > 0 else message_type_name
202
- self.__message_types_by_fullname[mt_fullname] = mt
203
- if Tools.do_log(logger, logging.DEBUG):
204
- logger.debug(f"[ProtobufMessages] New managed message type '{mt_fullname}' (type: '{mt.__qualname__}')")
167
+ filename = os.path.splitext(os.path.basename(compiled_proto_file_path))[0]
168
+ module_name = f"{package_name}.{filename}" if package_name is not None and len(package_name) > 0 else filename
205
169
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
206
- logger.trace(f"[ProtobufMessages] Message type '{mt_fullname}': {Tools.represent_object(mt)}")
170
+ logger.trace(f"[ProtobufMessages] Importing module '{module_name}'")
171
+ module = importlib.import_module(module_name)
172
+
207
173
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
208
- logger.trace(f"[ProtobufMessages] DESCRIPTOR of message type '{mt_fullname}': {self.__represent_descriptor(mt.DESCRIPTOR)}")
209
174
 
175
+ logger.trace(f"[ProtobufMessages] DESCRIPTOR of module '{module_name}': {self.__represent_descriptor(module.DESCRIPTOR)}")
176
+ module_package = module.DESCRIPTOR.package if hasattr(module.DESCRIPTOR, 'package') else package_name
177
+ self.__import_compiled_proto_object(module, module_package)
178
+
179
+ def __import_compiled_proto_object(self, module_or_object, module_or_object_fullname):
180
+ # Import message types
181
+ if hasattr(module_or_object.DESCRIPTOR, 'message_types_by_name'):
182
+ for mt_name in module_or_object.DESCRIPTOR.message_types_by_name:
183
+ self.__import_compiled_proto_message(module_or_object, module_or_object_fullname, mt_name)
184
+
185
+ # Import enum types
186
+ if hasattr(module_or_object.DESCRIPTOR, 'enum_types_by_name'):
187
+ for et_name in module_or_object.DESCRIPTOR.enum_types_by_name:
188
+ self.__import_compiled_proto_enum(module_or_object, module_or_object_fullname, et_name)
189
+
210
190
  # Import nested types
211
- self.__import_compiled_proto_object(mt, mt_fullname)
212
- else:
213
- raise TechnicalException(f"Not found message type '{message_type_name}' in '{module_or_object_fullname}': {Tools.represent_object(module_or_object)}")
214
-
215
- def __import_compiled_proto_enum(self, module_or_object, module_or_object_fullname, enum_type_name):
216
- if hasattr(module_or_object, enum_type_name):
217
- et = getattr(module_or_object, enum_type_name)
218
- et_fullname = f"{module_or_object_fullname}.{enum_type_name}" if module_or_object_fullname is not None and len(module_or_object_fullname) > 0 else enum_type_name
219
- self.__enum_types_by_fullname[et_fullname] = et
220
- if Tools.do_log(logger, logging.DEBUG):
221
- logger.debug(f"[ProtobufMessages] New managed enum type '{et_fullname}' (type: '{Typing.get_object_class_fullname(et)}')")
222
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
223
- logger.trace(f"[ProtobufMessages] Enum type '{et_fullname}': {Tools.represent_object(et)}")
224
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
225
- logger.trace(f"[ProtobufMessages] DESCRIPTOR of enum type '{et_fullname}': {self.__represent_descriptor(et.DESCRIPTOR)}")
226
- else:
227
- raise TechnicalException(f"Not found enum type '{enum_type_name}' in '{module_or_object_fullname}': {Tools.represent_object(module_or_object)}")
228
-
229
- def has_object_type(self, type_fullname):
230
- """Return if type fullname is known."""
231
- return self.has_message_type(type_fullname) or self.has_enum_type(type_fullname)
232
-
233
- def has_message_type(self, message_type_fullname):
234
- """Return if message type fullname is known."""
235
- return message_type_fullname in self.__message_types_by_fullname
236
-
237
- def has_enum_type(self, enum_type_fullname):
238
- """Return if enum type fullname is known."""
239
- return enum_type_fullname in self.__enum_types_by_fullname
240
-
241
- def get_object_type(self, type_fullname):
242
- """Return type object for given type fullname."""
243
- if self.has_message_type(type_fullname):
244
- return self.get_message_type(type_fullname)
245
- else:
246
- raise FunctionalException(f"Unknown type fullname '{type_fullname}'")
247
-
248
- def get_message_type(self, message_type_fullname):
249
- """Return type object for given message type fullname."""
250
- if self.has_message_type(message_type_fullname):
251
- return self.__message_types_by_fullname[message_type_fullname]
252
- else:
253
- raise FunctionalException(f"Unknown message type fullname '{message_type_fullname}'")
254
-
255
- def get_enum_type(self, enum_type_fullname):
256
- """Return type object for given message type fullname."""
257
- if self.has_enum_type(enum_type_fullname):
258
- return self.__enum_types_by_fullname[enum_type_fullname]
259
- else:
260
- raise FunctionalException(f"Unknown enum type fullname '{enum_type_fullname}' (known enums: {list(self.__enum_types_by_fullname.keys())})")
261
-
262
- def get_enum_name(self, enum_value, enum_type_fullname):
263
- enum_type = self.get_enum_type(enum_type_fullname)
264
- return self.__get_enum_name(enum_value, enum_type=enum_type)
265
-
266
- def get_enum_value(self, fullname=None, enum_type_fullname=None, enum_name=None):
267
- if fullname is not None:
268
- enum_type_fullname, enum_name = fullname.rsplit('.', 1)
269
- enum_type = self.get_enum_type(enum_type_fullname)
270
- return self.__get_enum_value(enum_name, enum_type=enum_type)
271
-
272
- def new_object(self, type_fullname):
273
- """Return a new object of given type fullname."""
274
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
275
- logger.trace(f"Creating new object of type '{type_fullname}'...")
276
- if self.has_object_type(type_fullname):
191
+ if hasattr(module_or_object.DESCRIPTOR, 'nested_types_by_name'):
192
+ for nt_name in module_or_object.DESCRIPTOR.nested_types_by_name:
193
+ nt = module_or_object.DESCRIPTOR.nested_types_by_name[nt_name]
194
+ if self.is_descriptor_message(nt):
195
+ self.__import_compiled_proto_message(module_or_object, module_or_object_fullname, nt_name)
196
+ elif self.is_descriptor_enum(nt):
197
+ self.__import_compiled_proto_enum(module_or_object, module_or_object_fullname, nt_name)
198
+ else:
199
+ raise TechnicalException(f"Unmanaged nested type '{nt_name}' having descriptor: {self.__represent_descriptor(nt)}")
200
+
201
+ def __import_compiled_proto_message(self, module_or_object, module_or_object_fullname, message_type_name):
202
+ if hasattr(module_or_object, message_type_name):
203
+ mt = getattr(module_or_object, message_type_name)
204
+ mt_fullname = f"{module_or_object_fullname}.{message_type_name}" if module_or_object_fullname is not None and len(module_or_object_fullname) > 0 else message_type_name
205
+ self.__message_types_by_fullname[mt_fullname] = mt
206
+ if Tools.do_log(logger, logging.DEBUG):
207
+ logger.debug(f"[ProtobufMessages] New managed message type '{mt_fullname}' (type: '{mt.__qualname__}')")
208
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
209
+ logger.trace(f"[ProtobufMessages] Message type '{mt_fullname}': {Tools.represent_object(mt)}")
210
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
211
+ logger.trace(f"[ProtobufMessages] DESCRIPTOR of message type '{mt_fullname}': {self.__represent_descriptor(mt.DESCRIPTOR)}")
212
+
213
+ # Import nested types
214
+ self.__import_compiled_proto_object(mt, mt_fullname)
215
+ else:
216
+ raise TechnicalException(f"Not found message type '{message_type_name}' in '{module_or_object_fullname}': {Tools.represent_object(module_or_object)}")
217
+
218
+ def __import_compiled_proto_enum(self, module_or_object, module_or_object_fullname, enum_type_name):
219
+ if hasattr(module_or_object, enum_type_name):
220
+ et = getattr(module_or_object, enum_type_name)
221
+ et_fullname = f"{module_or_object_fullname}.{enum_type_name}" if module_or_object_fullname is not None and len(module_or_object_fullname) > 0 else enum_type_name
222
+ self.__enum_types_by_fullname[et_fullname] = et
223
+ if Tools.do_log(logger, logging.DEBUG):
224
+ logger.debug(f"[ProtobufMessages] New managed enum type '{et_fullname}' (type: '{Typing.get_object_class_fullname(et)}')")
225
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
226
+ logger.trace(f"[ProtobufMessages] Enum type '{et_fullname}': {Tools.represent_object(et)}")
227
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
228
+ logger.trace(f"[ProtobufMessages] DESCRIPTOR of enum type '{et_fullname}': {self.__represent_descriptor(et.DESCRIPTOR)}")
229
+ else:
230
+ raise TechnicalException(f"Not found enum type '{enum_type_name}' in '{module_or_object_fullname}': {Tools.represent_object(module_or_object)}")
231
+
232
+ def has_object_type(self, type_fullname):
233
+ """Return if type fullname is known."""
234
+ return self.has_message_type(type_fullname) or self.has_enum_type(type_fullname)
235
+
236
+ def has_message_type(self, message_type_fullname):
237
+ """Return if message type fullname is known."""
238
+ return message_type_fullname in self.__message_types_by_fullname
239
+
240
+ def has_enum_type(self, enum_type_fullname):
241
+ """Return if enum type fullname is known."""
242
+ return enum_type_fullname in self.__enum_types_by_fullname
243
+
244
+ def get_object_type(self, type_fullname):
245
+ """Return type object for given type fullname."""
277
246
  if self.has_message_type(type_fullname):
278
- mt = self.get_message_type(type_fullname)
279
- res = mt()
247
+ return self.get_message_type(type_fullname)
280
248
  else:
281
- raise TechnicalException(f"Unmanaged object creation for type fullname '{type_fullname}' (all managed types are logged at start with level DEBUG)")
282
- else:
283
- raise TechnicalException(f"Unknown type fullname '{type_fullname}' (all known types are logged at start with level DEBUG)")
284
-
285
- if Tools.do_log(logger, logging.DEBUG):
286
- logger.debug(f"New object of type '{type_fullname}' => {res}")
287
- return res
288
-
289
- def new_message(self, message_type_fullname, fields_table=None, fields_dict=None, serialized_string=None):
290
- """Return a new message of given message type fullname.
291
- The content of the message can be filled from serialized string, or from field values in a Name/Value table.
292
- """
293
- res = self.new_object(message_type_fullname)
294
-
295
- if serialized_string is not None:
296
- res.ParseFromString(serialized_string)
297
- elif fields_table is not None:
298
- if ValueTableManager.verify_table_is_name_value_table(fields_table, raise_exception=False):
299
- self.__set_object_fields_with_name_value_table(res, fields_table)
249
+ raise FunctionalException(f"Unknown type fullname '{type_fullname}'")
250
+
251
+ def get_message_type(self, message_type_fullname):
252
+ """Return type object for given message type fullname."""
253
+ if self.has_message_type(message_type_fullname):
254
+ return self.__message_types_by_fullname[message_type_fullname]
300
255
  else:
301
- raise TechnicalException(f"When defining parameter fields_table, it must be a Name/Value table")
302
- elif fields_dict is not None:
303
- self.__set_object_fields_with_dict(res, fields_dict)
304
-
305
- if Tools.do_log(logger, logging.DEBUG):
306
- # logger.debug(f"New message of type '{message_type_fullname}' => {res}")
307
- logger.debug(f"New message of type '{message_type_fullname}' => {Tools.represent_object(res)}")
308
- return res
309
-
310
- def get_object_field_names(self, obj, recursive=False, uncollapse_repeated=False, add_repeated_index=False, with_unset=True, sort_order=SortOrder.Definition):
311
- res = self.__get_object_field_names(obj, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, is_message_field=False, sort_order=sort_order)
312
- # logger.trace(f"Object of type '{self.get_object_type_fullname(obj)}' has field names: {res}")
313
- return res
314
-
315
- def get_message_field_names(self, obj, recursive=False, uncollapse_repeated=False, add_repeated_index=False, with_unset=True):
316
- res = self.__get_message_field_names(obj, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset)
317
- # logger.trace(f"Message of type '{self.get_object_type_fullname(obj)}' has field names: {res}")
318
- return res
319
-
320
- def get_object_field_values(self, obj, attribute_expression):
321
- """
322
- Return a list of values for attribute names matching given expression.
323
- Attribute name expression can contain "." for sub-fields, and "[]" to access all elements of the repeated field.
324
- The list contains only one value unless a repeated field is included in attribute expression with suffix '[]'.
325
- """
326
- attr_names = attribute_expression.split('.')
327
- res_list = [(obj, "")]
328
- for attr_name in attr_names:
329
- old_list = res_list
330
- if attr_name.endswith("[]"):
331
- if len(old_list) > 1:
332
- raise TechnicalException("Uncollapse two different repeated fields in the same message is not managed.")
333
- cur_res = old_list[0][0]
334
- cur_fullname = old_list[0][1]
335
- real_attr_name = attr_name[:-2]
336
-
337
- cur_attr_fullname = cur_fullname + '.' + real_attr_name if len(cur_fullname) > 0 else real_attr_name
338
- if not hasattr(cur_res, real_attr_name):
339
- raise TechnicalException(f"Attribute '{cur_attr_fullname}' doesn't exist in object [{cur_res}]")
340
-
341
- res_list = []
342
- for index, attr_obj in enumerate(getattr(cur_res, real_attr_name)):
343
- new_attr_fullname = f"{cur_attr_fullname}[{index}]"
344
- res_list.append((attr_obj, new_attr_fullname))
256
+ raise FunctionalException(f"Unknown message type fullname '{message_type_fullname}'")
257
+
258
+ def get_enum_type(self, enum_type_fullname):
259
+ """Return type object for given message type fullname."""
260
+ if self.has_enum_type(enum_type_fullname):
261
+ return self.__enum_types_by_fullname[enum_type_fullname]
345
262
  else:
346
- res_list = []
347
- for obj, obj_attr_fullname in old_list:
348
- new_attr_fullname = f"{obj_attr_fullname}.{attr_name}"
349
- if self.__has_object_field(obj, field_name=attr_name):
350
- attr_obj = self.__get_object_field(obj, field_name=attr_name)
351
- res_list.append((attr_obj, new_attr_fullname))
352
- else:
353
- raise TechnicalException(f"Attribute '{new_attr_fullname}' doesn't exist in object [{obj}]")
354
-
355
- return [obj for obj, _ in res_list]
263
+ raise FunctionalException(f"Unknown enum type fullname '{enum_type_fullname}' (known enums: {list(self.__enum_types_by_fullname.keys())})")
356
264
 
357
- def has_object_field(self, obj, attribute_expression, create_field=False):
358
- leaf_obj, _, attr_last_name = self.__get_leaf_object_and_attribute_names(obj, attribute_expression, create_field=create_field)
359
- return self.__has_object_field(leaf_obj, field_fullname=attr_last_name)
360
-
361
- def get_object_field_value(self, obj, attribute_expression, create_field=False):
362
- """
363
- Return the value for attribute name matching given expression.
364
- Attribute name expression can contain "." for sub-fields.
365
- """
366
- attr_names = attribute_expression.split('.')
367
- res = obj
368
- attr_fullname = ""
369
- for attr_name in attr_names:
370
- if self.__has_object_field(res, field_fullname=attr_name):
371
- res = self.__get_object_field(res, field_fullname=attr_name, create_field=create_field)
372
- attr_fullname = attr_fullname + '.' + attr_name if len(attr_fullname) > 0 else attr_name
265
+ def get_enum_name(self, enum_value, enum_type_fullname):
266
+ enum_type = self.get_enum_type(enum_type_fullname)
267
+ return self.__get_enum_name(enum_value, enum_type=enum_type)
268
+
269
+ def get_enum_value(self, fullname=None, enum_type_fullname=None, enum_name=None):
270
+ if fullname is not None:
271
+ enum_type_fullname, enum_name = fullname.rsplit('.', 1)
272
+ enum_type = self.get_enum_type(enum_type_fullname)
273
+ return self.__get_enum_value(enum_name, enum_type=enum_type)
274
+
275
+ def new_object(self, type_fullname):
276
+ """Return a new object of given type fullname."""
277
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
278
+ logger.trace(f"Creating new object of type '{type_fullname}'...")
279
+ if self.has_object_type(type_fullname):
280
+ if self.has_message_type(type_fullname):
281
+ mt = self.get_message_type(type_fullname)
282
+ res = mt()
283
+ else:
284
+ raise TechnicalException(f"Unmanaged object creation for type fullname '{type_fullname}' (all managed types are logged at start with level DEBUG)")
373
285
  else:
374
- attr_name, _ = self.__split_attribute_fullname(attr_name)
375
- if len(attr_fullname) > 0:
376
- attr_fullname = attr_fullname + '.' + attr_name
377
- raise FunctionalException(f"Field '{attr_fullname}' doesn't exist in message type '{self.get_object_type_fullname(obj)}' (in sub-message type '{self.get_object_type_fullname(res)}', existing fields: {self.__get_object_descriptor_field_names(res, False)})")
286
+ raise TechnicalException(f"Unknown type fullname '{type_fullname}' (all known types are logged at start with level DEBUG)")
287
+
288
+ if Tools.do_log(logger, logging.DEBUG):
289
+ logger.debug(f"New object of type '{type_fullname}' => {res}")
290
+ return res
291
+
292
+ def new_message(self, message_type_fullname, fields_table=None, fields_dict=None, serialized_string=None):
293
+ """Return a new message of given message type fullname.
294
+ The content of the message can be filled from serialized string, or from field values in a Name/Value table.
295
+ """
296
+ res = self.new_object(message_type_fullname)
297
+
298
+ if serialized_string is not None:
299
+ res.ParseFromString(serialized_string)
300
+ elif fields_table is not None:
301
+ if ValueTableManager.verify_table_is_name_value_table(fields_table, raise_exception=False):
302
+ self.__set_object_fields_with_name_value_table(res, fields_table)
378
303
  else:
379
- raise FunctionalException(f"Field '{attr_name}' doesn't exist in message type '{self.get_object_type_fullname(obj)}' (existing fields: {self.__get_object_descriptor_field_names(obj, False)})")
304
+ raise TechnicalException(f"When defining parameter fields_table, it must be a Name/Value table")
305
+ elif fields_dict is not None:
306
+ self.__set_object_fields_with_dict(res, fields_dict)
380
307
 
381
- return res
308
+ if Tools.do_log(logger, logging.DEBUG):
309
+ # logger.debug(f"New message of type '{message_type_fullname}' => {res}")
310
+ logger.debug(f"New message of type '{message_type_fullname}' => {Tools.represent_object(res)}")
311
+ return res
382
312
 
383
- def set_object_field_value(self, obj, attribute_expression, value):
384
- if Tools.do_log(logger, logging.DEBUG):
385
- logger.debug(f"Setting protobuf object ({id(obj)}) field '{attribute_expression}' with value [{value}] (type: {Typing.get_object_class_fullname(value)})")
386
- leaf_obj, leaf_attribute_expression, attr_last_name = self.__get_leaf_object_and_attribute_names(obj, attribute_expression, create_field=True)
313
+ def get_object_field_names(self, obj, recursive=False, uncollapse_repeated=False, add_repeated_index=False, with_unset=True, sort_order=SortOrder.Definition):
314
+ res = self.__get_object_field_names(obj, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, is_message_field=False, sort_order=sort_order)
315
+ # logger.trace(f"Object of type '{self.get_object_type_fullname(obj)}' has field names: {res}")
316
+ return res
387
317
 
388
- # Set value
389
- if self.__has_object_field(leaf_obj, field_fullname=attr_last_name):
390
- self.__set_object_field(leaf_obj, field_fullname=attr_last_name, value=value, create_field=True)
391
- else:
392
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
393
- logger.trace(f"Field '{attr_last_name}' doesn't exist in type '{self.get_object_type_fullname(leaf_obj)}'")
394
- attr_name, _ = self.__split_attribute_fullname(attr_last_name)
395
- if leaf_attribute_expression is not None:
396
- attr_fullname = leaf_attribute_expression + '.' + attr_name
397
- raise FunctionalException(f"Field '{attr_fullname}' doesn't exist in object type '{self.get_object_type_fullname(obj)}' (in sub-message type '{self.get_object_type_fullname(leaf_obj)}', existing fields: {self.__get_object_descriptor_field_names(leaf_obj, False)})")
398
- else:
399
- raise FunctionalException(f"Field '{attr_name}' doesn't exist in object type '{self.get_object_type_fullname(obj)}' (existing fields: {self.__get_object_descriptor_field_names(obj, False)})")
318
+ def get_message_field_names(self, obj, recursive=False, uncollapse_repeated=False, add_repeated_index=False, with_unset=True):
319
+ res = self.__get_message_field_names(obj, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset)
320
+ # logger.trace(f"Message of type '{self.get_object_type_fullname(obj)}' has field names: {res}")
321
+ return res
400
322
 
401
- def __get_leaf_object_and_attribute_names(self, obj, attribute_expression, create_field=False):
402
- try:
403
- leaf_attribute_expression, attr_last_name = attribute_expression.rsplit('.', 1)
404
- except ValueError:
405
- leaf_obj = obj
406
- leaf_attribute_expression = None
407
- attr_last_name = attribute_expression
408
- else:
409
- # Get "leaf" object (in object tree) containing the leaf attribute to set
410
- leaf_obj = self.get_object_field_value(obj, leaf_attribute_expression, create_field=create_field)
411
- return leaf_obj, leaf_attribute_expression, attr_last_name
412
-
413
- def __get_object_field_names(self, obj, recursive=False, uncollapse_repeated=False, add_repeated_index=True, with_unset=True, prefix="", is_message_field=False, sort_order=SortOrder.Definition):
414
- res = []
415
- if uncollapse_repeated and ProtobufMessages.is_object_repeated(obj):
416
- if add_repeated_index:
417
- for index, value in enumerate(obj):
418
- new_prefix = f"{prefix}[{index}]"
323
+ def get_object_field_values(self, obj, attribute_expression):
324
+ """
325
+ Return a list of values for attribute names matching given expression.
326
+ Attribute name expression can contain "." for sub-fields, and "[]" to access all elements of the repeated field.
327
+ The list contains only one value unless a repeated field is included in attribute expression with suffix '[]'.
328
+ """
329
+ attr_names = attribute_expression.split('.')
330
+ res_list = [(obj, "")]
331
+ for attr_name in attr_names:
332
+ old_list = res_list
333
+ if attr_name.endswith("[]"):
334
+ if len(old_list) > 1:
335
+ raise TechnicalException("Uncollapse two different repeated fields in the same message is not managed.")
336
+ cur_res = old_list[0][0]
337
+ cur_fullname = old_list[0][1]
338
+ real_attr_name = attr_name[:-2]
339
+
340
+ cur_attr_fullname = cur_fullname + '.' + real_attr_name if len(cur_fullname) > 0 else real_attr_name
341
+ if not hasattr(cur_res, real_attr_name):
342
+ raise TechnicalException(f"Attribute '{cur_attr_fullname}' doesn't exist in object [{cur_res}]")
343
+
344
+ res_list = []
345
+ for index, attr_obj in enumerate(getattr(cur_res, real_attr_name)):
346
+ new_attr_fullname = f"{cur_attr_fullname}[{index}]"
347
+ res_list.append((attr_obj, new_attr_fullname))
348
+ else:
349
+ res_list = []
350
+ for obj, obj_attr_fullname in old_list:
351
+ new_attr_fullname = f"{obj_attr_fullname}.{attr_name}"
352
+ if self.__has_object_field(obj, field_name=attr_name):
353
+ attr_obj = self.__get_object_field(obj, field_name=attr_name)
354
+ res_list.append((attr_obj, new_attr_fullname))
355
+ else:
356
+ raise TechnicalException(f"Attribute '{new_attr_fullname}' doesn't exist in object [{obj}]")
357
+
358
+ return [obj for obj, _ in res_list]
359
+
360
+ def has_object_field(self, obj, attribute_expression, create_field=False):
361
+ leaf_obj, _, attr_last_name = self.__get_leaf_object_and_attribute_names(obj, attribute_expression, create_field=create_field)
362
+ return self.__has_object_field(leaf_obj, field_fullname=attr_last_name)
363
+
364
+ def get_object_field_value(self, obj, attribute_expression, create_field=False):
365
+ """
366
+ Return the value for attribute name matching given expression.
367
+ Attribute name expression can contain "." for sub-fields.
368
+ """
369
+ attr_names = attribute_expression.split('.')
370
+ res = obj
371
+ attr_fullname = ""
372
+ for attr_name in attr_names:
373
+ if self.__has_object_field(res, field_fullname=attr_name):
374
+ res = self.__get_object_field(res, field_fullname=attr_name, create_field=create_field)
375
+ attr_fullname = attr_fullname + '.' + attr_name if len(attr_fullname) > 0 else attr_name
376
+ else:
377
+ attr_name, _ = self.__split_attribute_fullname(attr_name)
378
+ if len(attr_fullname) > 0:
379
+ attr_fullname = attr_fullname + '.' + attr_name
380
+ raise FunctionalException(f"Field '{attr_fullname}' doesn't exist in message type '{self.get_object_type_fullname(obj)}' (in sub-message type '{self.get_object_type_fullname(res)}', existing fields: {self.__get_object_descriptor_field_names(res, False)})")
381
+ else:
382
+ raise FunctionalException(f"Field '{attr_name}' doesn't exist in message type '{self.get_object_type_fullname(obj)}' (existing fields: {self.__get_object_descriptor_field_names(obj, False)})")
383
+
384
+ return res
385
+
386
+ def set_object_field_value(self, obj, attribute_expression, value):
387
+ if Tools.do_log(logger, logging.DEBUG):
388
+ logger.debug(f"Setting protobuf object ({id(obj)}) field '{attribute_expression}' with value [{value}] (type: {Typing.get_object_class_fullname(value)})")
389
+ leaf_obj, leaf_attribute_expression, attr_last_name = self.__get_leaf_object_and_attribute_names(obj, attribute_expression, create_field=True)
390
+
391
+ # Set value
392
+ if self.__has_object_field(leaf_obj, field_fullname=attr_last_name):
393
+ self.__set_object_field(leaf_obj, field_fullname=attr_last_name, value=value, create_field=True)
394
+ else:
395
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
396
+ logger.trace(f"Field '{attr_last_name}' doesn't exist in type '{self.get_object_type_fullname(leaf_obj)}'")
397
+ attr_name, _ = self.__split_attribute_fullname(attr_last_name)
398
+ if leaf_attribute_expression is not None:
399
+ attr_fullname = leaf_attribute_expression + '.' + attr_name
400
+ raise FunctionalException(f"Field '{attr_fullname}' doesn't exist in object type '{self.get_object_type_fullname(obj)}' (in sub-message type '{self.get_object_type_fullname(leaf_obj)}', existing fields: {self.__get_object_descriptor_field_names(leaf_obj, False)})")
401
+ else:
402
+ raise FunctionalException(f"Field '{attr_name}' doesn't exist in object type '{self.get_object_type_fullname(obj)}' (existing fields: {self.__get_object_descriptor_field_names(obj, False)})")
403
+
404
+ def __get_leaf_object_and_attribute_names(self, obj, attribute_expression, create_field=False):
405
+ try:
406
+ leaf_attribute_expression, attr_last_name = attribute_expression.rsplit('.', 1)
407
+ except ValueError:
408
+ leaf_obj = obj
409
+ leaf_attribute_expression = None
410
+ attr_last_name = attribute_expression
411
+ else:
412
+ # Get "leaf" object (in object tree) containing the leaf attribute to set
413
+ leaf_obj = self.get_object_field_value(obj, leaf_attribute_expression, create_field=create_field)
414
+ return leaf_obj, leaf_attribute_expression, attr_last_name
415
+
416
+ def __get_object_field_names(self, obj, recursive=False, uncollapse_repeated=False, add_repeated_index=True, with_unset=True, prefix="", is_message_field=False, sort_order=SortOrder.Definition):
417
+ res = []
418
+ if uncollapse_repeated and ProtobufMessages.is_object_repeated(obj):
419
+ if add_repeated_index:
420
+ for index, value in enumerate(obj):
421
+ new_prefix = f"{prefix}[{index}]"
422
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
423
+ logger.trace(f"Adding field names of repeated with prefix '{new_prefix}' (type: {Typing.get_object_class_fullname(value)})")
424
+ res.extend(self.__get_object_field_names(value, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, prefix=new_prefix, is_message_field=is_message_field, sort_order=sort_order))
425
+ else:
426
+ new_prefix = f"{prefix}[]"
427
+ value = obj[0]
419
428
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
420
429
  logger.trace(f"Adding field names of repeated with prefix '{new_prefix}' (type: {Typing.get_object_class_fullname(value)})")
421
430
  res.extend(self.__get_object_field_names(value, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, prefix=new_prefix, is_message_field=is_message_field, sort_order=sort_order))
422
- else:
423
- new_prefix = f"{prefix}[]"
424
- value = obj[0]
431
+ elif (recursive or not is_message_field) and ProtobufMessages.is_object_map(obj):
432
+ sorted_dict = dict(sorted(obj.items()))
433
+ for key, value in sorted_dict.items():
434
+ key_prefix = f"{prefix}[{key}]" if len(prefix) > 0 else key
435
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
436
+ logger.trace(f"Adding field names of object of prefix '{key_prefix}' (type: {Typing.get_object_class_fullname(value)})")
437
+ res.extend(self.__get_object_field_names(value, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, prefix=key_prefix, is_message_field=is_message_field))
438
+ elif (recursive or not is_message_field) and ProtobufMessages.is_object_message(obj):
425
439
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
426
- logger.trace(f"Adding field names of repeated with prefix '{new_prefix}' (type: {Typing.get_object_class_fullname(value)})")
427
- res.extend(self.__get_object_field_names(value, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, prefix=new_prefix, is_message_field=is_message_field, sort_order=sort_order))
428
- elif (recursive or not is_message_field) and ProtobufMessages.is_object_map(obj):
429
- sorted_dict = dict(sorted(obj.items()))
430
- for key, value in sorted_dict.items():
431
- key_prefix = f"{prefix}[{key}]" if len(prefix) > 0 else key
440
+ logger.trace(f"Adding field names of message of prefix '{prefix}' (type: {Typing.get_object_class_fullname(obj)})")
441
+ res.extend(self.__get_message_field_names(obj, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, prefix=prefix, sort_order=sort_order))
442
+ elif len(prefix) > 0:
432
443
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
433
- logger.trace(f"Adding field names of object of prefix '{key_prefix}' (type: {Typing.get_object_class_fullname(value)})")
434
- res.extend(self.__get_object_field_names(value, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, prefix=key_prefix, is_message_field=is_message_field))
435
- elif (recursive or not is_message_field) and ProtobufMessages.is_object_message(obj):
436
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
437
- logger.trace(f"Adding field names of message of prefix '{prefix}' (type: {Typing.get_object_class_fullname(obj)})")
438
- res.extend(self.__get_message_field_names(obj, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, prefix=prefix, sort_order=sort_order))
439
- elif len(prefix) > 0:
440
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
441
- logger.trace(f"Adding field name '{prefix}' (value type: {Typing.get_object_class_fullname(obj)})")
442
- res.append(prefix)
443
- else:
444
- # logger.trace(f"Adding field name '{attr_name}' (value type: {Typing.get_object_class_fullname(attr_val)})")
445
- raise TechnicalException(f"Object has no field and prefix is empty (object: {obj} ; type: {Typing.get_object_class_fullname(obj)})")
446
- return res
447
-
448
- def __get_message_field_names(self, obj, recursive=False, uncollapse_repeated=False, add_repeated_index=True, with_unset=True, prefix="", sort_order=SortOrder.Definition):
449
- res = []
450
- attribute_names = self.__get_object_descriptor_field_names(obj, sort_order=sort_order)
451
- for attr_name in attribute_names:
452
- attr_val = getattr(obj, attr_name)
453
- new_prefix = f"{prefix + '.' if len(prefix) > 0 else ''}{attr_name}"
454
-
455
- # Skip field not set
456
- if not with_unset:
457
- set_status = self.__is_message_field_set(obj, attr_name)
458
- if set_status == False:
459
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
460
- logger.trace(f"Hide unset field '{attr_name}' in object type '{self.get_object_type_fullname(obj)}' (field type: {Typing.get_object_class_fullname(attr_val)})")
461
- continue
462
-
463
- # Skip optional fields that are not set
464
- if self.__is_message_field_optional(obj, attr_name):
465
- set_status = self.__is_message_field_set(obj, attr_name)
466
- if set_status == False:
467
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
468
- logger.trace(f"Hide unset optional field '{attr_name}' in object type '{self.get_object_type_fullname(obj)}' (field type: {Typing.get_object_class_fullname(attr_val)})")
469
- continue
470
-
471
- # Skip oneof field that is not set
472
- if self.__is_message_field_oneof_field(obj, attr_name):
473
- set_status = self.__is_message_field_set(obj, attr_name)
474
- if set_status == False:
475
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
476
- logger.trace(f"Hide unset oneof field '{attr_name}' in object type '{self.get_object_type_fullname(obj)}' (field type: {Typing.get_object_class_fullname(attr_val)})")
477
- continue
478
-
479
- res.extend(self.__get_object_field_names(attr_val, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, prefix=new_prefix, is_message_field=True, sort_order=sort_order))
480
- return res
481
-
482
- def __is_message_field_oneof_field(self, obj, field_name):
483
- field_descr = self.__get_object_field_descriptor(obj, field_name)
484
- res = (field_descr.label == FieldDescriptor.LABEL_OPTIONAL
485
- and field_descr.containing_oneof is not None
486
- and field_descr.has_presence)
487
- return res
488
-
489
- def __is_message_field_optional(self, obj, field_name):
490
- field_descr = self.__get_object_field_descriptor(obj, field_name)
491
- res = (field_descr.label == FieldDescriptor.LABEL_OPTIONAL
492
- and field_descr.containing_oneof is not None and len(field_descr.containing_oneof.fields) == 1
493
- and field_descr.has_presence)
494
- return res
495
-
496
- def __is_message_field_repeated(self, obj, field_name):
497
- field_descr = self.__get_object_field_descriptor(obj, field_name)
498
- return (field_descr.label == FieldDescriptor.LABEL_REPEATED)
499
-
500
- def __is_message_field_required(self, obj, field_name):
501
- field_descr = self.__get_object_field_descriptor(obj, field_name)
502
- return (field_descr.label == FieldDescriptor.LABEL_REQUIRED)
503
-
504
- def __is_message_field_set(self, obj, field_name):
505
- """
506
- If field can distinguish between unpopulated and default values, return if field is set, else return None.
507
- """
508
- try:
509
- return obj.HasField(field_name)
510
- except ValueError:
511
- # logger.trace(f"Field '{field_name}' is not optional. Got error: {exc}")
512
- return None
444
+ logger.trace(f"Adding field name '{prefix}' (value type: {Typing.get_object_class_fullname(obj)})")
445
+ res.append(prefix)
446
+ else:
447
+ # logger.trace(f"Adding field name '{attr_name}' (value type: {Typing.get_object_class_fullname(attr_val)})")
448
+ raise TechnicalException(f"Object has no field and prefix is empty (object: {obj} ; type: {Typing.get_object_class_fullname(obj)})")
449
+ return res
450
+
451
+ def __get_message_field_names(self, obj, recursive=False, uncollapse_repeated=False, add_repeated_index=True, with_unset=True, prefix="", sort_order=SortOrder.Definition):
452
+ res = []
453
+ attribute_names = self.__get_object_descriptor_field_names(obj, sort_order=sort_order)
454
+ for attr_name in attribute_names:
455
+ attr_val = getattr(obj, attr_name)
456
+ new_prefix = f"{prefix + '.' if len(prefix) > 0 else ''}{attr_name}"
457
+
458
+ # Skip field not set
459
+ if not with_unset:
460
+ set_status = self.__is_message_field_set(obj, attr_name)
461
+ if set_status == False:
462
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
463
+ logger.trace(f"Hide unset field '{attr_name}' in object type '{self.get_object_type_fullname(obj)}' (field type: {Typing.get_object_class_fullname(attr_val)})")
464
+ continue
465
+
466
+ # Skip optional fields that are not set
467
+ if self.__is_message_field_optional(obj, attr_name):
468
+ set_status = self.__is_message_field_set(obj, attr_name)
469
+ if set_status == False:
470
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
471
+ logger.trace(f"Hide unset optional field '{attr_name}' in object type '{self.get_object_type_fullname(obj)}' (field type: {Typing.get_object_class_fullname(attr_val)})")
472
+ continue
473
+
474
+ # Skip oneof field that is not set
475
+ if self.__is_message_field_oneof_field(obj, attr_name):
476
+ set_status = self.__is_message_field_set(obj, attr_name)
477
+ if set_status == False:
478
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
479
+ logger.trace(f"Hide unset oneof field '{attr_name}' in object type '{self.get_object_type_fullname(obj)}' (field type: {Typing.get_object_class_fullname(attr_val)})")
480
+ continue
481
+
482
+ res.extend(self.__get_object_field_names(attr_val, recursive=recursive, uncollapse_repeated=uncollapse_repeated, add_repeated_index=add_repeated_index, with_unset=with_unset, prefix=new_prefix, is_message_field=True, sort_order=sort_order))
483
+ return res
484
+
485
+ def __is_message_field_oneof_field(self, obj, field_name):
486
+ field_descr = self.__get_object_field_descriptor(obj, field_name)
487
+ res = (field_descr.label == FieldDescriptor.LABEL_OPTIONAL
488
+ and field_descr.containing_oneof is not None
489
+ and field_descr.has_presence)
490
+ return res
513
491
 
514
- def __get_object_descriptor_field_names(self, obj, raise_exception=True, sort_order=SortOrder.Definition):
515
- #TODO EKL: manage oneof fields => return only the name of the oneof field that is defined
516
- if hasattr(obj, 'DESCRIPTOR'):
517
- descriptor = getattr(obj, 'DESCRIPTOR')
518
- # TODO: When it will be possible with python generated code, remove from result the deprecated fields
519
- # logger.info(f"+++++++++++++ descriptor: {self.__represent_descriptor(descriptor)}")
520
- res = [f.name for f in descriptor.fields if not hasattr(f, "isDeprecated")]
521
- if sort_order == SortOrder.Alphabetic:
522
- res.sort()
492
+ def __is_message_field_optional(self, obj, field_name):
493
+ field_descr = self.__get_object_field_descriptor(obj, field_name)
494
+ res = (field_descr.label == FieldDescriptor.LABEL_OPTIONAL
495
+ and field_descr.containing_oneof is not None and len(field_descr.containing_oneof.fields) == 1
496
+ and field_descr.has_presence)
523
497
  return res
524
- else:
525
- # return Typing.get_object_attribute_names(obj)
526
- if raise_exception:
498
+
499
+ def __is_message_field_repeated(self, obj, field_name):
500
+ field_descr = self.__get_object_field_descriptor(obj, field_name)
501
+ return (field_descr.label == FieldDescriptor.LABEL_REPEATED)
502
+
503
+ def __is_message_field_required(self, obj, field_name):
504
+ field_descr = self.__get_object_field_descriptor(obj, field_name)
505
+ return (field_descr.label == FieldDescriptor.LABEL_REQUIRED)
506
+
507
+ def __is_message_field_set(self, obj, field_name):
508
+ """
509
+ If field can distinguish between unpopulated and default values, return if field is set, else return None.
510
+ """
511
+ try:
512
+ return obj.HasField(field_name)
513
+ except ValueError:
514
+ # logger.trace(f"Field '{field_name}' is not optional. Got error: {exc}")
515
+ return None
516
+
517
+ def __get_object_descriptor_field_names(self, obj, raise_exception=True, sort_order=SortOrder.Definition):
518
+ #TODO EKL: manage oneof fields => return only the name of the oneof field that is defined
519
+ if hasattr(obj, 'DESCRIPTOR'):
520
+ descriptor = getattr(obj, 'DESCRIPTOR')
521
+ # TODO: When it will be possible with python generated code, remove from result the deprecated fields
522
+ # logger.info(f"+++++++++++++ descriptor: {self.__represent_descriptor(descriptor)}")
523
+ res = [f.name for f in descriptor.fields if not hasattr(f, "isDeprecated")]
524
+ if sort_order == SortOrder.Alphabetic:
525
+ res.sort()
526
+ return res
527
+ else:
528
+ # return Typing.get_object_attribute_names(obj)
529
+ if raise_exception:
530
+ raise TechnicalException(f"Not found attribute 'DESCRIPTOR' in object of type '{self.get_object_type_fullname(obj)}' [{obj}]")
531
+ else:
532
+ return []
533
+
534
+ def __get_object_field_descriptor(self, obj, field_name):
535
+ if hasattr(obj, 'DESCRIPTOR'):
536
+ descriptor = getattr(obj, 'DESCRIPTOR')
537
+ if field_name in descriptor.fields_by_name:
538
+ return descriptor.fields_by_name[field_name]
539
+ else:
540
+ raise FunctionalException(f"Field '{field_name}' doesn't exist in type '{self.get_object_type_fullname(obj)}'")
541
+ else:
527
542
  raise TechnicalException(f"Not found attribute 'DESCRIPTOR' in object of type '{self.get_object_type_fullname(obj)}' [{obj}]")
543
+
544
+ def __has_object_field(self, obj, field_name=None, field_fullname=None):
545
+ param_in_brackets = None
546
+ if field_name is None:
547
+ field_name, param_in_brackets = self.__split_attribute_fullname(field_fullname)
548
+
549
+ if len(field_name) == 0:
550
+ # Manage field_fullname in format "[XXX]"
551
+ if param_in_brackets is not None:
552
+ if self.is_object_repeated(obj):
553
+ if Converter.is_integer(param_in_brackets):
554
+ li_index = int(param_in_brackets)
555
+ res = li_index < len(obj)
556
+ else:
557
+ raise FunctionalException(f"For repeated objects, the parameter in brackets must be an integer (field fullname: '{field_fullname}')")
558
+ elif self.is_object_map(obj):
559
+ res = param_in_brackets in obj
560
+ # if not res:
561
+ # logger.trace(f"++++++ Key '{param_in_brackets}' in not in map {obj}")
562
+ else:
563
+ raise TechnicalException(f"Unexpected brackets in field fullname '{field_fullname}' for object of type '{self.get_object_type_fullname(obj)}'")
564
+ else:
565
+ raise TechnicalException(f"Unexpected field " + f"fullname '{field_fullname}'" if field_fullname is not None else f"name '{field_name}'")
566
+ elif self.is_object_map(obj):
567
+ res = field_name in obj
528
568
  else:
529
- return []
569
+ res = field_name in self.__get_object_descriptor_field_names(obj, False)
570
+
571
+ if not res:
572
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
573
+ logger.trace(f"Field '{field_name}' doesn't exist in type '{self.get_object_type_fullname(obj)}' (existing fields: {self.__get_object_descriptor_field_names(obj, False)})")
574
+ return res
575
+
576
+ def __get_object_field_type_fullname(self, obj, field_name):
577
+ if not self.__has_object_field(obj, field_name):
578
+ raise FunctionalException()
530
579
 
531
- def __get_object_field_descriptor(self, obj, field_name):
532
- if hasattr(obj, 'DESCRIPTOR'):
533
- descriptor = getattr(obj, 'DESCRIPTOR')
534
- if field_name in descriptor.fields_by_name:
535
- return descriptor.fields_by_name[field_name]
580
+ field_descr = self.__get_object_field_descriptor(obj, field_name)
581
+ if field_descr.message_type:
582
+ return self.get_object_type_fullname(descriptor=field_descr.message_type)
583
+ elif field_descr.enum_type:
584
+ return self.get_object_type_fullname(descriptor=field_descr.enum_type)
536
585
  else:
537
- raise FunctionalException(f"Field '{field_name}' doesn't exist in type '{self.get_object_type_fullname(obj)}'")
538
- else:
539
- raise TechnicalException(f"Not found attribute 'DESCRIPTOR' in object of type '{self.get_object_type_fullname(obj)}' [{obj}]")
540
-
541
- def __has_object_field(self, obj, field_name=None, field_fullname=None):
542
- param_in_brackets = None
543
- if field_name is None:
544
- field_name, param_in_brackets = self.__split_attribute_fullname(field_fullname)
586
+ return field_descr.type
587
+
588
+ def __get_object_field(self, obj, field_name=None, field_fullname=None, create_field=False):
589
+ param_in_brackets = None
590
+ if field_name is None:
591
+ field_name, param_in_brackets = self.__split_attribute_fullname(field_fullname)
545
592
 
546
- if len(field_name) == 0:
547
- # Manage field_fullname in format "[XXX]"
548
- if param_in_brackets is not None:
549
- if self.is_object_repeated(obj):
550
- if Converter.is_integer(param_in_brackets):
551
- li_index = int(param_in_brackets)
552
- res = li_index < len(obj)
593
+ if len(field_name) == 0:
594
+ # Manage field_fullname in format "[XXX]"
595
+ if param_in_brackets is not None:
596
+ if self.is_object_repeated(obj):
597
+ if Converter.is_integer(param_in_brackets):
598
+ li_index = int(param_in_brackets)
599
+ res = self.__get_object_repeated_by_index(obj, li_index, add_index=create_field)
600
+ else:
601
+ raise FunctionalException(f"For repeated objects, the parameter in brackets must be an integer (field fullname: '{field_fullname}')")
602
+ elif self.is_object_map(obj):
603
+ res = obj[param_in_brackets]
553
604
  else:
554
- raise FunctionalException(f"For repeated objects, the parameter in brackets must be an integer (field fullname: '{field_fullname}')")
555
- elif self.is_object_map(obj):
556
- res = param_in_brackets in obj
557
- # if not res:
558
- # logger.trace(f"++++++ Key '{param_in_brackets}' in not in map {obj}")
605
+ raise TechnicalException(f"Unexpected brackets in field fullname '{field_fullname}' for object of type '{self.get_object_type_fullname(obj)}'")
559
606
  else:
560
- raise TechnicalException(f"Unexpected brackets in field fullname '{field_fullname}' for object of type '{self.get_object_type_fullname(obj)}'")
561
- else:
562
- raise TechnicalException(f"Unexpected field " + f"fullname '{field_fullname}'" if field_fullname is not None else f"name '{field_name}'")
563
- elif self.is_object_map(obj):
564
- res = field_name in obj
565
- else:
566
- res = field_name in self.__get_object_descriptor_field_names(obj, False)
607
+ raise TechnicalException(f"Unexpected field " + f"fullname '{field_fullname}'" if field_fullname is not None else f"name '{field_name}'")
567
608
 
568
- if not res:
569
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
570
- logger.trace(f"Field '{field_name}' doesn't exist in type '{self.get_object_type_fullname(obj)}' (existing fields: {self.__get_object_descriptor_field_names(obj, False)})")
571
- return res
572
-
573
- def __get_object_field_type_fullname(self, obj, field_name):
574
- if not self.__has_object_field(obj, field_name):
575
- raise FunctionalException()
576
-
577
- field_descr = self.__get_object_field_descriptor(obj, field_name)
578
- if field_descr.message_type:
579
- return self.get_object_type_fullname(descriptor=field_descr.message_type)
580
- elif field_descr.enum_type:
581
- return self.get_object_type_fullname(descriptor=field_descr.enum_type)
582
- else:
583
- return field_descr.type
584
-
585
- def __get_object_field(self, obj, field_name=None, field_fullname=None, create_field=False):
586
- param_in_brackets = None
587
- if field_name is None:
588
- field_name, param_in_brackets = self.__split_attribute_fullname(field_fullname)
589
-
590
- if len(field_name) == 0:
591
- # Manage field_fullname in format "[XXX]"
592
- if param_in_brackets is not None:
593
- if self.is_object_repeated(obj):
609
+ elif self.is_object_map(obj):
610
+ res = obj[field_name]
611
+
612
+ elif hasattr(obj, field_name):
613
+ if param_in_brackets is not None:
594
614
  if Converter.is_integer(param_in_brackets):
595
615
  li_index = int(param_in_brackets)
596
- res = self.__get_object_repeated_by_index(obj, li_index, add_index=create_field)
616
+ res = self.__get_object_repeated_field_by_index(obj, field_name, li_index, add_index=create_field)
597
617
  else:
598
- raise FunctionalException(f"For repeated objects, the parameter in brackets must be an integer (field fullname: '{field_fullname}')")
599
- elif self.is_object_map(obj):
600
- res = obj[param_in_brackets]
618
+ res = getattr(obj, field_name)[param_in_brackets]
601
619
  else:
602
- raise TechnicalException(f"Unexpected brackets in field fullname '{field_fullname}' for object of type '{self.get_object_type_fullname(obj)}'")
620
+ res = getattr(obj, field_name)
621
+
622
+ # Manage enum
623
+ res = self.__get_enum_name_if_field_is_enum(res, obj=obj, field_name=field_name)
624
+
625
+ elif self.__has_object_field(obj, field_name=field_name):
626
+ if create_field:
627
+ field_type_fullname = self.__get_object_field_type_fullname(obj, field_name)
628
+ if isinstance(field_type_fullname, int):
629
+ raise TechnicalException("Unexpected case: the native types are expected to exist in object")
630
+ res = self.new_object(field_type_fullname)
631
+ setattr(obj, field_name, res)
632
+ else:
633
+ raise FunctionalException(f"Field '{field_name}' exists in type '{self.get_object_type_fullname(obj)}' but not in instance [{obj}]")
603
634
  else:
604
- raise TechnicalException(f"Unexpected field " + f"fullname '{field_fullname}'" if field_fullname is not None else f"name '{field_name}'")
635
+ raise FunctionalException(f"Field '{field_name}' doesn't exist in type '{self.get_object_type_fullname(obj)}'")
636
+
637
+ return res
605
638
 
606
- elif self.is_object_map(obj):
607
- res = obj[field_name]
639
+ def __get_object_repeated_by_index(self, obj, index, add_index=False):
640
+ if not ProtobufMessages.is_object_repeated(obj):
641
+ raise FunctionalException(f"Object of type '{self.get_object_type_fullname(obj)}' is not a repeated")
608
642
 
609
- elif hasattr(obj, field_name):
610
- if param_in_brackets is not None:
611
- if Converter.is_integer(param_in_brackets):
612
- li_index = int(param_in_brackets)
613
- res = self.__get_object_repeated_field_by_index(obj, field_name, li_index, add_index=create_field)
643
+ # Add repeated element if it doesn't exist
644
+ if len(obj) < index + 1:
645
+ if add_index:
646
+ for _ in range(index + 1 - len(obj)):
647
+ res = obj.add()
614
648
  else:
615
- res = getattr(obj, field_name)[param_in_brackets]
616
- else:
617
- res = getattr(obj, field_name)
618
-
619
- # Manage enum
620
- res = self.__get_enum_name_if_field_is_enum(res, obj=obj, field_name=field_name)
621
-
622
- elif self.__has_object_field(obj, field_name=field_name):
623
- if create_field:
624
- field_type_fullname = self.__get_object_field_type_fullname(obj, field_name)
625
- if isinstance(field_type_fullname, int):
626
- raise TechnicalException("Unexpected case: the native types are expected to exist in object")
627
- res = self.new_object(field_type_fullname)
628
- setattr(obj, field_name, res)
649
+ raise FunctionalException(f"Index {index} exceeds repeated length {len(obj)}")
629
650
  else:
630
- raise FunctionalException(f"Field '{field_name}' exists in type '{self.get_object_type_fullname(obj)}' but not in instance [{obj}]")
631
- else:
632
- raise FunctionalException(f"Field '{field_name}' doesn't exist in type '{self.get_object_type_fullname(obj)}'")
633
-
634
- return res
635
-
636
- def __get_object_repeated_by_index(self, obj, index, add_index=False):
637
- if not ProtobufMessages.is_object_repeated(obj):
638
- raise FunctionalException(f"Object of type '{self.get_object_type_fullname(obj)}' is not a repeated")
651
+ res = obj[index]
652
+
653
+ return res
639
654
 
640
- # Add repeated element if it doesn't exist
641
- if len(obj) < index + 1:
642
- if add_index:
643
- for _ in range(index + 1 - len(obj)):
644
- res = obj.add()
645
- else:
646
- raise FunctionalException(f"Index {index} exceeds repeated length {len(obj)}")
647
- else:
648
- res = obj[index]
655
+ def __get_object_repeated_field_by_index(self, obj, field_name, index, add_index=False):
656
+ field_obj = getattr(obj, field_name)
657
+ if not ProtobufMessages.is_object_repeated(field_obj):
658
+ raise FunctionalException(f"Field '{field_name}' is not a repeated in type '{self.get_object_type_fullname(obj)}'")
659
+ if len(field_obj) < index + 1 and not add_index:
660
+ raise FunctionalException(f"Index {index} exceeds repeated length {len(field_obj)} (field '{field_name}' in object of type '{self.get_object_type_fullname(obj)}' [{obj}])")
649
661
 
650
- return res
651
-
652
- def __get_object_repeated_field_by_index(self, obj, field_name, index, add_index=False):
653
- field_obj = getattr(obj, field_name)
654
- if not ProtobufMessages.is_object_repeated(field_obj):
655
- raise FunctionalException(f"Field '{field_name}' is not a repeated in type '{self.get_object_type_fullname(obj)}'")
656
- if len(field_obj) < index + 1 and not add_index:
657
- raise FunctionalException(f"Index {index} exceeds repeated length {len(field_obj)} (field '{field_name}' in object of type '{self.get_object_type_fullname(obj)}' [{obj}])")
662
+ return self.__get_object_repeated_by_index(field_obj, index, add_index)
658
663
 
659
- return self.__get_object_repeated_by_index(field_obj, index, add_index)
664
+ def get_object_type_fullname(self, obj=None, obj_class=None, descriptor=None):
665
+ # None type
666
+ if obj is None and obj_class is None and descriptor is None:
667
+ return None.__class__.__name__
660
668
 
661
- def get_object_type_fullname(self, obj=None, obj_class=None, descriptor=None):
662
- # None type
663
- if obj is None and obj_class is None and descriptor is None:
664
- return None.__class__.__name__
665
-
666
- # Object -> object class
667
- if obj is not None:
668
- return self.get_object_type_fullname(obj_class=type(obj))
669
-
670
- # Object class -> object class descriptor
671
- if hasattr(obj_class, 'DESCRIPTOR'):
672
- return self.get_object_type_fullname(descriptor=obj_class.DESCRIPTOR)
673
-
674
- # Extract information from descriptor
675
- if descriptor:
676
- if hasattr(descriptor, 'full_name'):
677
- return descriptor.full_name
678
- elif descriptor.containing_type is not None:
679
- containing_fullname = self.get_object_type_fullname(obj_class=descriptor.containing_type)
680
- return containing_fullname + '.' + descriptor.name
681
- else:
682
- raise TechnicalException(f"Failed to extract type fullname from descriptor: {self.__represent_descriptor(descriptor)}")
669
+ # Object -> object class
670
+ if obj is not None:
671
+ return self.get_object_type_fullname(obj_class=type(obj))
672
+
673
+ # Object class -> object class descriptor
674
+ if hasattr(obj_class, 'DESCRIPTOR'):
675
+ return self.get_object_type_fullname(descriptor=obj_class.DESCRIPTOR)
683
676
 
684
- # Extract information from classzhDM
685
- if obj_class.__module__.endswith('_pb2'):
686
- package_name = os.path.splitext(obj_class.__module__)[0]
687
- return package_name + '.' + obj_class.__name__
688
- else:
689
- return obj_class.__module__ + '.' + obj_class.__name__
690
-
691
- def __set_object_fields_with_name_value_table(self, obj, table):
692
- # Verify table structure
693
- ValueTableManager.verify_table_is_name_value_table(table)
694
-
695
- for row in table.rows:
696
- if row.get_cell(1).value_type not in [ValueTypes.NotApplicable]:
697
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
698
- logger.trace(f"Setting protobuf object field with row ({row})")
699
-
700
- name = row.get_cell(0).value
701
- value = row.get_cell(1).value
702
-
703
- self.set_object_field_value(obj, name, value)
677
+ # Extract information from descriptor
678
+ if descriptor:
679
+ if hasattr(descriptor, 'full_name'):
680
+ return descriptor.full_name
681
+ elif descriptor.containing_type is not None:
682
+ containing_fullname = self.get_object_type_fullname(obj_class=descriptor.containing_type)
683
+ return containing_fullname + '.' + descriptor.name
684
+ else:
685
+ raise TechnicalException(f"Failed to extract type fullname from descriptor: {self.__represent_descriptor(descriptor)}")
704
686
 
705
- def __set_object_fields_with_dict(self, obj, values_dict):
706
- for name, value in values_dict.items():
707
- self.set_object_field_value(obj, name, value)
687
+ # Extract information from classzhDM
688
+ if obj_class.__module__.endswith('_pb2'):
689
+ package_name = os.path.splitext(obj_class.__module__)[0]
690
+ return package_name + '.' + obj_class.__name__
691
+ else:
692
+ return obj_class.__module__ + '.' + obj_class.__name__
708
693
 
709
- def __check_field_value_to_set_is_valid(self, value):
710
- if value is undefined_argument or value is undefined_value:
711
- raise ValueError(f"Special objects undefined_* are not valid field values")
712
-
713
- def __set_object_field(self, obj, field_name=None, field_fullname=None, value=None, create_field=False):
714
- in_brackets_str = None
715
- if field_name is None:
716
- field_name, in_brackets_str = self.__split_attribute_fullname(field_fullname)
717
- if not self.__has_object_field(obj, field_name):
718
- raise TechnicalException(f"Field '{field_name}' doesn't exist in type '{self.get_object_type_fullname(obj)}'")
719
- self.__check_field_value_to_set_is_valid(value)
694
+ def __set_object_fields_with_name_value_table(self, obj, table):
695
+ # Verify table structure
696
+ ValueTableManager.verify_table_is_name_value_table(table)
697
+
698
+ for row in table.rows:
699
+ if row.get_cell(1).value_type not in [ValueTypes.NotApplicable]:
700
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
701
+ logger.trace(f"Setting protobuf object field with row ({row})")
702
+
703
+ name = row.get_cell(0).value
704
+ value = row.get_cell(1).value
705
+
706
+ self.set_object_field_value(obj, name, value)
707
+
708
+ def __set_object_fields_with_dict(self, obj, values_dict):
709
+ for name, value in values_dict.items():
710
+ self.set_object_field_value(obj, name, value)
720
711
 
721
- try:
722
- if hasattr(obj, field_name):
723
- if in_brackets_str is not None:
724
- from holado_test.scenario.step_tools import StepTools
725
- in_brackets_obj = StepTools.evaluate_scenario_parameter(in_brackets_str)
726
- if isinstance(in_brackets_obj, int):
727
- li_index = in_brackets_obj
728
- self.__set_object_repeated_field_by_index(obj, field_name, li_index, value, add_index=create_field)
729
- else:
712
+ def __check_field_value_to_set_is_valid(self, value):
713
+ if value is undefined_argument or value is undefined_value:
714
+ raise ValueError(f"Special objects undefined_* are not valid field values")
715
+
716
+ def __set_object_field(self, obj, field_name=None, field_fullname=None, value=None, create_field=False):
717
+ in_brackets_str = None
718
+ if field_name is None:
719
+ field_name, in_brackets_str = self.__split_attribute_fullname(field_fullname)
720
+ if not self.__has_object_field(obj, field_name):
721
+ raise TechnicalException(f"Field '{field_name}' doesn't exist in type '{self.get_object_type_fullname(obj)}'")
722
+ self.__check_field_value_to_set_is_valid(value)
723
+
724
+ try:
725
+ if hasattr(obj, field_name):
726
+ if in_brackets_str is not None:
727
+ from holado_test.scenario.step_tools import StepTools
728
+ in_brackets_obj = StepTools.evaluate_scenario_parameter(in_brackets_str)
729
+ if isinstance(in_brackets_obj, int):
730
+ li_index = in_brackets_obj
731
+ self.__set_object_repeated_field_by_index(obj, field_name, li_index, value, add_index=create_field)
732
+ else:
733
+ field_obj = getattr(obj, field_name)
734
+ field_obj[in_brackets_obj] = value
735
+ elif self.is_object_map(getattr(obj, field_name)):
730
736
  field_obj = getattr(obj, field_name)
731
- field_obj[in_brackets_obj] = value
732
- elif self.is_object_map(getattr(obj, field_name)):
733
- field_obj = getattr(obj, field_name)
734
- for key in value:
735
- field_obj[key] = value[key]
736
- elif self.is_object_repeated(getattr(obj, field_name)):
737
- self.__set_object_repeated_field(obj, field_name, value, add_index=True)
738
- else:
739
- field_type_fullname = self.__get_object_field_type_fullname(obj, field_name)
740
- if isinstance(field_type_fullname, int):
741
- self.__set_object_field_attr(obj, field_name, value)
737
+ for key in value:
738
+ field_obj[key] = value[key]
739
+ elif self.is_object_repeated(getattr(obj, field_name)):
740
+ self.__set_object_repeated_field(obj, field_name, value, add_index=True)
742
741
  else:
743
- field_descr = self.__get_object_field_descriptor(obj, field_name)
744
- # logger.trace(f"+++++ Setting field '{field_name}' of descriptor: {self.__represent_descriptor(field_descr)}")
745
- if field_descr.enum_type is not None:
746
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
747
- logger.trace(f"Setting enum field '{field_name}' (type: {field_type_fullname}) with value [{value}] (type: {Typing.get_object_class_fullname(value)})")
748
- enum_value = self.__get_enum_value(value, enum_type_descriptor=field_descr.enum_type)
749
- self.__set_object_field_attr(obj, field_name, enum_value)
742
+ field_type_fullname = self.__get_object_field_type_fullname(obj, field_name)
743
+ if isinstance(field_type_fullname, int):
744
+ self.__set_object_field_attr(obj, field_name, value)
750
745
  else:
751
- field_obj = getattr(obj, field_name)
752
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
753
- logger.trace(f"Setting field '{field_name}' (type: {field_type_fullname}) with value [{value}] (type: {Typing.get_object_class_fullname(value)})")
746
+ field_descr = self.__get_object_field_descriptor(obj, field_name)
747
+ # logger.trace(f"+++++ Setting field '{field_name}' of descriptor: {self.__represent_descriptor(field_descr)}")
748
+ if field_descr.enum_type is not None:
749
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
750
+ logger.trace(f"Setting enum field '{field_name}' (type: {field_type_fullname}) with value [{value}] (type: {Typing.get_object_class_fullname(value)})")
751
+ enum_value = self.__get_enum_value(value, enum_type_descriptor=field_descr.enum_type)
752
+ self.__set_object_field_attr(obj, field_name, enum_value)
753
+ else:
754
+ field_obj = getattr(obj, field_name)
755
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
756
+ logger.trace(f"Setting field '{field_name}' (type: {field_type_fullname}) with value [{value}] (type: {Typing.get_object_class_fullname(value)})")
757
+ try:
758
+ self.__set_object_value(field_obj, value)
759
+ except HAException as exc:
760
+ raise TechnicalException(f"Unmanaged set of value [{value}] (type: {Typing.get_object_class_fullname(value)}) in field of type '{field_type_fullname}' (field '{field_name}' in object of type '{self.get_object_type_fullname(obj)}' [{obj}])\n -> {exc.message}") from exc
761
+ except Exception as exc:
762
+ raise TechnicalException(f"Unmanaged set of value [{value}] (type: {Typing.get_object_class_fullname(value)}) in field of type '{field_type_fullname}' (field '{field_name}' in object of type '{self.get_object_type_fullname(obj)}' [{obj}])\n -> {str(exc)}") from exc
763
+ elif self.__has_object_field(obj, field_name=field_name):
764
+ if create_field:
765
+ field_type_fullname = self.__get_object_field_type_fullname(obj, field_name)
766
+ if isinstance(field_type_fullname, int):
767
+ self.__set_object_field_attr(obj, field_name, value)
768
+ else:
769
+ res = self.new_object(field_type_fullname)
754
770
  try:
755
- self.__set_object_value(field_obj, value)
756
- except HAException as exc:
757
- raise TechnicalException(f"Unmanaged set of value [{value}] (type: {Typing.get_object_class_fullname(value)}) in field of type '{field_type_fullname}' (field '{field_name}' in object of type '{self.get_object_type_fullname(obj)}' [{obj}])\n -> {exc.message}") from exc
771
+ self.__set_object_value(res, value)
758
772
  except Exception as exc:
759
- raise TechnicalException(f"Unmanaged set of value [{value}] (type: {Typing.get_object_class_fullname(value)}) in field of type '{field_type_fullname}' (field '{field_name}' in object of type '{self.get_object_type_fullname(obj)}' [{obj}])\n -> {str(exc)}") from exc
760
- elif self.__has_object_field(obj, field_name=field_name):
761
- if create_field:
762
- field_type_fullname = self.__get_object_field_type_fullname(obj, field_name)
763
- if isinstance(field_type_fullname, int):
764
- self.__set_object_field_attr(obj, field_name, value)
773
+ raise TechnicalException(f"Unmanaged set of value [{value}] (type: {Typing.get_object_class_fullname(value)}) in field of type '{field_type_fullname}' (field '{field_name}' in object of type '{self.get_object_type_fullname(obj)}' [{obj}])\n -> {exc.message}") from exc
774
+ setattr(obj, field_name, res)
765
775
  else:
766
- res = self.new_object(field_type_fullname)
767
- try:
768
- self.__set_object_value(res, value)
769
- except Exception as exc:
770
- raise TechnicalException(f"Unmanaged set of value [{value}] (type: {Typing.get_object_class_fullname(value)}) in field of type '{field_type_fullname}' (field '{field_name}' in object of type '{self.get_object_type_fullname(obj)}' [{obj}])\n -> {exc.message}") from exc
771
- setattr(obj, field_name, res)
776
+ raise FunctionalException(f"Field '{field_name}' exists in type '{self.get_object_type_fullname(obj)}' but not in instance [{obj}]")
772
777
  else:
773
- raise FunctionalException(f"Field '{field_name}' exists in type '{self.get_object_type_fullname(obj)}' but not in instance [{obj}]")
778
+ raise FunctionalException(f"Field '{field_name}' doesn't exist in type '{self.get_object_type_fullname(obj)}'")
779
+ except (FunctionalException, TechnicalException):
780
+ raise
781
+ except Exception as exc:
782
+ if hasattr(obj, field_name):
783
+ field_obj = getattr(obj, field_name)
784
+ raise TechnicalException(f"Failed to set field '{field_name}' (type: '{Typing.get_object_class_fullname(field_obj)}') with value [{value}] (type '{Typing.get_object_class_fullname(value)}')") from exc
785
+ else:
786
+ raise TechnicalException(f"Failed to set field '{field_name}' (type: Unknown) with value [{value}] (type '{Typing.get_object_class_fullname(value)}')") from exc
787
+
788
+ def __set_object_field_attr(self, obj, field_name, value):
789
+ if value is None:
790
+ obj.ClearField(field_name)
774
791
  else:
775
- raise FunctionalException(f"Field '{field_name}' doesn't exist in type '{self.get_object_type_fullname(obj)}'")
776
- except (FunctionalException, TechnicalException):
777
- raise
778
- except Exception as exc:
779
- if hasattr(obj, field_name):
780
- field_obj = getattr(obj, field_name)
781
- raise TechnicalException(f"Failed to set field '{field_name}' (type: '{Typing.get_object_class_fullname(field_obj)}') with value [{value}] (type '{Typing.get_object_class_fullname(value)}')") from exc
792
+ setattr(obj, field_name, value)
793
+
794
+ def __get_enum_name_if_field_is_enum(self, value, field_descriptor=None, obj=None, field_name=None):
795
+ if field_descriptor is None:
796
+ field_descriptor = self.__get_object_field_descriptor(obj, field_name)
797
+ if field_descriptor.enum_type is not None:
798
+ enum_name = self.__get_enum_name(value, enum_type_descriptor=field_descriptor.enum_type)
799
+ if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
800
+ logger.trace(f"Getting enum field '{field_descriptor.name}' (type: {field_descriptor.enum_type} ; full_name: {field_descriptor.full_name}): value [{value}] -> name [{enum_name}]")
801
+ return enum_name
782
802
  else:
783
- raise TechnicalException(f"Failed to set field '{field_name}' (type: Unknown) with value [{value}] (type '{Typing.get_object_class_fullname(value)}')") from exc
803
+ return value
804
+
805
+ def __get_enum_name(self, name_or_value, enum_type=None, enum_type_descriptor=None):
806
+ if enum_type is None and enum_type_descriptor is None:
807
+ raise TechnicalException(f"Parameter 'enum_type' or 'enum_type_descriptor' must be defined")
808
+ if enum_type is not None:
809
+ enum_type_descriptor = enum_type.DESCRIPTOR
784
810
 
785
- def __set_object_field_attr(self, obj, field_name, value):
786
- if value is None:
787
- obj.ClearField(field_name)
788
- else:
789
- setattr(obj, field_name, value)
790
-
791
- def __get_enum_name_if_field_is_enum(self, value, field_descriptor=None, obj=None, field_name=None):
792
- if field_descriptor is None:
793
- field_descriptor = self.__get_object_field_descriptor(obj, field_name)
794
- if field_descriptor.enum_type is not None:
795
- enum_name = self.__get_enum_name(value, enum_type_descriptor=field_descriptor.enum_type)
796
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
797
- logger.trace(f"Getting enum field '{field_descriptor.name}' (type: {field_descriptor.enum_type} ; full_name: {field_descriptor.full_name}): value [{value}] -> name [{enum_name}]")
798
- return enum_name
799
- else:
800
- return value
801
-
802
- def __get_enum_name(self, name_or_value, enum_type=None, enum_type_descriptor=None):
803
- if enum_type is None and enum_type_descriptor is None:
804
- raise TechnicalException(f"Parameter 'enum_type' or 'enum_type_descriptor' must be defined")
805
- if enum_type is not None:
806
- enum_type_descriptor = enum_type.DESCRIPTOR
807
-
808
- if isinstance(name_or_value, str):
809
- return name_or_value
810
- elif isinstance(name_or_value, int):
811
- if name_or_value in enum_type_descriptor.values_by_number:
812
- return self.__get_enum_name_for_value(enum_type_descriptor, name_or_value)
811
+ if isinstance(name_or_value, str):
812
+ return name_or_value
813
+ elif isinstance(name_or_value, int):
814
+ if name_or_value in enum_type_descriptor.values_by_number:
815
+ return self.__get_enum_name_for_value(enum_type_descriptor, name_or_value)
816
+ else:
817
+ raise FunctionalException(f"Enum type '{enum_type_descriptor.full_name}' has no value '{name_or_value}' (possible values: {[k for k in enum_type_descriptor.values_by_number]})")
818
+ elif self.is_object_repeated(name_or_value):
819
+ return [self.__get_enum_name(v, enum_type_descriptor=enum_type_descriptor) for v in name_or_value]
813
820
  else:
814
- raise FunctionalException(f"Enum type '{enum_type_descriptor.full_name}' has no value '{name_or_value}' (possible values: {[k for k in enum_type_descriptor.values_by_number]})")
815
- elif self.is_object_repeated(name_or_value):
816
- return [self.__get_enum_name(v, enum_type_descriptor=enum_type_descriptor) for v in name_or_value]
817
- else:
818
- raise TechnicalException(f"Unexpected value type '{Typing.get_object_class_fullname(name_or_value)}'")
819
-
820
- def __get_enum_name_for_value(self, enum_type_descriptor, value):
821
- enum_type_fullname = self.get_object_type_fullname(descriptor=enum_type_descriptor)
822
- if not enum_type_fullname in self.__enum_data_by_fullname:
823
- self.__load_enum_data(enum_type_fullname, enum_type_descriptor)
824
- return self.__enum_data_by_fullname[enum_type_fullname].values_by_number[value].name
821
+ raise TechnicalException(f"Unexpected value type '{Typing.get_object_class_fullname(name_or_value)}'")
825
822
 
826
- def __get_enum_value(self, name_or_value, enum_type=None, enum_type_descriptor=None):
827
- if enum_type is None and enum_type_descriptor is None:
828
- raise TechnicalException(f"Parameter 'enum_type' or 'enum_type_descriptor' must be defined")
829
- if enum_type is not None:
830
- enum_type_descriptor = enum_type.DESCRIPTOR
823
+ def __get_enum_name_for_value(self, enum_type_descriptor, value):
824
+ enum_type_fullname = self.get_object_type_fullname(descriptor=enum_type_descriptor)
825
+ if not enum_type_fullname in self.__enum_data_by_fullname:
826
+ self.__load_enum_data(enum_type_fullname, enum_type_descriptor)
827
+ return self.__enum_data_by_fullname[enum_type_fullname].values_by_number[value].name
831
828
 
832
- if isinstance(name_or_value, str):
833
- if name_or_value in enum_type_descriptor.values_by_name:
834
- return enum_type_descriptor.values_by_name[name_or_value].number
835
- else:
836
- raise FunctionalException(f"Enum type '{enum_type_descriptor.full_name}' has no name '{name_or_value}' (possible names: {[k for k in enum_type_descriptor.values_by_name]})")
837
- else:
838
- return name_or_value
839
-
840
- def __load_enum_data(self, enum_type_fullname, enum_type_descriptor):
841
- if enum_type_fullname in self.__enum_data_by_fullname:
842
- raise TechnicalException(f"Data of enum type '{enum_type_fullname}' was already loaded")
843
- data = NamedTuple('EnumData', values_by_number=dict)
844
- data.values_by_number = {}
845
- for value in enum_type_descriptor.values:
846
- if value.number not in data.values_by_number or value.index > data.values_by_number[value.number].index:
847
- data.values_by_number[value.number] = value
848
- self.__enum_data_by_fullname[enum_type_fullname] = data
849
-
850
- def __set_object_value(self, field_obj, value, raise_exception=True):
851
- res = False
852
- for hpt in self.__registered_types:
853
- if hpt.is_instance_of(field_obj):
854
- res = hpt.set_object_value(field_obj, value, raise_exception=raise_exception)
855
- if res:
856
- break
829
+ def __get_enum_value(self, name_or_value, enum_type=None, enum_type_descriptor=None):
830
+ if enum_type is None and enum_type_descriptor is None:
831
+ raise TechnicalException(f"Parameter 'enum_type' or 'enum_type_descriptor' must be defined")
832
+ if enum_type is not None:
833
+ enum_type_descriptor = enum_type.DESCRIPTOR
857
834
 
858
- if not res and raise_exception:
859
- field_classes = inspect.getmro(type(field_obj))
860
- registered_types_str = ', '.join([f"{t} ({t.protobuf_class()})" for t in self.__registered_types])
861
- raise TechnicalException(f"Failed to manage type of field {Typing.get_object_class_fullname(field_obj)} (classes: {field_classes}) with registered types (and internal types): {registered_types_str}")
862
- return res
863
-
864
- def __set_object_repeated_field(self, obj, field_name, values, add_index=False):
865
- if not isinstance(values, list):
866
- raise FunctionalException(f"For repeated field '{field_name}', parameter 'values' is not a list (type: {Typing.get_object_class_fullname(values)})")
835
+ if isinstance(name_or_value, str):
836
+ if name_or_value in enum_type_descriptor.values_by_name:
837
+ return enum_type_descriptor.values_by_name[name_or_value].number
838
+ else:
839
+ raise FunctionalException(f"Enum type '{enum_type_descriptor.full_name}' has no name '{name_or_value}' (possible names: {[k for k in enum_type_descriptor.values_by_name]})")
840
+ else:
841
+ return name_or_value
867
842
 
868
- for index, value in enumerate(values):
869
- self.__set_object_repeated_field_by_index(obj, field_name, index, value, add_index)
870
-
871
- def __set_object_repeated_field_by_index(self, obj, field_name, index, value, add_index=False):
872
- repeated_field_obj = getattr(obj, field_name)
873
- if not ProtobufMessages.is_object_repeated(repeated_field_obj):
874
- raise FunctionalException(f"Field '{field_name}' is not a repeated in type '{self.get_object_type_fullname(obj)}'")
875
- self.__check_field_value_to_set_is_valid(value)
843
+ def __load_enum_data(self, enum_type_fullname, enum_type_descriptor):
844
+ if enum_type_fullname in self.__enum_data_by_fullname:
845
+ raise TechnicalException(f"Data of enum type '{enum_type_fullname}' was already loaded")
846
+ data = NamedTuple('EnumData', values_by_number=dict)
847
+ data.values_by_number = {}
848
+ for value in enum_type_descriptor.values:
849
+ if value.number not in data.values_by_number or value.index > data.values_by_number[value.number].index:
850
+ data.values_by_number[value.number] = value
851
+ self.__enum_data_by_fullname[enum_type_fullname] = data
876
852
 
877
- field_descr = self.__get_object_field_descriptor(obj, field_name)
878
- if field_descr.message_type is not None:
879
- # Get field object at given index
880
- if len(repeated_field_obj) < index + 1:
881
- if add_index:
882
- for _ in range(index + 1 - len(repeated_field_obj)):
883
- obj_at_index = repeated_field_obj.add()
853
+ def __set_object_value(self, field_obj, value, raise_exception=True):
854
+ res = False
855
+ for hpt in self.__registered_types:
856
+ if hpt.is_instance_of(field_obj):
857
+ res = hpt.set_object_value(field_obj, value, raise_exception=raise_exception)
858
+ if res:
859
+ break
860
+
861
+ if not res and raise_exception:
862
+ field_classes = inspect.getmro(type(field_obj))
863
+ registered_types_str = ', '.join([f"{t} ({t.protobuf_class()})" for t in self.__registered_types])
864
+ raise TechnicalException(f"Failed to manage type of field {Typing.get_object_class_fullname(field_obj)} (classes: {field_classes}) with registered types (and internal types): {registered_types_str}")
865
+ return res
866
+
867
+ def __set_object_repeated_field(self, obj, field_name, values, add_index=False):
868
+ if not isinstance(values, list):
869
+ raise FunctionalException(f"For repeated field '{field_name}', parameter 'values' is not a list (type: {Typing.get_object_class_fullname(values)})")
870
+
871
+ for index, value in enumerate(values):
872
+ self.__set_object_repeated_field_by_index(obj, field_name, index, value, add_index)
873
+
874
+ def __set_object_repeated_field_by_index(self, obj, field_name, index, value, add_index=False):
875
+ repeated_field_obj = getattr(obj, field_name)
876
+ if not ProtobufMessages.is_object_repeated(repeated_field_obj):
877
+ raise FunctionalException(f"Field '{field_name}' is not a repeated in type '{self.get_object_type_fullname(obj)}'")
878
+ self.__check_field_value_to_set_is_valid(value)
879
+
880
+ field_descr = self.__get_object_field_descriptor(obj, field_name)
881
+ if field_descr.message_type is not None:
882
+ # Get field object at given index
883
+ if len(repeated_field_obj) < index + 1:
884
+ if add_index:
885
+ for _ in range(index + 1 - len(repeated_field_obj)):
886
+ obj_at_index = repeated_field_obj.add()
887
+ else:
888
+ raise FunctionalException(f"Index {index} exceeds repeated length {len(repeated_field_obj)} (field '{field_name}' in type '{self.get_object_type_fullname(obj)}')")
884
889
  else:
885
- raise FunctionalException(f"Index {index} exceeds repeated length {len(repeated_field_obj)} (field '{field_name}' in type '{self.get_object_type_fullname(obj)}')")
886
- else:
887
- obj_at_index = repeated_field_obj[index]
888
-
889
- # Set field object value
890
- try:
891
- self.__set_object_value(obj_at_index, value)
892
- except Exception as exc:
893
- raise TechnicalException(f"Unmanaged set of value [{value}] (type: {Typing.get_object_class_fullname(value)}) in repeated field of type '{self.get_object_type_fullname(obj_at_index)}' (at index {index} of field '{field_name}' in object of type '{self.get_object_type_fullname(obj)}' [{obj}])\n -> {exc.message}") from exc
894
- else:
895
- if field_descr.enum_type is not None:
896
- value_to_set = self.__get_enum_value(value, enum_type_descriptor=field_descr.enum_type)
890
+ obj_at_index = repeated_field_obj[index]
891
+
892
+ # Set field object value
893
+ try:
894
+ self.__set_object_value(obj_at_index, value)
895
+ except Exception as exc:
896
+ raise TechnicalException(f"Unmanaged set of value [{value}] (type: {Typing.get_object_class_fullname(value)}) in repeated field of type '{self.get_object_type_fullname(obj_at_index)}' (at index {index} of field '{field_name}' in object of type '{self.get_object_type_fullname(obj)}' [{obj}])\n -> {exc.message}") from exc
897
897
  else:
898
- value_to_set = value
899
-
900
- if len(repeated_field_obj) < index:
901
- if add_index:
902
- for _ in range(index - len(repeated_field_obj)):
903
- repeated_field_obj.append(type(value)())
898
+ if field_descr.enum_type is not None:
899
+ value_to_set = self.__get_enum_value(value, enum_type_descriptor=field_descr.enum_type)
900
+ else:
901
+ value_to_set = value
902
+
903
+ if len(repeated_field_obj) < index:
904
+ if add_index:
905
+ for _ in range(index - len(repeated_field_obj)):
906
+ repeated_field_obj.append(type(value)())
907
+ else:
908
+ raise FunctionalException(f"Index {index} exceeds repeated length {len(repeated_field_obj)} (field '{field_name}' in object [{obj}])")
909
+
910
+ if len(repeated_field_obj) == index:
911
+ if add_index:
912
+ try:
913
+ repeated_field_obj.append(value_to_set)
914
+ except Exception as exc:
915
+ raise TechnicalException(f"Failed to add value [{value_to_set}] in repeated field at index {index} (field '{field_name}' in type '{self.get_object_type_fullname(obj)}')") from exc
916
+ else:
917
+ raise FunctionalException(f"Index {index} exceeds repeated length {len(repeated_field_obj)} (field '{field_name}' in type '{self.get_object_type_fullname(obj)}')")
904
918
  else:
905
- raise FunctionalException(f"Index {index} exceeds repeated length {len(repeated_field_obj)} (field '{field_name}' in object [{obj}])")
906
-
907
- if len(repeated_field_obj) == index:
908
- if add_index:
909
919
  try:
910
- repeated_field_obj.append(value_to_set)
920
+ repeated_field_obj[index] = value_to_set
911
921
  except Exception as exc:
912
- raise TechnicalException(f"Failed to add value [{value_to_set}] in repeated field at index {index} (field '{field_name}' in type '{self.get_object_type_fullname(obj)}')") from exc
922
+ raise TechnicalException(f"Failed to set value [{value_to_set}] in repeated field at index {index} (field '{field_name}' in type '{self.get_object_type_fullname(obj)}')") from exc
923
+
924
+ def __split_attribute_fullname(self, attr_fullname):
925
+ m = self.__regex_attribute_fullname.match(attr_fullname)
926
+ res = [m.group(1), m.group(2)]
927
+ # logger.trace(f"++++++++++ __split_attribute_fullname('{attr_fullname}') => {res}")
928
+ return res
929
+
930
+ def __represent_descriptor(self, descr, indent=0):
931
+ res_str = [str(type(descr))]
932
+ for name, value in Typing.get_object_attributes(descr):
933
+ if "_by_" in name:
934
+ res_str.append(f" {name}:")
935
+ for el in value:
936
+ res_str.append(f" {el}: {self.__represent_descriptor(value[el], 8) if 'Descriptor' in str(type(value[el])) else value[el]}")
913
937
  else:
914
- raise FunctionalException(f"Index {index} exceeds repeated length {len(repeated_field_obj)} (field '{field_name}' in type '{self.get_object_type_fullname(obj)}')")
915
- else:
916
- try:
917
- repeated_field_obj[index] = value_to_set
918
- except Exception as exc:
919
- raise TechnicalException(f"Failed to set value [{value_to_set}] in repeated field at index {index} (field '{field_name}' in type '{self.get_object_type_fullname(obj)}')") from exc
938
+ # if name == "containing_type":
939
+ res_str.append(f" {name}: {value}")
940
+ # else:
941
+ # res_str.append(f" {name}: {self.__represent_descriptor(value, 4) if 'Descriptor' in str(type(value)) else value}")
942
+ return Tools.indent_string(indent, "\n".join(res_str))
920
943
 
921
- def __split_attribute_fullname(self, attr_fullname):
922
- m = self.__regex_attribute_fullname.match(attr_fullname)
923
- res = [m.group(1), m.group(2)]
924
- # logger.trace(f"++++++++++ __split_attribute_fullname('{attr_fullname}') => {res}")
925
- return res
926
-
927
- def __represent_descriptor(self, descr, indent=0):
928
- res_str = [str(type(descr))]
929
- for name, value in Typing.get_object_attributes(descr):
930
- if "_by_" in name:
931
- res_str.append(f" {name}:")
932
- for el in value:
933
- res_str.append(f" {el}: {self.__represent_descriptor(value[el], 8) if 'Descriptor' in str(type(value[el])) else value[el]}")
944
+ def _register_types(self):
945
+ # Duration must be registered before Message
946
+ from holado_protobuf.ipc.protobuf.types.google.protobuf import Duration as hpt_Duration
947
+ self.register_type(hpt_Duration)
948
+
949
+ # Timestamp must be registered before Message
950
+ from holado_protobuf.ipc.protobuf.types.google.protobuf import Timestamp as hpt_Timestamp
951
+ self.register_type(hpt_Timestamp)
952
+
953
+ from holado_protobuf.ipc.protobuf.types.google.protobuf import Message as hpt_Message
954
+ self.register_type(hpt_Message)
955
+
956
+ def register_type(self, protobuf_type, index=None):
957
+ """
958
+ Register a holado protobuf type (subclass of holado_protobuf.ipc.protobuf.abstracts.type.Type)
959
+ """
960
+ if protobuf_type in self.__registered_types:
961
+ raise TechnicalException(f"Protobuf type '{protobuf_type.__class__.__name__}' is already registered")
962
+
963
+ if index is not None:
964
+ self.__registered_types.insert(index, protobuf_type)
934
965
  else:
935
- # if name == "containing_type":
936
- res_str.append(f" {name}: {value}")
937
- # else:
938
- # res_str.append(f" {name}: {self.__represent_descriptor(value, 4) if 'Descriptor' in str(type(value)) else value}")
939
- return Tools.indent_string(indent, "\n".join(res_str))
940
-
941
- def _register_types(self):
942
- # Duration must be registered before Message
943
- from holado_protobuf.ipc.protobuf.types.google.protobuf import Duration as hpt_Duration
944
- self.register_type(hpt_Duration)
945
-
946
- # Timestamp must be registered before Message
947
- from holado_protobuf.ipc.protobuf.types.google.protobuf import Timestamp as hpt_Timestamp
948
- self.register_type(hpt_Timestamp)
949
-
950
- from holado_protobuf.ipc.protobuf.types.google.protobuf import Message as hpt_Message
951
- self.register_type(hpt_Message)
952
-
953
- def register_type(self, protobuf_type, index=None):
954
- """
955
- Register a holado protobuf type (subclass of holado_protobuf.ipc.protobuf.abstracts.type.Type)
956
- """
957
- if protobuf_type in self.__registered_types:
958
- raise TechnicalException(f"Protobuf type '{protobuf_type.__class__.__name__}' is already registered")
959
-
960
- if index is not None:
961
- self.__registered_types.insert(index, protobuf_type)
962
- else:
963
- self.__registered_types.append(protobuf_type)
966
+ self.__registered_types.append(protobuf_type)
964
967
 
965
968