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.
- holado/__init__.py +61 -23
- holado/common/context/service_manager.py +10 -2
- holado/common/context/session_context.py +43 -12
- holado/common/handlers/object.py +12 -4
- holado/holado_config.py +1 -0
- {holado-0.2.3.dist-info → holado-0.2.5.dist-info}/METADATA +1 -1
- {holado-0.2.3.dist-info → holado-0.2.5.dist-info}/RECORD +30 -30
- holado_ais/ais/ais_messages.py +140 -139
- holado_core/common/tools/path_manager.py +8 -4
- holado_grpc/api/rpc/grpc_client.py +122 -118
- holado_helper/docker/logging.conf +3 -1
- holado_helper/docker/run_holado_test_nonreg_in_docker.sh +28 -28
- holado_helper/docker/run_terminal_in_docker-with_docker_control.sh +27 -27
- holado_helper/docker/run_terminal_in_docker.sh +26 -26
- holado_helper/script/initialize_script.py +5 -5
- holado_logging/__init__.py +7 -9
- holado_logging/common/logging/holado_logger.py +2 -2
- holado_logging/common/logging/log_config.py +152 -127
- holado_logging/common/logging/log_manager.py +20 -19
- holado_multitask/multitasking/multitask_manager.py +1 -1
- holado_multitask/multithreading/thread.py +8 -4
- holado_protobuf/__init__.py +1 -1
- holado_protobuf/ipc/protobuf/protobuf_messages.py +821 -818
- holado_rabbitmq/tools/rabbitmq/rabbitmq_client.py +1 -2
- holado_test/behave/independant_runner.py +3 -5
- holado_test/scenario/step_tools.py +2 -0
- test_holado/environment.py +1 -1
- test_holado/logging.conf +3 -1
- {holado-0.2.3.dist-info → holado-0.2.5.dist-info}/WHEEL +0 -0
- {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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
108
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
116
|
-
|
|
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
|
-
|
|
119
|
-
if
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
188
|
-
|
|
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]
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return self.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
|
|
279
|
-
res = mt()
|
|
247
|
+
return self.get_message_type(type_fullname)
|
|
280
248
|
else:
|
|
281
|
-
raise
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
-
|
|
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
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
logger.
|
|
386
|
-
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
self.
|
|
391
|
-
|
|
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
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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
|
-
|
|
423
|
-
|
|
424
|
-
value
|
|
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
|
|
427
|
-
res.extend(self.
|
|
428
|
-
|
|
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
|
|
434
|
-
res.
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
res
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
res
|
|
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
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
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
|
-
|
|
525
|
-
|
|
526
|
-
|
|
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
|
-
|
|
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
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
return descriptor.
|
|
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
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
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
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
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.
|
|
616
|
+
res = self.__get_object_repeated_field_by_index(obj, field_name, li_index, add_index=create_field)
|
|
597
617
|
else:
|
|
598
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
607
|
-
|
|
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
|
-
|
|
610
|
-
if
|
|
611
|
-
if
|
|
612
|
-
|
|
613
|
-
|
|
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
|
-
|
|
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
|
-
|
|
631
|
-
|
|
632
|
-
|
|
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
|
-
|
|
641
|
-
|
|
642
|
-
if
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
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
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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
|
-
|
|
706
|
-
|
|
707
|
-
|
|
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
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
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
|
-
|
|
722
|
-
if
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
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
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
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
|
-
|
|
744
|
-
|
|
745
|
-
|
|
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
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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(
|
|
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 -> {
|
|
760
|
-
|
|
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
|
-
|
|
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}'
|
|
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
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
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
|
-
|
|
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
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
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
|
|
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
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
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
|
-
|
|
833
|
-
if
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
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
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
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
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
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
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
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
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
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
|
|
920
|
+
repeated_field_obj[index] = value_to_set
|
|
911
921
|
except Exception as exc:
|
|
912
|
-
raise TechnicalException(f"Failed to
|
|
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
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
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
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
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
|
-
|
|
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
|
|