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.
Files changed (56) hide show
  1. bosdyn/client/__init__.py +5 -6
  2. bosdyn/client/area_callback_region_handler_base.py +19 -4
  3. bosdyn/client/area_callback_service_servicer.py +29 -1
  4. bosdyn/client/area_callback_service_utils.py +45 -51
  5. bosdyn/client/auth.py +13 -28
  6. bosdyn/client/autowalk.py +3 -0
  7. bosdyn/client/channel.py +23 -26
  8. bosdyn/client/command_line.py +64 -13
  9. bosdyn/client/common.py +4 -4
  10. bosdyn/client/data_acquisition.py +47 -6
  11. bosdyn/client/data_acquisition_plugin.py +12 -2
  12. bosdyn/client/data_acquisition_plugin_service.py +33 -2
  13. bosdyn/client/data_acquisition_store.py +38 -0
  14. bosdyn/client/data_buffer.py +22 -8
  15. bosdyn/client/data_chunk.py +1 -0
  16. bosdyn/client/directory_registration.py +1 -14
  17. bosdyn/client/exceptions.py +0 -4
  18. bosdyn/client/frame_helpers.py +3 -1
  19. bosdyn/client/gps/NMEAParser.py +189 -0
  20. bosdyn/client/gps/__init__.py +6 -0
  21. bosdyn/client/gps/aggregator_client.py +56 -0
  22. bosdyn/client/gps/gps_listener.py +153 -0
  23. bosdyn/client/gps/registration_client.py +48 -0
  24. bosdyn/client/graph_nav.py +50 -20
  25. bosdyn/client/image.py +20 -7
  26. bosdyn/client/image_service_helpers.py +14 -14
  27. bosdyn/client/lease.py +27 -22
  28. bosdyn/client/lease_validator.py +5 -5
  29. bosdyn/client/manipulation_api_client.py +1 -1
  30. bosdyn/client/map_processing.py +10 -5
  31. bosdyn/client/math_helpers.py +21 -11
  32. bosdyn/client/metrics_logging.py +147 -0
  33. bosdyn/client/network_compute_bridge_client.py +6 -0
  34. bosdyn/client/power.py +40 -0
  35. bosdyn/client/recording.py +3 -3
  36. bosdyn/client/robot.py +15 -16
  37. bosdyn/client/robot_command.py +341 -203
  38. bosdyn/client/robot_id.py +6 -5
  39. bosdyn/client/robot_state.py +6 -0
  40. bosdyn/client/sdk.py +5 -11
  41. bosdyn/client/server_util.py +11 -11
  42. bosdyn/client/service_customization_helpers.py +776 -64
  43. bosdyn/client/signals_helpers.py +105 -0
  44. bosdyn/client/spot_cam/compositor.py +6 -2
  45. bosdyn/client/spot_cam/ptz.py +24 -14
  46. bosdyn/client/spot_check.py +160 -0
  47. bosdyn/client/time_sync.py +5 -5
  48. bosdyn/client/units_helpers.py +39 -0
  49. bosdyn/client/util.py +100 -64
  50. bosdyn/client/world_object.py +5 -5
  51. {bosdyn_client-3.3.2.dist-info → bosdyn_client-4.0.1.dist-info}/METADATA +4 -3
  52. bosdyn_client-4.0.1.dist-info/RECORD +97 -0
  53. {bosdyn_client-3.3.2.dist-info → bosdyn_client-4.0.1.dist-info}/WHEEL +1 -1
  54. bosdyn/client/log_annotation.py +0 -359
  55. bosdyn_client-3.3.2.dist-info/RECORD +0 -90
  56. {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
- def validate_dict_spec(dict_spec: service_customization_pb2.DictParam.Spec) -> None:
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
- dict_spec: service_customization_pb2.DictParam.Spec
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[service_customization_pb2.CustomParamError]:
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 = service_customization_pb2.DictParam
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 = service_customization_pb2.CustomParamError(
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 service_customization_pb2.CustomParamError(
138
- status=service_customization_pb2.CustomParamError.STATUS_UNSUPPORTED_PARAMETER,
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 = service_customization_pb2.CustomParamError(
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 != service_customization_pb2.CustomParamError.STATUS_OK:
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
- num_value = param_value.value
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 service_customization_pb2.CustomParamError(
188
- status=service_customization_pb2.CustomParamError.STATUS_INVALID_VALUE,
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 service_customization_pb2.CustomParamError(
195
- status=service_customization_pb2.CustomParamError.STATUS_INVALID_VALUE,
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 = service_customization_pb2.Int64Param
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 = service_customization_pb2.DoubleParam
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 = service_customization_pb2.StringParam
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 service_customization_pb2.CustomParamError(
255
- status=service_customization_pb2.CustomParamError.STATUS_INVALID_VALUE,
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 = service_customization_pb2.BoolParam
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
- return super().validate_value(param_value)
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 = service_customization_pb2.RegionOfInterestParam
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 service_customization_pb2.CustomParamError(
304
- status=service_customization_pb2.CustomParamError.STATUS_INVALID_VALUE,
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 service_customization_pb2.CustomParamError(
308
- status=service_customization_pb2.CustomParamError.STATUS_INVALID_VALUE,
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 service_customization_pb2.CustomParamError(
312
- status=service_customization_pb2.CustomParamError.STATUS_INVALID_VALUE,
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 = service_customization_pb2.ListParam
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 service_customization_pb2.CustomParamError(
359
- status=service_customization_pb2.CustomParamError.STATUS_INVALID_VALUE,
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 service_customization_pb2.CustomParamError(
366
- status=service_customization_pb2.CustomParamError.STATUS_INVALID_VALUE,
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 = service_customization_pb2.CustomParamError(
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 = service_customization_pb2.CustomParamError.STATUS_INVALID_TYPE
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 != service_customization_pb2.CustomParamError.STATUS_OK:
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 = service_customization_pb2.OneOfParam
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 = service_customization_pb2.CustomParamError(
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 service_customization_pb2.CustomParamError(
426
- status=service_customization_pb2.CustomParamError.STATUS_INVALID_VALUE,
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 = service_customization_pb2.CustomParamError(
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)