bosdyn-client 3.3.2__py3-none-any.whl → 4.0.1__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.
- bosdyn/client/__init__.py +5 -6
- bosdyn/client/area_callback_region_handler_base.py +19 -4
- bosdyn/client/area_callback_service_servicer.py +29 -1
- bosdyn/client/area_callback_service_utils.py +45 -51
- bosdyn/client/auth.py +13 -28
- bosdyn/client/autowalk.py +3 -0
- bosdyn/client/channel.py +23 -26
- bosdyn/client/command_line.py +64 -13
- bosdyn/client/common.py +4 -4
- bosdyn/client/data_acquisition.py +47 -6
- bosdyn/client/data_acquisition_plugin.py +12 -2
- bosdyn/client/data_acquisition_plugin_service.py +33 -2
- bosdyn/client/data_acquisition_store.py +38 -0
- bosdyn/client/data_buffer.py +22 -8
- bosdyn/client/data_chunk.py +1 -0
- bosdyn/client/directory_registration.py +1 -14
- bosdyn/client/exceptions.py +0 -4
- bosdyn/client/frame_helpers.py +3 -1
- bosdyn/client/gps/NMEAParser.py +189 -0
- bosdyn/client/gps/__init__.py +6 -0
- bosdyn/client/gps/aggregator_client.py +56 -0
- bosdyn/client/gps/gps_listener.py +153 -0
- bosdyn/client/gps/registration_client.py +48 -0
- bosdyn/client/graph_nav.py +50 -20
- bosdyn/client/image.py +20 -7
- bosdyn/client/image_service_helpers.py +14 -14
- bosdyn/client/lease.py +27 -22
- bosdyn/client/lease_validator.py +5 -5
- bosdyn/client/manipulation_api_client.py +1 -1
- bosdyn/client/map_processing.py +10 -5
- bosdyn/client/math_helpers.py +21 -11
- bosdyn/client/metrics_logging.py +147 -0
- bosdyn/client/network_compute_bridge_client.py +6 -0
- bosdyn/client/power.py +40 -0
- bosdyn/client/recording.py +3 -3
- bosdyn/client/robot.py +15 -16
- bosdyn/client/robot_command.py +341 -203
- bosdyn/client/robot_id.py +6 -5
- bosdyn/client/robot_state.py +6 -0
- bosdyn/client/sdk.py +5 -11
- bosdyn/client/server_util.py +11 -11
- bosdyn/client/service_customization_helpers.py +776 -64
- bosdyn/client/signals_helpers.py +105 -0
- bosdyn/client/spot_cam/compositor.py +6 -2
- bosdyn/client/spot_cam/ptz.py +24 -14
- bosdyn/client/spot_check.py +160 -0
- bosdyn/client/time_sync.py +5 -5
- bosdyn/client/units_helpers.py +39 -0
- bosdyn/client/util.py +100 -64
- bosdyn/client/world_object.py +5 -5
- {bosdyn_client-3.3.2.dist-info → bosdyn_client-4.0.1.dist-info}/METADATA +4 -3
- bosdyn_client-4.0.1.dist-info/RECORD +97 -0
- {bosdyn_client-3.3.2.dist-info → bosdyn_client-4.0.1.dist-info}/WHEEL +1 -1
- bosdyn/client/log_annotation.py +0 -359
- bosdyn_client-3.3.2.dist-info/RECORD +0 -90
- {bosdyn_client-3.3.2.dist-info → bosdyn_client-4.0.1.dist-info}/top_level.txt +0 -0
|
@@ -5,9 +5,15 @@
|
|
|
5
5
|
# Development Kit License (20191101-BDSDK-SL).
|
|
6
6
|
|
|
7
7
|
from abc import ABC, abstractmethod
|
|
8
|
-
from typing import Callable, Optional
|
|
8
|
+
from typing import Callable, Dict, List, Optional, Union
|
|
9
|
+
|
|
10
|
+
from bosdyn.api.image_geometry_pb2 import AreaI
|
|
11
|
+
from bosdyn.api.service_customization_pb2 import (BoolParam, CustomParam, CustomParamError,
|
|
12
|
+
DictParam, DoubleParam, Int64Param, ListParam,
|
|
13
|
+
OneOfParam, RegionOfInterestParam, StringParam,
|
|
14
|
+
UserInterfaceInfo)
|
|
15
|
+
from bosdyn.api.units_pb2 import Units
|
|
9
16
|
|
|
10
|
-
from bosdyn.api import service_customization_pb2
|
|
11
17
|
|
|
12
18
|
|
|
13
19
|
class InvalidCustomParamSpecError(ValueError):
|
|
@@ -15,7 +21,15 @@ class InvalidCustomParamSpecError(ValueError):
|
|
|
15
21
|
with a list of error messages explaining why the spec is invalid"""
|
|
16
22
|
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
class InvalidCustomParamValueError(ValueError):
|
|
25
|
+
"""Error indicating that the defined custom parameter value does not match
|
|
26
|
+
the associated Spec, with a list of error messages explaining why."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, proto_error: CustomParamError):
|
|
29
|
+
self.proto_error = proto_error
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def validate_dict_spec(dict_spec: DictParam.Spec) -> None:
|
|
19
33
|
"""
|
|
20
34
|
Checks that a DictParam.Spec is valid
|
|
21
35
|
|
|
@@ -32,9 +46,7 @@ def validate_dict_spec(dict_spec: service_customization_pb2.DictParam.Spec) -> N
|
|
|
32
46
|
|
|
33
47
|
|
|
34
48
|
def create_value_validator(
|
|
35
|
-
|
|
36
|
-
) -> Callable[[service_customization_pb2.DictParam],
|
|
37
|
-
Optional[service_customization_pb2.CustomParamError]]:
|
|
49
|
+
dict_spec: DictParam.Spec) -> Callable[[DictParam], Optional[CustomParamError]]:
|
|
38
50
|
"""
|
|
39
51
|
Checks if the DictParam.Spec is value and if so, returns a function that can be used to validate any DictParam value
|
|
40
52
|
|
|
@@ -57,6 +69,97 @@ def create_value_validator(
|
|
|
57
69
|
return validator.validate_value
|
|
58
70
|
|
|
59
71
|
|
|
72
|
+
def dict_params_to_dict(dict_param: DictParam, dict_spec: DictParam.Spec,
|
|
73
|
+
validate: bool = True) -> Dict:
|
|
74
|
+
if validate:
|
|
75
|
+
validator = create_value_validator(dict_spec)
|
|
76
|
+
validate_res = validator(dict_param)
|
|
77
|
+
if validate_res:
|
|
78
|
+
raise InvalidCustomParamValueError(validate_res)
|
|
79
|
+
|
|
80
|
+
values = {}
|
|
81
|
+
for (key, custom_param) in dict_param.values.items():
|
|
82
|
+
value_field = custom_param.WhichOneof("value")
|
|
83
|
+
spec_field = dict_spec.specs[key].spec.WhichOneof("spec")
|
|
84
|
+
param_value = getattr(custom_param, value_field)
|
|
85
|
+
param_spec = getattr(dict_spec.specs[key].spec, spec_field)
|
|
86
|
+
|
|
87
|
+
if value_field == 'dict_value':
|
|
88
|
+
values[key] = dict_params_to_dict(param_value, param_spec, validate=False)
|
|
89
|
+
elif value_field == 'list_value':
|
|
90
|
+
values[key] = list_params_to_list(param_value, param_spec, validate=False)
|
|
91
|
+
elif value_field == 'one_of_value':
|
|
92
|
+
values[key] = oneof_param_to_dict(param_value, param_spec, validate=False)
|
|
93
|
+
elif value_field == 'roi_value':
|
|
94
|
+
values[key] = param_value
|
|
95
|
+
elif value_field in ['int_value', 'double_value', 'string_value', 'bool_value']:
|
|
96
|
+
values[key] = param_value.value
|
|
97
|
+
else:
|
|
98
|
+
raise NotImplementedError(
|
|
99
|
+
f'No handler for conversion of {value_field} from dict members.')
|
|
100
|
+
|
|
101
|
+
return values
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def list_params_to_list(list_param: ListParam, list_spec: ListParam.Spec,
|
|
105
|
+
validate: bool = True) -> List:
|
|
106
|
+
if validate:
|
|
107
|
+
validator = _ListParamValidator(list_spec)
|
|
108
|
+
validator.validate_spec()
|
|
109
|
+
validate_res = validator.validate_value(list_param)
|
|
110
|
+
if validate_res:
|
|
111
|
+
raise InvalidCustomParamValueError(validate_res)
|
|
112
|
+
|
|
113
|
+
values = []
|
|
114
|
+
for (ind, custom_param) in enumerate(list_param.values):
|
|
115
|
+
value_field = custom_param.WhichOneof("value")
|
|
116
|
+
spec_field = list_spec.element_spec.WhichOneof("spec")
|
|
117
|
+
param_value = getattr(custom_param, value_field)
|
|
118
|
+
param_spec = getattr(list_spec.element_spec, spec_field)
|
|
119
|
+
|
|
120
|
+
if value_field == 'dict_value':
|
|
121
|
+
values.append(dict_params_to_dict(param_value, param_spec, validate=False))
|
|
122
|
+
elif value_field == 'list_value':
|
|
123
|
+
values.append(list_params_to_list(param_value, param_spec, validate=False))
|
|
124
|
+
elif value_field == 'one_of_value':
|
|
125
|
+
values.append(oneof_param_to_dict(param_value, param_spec, validate=False))
|
|
126
|
+
elif value_field == 'roi_value':
|
|
127
|
+
values.append(param_value)
|
|
128
|
+
elif value_field in ['int_value', 'double_value', 'string_value', 'bool_value']:
|
|
129
|
+
values.append(param_value.value)
|
|
130
|
+
else:
|
|
131
|
+
raise NotImplementedError(
|
|
132
|
+
f'No handler for conversion of {value_field} from list members.')
|
|
133
|
+
|
|
134
|
+
return values
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def oneof_param_to_dict(oneof_param: OneOfParam, oneof_spec: OneOfParam.Spec,
|
|
138
|
+
validate: bool = True) -> List:
|
|
139
|
+
if validate:
|
|
140
|
+
validator = _OneOfParamValidator(oneof_spec)
|
|
141
|
+
validator.validate_spec()
|
|
142
|
+
validate_res = validator.validate_value(oneof_param)
|
|
143
|
+
if validate_res:
|
|
144
|
+
raise InvalidCustomParamValueError(validate_res)
|
|
145
|
+
|
|
146
|
+
dict_param = oneof_param.values[oneof_param.key]
|
|
147
|
+
dict_spec = oneof_spec.specs[oneof_param.key].spec
|
|
148
|
+
return dict_params_to_dict(dict_param, dict_spec)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def check_types_match(param, proto_type):
|
|
152
|
+
if type(param) != proto_type:
|
|
153
|
+
return CustomParamError(
|
|
154
|
+
status=CustomParamError.STATUS_INVALID_VALUE,
|
|
155
|
+
error_messages=[
|
|
156
|
+
f"Param {param} has type {type(param)}" \
|
|
157
|
+
f" but the spec requires {proto_type}."
|
|
158
|
+
])
|
|
159
|
+
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
|
|
60
163
|
class _ParamValidatorInterface(ABC):
|
|
61
164
|
""" Class providing a common structure and interface to validate parameter types.
|
|
62
165
|
|
|
@@ -83,7 +186,7 @@ class _ParamValidatorInterface(ABC):
|
|
|
83
186
|
pass
|
|
84
187
|
|
|
85
188
|
@abstractmethod
|
|
86
|
-
def validate_value(self, param_value) -> Optional[
|
|
189
|
+
def validate_value(self, param_value) -> Optional[CustomParamError]:
|
|
87
190
|
"""
|
|
88
191
|
Checks if a parameter value is valid for this class's self.param_spec
|
|
89
192
|
|
|
@@ -103,15 +206,14 @@ class _DictParamValidator(_ParamValidatorInterface):
|
|
|
103
206
|
Args:
|
|
104
207
|
param_spec (service_customization_pb2.DictParam.Spec): The DictParam Spec this helper instance is being used for
|
|
105
208
|
"""
|
|
106
|
-
proto_type =
|
|
209
|
+
proto_type = DictParam
|
|
107
210
|
custom_param_value_field = "dict_value"
|
|
108
211
|
|
|
109
212
|
def __init__(self, param_spec):
|
|
110
213
|
super().__init__(param_spec)
|
|
111
214
|
|
|
112
215
|
def validate_spec(self):
|
|
113
|
-
custom_param_error =
|
|
114
|
-
status=service_customization_pb2.CustomParamError.STATUS_OK)
|
|
216
|
+
custom_param_error = CustomParamError(status=CustomParamError.STATUS_OK)
|
|
115
217
|
error_list = []
|
|
116
218
|
for name, child_spec in self.param_spec.specs.items():
|
|
117
219
|
try:
|
|
@@ -131,16 +233,18 @@ class _DictParamValidator(_ParamValidatorInterface):
|
|
|
131
233
|
Returns:
|
|
132
234
|
Nothing for a valid spec, and raises a service_customization_pb2.CustomParamError for an invalid Spec.
|
|
133
235
|
"""
|
|
236
|
+
err = check_types_match(param_value, self.proto_type)
|
|
237
|
+
if err:
|
|
238
|
+
return err
|
|
239
|
+
|
|
134
240
|
value_keys = set(param_value.values.keys())
|
|
135
241
|
spec_keys = set(self.param_spec.specs.keys())
|
|
136
242
|
if not value_keys.issubset(spec_keys):
|
|
137
|
-
return
|
|
138
|
-
status=
|
|
139
|
-
error_messages=[
|
|
243
|
+
return CustomParamError(
|
|
244
|
+
status=CustomParamError.STATUS_UNSUPPORTED_PARAMETER, error_messages=[
|
|
140
245
|
f"DictParam value contains keys {value_keys - spec_keys} not present in the spec."
|
|
141
246
|
])
|
|
142
|
-
custom_param_error =
|
|
143
|
-
status=service_customization_pb2.CustomParamError.STATUS_OK)
|
|
247
|
+
custom_param_error = CustomParamError(status=CustomParamError.STATUS_OK)
|
|
144
248
|
for name, custom_param in param_value.values.items():
|
|
145
249
|
child_spec = self.param_spec.specs[name].spec
|
|
146
250
|
child_value = getattr(custom_param, custom_param.WhichOneof("value"))
|
|
@@ -150,7 +254,7 @@ class _DictParamValidator(_ParamValidatorInterface):
|
|
|
150
254
|
custom_param_error.status = error_proto.status
|
|
151
255
|
custom_param_error.error_messages.extend(
|
|
152
256
|
_nested_error_message_helper(name, error_proto.error_messages))
|
|
153
|
-
if custom_param_error.status !=
|
|
257
|
+
if custom_param_error.status != CustomParamError.STATUS_OK:
|
|
154
258
|
return custom_param_error
|
|
155
259
|
|
|
156
260
|
|
|
@@ -180,20 +284,21 @@ class _NumericalParamValidator(_ParamValidatorInterface):
|
|
|
180
284
|
raise InvalidCustomParamSpecError(error_messages)
|
|
181
285
|
|
|
182
286
|
def validate_value(self, param_value):
|
|
183
|
-
|
|
287
|
+
err = check_types_match(param_value, self.proto_type)
|
|
288
|
+
if err:
|
|
289
|
+
return err
|
|
184
290
|
|
|
291
|
+
num_value = param_value.value
|
|
185
292
|
if self.param_spec.HasField("min_value"):
|
|
186
293
|
if num_value < self.param_spec.min_value.value:
|
|
187
|
-
return
|
|
188
|
-
status=
|
|
189
|
-
error_messages=[
|
|
294
|
+
return CustomParamError(
|
|
295
|
+
status=CustomParamError.STATUS_INVALID_VALUE, error_messages=[
|
|
190
296
|
f"Value {num_value} below min_bound {self.param_spec.min_value.value}"
|
|
191
297
|
])
|
|
192
298
|
if self.param_spec.HasField("max_value"):
|
|
193
299
|
if num_value > self.param_spec.max_value.value:
|
|
194
|
-
return
|
|
195
|
-
status=
|
|
196
|
-
error_messages=[
|
|
300
|
+
return CustomParamError(
|
|
301
|
+
status=CustomParamError.STATUS_INVALID_VALUE, error_messages=[
|
|
197
302
|
f"Value {num_value} above max_bound {self.param_spec.max_value.value}"
|
|
198
303
|
])
|
|
199
304
|
|
|
@@ -206,7 +311,7 @@ class _Int64ParamValidator(_NumericalParamValidator):
|
|
|
206
311
|
param_spec (service_customization_pb2.Int64Param.Spec): The Int64Param Spec this helper instance is being used for
|
|
207
312
|
"""
|
|
208
313
|
|
|
209
|
-
proto_type =
|
|
314
|
+
proto_type = Int64Param
|
|
210
315
|
custom_param_value_field = "int_value"
|
|
211
316
|
|
|
212
317
|
def __init__(self, param_spec):
|
|
@@ -220,7 +325,7 @@ class _DoubleParamValidator(_NumericalParamValidator):
|
|
|
220
325
|
Args:
|
|
221
326
|
param_spec (service_customization_pb2.DoubleParam.Spec): The DoubleParam Spec this helper instance is being used for
|
|
222
327
|
"""
|
|
223
|
-
proto_type =
|
|
328
|
+
proto_type = DoubleParam
|
|
224
329
|
custom_param_value_field = "double_value"
|
|
225
330
|
|
|
226
331
|
def __init__(self, param_spec):
|
|
@@ -234,14 +339,14 @@ class _StringParamValidator(_ParamValidatorInterface):
|
|
|
234
339
|
Args:
|
|
235
340
|
param_spec (service_customization_pb2.StringParam.Spec): The StringParam Spec this helper instance is being used for
|
|
236
341
|
"""
|
|
237
|
-
proto_type =
|
|
342
|
+
proto_type = StringParam
|
|
238
343
|
custom_param_value_field = "string_value"
|
|
239
344
|
|
|
240
345
|
def __init__(self, param_spec):
|
|
241
346
|
super().__init__(param_spec)
|
|
242
347
|
|
|
243
348
|
def validate_spec(self):
|
|
244
|
-
if self.param_spec.default_value and self.param_spec.options and len(
|
|
349
|
+
if self.param_spec.default_value and not self.param_spec.editable and self.param_spec.options and len(
|
|
245
350
|
self.param_spec.options) > 0:
|
|
246
351
|
if self.param_spec.default_value not in self.param_spec.options:
|
|
247
352
|
raise InvalidCustomParamSpecError([
|
|
@@ -249,11 +354,14 @@ class _StringParamValidator(_ParamValidatorInterface):
|
|
|
249
354
|
])
|
|
250
355
|
|
|
251
356
|
def validate_value(self, param_value):
|
|
357
|
+
err = check_types_match(param_value, self.proto_type)
|
|
358
|
+
if err:
|
|
359
|
+
return err
|
|
360
|
+
|
|
252
361
|
if len(self.param_spec.options) > 0:
|
|
253
362
|
if param_value.value not in self.param_spec.options:
|
|
254
|
-
return
|
|
255
|
-
status=
|
|
256
|
-
error_messages=[
|
|
363
|
+
return CustomParamError(
|
|
364
|
+
status=CustomParamError.STATUS_INVALID_VALUE, error_messages=[
|
|
257
365
|
f"Chosen string value {param_value.value} not among options {self.param_spec.options}"
|
|
258
366
|
])
|
|
259
367
|
|
|
@@ -265,7 +373,7 @@ class _BoolParamValidator(_ParamValidatorInterface):
|
|
|
265
373
|
Args:
|
|
266
374
|
param_spec (service_customization_pb2.BoolParam.Spec): The BoolParam Spec this helper instance is being used for
|
|
267
375
|
"""
|
|
268
|
-
proto_type =
|
|
376
|
+
proto_type = BoolParam
|
|
269
377
|
custom_param_field = "bool"
|
|
270
378
|
|
|
271
379
|
def __init__(self, param_spec):
|
|
@@ -275,7 +383,9 @@ class _BoolParamValidator(_ParamValidatorInterface):
|
|
|
275
383
|
return super().validate_spec()
|
|
276
384
|
|
|
277
385
|
def validate_value(self, param_value):
|
|
278
|
-
|
|
386
|
+
err = check_types_match(param_value, self.proto_type)
|
|
387
|
+
if err:
|
|
388
|
+
return err
|
|
279
389
|
|
|
280
390
|
|
|
281
391
|
class _RegionOfInterestParamValidator(_ParamValidatorInterface):
|
|
@@ -285,7 +395,7 @@ class _RegionOfInterestParamValidator(_ParamValidatorInterface):
|
|
|
285
395
|
Args:
|
|
286
396
|
param_spec (service_customization_pb2.RegionOfInterestParam.Spec): The RegionOfInterestParam Spec this helper instance is being used for
|
|
287
397
|
"""
|
|
288
|
-
proto_type =
|
|
398
|
+
proto_type = RegionOfInterestParam
|
|
289
399
|
custom_param_value_field = "roi_value"
|
|
290
400
|
|
|
291
401
|
def __init__(self, param_spec):
|
|
@@ -298,19 +408,21 @@ class _RegionOfInterestParamValidator(_ParamValidatorInterface):
|
|
|
298
408
|
["Default area is a rectangle despite not being allowed"])
|
|
299
409
|
|
|
300
410
|
def validate_value(self, param_value):
|
|
411
|
+
err = check_types_match(param_value, self.proto_type)
|
|
412
|
+
if err:
|
|
413
|
+
return err
|
|
414
|
+
|
|
301
415
|
if not self.param_spec.allows_rectangle:
|
|
302
416
|
if param_value.area.rectangle:
|
|
303
|
-
return
|
|
304
|
-
status=
|
|
417
|
+
return CustomParamError(
|
|
418
|
+
status=CustomParamError.STATUS_INVALID_VALUE,
|
|
305
419
|
error_messages=["Chosen area is a rectangle despite not being allowed"])
|
|
306
420
|
if param_value.image_cols < 0:
|
|
307
|
-
return
|
|
308
|
-
|
|
309
|
-
error_messages=["Number of columns in image must be positive"])
|
|
421
|
+
return CustomParamError(status=CustomParamError.STATUS_INVALID_VALUE,
|
|
422
|
+
error_messages=["Number of columns in image must be positive"])
|
|
310
423
|
if param_value.image_rows < 0:
|
|
311
|
-
return
|
|
312
|
-
|
|
313
|
-
error_messages=["Number of rows in image must be positive"])
|
|
424
|
+
return CustomParamError(status=CustomParamError.STATUS_INVALID_VALUE,
|
|
425
|
+
error_messages=["Number of rows in image must be positive"])
|
|
314
426
|
|
|
315
427
|
|
|
316
428
|
class _ListParamValidator(_ParamValidatorInterface):
|
|
@@ -320,14 +432,14 @@ class _ListParamValidator(_ParamValidatorInterface):
|
|
|
320
432
|
Args:
|
|
321
433
|
param_spec (service_customization_pb2.ListParam.Spec): The ListParam Spec this helper instance is being used for
|
|
322
434
|
"""
|
|
323
|
-
proto_type =
|
|
435
|
+
proto_type = ListParam
|
|
324
436
|
custom_param_value_field = "list_value"
|
|
325
437
|
|
|
326
438
|
def __init__(self, param_spec):
|
|
327
439
|
super().__init__(param_spec)
|
|
328
440
|
|
|
329
441
|
def validate_spec(self):
|
|
330
|
-
#First check element_spec
|
|
442
|
+
# First check element_spec
|
|
331
443
|
if not self.param_spec.HasField("element_spec"):
|
|
332
444
|
raise InvalidCustomParamSpecError(["ListParam needs a defined element_spec"])
|
|
333
445
|
element_spec_error = _CustomParamValidator(
|
|
@@ -336,7 +448,7 @@ class _ListParamValidator(_ParamValidatorInterface):
|
|
|
336
448
|
raise InvalidCustomParamSpecError(
|
|
337
449
|
_nested_error_message_helper("element_spec", element_spec_error.error_messages))
|
|
338
450
|
|
|
339
|
-
#If that's valid, then check list bounds
|
|
451
|
+
# If that's valid, then check list bounds
|
|
340
452
|
error_messages = []
|
|
341
453
|
if (
|
|
342
454
|
self.param_spec.HasField("min_number_of_values") and
|
|
@@ -353,30 +465,31 @@ class _ListParamValidator(_ParamValidatorInterface):
|
|
|
353
465
|
raise InvalidCustomParamSpecError(error_messages)
|
|
354
466
|
|
|
355
467
|
def validate_value(self, param_value):
|
|
468
|
+
err = check_types_match(param_value, self.proto_type)
|
|
469
|
+
if err:
|
|
470
|
+
return err
|
|
471
|
+
|
|
356
472
|
if self.param_spec.HasField("min_number_of_values") and len(
|
|
357
473
|
param_value.values) < self.param_spec.min_number_of_values.value:
|
|
358
|
-
return
|
|
359
|
-
status=
|
|
360
|
-
error_messages=[
|
|
474
|
+
return CustomParamError(
|
|
475
|
+
status=CustomParamError.STATUS_INVALID_VALUE, error_messages=[
|
|
361
476
|
f"ListParam has {len(param_value.values)} values, which is less than the required minimum {self.param_spec.min_number_of_values}"
|
|
362
477
|
])
|
|
363
478
|
if self.param_spec.HasField("max_number_of_values") and len(
|
|
364
479
|
param_value.values) > self.param_spec.max_number_of_values.value:
|
|
365
|
-
return
|
|
366
|
-
status=
|
|
367
|
-
error_messages=[
|
|
480
|
+
return CustomParamError(
|
|
481
|
+
status=CustomParamError.STATUS_INVALID_VALUE, error_messages=[
|
|
368
482
|
f"ListParam has {len(param_value.values)} values, which is more than the allowed maximum {self.param_spec.max_number_of_values}"
|
|
369
483
|
])
|
|
370
|
-
custom_param_error =
|
|
371
|
-
status=service_customization_pb2.CustomParamError.STATUS_OK)
|
|
484
|
+
custom_param_error = CustomParamError(status=CustomParamError.STATUS_OK)
|
|
372
485
|
for custom_param_index in range(len(param_value.values)):
|
|
373
486
|
custom_param = param_value.values[custom_param_index]
|
|
374
487
|
spec_type = self.param_spec.element_spec.WhichOneof("spec")
|
|
375
488
|
value_type = custom_param.WhichOneof("value")
|
|
376
489
|
if spec_type.split("_")[0] != value_type.split("_")[0]:
|
|
377
|
-
custom_param_error.status =
|
|
490
|
+
custom_param_error.status = CustomParamError.STATUS_INVALID_TYPE
|
|
378
491
|
custom_param_error.error_messages.append(
|
|
379
|
-
"Value is defined as {value_type} at index {custom_param_index} while the List Param Spec expects {spec_type}"
|
|
492
|
+
f"Value is defined as {value_type} at index {custom_param_index} while the List Param Spec expects {spec_type}"
|
|
380
493
|
)
|
|
381
494
|
continue
|
|
382
495
|
custom_param_value = getattr(custom_param, custom_param.WhichOneof("value"))
|
|
@@ -387,7 +500,7 @@ class _ListParamValidator(_ParamValidatorInterface):
|
|
|
387
500
|
custom_param_error.error_messages.extend(
|
|
388
501
|
_nested_error_message_helper(f"[{custom_param_index}]",
|
|
389
502
|
error_proto.error_messages))
|
|
390
|
-
if custom_param_error.status !=
|
|
503
|
+
if custom_param_error.status != CustomParamError.STATUS_OK:
|
|
391
504
|
return custom_param_error
|
|
392
505
|
|
|
393
506
|
|
|
@@ -398,7 +511,7 @@ class _OneOfParamValidator(_ParamValidatorInterface):
|
|
|
398
511
|
Args:
|
|
399
512
|
param_spec (service_customization_pb2.OneOfInterestParam.Spec): The OneOfInterestParam Spec this helper instance is being used for
|
|
400
513
|
"""
|
|
401
|
-
proto_type =
|
|
514
|
+
proto_type = OneOfParam
|
|
402
515
|
custom_param_value_field = "one_of_value"
|
|
403
516
|
|
|
404
517
|
def __init__(self, param_spec):
|
|
@@ -409,8 +522,7 @@ class _OneOfParamValidator(_ParamValidatorInterface):
|
|
|
409
522
|
):
|
|
410
523
|
raise InvalidCustomParamSpecError(
|
|
411
524
|
[f"OneOf parameter has nonexistent default key of {self.param_spec.default_key}"])
|
|
412
|
-
custom_param_error =
|
|
413
|
-
status=service_customization_pb2.CustomParamError.STATUS_OK)
|
|
525
|
+
custom_param_error = CustomParamError(status=CustomParamError.STATUS_OK)
|
|
414
526
|
error_list = []
|
|
415
527
|
for key, child_spec in self.param_spec.specs.items():
|
|
416
528
|
try:
|
|
@@ -421,17 +533,21 @@ class _OneOfParamValidator(_ParamValidatorInterface):
|
|
|
421
533
|
raise InvalidCustomParamSpecError(error_list)
|
|
422
534
|
|
|
423
535
|
def validate_value(self, param_value):
|
|
536
|
+
err = check_types_match(param_value, self.proto_type)
|
|
537
|
+
if err:
|
|
538
|
+
return err
|
|
539
|
+
|
|
424
540
|
if param_value.key not in self.param_spec.specs.keys():
|
|
425
|
-
return
|
|
426
|
-
status=
|
|
541
|
+
return CustomParamError(
|
|
542
|
+
status=CustomParamError.STATUS_INVALID_VALUE,
|
|
427
543
|
error_messages=[f"OneOf parameter value has nonexistent key of {param_value.key}"])
|
|
428
544
|
|
|
429
|
-
#Only check active key since our spec doesn't guarantee valid values at unselected OneOf keys
|
|
545
|
+
# Only check active key since our spec doesn't guarantee valid values at unselected OneOf keys
|
|
430
546
|
chosen_param_error = _DictParamValidator(
|
|
431
547
|
self.param_spec.specs[param_value.key].spec).validate_value(
|
|
432
548
|
param_value.values[param_value.key])
|
|
433
549
|
if chosen_param_error:
|
|
434
|
-
full_error =
|
|
550
|
+
full_error = CustomParamError(
|
|
435
551
|
status=chosen_param_error.status,
|
|
436
552
|
error_messages=_nested_error_message_helper(param_value.key,
|
|
437
553
|
chosen_param_error.error_messages))
|
|
@@ -490,13 +606,609 @@ def _nested_error_message_helper(child_name, child_error_messages):
|
|
|
490
606
|
"""
|
|
491
607
|
joiner_string = " param has error: "
|
|
492
608
|
for message_index, child_error in enumerate(child_error_messages):
|
|
493
|
-
#If already nested, add child_name with period delimiter
|
|
609
|
+
# If already nested, add child_name with period delimiter
|
|
494
610
|
if joiner_string in child_error:
|
|
495
611
|
child_error_messages[message_index] = child_name + "." + child_error
|
|
496
|
-
#Else, make into a human-readable nested format
|
|
612
|
+
# Else, make into a human-readable nested format
|
|
497
613
|
else:
|
|
498
614
|
child_error_messages[message_index] = child_name + joiner_string + child_error
|
|
499
615
|
|
|
500
616
|
# Remove period delimiter for list indices
|
|
501
617
|
child_error_messages[message_index] = child_error_messages[message_index].replace(".[", "[")
|
|
502
618
|
return child_error_messages
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def custom_spec_to_default(spec):
|
|
622
|
+
"""
|
|
623
|
+
Create a default service_customization_pb2.CustomParam based off of the service_customization_pb2.CustomParam.Spec argument
|
|
624
|
+
|
|
625
|
+
Args:
|
|
626
|
+
spec (service_customization_pb2.CustomParam.Spec): spec to which the parameter should be defaulted
|
|
627
|
+
"""
|
|
628
|
+
which_spec = spec.WhichOneof('spec')
|
|
629
|
+
|
|
630
|
+
default_func = _SPEC_VALUES[which_spec][1]
|
|
631
|
+
|
|
632
|
+
param_value = default_func(getattr(spec, which_spec))
|
|
633
|
+
if param_value is None:
|
|
634
|
+
return None
|
|
635
|
+
|
|
636
|
+
if which_spec == 'dict_spec':
|
|
637
|
+
return CustomParam(dict_value=param_value)
|
|
638
|
+
elif which_spec == 'list_spec':
|
|
639
|
+
return CustomParam(list_value=param_value)
|
|
640
|
+
elif which_spec == 'int_spec':
|
|
641
|
+
return CustomParam(int_value=param_value)
|
|
642
|
+
elif which_spec == 'double_spec':
|
|
643
|
+
return CustomParam(double_value=param_value)
|
|
644
|
+
elif which_spec == 'string_spec':
|
|
645
|
+
return CustomParam(string_value=param_value)
|
|
646
|
+
elif which_spec == 'roi_spec':
|
|
647
|
+
return CustomParam(roi_value=param_value)
|
|
648
|
+
elif which_spec == 'bool_spec':
|
|
649
|
+
return CustomParam(bool_value=param_value)
|
|
650
|
+
elif which_spec == 'one_of_spec':
|
|
651
|
+
return CustomParam(one_of_value=param_value)
|
|
652
|
+
else:
|
|
653
|
+
return None
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
def dict_spec_to_default(spec):
|
|
657
|
+
"""
|
|
658
|
+
Create a default service_customization_pb2.DictParam based off of the service_customization_pb2.DictParam.Spec argument.
|
|
659
|
+
|
|
660
|
+
Args:
|
|
661
|
+
spec (service_customization_pb2.DictParam.Spec): spec to which the parameter should be defaulted
|
|
662
|
+
"""
|
|
663
|
+
param = DictParam()
|
|
664
|
+
for (key, value) in spec.specs.items():
|
|
665
|
+
default_value_param = custom_spec_to_default(value.spec)
|
|
666
|
+
if default_value_param is not None:
|
|
667
|
+
param.values[key].CopyFrom(default_value_param)
|
|
668
|
+
return param
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
def list_spec_to_default(spec):
|
|
672
|
+
"""
|
|
673
|
+
Create a default service_customization_pb2.ListParam based off of the service_customization_pb2.ListParam.Spec argument
|
|
674
|
+
|
|
675
|
+
Args:
|
|
676
|
+
spec (service_customization_pb2.ListParam.Spec): spec to which the parameter should be defaulted
|
|
677
|
+
"""
|
|
678
|
+
param = ListParam()
|
|
679
|
+
default_element_spec = custom_spec_to_default(spec.element_spec)
|
|
680
|
+
if default_element_spec is not None:
|
|
681
|
+
for i in range(0, spec.min_number_of_values.value):
|
|
682
|
+
param.values.append(default_element_spec)
|
|
683
|
+
|
|
684
|
+
return param
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
def int_spec_to_default(spec):
|
|
688
|
+
"""
|
|
689
|
+
Create a default service_customization_pb2.IntParam based off of the service_customization_pb2.IntParam.Spec argument
|
|
690
|
+
|
|
691
|
+
Args:
|
|
692
|
+
spec (service_customization_pb2.IntParam.Spec): spec to which the parameter should be defaulted
|
|
693
|
+
"""
|
|
694
|
+
param = Int64Param()
|
|
695
|
+
if spec.HasField('default_value'):
|
|
696
|
+
param.value = spec.default_value.value
|
|
697
|
+
elif spec.HasField('min_value'):
|
|
698
|
+
param.value = spec.min_value.value
|
|
699
|
+
elif spec.HasField('max_value'):
|
|
700
|
+
param.value = spec.max_value.value
|
|
701
|
+
else:
|
|
702
|
+
param.value = 0
|
|
703
|
+
return param
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
def double_spec_to_default(spec):
|
|
707
|
+
"""
|
|
708
|
+
Create a default service_customization_pb2.DoubleParam based off of the service_customization_pb2.DoubleParam.Spec argument
|
|
709
|
+
|
|
710
|
+
Args:
|
|
711
|
+
spec (service_customization_pb2.DoubleParam.Spec): spec to which the parameter should be defaulted
|
|
712
|
+
"""
|
|
713
|
+
param = DoubleParam()
|
|
714
|
+
if spec.HasField('default_value'):
|
|
715
|
+
param.value = spec.default_value.value
|
|
716
|
+
elif spec.HasField('min_value'):
|
|
717
|
+
param.value = spec.min_value.value
|
|
718
|
+
elif spec.HasField('max_value'):
|
|
719
|
+
param.value = spec.max_value.value
|
|
720
|
+
else:
|
|
721
|
+
param.value = 0
|
|
722
|
+
return param
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
def string_spec_to_default(spec):
|
|
726
|
+
"""
|
|
727
|
+
Create a default service_customization_pb2.StringParam based off of the service_customization_pb2.StringParam.Spec argument
|
|
728
|
+
|
|
729
|
+
Args:
|
|
730
|
+
spec (service_customization_pb2.StringParam.Spec): spec to which the parameter should be defaulted
|
|
731
|
+
"""
|
|
732
|
+
param = StringParam()
|
|
733
|
+
if spec.default_value != '':
|
|
734
|
+
param.value = spec.default_value
|
|
735
|
+
elif len(spec.options) > 0:
|
|
736
|
+
param.value = spec.options[0]
|
|
737
|
+
else:
|
|
738
|
+
param.value = ''
|
|
739
|
+
return param
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
def roi_spec_to_default(spec):
|
|
743
|
+
"""
|
|
744
|
+
Create a default service_customization_pb2.RegionOfInterestParam based off of the service_customization_pb2.RegionOfInterestParam.Spec argument
|
|
745
|
+
|
|
746
|
+
Args:
|
|
747
|
+
spec (service_customization_pb2.RegionOfInterestParam.Spec): spec to which the parameter should be defaulted
|
|
748
|
+
"""
|
|
749
|
+
if not spec.allows_rectangle:
|
|
750
|
+
return None
|
|
751
|
+
param = RegionOfInterestParam()
|
|
752
|
+
if spec.HasField('default_area'):
|
|
753
|
+
param.area.CopyFrom(spec.default_area)
|
|
754
|
+
if spec.HasField('service_and_source'):
|
|
755
|
+
param.service_and_source.CopyFrom(spec.service_and_source)
|
|
756
|
+
return param
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
def bool_spec_to_default(spec):
|
|
760
|
+
"""
|
|
761
|
+
Create a default service_customization_pb2.BoolParam based off of the service_customization_pb2.BoolParam.Spec argument
|
|
762
|
+
|
|
763
|
+
Args:
|
|
764
|
+
spec (service_customization_pb2.BoolParam.Spec): spec to which the parameter should be defaulted
|
|
765
|
+
"""
|
|
766
|
+
return BoolParam(value=spec.default_value.value)
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
def one_of_spec_to_default(spec):
|
|
770
|
+
"""
|
|
771
|
+
Create a default service_customization_pb2.OneOfParam based off of the service_customization_pb2.OneOfParam.Spec argument
|
|
772
|
+
|
|
773
|
+
Args:
|
|
774
|
+
spec (service_customization_pb2.OneOfParam.Spec): spec to which the parameter should be defaulted
|
|
775
|
+
"""
|
|
776
|
+
param = OneOfParam()
|
|
777
|
+
key = spec.default_key
|
|
778
|
+
if key not in spec.specs.keys():
|
|
779
|
+
return None
|
|
780
|
+
|
|
781
|
+
param.key = key
|
|
782
|
+
for (key, value) in spec.specs.items():
|
|
783
|
+
param.values[key].CopyFrom(dict_spec_to_default(value.spec))
|
|
784
|
+
return param
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
def dict_param_coerce_to(param, spec):
|
|
788
|
+
"""
|
|
789
|
+
Coerce a service_customization_pb2.DictParam based off of the spec passed in. The parameter is modified in-place.
|
|
790
|
+
|
|
791
|
+
Args:
|
|
792
|
+
param (service_customization_pb2.DictParam): parameter that requires coercing
|
|
793
|
+
spec (service_customization_pb2.DictParam.Spec): spec to which the parameter should be coerced
|
|
794
|
+
|
|
795
|
+
Returns:
|
|
796
|
+
`True` if parameter was coerced
|
|
797
|
+
`False` otherwise
|
|
798
|
+
"""
|
|
799
|
+
did_coerce = False
|
|
800
|
+
new_map = {}
|
|
801
|
+
for (key, child_spec) in spec.specs.items():
|
|
802
|
+
p = param.values[key]
|
|
803
|
+
if p is None:
|
|
804
|
+
default_param = custom_spec_to_default(child_spec.spec)
|
|
805
|
+
new_map[key] = default_param
|
|
806
|
+
did_coerce = True
|
|
807
|
+
else:
|
|
808
|
+
if custom_param_coerce_to(p, child_spec.spec):
|
|
809
|
+
did_coerce = True
|
|
810
|
+
new_map[key] = p
|
|
811
|
+
param.ClearField('values')
|
|
812
|
+
for key in spec.specs.keys():
|
|
813
|
+
param.values[key].CopyFrom(new_map[key])
|
|
814
|
+
return did_coerce
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
def list_param_coerce_to(param, spec):
|
|
818
|
+
"""
|
|
819
|
+
Coerce a service_customization_pb2.ListParam based off of the spec passed in. The parameter is modified in-place.
|
|
820
|
+
|
|
821
|
+
Args:
|
|
822
|
+
param (service_customization_pb2.ListParam): parameter that requires coercing
|
|
823
|
+
spec (service_customization_pb2.ListParam.Spec): spec to which the parameter should be coerced
|
|
824
|
+
|
|
825
|
+
Returns:
|
|
826
|
+
`True` if parameter was coerced
|
|
827
|
+
`False` otherwise
|
|
828
|
+
"""
|
|
829
|
+
did_coerce = False
|
|
830
|
+
if spec.HasField('min_number_of_values'):
|
|
831
|
+
if len(param.values) < spec.min_number_of_values.value:
|
|
832
|
+
default_element_param = custom_spec_to_default(spec.element_spec)
|
|
833
|
+
param.values.extend(
|
|
834
|
+
[default_element_param] * (spec.min_number_of_values.value - len(param.values)))
|
|
835
|
+
did_coerce = True
|
|
836
|
+
if spec.HasField('max_number_of_values'):
|
|
837
|
+
while len(param.values) > spec.max_number_of_values.value:
|
|
838
|
+
param.values.pop()
|
|
839
|
+
did_coerce = True
|
|
840
|
+
for i in range(0, len(param.values)):
|
|
841
|
+
if custom_param_coerce_to(param.values[i], spec.element_spec):
|
|
842
|
+
did_coerce = True
|
|
843
|
+
return did_coerce
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
def int_param_coerce_to(param, spec):
|
|
847
|
+
"""
|
|
848
|
+
Coerce a service_customization_pb2.IntParam based off of the spec passed in. The parameter is modified in-place.
|
|
849
|
+
|
|
850
|
+
Args:
|
|
851
|
+
param (service_customization_pb2.IntParam): parameter that requires coercing
|
|
852
|
+
spec (service_customization_pb2.Int.Spec): spec to which the parameter should be coerced
|
|
853
|
+
|
|
854
|
+
Returns:
|
|
855
|
+
`True` if parameter was coerced
|
|
856
|
+
`False` otherwise
|
|
857
|
+
"""
|
|
858
|
+
invalid_max = spec.HasField('max_value') and param.value > spec.max_value.value
|
|
859
|
+
invalid_min = spec.HasField('min_value') and param.value < spec.min_value.value
|
|
860
|
+
if invalid_max or invalid_min:
|
|
861
|
+
param.Clear()
|
|
862
|
+
param.MergeFrom(int_spec_to_default(spec))
|
|
863
|
+
return True
|
|
864
|
+
return False
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
def double_param_coerce_to(param, spec):
|
|
868
|
+
"""
|
|
869
|
+
Coerce a service_customization_pb2.CustomParam based off of the spec passed in. The parameter is modified in-place.
|
|
870
|
+
|
|
871
|
+
Args:
|
|
872
|
+
param (service_customization_pb2.DoubleParam): parameter that requires coercing
|
|
873
|
+
spec (service_customization_pb2.DoubleParam.Spec): spec to which the parameter should be coerced
|
|
874
|
+
|
|
875
|
+
Returns:
|
|
876
|
+
`True` if parameter was coerced
|
|
877
|
+
`False` otherwise
|
|
878
|
+
"""
|
|
879
|
+
invalid_max = spec.HasField('max_value') and param.value > spec.max_value.value
|
|
880
|
+
invalid_min = spec.HasField('min_value') and param.value < spec.min_value.value
|
|
881
|
+
if invalid_max or invalid_min:
|
|
882
|
+
param.Clear()
|
|
883
|
+
param.MergeFrom(double_spec_to_default(spec))
|
|
884
|
+
return True
|
|
885
|
+
return False
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
def string_param_coerce_to(param, spec):
|
|
889
|
+
"""
|
|
890
|
+
Coerce a service_customization_pb2.StringParam based off of the spec passed in. The parameter is modified in-place.
|
|
891
|
+
|
|
892
|
+
Args:
|
|
893
|
+
param (service_customization_pb2.StringParam): parameter that requires coercing
|
|
894
|
+
spec (service_customization_pb2.StringParam.Spec): spec to which the parameter should be coerced
|
|
895
|
+
|
|
896
|
+
Returns:
|
|
897
|
+
`True` if parameter was coerced
|
|
898
|
+
`False` otherwise
|
|
899
|
+
"""
|
|
900
|
+
if not spec.editable and param.value not in spec.options and len(spec.options) > 0:
|
|
901
|
+
param.Clear()
|
|
902
|
+
param.MergeFrom(string_spec_to_default(spec))
|
|
903
|
+
return True
|
|
904
|
+
return False
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
def roi_param_coerce_to(param, spec):
|
|
908
|
+
"""
|
|
909
|
+
Coercion is tricky with ROI parameters due to the fact that there is no standard frame size. ROI parameter is not
|
|
910
|
+
modified in place; rather, a boolean value is returned.
|
|
911
|
+
|
|
912
|
+
Args:
|
|
913
|
+
param (service_customization_pb2.RegionOfInterestParam): parameter that requires coercing
|
|
914
|
+
spec (service_customization_pb2.RegionOfInterestParam.Spec): spec to which the parameter should be coerced
|
|
915
|
+
|
|
916
|
+
Returns:
|
|
917
|
+
`True` if service_and_source is unset or if the spec and the parameter match
|
|
918
|
+
`False` otherwise
|
|
919
|
+
"""
|
|
920
|
+
return not spec.HasField(
|
|
921
|
+
'service_and_source') or spec.service_and_source == param.service_and_source
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
def one_of_param_coerce_to(param, spec):
|
|
925
|
+
"""
|
|
926
|
+
Coerce a service_customization_pb2.OneOfParam based off of the spec passed in. The parameter is modified in-place.
|
|
927
|
+
|
|
928
|
+
Args:
|
|
929
|
+
param (service_customization_pb2.OneOfParam): parameter that requires coercing
|
|
930
|
+
spec (service_customization_pb2.OneOfParam.Spec): spec to which the parameter should be coerced
|
|
931
|
+
|
|
932
|
+
Returns:
|
|
933
|
+
`True` if parameter was coerced
|
|
934
|
+
`False` otherwise
|
|
935
|
+
"""
|
|
936
|
+
did_coerce = False
|
|
937
|
+
if param.key not in spec.specs.keys():
|
|
938
|
+
param.key = sorted(list(spec.specs.keys()))[0]
|
|
939
|
+
did_coerce = True
|
|
940
|
+
new_map = {}
|
|
941
|
+
for (key, child_spec) in spec.specs.items():
|
|
942
|
+
value_param = param.values[key]
|
|
943
|
+
if value_param is None:
|
|
944
|
+
new_map[key] = dict_spec_to_default(child_spec.spec)
|
|
945
|
+
did_coerce = True
|
|
946
|
+
else:
|
|
947
|
+
if dict_param_coerce_to(value_param, child_spec.spec):
|
|
948
|
+
did_coerce = True
|
|
949
|
+
new_map[key] = value_param
|
|
950
|
+
|
|
951
|
+
param.ClearField('values')
|
|
952
|
+
for key in spec.specs.keys():
|
|
953
|
+
param.values[key].CopyFrom(new_map[key])
|
|
954
|
+
|
|
955
|
+
return did_coerce
|
|
956
|
+
|
|
957
|
+
|
|
958
|
+
_SPEC_VALUES = {
|
|
959
|
+
'dict_spec': ('dict_value', dict_spec_to_default, dict_param_coerce_to),
|
|
960
|
+
'list_spec': ('list_value', list_spec_to_default, list_param_coerce_to),
|
|
961
|
+
'int_spec': ('int_value', int_spec_to_default, int_param_coerce_to),
|
|
962
|
+
'double_spec': ('double_value', double_spec_to_default, double_param_coerce_to),
|
|
963
|
+
'string_spec': ('string_value', string_spec_to_default, string_param_coerce_to),
|
|
964
|
+
'roi_spec': ('roi_value', roi_spec_to_default, roi_param_coerce_to),
|
|
965
|
+
'bool_spec':
|
|
966
|
+
('bool_value', bool_spec_to_default, None), # No coercing, there are no illegal values.
|
|
967
|
+
'one_of_spec': ('one_of_value', one_of_spec_to_default, one_of_param_coerce_to),
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
def custom_param_coerce_to(param, spec):
|
|
972
|
+
"""
|
|
973
|
+
Coerce a service_customization_pb2.CustomParam based off of the spec passed in. The parameter is modified in-place.
|
|
974
|
+
|
|
975
|
+
Args:
|
|
976
|
+
param (service_customization_pb2.CustomParam): parameter that requires coercing
|
|
977
|
+
spec (service_customization_pb2.CustomParam.Spec): spec to which the parameter should be coerced
|
|
978
|
+
|
|
979
|
+
Returns:
|
|
980
|
+
`True` if parameter was coerced
|
|
981
|
+
`False` otherwise
|
|
982
|
+
"""
|
|
983
|
+
did_coerce = False
|
|
984
|
+
which_spec = spec.WhichOneof('spec')
|
|
985
|
+
|
|
986
|
+
field_name, default_value_func, coercion_func = _SPEC_VALUES[which_spec]
|
|
987
|
+
if param.HasField(field_name):
|
|
988
|
+
if coercion_func is not None:
|
|
989
|
+
if coercion_func(getattr(param, field_name), getattr(spec, which_spec)):
|
|
990
|
+
did_coerce = True
|
|
991
|
+
else:
|
|
992
|
+
param.Clear()
|
|
993
|
+
getattr(param, field_name).CopyFrom(default_value_func(getattr(spec, which_spec)))
|
|
994
|
+
did_coerce = True
|
|
995
|
+
return did_coerce
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
def make_custom_param_spec(
|
|
999
|
+
spec: Union[DictParam.Spec, ListParam.Spec, Int64Param.Spec, DoubleParam.Spec, StringParam.Spec,
|
|
1000
|
+
RegionOfInterestParam.Spec, BoolParam.Spec, OneOfParam.Spec]
|
|
1001
|
+
) -> CustomParam.Spec:
|
|
1002
|
+
"""
|
|
1003
|
+
Helper function to create a CustomParam.Spec
|
|
1004
|
+
|
|
1005
|
+
Args:
|
|
1006
|
+
spec: spec to be wrapped by a CustomParam.Spec
|
|
1007
|
+
"""
|
|
1008
|
+
if isinstance(spec, DictParam.Spec):
|
|
1009
|
+
return CustomParam.Spec(dict_spec=spec)
|
|
1010
|
+
if isinstance(spec, ListParam.Spec):
|
|
1011
|
+
return CustomParam.Spec(list_spec=spec)
|
|
1012
|
+
if isinstance(spec, Int64Param.Spec):
|
|
1013
|
+
return CustomParam.Spec(int_spec=spec)
|
|
1014
|
+
if isinstance(spec, DoubleParam.Spec):
|
|
1015
|
+
return CustomParam.Spec(double_spec=spec)
|
|
1016
|
+
if isinstance(spec, StringParam.Spec):
|
|
1017
|
+
return CustomParam.Spec(string_spec=spec)
|
|
1018
|
+
if isinstance(spec, RegionOfInterestParam.Spec):
|
|
1019
|
+
return CustomParam.Spec(roi_spec=spec)
|
|
1020
|
+
if isinstance(spec, BoolParam.Spec):
|
|
1021
|
+
return CustomParam.Spec(bool_spec=spec)
|
|
1022
|
+
if isinstance(spec, OneOfParam.Spec):
|
|
1023
|
+
return CustomParam.Spec(one_of_spec=spec)
|
|
1024
|
+
raise ValueError('Must provide a spec from service_customization_pb2 to this function.')
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
def make_dict_child_spec(param_spec: Union[DictParam.Spec, ListParam.Spec, Int64Param.Spec,
|
|
1028
|
+
DoubleParam.Spec, StringParam.Spec,
|
|
1029
|
+
RegionOfInterestParam.Spec, BoolParam.Spec,
|
|
1030
|
+
OneOfParam.Spec],
|
|
1031
|
+
ui_info: Optional[UserInterfaceInfo] = None) -> DictParam.ChildSpec:
|
|
1032
|
+
"""
|
|
1033
|
+
Helper function to create a DictParam.ChildSpec
|
|
1034
|
+
|
|
1035
|
+
Args:
|
|
1036
|
+
param_spec: spec for DictParam.ChildSpec that is converted into a CustomParam.Spec when forming the ChildSpec
|
|
1037
|
+
ui_info: instantiation of service_customization_pb2.UserInterfaceInfo
|
|
1038
|
+
"""
|
|
1039
|
+
return DictParam.ChildSpec(spec=make_custom_param_spec(param_spec), ui_info=ui_info)
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
def make_dict_param_spec(specs: Dict[str, DictParam.ChildSpec],
|
|
1043
|
+
is_hidden_by_default: bool) -> DictParam.Spec:
|
|
1044
|
+
"""
|
|
1045
|
+
Helper function to create a DictParam.Spec
|
|
1046
|
+
|
|
1047
|
+
Args:
|
|
1048
|
+
specs: specs contained by the DictParam
|
|
1049
|
+
is_hidden_by_default: controls whether the UI shows this spec as collapsed by default
|
|
1050
|
+
"""
|
|
1051
|
+
return DictParam.Spec(specs=specs, is_hidden_by_default=is_hidden_by_default)
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
def make_one_of_child_spec(dict_param_spec: DictParam.Spec,
|
|
1055
|
+
ui_info: Optional[UserInterfaceInfo] = None) -> OneOfParam.ChildSpec:
|
|
1056
|
+
"""
|
|
1057
|
+
Helper function to create a OneOfParam.ChildSpec
|
|
1058
|
+
|
|
1059
|
+
Args:
|
|
1060
|
+
dict_param_spec: spec for OneOfParam.ChildSpec
|
|
1061
|
+
ui_info: instantiation of service_customization_pb2.UserInterfaceInfo
|
|
1062
|
+
"""
|
|
1063
|
+
return OneOfParam.ChildSpec(spec=dict_param_spec, ui_info=ui_info)
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
def make_one_of_param_spec(specs: Dict[str, OneOfParam.ChildSpec],
|
|
1067
|
+
default_key: Optional[str] = None) -> OneOfParam.Spec:
|
|
1068
|
+
"""
|
|
1069
|
+
Helper function to create a OneOfParam.Spec
|
|
1070
|
+
|
|
1071
|
+
Args:
|
|
1072
|
+
specs: specs contained by the OneOfParam
|
|
1073
|
+
default_key: the key to which the OneOfParam.Spec should default in the UI
|
|
1074
|
+
"""
|
|
1075
|
+
return OneOfParam.Spec(specs=specs, default_key=default_key)
|
|
1076
|
+
|
|
1077
|
+
|
|
1078
|
+
def make_list_param_spec(element_spec: CustomParam.Spec, min_number_of_values: Optional[int] = None,
|
|
1079
|
+
max_number_of_values: Optional[int] = None) -> ListParam.Spec:
|
|
1080
|
+
"""
|
|
1081
|
+
Helper function to create a ListParam.Spec
|
|
1082
|
+
|
|
1083
|
+
Args:
|
|
1084
|
+
element_spec: spec for each element of the list
|
|
1085
|
+
min_number_of_values: minimum number of elements in the list
|
|
1086
|
+
max_number_of_values: maximum number of elements in the list
|
|
1087
|
+
"""
|
|
1088
|
+
spec = ListParam.Spec(element_spec=element_spec)
|
|
1089
|
+
if min_number_of_values is not None:
|
|
1090
|
+
spec.min_number_of_values.value = min_number_of_values
|
|
1091
|
+
if max_number_of_values is not None:
|
|
1092
|
+
spec.max_number_of_values.value = max_number_of_values
|
|
1093
|
+
return spec
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
def make_int64_param_spec(default_value: Optional[int] = None, units: Optional[Units] = None,
|
|
1097
|
+
min_value: Optional[int] = None,
|
|
1098
|
+
max_value: Optional[int] = None) -> Int64Param.Spec:
|
|
1099
|
+
"""
|
|
1100
|
+
Helper function to create an Int64Param.Spec
|
|
1101
|
+
|
|
1102
|
+
Args:
|
|
1103
|
+
default_value: starting value for Int64Param
|
|
1104
|
+
units: units of the Int64Param
|
|
1105
|
+
min_value: smallest value the Int64Param may be
|
|
1106
|
+
max_value: largest value the Int64Param may be
|
|
1107
|
+
"""
|
|
1108
|
+
spec = Int64Param.Spec(units=units)
|
|
1109
|
+
if default_value is not None:
|
|
1110
|
+
spec.default_value.value = default_value
|
|
1111
|
+
if min_value is not None:
|
|
1112
|
+
spec.min_value.value = min_value
|
|
1113
|
+
if max_value is not None:
|
|
1114
|
+
spec.max_value.value = max_value
|
|
1115
|
+
return spec
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
def make_double_param_spec(default_value: Optional[float] = None, units: Optional[Units] = None,
|
|
1119
|
+
min_value: Optional[float] = None,
|
|
1120
|
+
max_value: Optional[float] = None) -> DoubleParam.Spec:
|
|
1121
|
+
"""
|
|
1122
|
+
Helper function to create a DoubleParam.Spec
|
|
1123
|
+
|
|
1124
|
+
Args:
|
|
1125
|
+
default_value: starting value for DoubleParam
|
|
1126
|
+
units: units of the DoubleParam
|
|
1127
|
+
min_value: smallest value the DoubleParam may be
|
|
1128
|
+
max_value: largest value the DoubleParam may be
|
|
1129
|
+
"""
|
|
1130
|
+
spec = DoubleParam.Spec(units=units)
|
|
1131
|
+
if default_value is not None:
|
|
1132
|
+
spec.default_value.value = default_value
|
|
1133
|
+
if min_value is not None:
|
|
1134
|
+
spec.min_value.value = min_value
|
|
1135
|
+
if max_value is not None:
|
|
1136
|
+
spec.max_value.value = max_value
|
|
1137
|
+
return spec
|
|
1138
|
+
|
|
1139
|
+
|
|
1140
|
+
def make_string_param_spec(options: Optional[List[str]] = None, editable: Optional[bool] = None,
|
|
1141
|
+
default_value: Optional[str] = None) -> StringParam.Spec:
|
|
1142
|
+
"""
|
|
1143
|
+
Helper function to create a StringParam.Spec
|
|
1144
|
+
|
|
1145
|
+
Args:
|
|
1146
|
+
options: predetermined options the StringParam may be
|
|
1147
|
+
editable: whether the value may be edited
|
|
1148
|
+
default_value: initial value for StringParam
|
|
1149
|
+
"""
|
|
1150
|
+
return StringParam.Spec(options=options, editable=editable, default_value=default_value)
|
|
1151
|
+
|
|
1152
|
+
|
|
1153
|
+
def make_bool_param_spec(default_value: Optional[bool] = None) -> BoolParam.Spec:
|
|
1154
|
+
"""
|
|
1155
|
+
Helper function to create an BoolParam.Spec
|
|
1156
|
+
|
|
1157
|
+
Args:
|
|
1158
|
+
default_value: starting value for BoolParam
|
|
1159
|
+
"""
|
|
1160
|
+
spec = BoolParam.Spec()
|
|
1161
|
+
if default_value is not None:
|
|
1162
|
+
spec.default_value.value = default_value
|
|
1163
|
+
return spec
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
def make_region_of_interest_param_spec(
|
|
1167
|
+
service_and_source: Optional[RegionOfInterestParam.ServiceAndSource] = None,
|
|
1168
|
+
default_area: Optional[AreaI] = None,
|
|
1169
|
+
allows_rectangle: bool = False) -> RegionOfInterestParam.Spec:
|
|
1170
|
+
"""
|
|
1171
|
+
Helper function to create a RegionOfInterestParam.Spec
|
|
1172
|
+
|
|
1173
|
+
Args:
|
|
1174
|
+
service_and_source: service and source to which the RegionOfInterestParam should adhere
|
|
1175
|
+
default_area: starting area for the RegionOfInterestParam
|
|
1176
|
+
allows_rectangle: whether a rectangle may be drawn for the selected area
|
|
1177
|
+
"""
|
|
1178
|
+
return RegionOfInterestParam.Spec(default_area=default_area,
|
|
1179
|
+
service_and_source=service_and_source,
|
|
1180
|
+
allows_rectangle=allows_rectangle)
|
|
1181
|
+
|
|
1182
|
+
|
|
1183
|
+
|
|
1184
|
+
|
|
1185
|
+
def make_user_interface_info(display_name: Optional[str] = None, description: Optional[str] = None,
|
|
1186
|
+
display_order: Optional[int] = None) -> UserInterfaceInfo:
|
|
1187
|
+
"""
|
|
1188
|
+
Helper function to create UserInterfaceInfo
|
|
1189
|
+
|
|
1190
|
+
Args:
|
|
1191
|
+
display_name: human-readable name displayed by the UI
|
|
1192
|
+
description: additional information for parameter (used in conjunction with display_name)
|
|
1193
|
+
display_order: order in which the fields should be displayed
|
|
1194
|
+
"""
|
|
1195
|
+
ui_info = UserInterfaceInfo()
|
|
1196
|
+
if display_name is not None:
|
|
1197
|
+
ui_info.display_name = display_name
|
|
1198
|
+
if description is not None:
|
|
1199
|
+
ui_info.description = description
|
|
1200
|
+
if display_order is not None:
|
|
1201
|
+
ui_info.display_order = display_order
|
|
1202
|
+
return ui_info
|
|
1203
|
+
|
|
1204
|
+
|
|
1205
|
+
def make_roi_service_and_source(service: str,
|
|
1206
|
+
source: str) -> RegionOfInterestParam.ServiceAndSource:
|
|
1207
|
+
"""
|
|
1208
|
+
Helper function to create a RegionOfInterestParam.ServiceAndSource
|
|
1209
|
+
|
|
1210
|
+
Args:
|
|
1211
|
+
service: the ImageService providing the image
|
|
1212
|
+
source: the ImageSource providing the image
|
|
1213
|
+
"""
|
|
1214
|
+
return RegionOfInterestParam.ServiceAndSource(service=service, source=source)
|