bosdyn-mission 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/mission/client.py CHANGED
@@ -36,6 +36,14 @@ class QuestionAlreadyAnswered(MissionResponseError):
36
36
  """The indicated question was already answered."""
37
37
 
38
38
 
39
+ class CustomParamsError(MissionResponseError):
40
+ """The indicated answer does not match the spec for the indicated answer"""
41
+
42
+
43
+ class IncompatibleAnswer(MissionResponseError):
44
+ """The indicated answer is not in a format expected by the indicated question."""
45
+
46
+
39
47
  class CompilationError(MissionResponseError):
40
48
  """Mission could not be compiled."""
41
49
 
@@ -105,25 +113,28 @@ class MissionClient(BaseClient):
105
113
  return self.call_async(self._stub.GetState, req, _get_state_value, common_header_errors,
106
114
  copy_request=False, **kwargs)
107
115
 
108
- def answer_question(self, question_id, code, **kwargs):
116
+ def answer_question(self, question_id, code=None, custom_params=None, **kwargs):
109
117
  """Specify an answer to the question asked by the mission.
110
118
  Args:
111
119
  question_id (int): ID of the question to answer.
112
120
  code (int): Answer code.
121
+ custom_params (DictParam): Answer to a custom params prompt.
113
122
 
114
123
  Raises:
115
124
  RpcError: Problem communicating with the robot.
116
125
  InvalidQuestionId: question_id was not a valid id.
117
126
  InvalidAnswerCode: code was not valid for the question.
118
127
  QuestionAlreadyAnswered: The question for question_id was already answered.
128
+ CustomParamsError: The answer did not match the spec for the question.
129
+ IncompatibleAnswer: The answer did not match a type expected for the question.
119
130
  """
120
- req = self._answer_question_request(question_id, code)
131
+ req = self._answer_question_request(question_id, code, custom_params)
121
132
  return self.call(self._stub.AnswerQuestion, req, None, _answer_question_error_from_response,
122
133
  copy_request=False, **kwargs)
123
134
 
124
- def answer_question_async(self, question_id, code, **kwargs):
135
+ def answer_question_async(self, question_id, code=None, custom_params=None, **kwargs):
125
136
  """Async version of answer_question()"""
126
- req = self._answer_question_request(question_id, code)
137
+ req = self._answer_question_request(question_id, code, custom_params)
127
138
  return self.call_async(self._stub.AnswerQuestion, req, None,
128
139
  _answer_question_error_from_response, copy_request=False, **kwargs)
129
140
 
@@ -287,8 +298,19 @@ class MissionClient(BaseClient):
287
298
  RpcError: Problem communicating with the robot.
288
299
  """
289
300
  req = self._get_info_request()
290
- return self.call(self._stub.GetInfo, req, _get_info_value, common_header_errors,
291
- copy_request=False, **kwargs)
301
+ try:
302
+ return self._get_info_as_chunks_call(req)
303
+ except UnimplementedError as err:
304
+ # This indicates that the software release running on robot does not yet have
305
+ # the implementation for the streaming response of GetInfo.
306
+ return self.call(self._stub.GetInfo, req, _get_info_value, common_header_errors,
307
+ copy_request=False, **kwargs)
308
+
309
+ def _get_info_as_chunks_call(self, req, **kwargs):
310
+ """Issues the GetInfoAsChunks RPC to the mission service."""
311
+ return self.call(self._stub.GetInfoAsChunks, req, _get_info_value,
312
+ error_from_response=common_header_errors,
313
+ assemble_type=mission_pb2.GetInfoResponse, copy_request=False, **kwargs)
292
314
 
293
315
  def get_info_async(self, **kwargs):
294
316
  """Async version of get_info."""
@@ -334,8 +356,9 @@ class MissionClient(BaseClient):
334
356
  return request
335
357
 
336
358
  @staticmethod
337
- def _answer_question_request(question_id, code):
338
- return mission_pb2.AnswerQuestionRequest(question_id=question_id, code=code)
359
+ def _answer_question_request(question_id, code, custom_params):
360
+ return mission_pb2.AnswerQuestionRequest(question_id=question_id, code=code,
361
+ custom_params=custom_params)
339
362
 
340
363
  @staticmethod
341
364
  def _load_mission_request(root, leases):
@@ -400,6 +423,10 @@ _ANSWER_QUESTION_STATUS_TO_ERROR.update({
400
423
  (InvalidAnswerCode, InvalidAnswerCode.__doc__),
401
424
  mission_pb2.AnswerQuestionResponse.STATUS_ALREADY_ANSWERED:
402
425
  (QuestionAlreadyAnswered, QuestionAlreadyAnswered.__doc__),
426
+ mission_pb2.AnswerQuestionResponse.STATUS_CUSTOM_PARAMS_ERROR:
427
+ (CustomParamsError, CustomParamsError.__doc__),
428
+ mission_pb2.AnswerQuestionResponse.STATUS_INCOMPATIBLE_ANSWER:
429
+ (IncompatibleAnswer, IncompatibleAnswer.__doc__),
403
430
  })
404
431
 
405
432
 
@@ -64,7 +64,7 @@ class RemoteClient(BaseClient):
64
64
 
65
65
  Args:
66
66
  leases (Iterable[Lease]): List of lease protobufs to establish session with.
67
- inputs (Iterable[bosdyn.api.mission.KeyValue]): any inputs needed by by the remote node.
67
+ inputs (Iterable[bosdyn.api.mission.KeyValue]): any inputs needed by the remote node.
68
68
  lease_resources (Iterable[str]): List of resource names to use from the lease wallet.
69
69
  Only applied if no leases are provided.
70
70
  """
@@ -92,7 +92,7 @@ class RemoteClient(BaseClient):
92
92
  Args:
93
93
  session_id: session
94
94
  leases (Iterable[Lease]): List of lease protobufs to use during the tick.
95
- inputs (Iterable[bosdyn.api.mission.KeyValue]): any inputs needed by by the remote node.
95
+ inputs (Iterable[bosdyn.api.mission.KeyValue]): any inputs needed by the remote node.
96
96
  lease_resources (Iterable[str]): List of resource names to use from the lease wallet.
97
97
  Only applied if no leases are provided.
98
98
  """
@@ -8,6 +8,7 @@ from deprecated.sphinx import deprecated
8
8
 
9
9
  import bosdyn.util
10
10
  from bosdyn.api import header_pb2
11
+ from bosdyn.deprecated import moved_to
11
12
 
12
13
 
13
14
 
@@ -34,7 +35,4 @@ class ResponseContext(object):
34
35
  self.rpc_logger.add_protobuf_async(self.response)
35
36
 
36
37
 
37
- set_response_header = deprecated(
38
- reason='The bosdyn.mission.set_response_header helper class has moved to a common '
39
- 'location. Please use bosdyn.client.server_util.populate_response_header.', version='3.0.0',
40
- action="always")(bosdyn.client.server_util.populate_response_header)
38
+ set_response_header = moved_to(bosdyn.client.server_util.populate_response_header, version='3.0.0')
bosdyn/mission/util.py CHANGED
@@ -9,16 +9,21 @@ import json
9
9
  import operator
10
10
  import re
11
11
  from builtins import str as text
12
+ from typing import Dict, Union
12
13
 
13
14
  import google.protobuf.message
14
15
  import google.protobuf.struct_pb2
15
16
  import google.protobuf.text_format
17
+ from deprecated.sphinx import deprecated
18
+ from google.protobuf import message_factory
16
19
 
17
20
  from bosdyn.api import data_acquisition_pb2, geometry_pb2, gripper_camera_param_pb2
18
21
  from bosdyn.api.autowalk import walks_pb2
19
22
  from bosdyn.api.docking import docking_pb2
20
23
  from bosdyn.api.graph_nav import graph_nav_pb2, map_pb2
21
24
  from bosdyn.api.mission import mission_pb2, nodes_pb2, util_pb2
25
+ from bosdyn.client.util import safe_pb_enum_to_string as _bosdyn_client_safe_pb_enum_to_string
26
+ from bosdyn.deprecated import moved_to
22
27
  from bosdyn.mission import constants
23
28
 
24
29
  # This is a special dummy message we'll use for TYPE_MESSAGE parameters.
@@ -61,7 +66,24 @@ def tree_to_string(root, start_level=0, include_status=False):
61
66
  return string
62
67
 
63
68
 
64
- def proto_from_tuple(tup):
69
+ def type_to_field_name(type_name):
70
+ """Use type name to reconstruct field name of bosdyn.api.mission.Node.type
71
+ Example: SimpleParallel becomes simple_parallel"""
72
+ node_type = str(type_name).split('.')[-1]
73
+ field_name = node_type[0].lower()
74
+ for char in node_type[1:]:
75
+ if char.isupper():
76
+ field_name += f'_{char.lower()}'
77
+ else:
78
+ field_name += char
79
+
80
+ oneof_field_names = [x.name for x in nodes_pb2.Node.DESCRIPTOR.oneofs_by_name['type'].fields]
81
+ assert field_name in oneof_field_names, f'{field_name} is not a field name in bosdyn.api.mission.Node.type'
82
+
83
+ return field_name
84
+
85
+
86
+ def proto_from_tuple(tup, pack_nodes=True):
65
87
  """Return a bosdyn.api.mission Node from a tuple. EXPERIMENTAL.
66
88
 
67
89
  Example:
@@ -81,7 +103,7 @@ def proto_from_tuple(tup):
81
103
  tup: (Name of node, Instantiated implementation of node protobuf, List of children tuples)
82
104
  """
83
105
  if isinstance(tup, nodes_pb2.Node):
84
- # Sometimes the short hand doesn't work nicely, and in those cases we allow setting
106
+ # Sometimes the shorthand doesn't work nicely, and in those cases we allow setting
85
107
  # The node itself.
86
108
  return tup
87
109
 
@@ -148,11 +170,15 @@ def proto_from_tuple(tup):
148
170
  elif num_children != 0:
149
171
  raise Error('Proto "{}" of type "{}" was given {} children, but I do not know how to add'
150
172
  ' them!'.format(node.name, inner_type, num_children))
151
-
152
- node.impl.Pack(inner_proto)
173
+ if pack_nodes:
174
+ node.impl.Pack(inner_proto)
175
+ else:
176
+ getattr(node, type_to_field_name(inner_type)).CopyFrom(inner_proto)
153
177
  return node
154
178
 
155
179
 
180
+
181
+
156
182
  def python_var_to_value(var):
157
183
  """Returns a ConstantValue with the appropriate oneof set."""
158
184
  value = util_pb2.ConstantValue()
@@ -318,7 +344,7 @@ def get_value_from_constant_value_message(const_proto):
318
344
  return value
319
345
 
320
346
 
321
- def get_value_from_value_message(node, blackboard, value_msg):
347
+ def get_value_from_value_message(node, blackboard, value_msg, is_validation=False):
322
348
  if value_msg.HasField(text("constant")):
323
349
  constant = value_msg.constant
324
350
  return get_value_from_constant_value_message(constant)
@@ -328,11 +354,31 @@ def get_value_from_value_message(node, blackboard, value_msg):
328
354
  raise AttributeError("Value must be a runtime variable or constant.")
329
355
 
330
356
 
331
- def safe_pb_enum_to_string(value, pb_enum_obj):
332
- try:
333
- return pb_enum_obj.Name(value)
334
- except ValueError:
335
- pass
336
- return '<unknown> (value: {})'.format(value)
357
+ safe_pb_enum_to_string = moved_to(_bosdyn_client_safe_pb_enum_to_string, version='4.0.0')
358
+
359
+
360
+ def create_value(
361
+ var: Union[bool, int, float, str, google.protobuf.message.Message]) -> util_pb2.Value:
362
+ """Returns a Value message containing a ConstantValue with the appropriate oneof set.
363
+ """
364
+ return util_pb2.Value(constant=python_var_to_value(var))
365
+
366
+
367
+ def define_blackboard(dict_values: Dict[str, util_pb2.Value]) -> nodes_pb2.DefineBlackboard:
368
+ """Returns a DefineBlackboard protobuf message for the key-value pairs in `dict_values`.
369
+ """
370
+ node_to_return = nodes_pb2.DefineBlackboard()
371
+ for (key, value) in dict_values.items():
372
+ node_to_return.blackboard_variables.add().CopyFrom(util_pb2.KeyValue(key=key, value=value))
373
+ return node_to_return
374
+
375
+
376
+ def set_blackboard(dict_values: Dict[str, util_pb2.Value]) -> nodes_pb2.SetBlackboard:
377
+ """Returns a SetBlackboard protobuf message for the key-value pairs in `dict_values`.
378
+ """
379
+ node_to_return = nodes_pb2.SetBlackboard()
380
+ for (key, value) in dict_values.items():
381
+ node_to_return.blackboard_variables.add().CopyFrom(util_pb2.KeyValue(key=key, value=value))
382
+ return node_to_return
337
383
 
338
384
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bosdyn-mission
3
- Version: 3.3.2
3
+ Version: 4.0.1
4
4
  Summary: Boston Dynamics mission code
5
5
  Home-page: https://dev.bostondynamics.com/
6
6
  Author: Boston Dynamics
@@ -15,8 +15,8 @@ Classifier: Programming Language :: Python :: 3.10
15
15
  Classifier: License :: Other/Proprietary License
16
16
  Classifier: Operating System :: OS Independent
17
17
  Description-Content-Type: text/markdown
18
- Requires-Dist: bosdyn-client (==3.3.2)
19
- Requires-Dist: bosdyn-api (==3.3.2)
18
+ Requires-Dist: bosdyn-client (==4.0.1)
19
+ Requires-Dist: bosdyn-api (==4.0.1)
20
20
 
21
21
  <!--
22
22
  Copyright (c) 2023 Boston Dynamics, Inc. All rights reserved.
@@ -37,5 +37,4 @@ missions, which are part of the Boston Dynamics Spot API. The client interfaces
37
37
  implement the mission-related Remote Procedure Calls (RPCs) defined in
38
38
  [bosdyn-api wheel](https://pypi.org/project/bosdyn-api/) and they utilize code included in the
39
39
  [bosdyn-client wheel](https://pypi.org/project/bosdyn-client/). Full design documentation for the
40
- functionality included in this wheel can be found
41
- [here](https://dev.bostondynamics.com/docs/concepts/autonomy/missions_service).
40
+ functionality included in this wheel can be found [here](../../docs/concepts/autonomy/missions_service.md).
@@ -0,0 +1,12 @@
1
+ bosdyn/__init__.py,sha256=CMQioQKK1NlMk3kZuY49b_Aw-JyvDeOtuqOCAul1I0s,330
2
+ bosdyn/mission/__init__.py,sha256=_BpC0ZVGQ5yH5S8rt_DrTMQkAuxzTn5YlPvwDzeFXdQ,483
3
+ bosdyn/mission/client.py,sha256=_jjFZ1FCDNaKKcJ0pzHZ6suADTKcaaXHqp0GV5691M8,22437
4
+ bosdyn/mission/constants.py,sha256=oSsl0XR1-fNzHASGNqs541YEO8qi64eewvbY9ICKaxE,435
5
+ bosdyn/mission/exceptions.py,sha256=UqGT0XK3zA6Bgwo_7KNC44yi_MvW9h3c8_pHKML8ELQ,3941
6
+ bosdyn/mission/remote_client.py,sha256=quGWyqLzpASgrR6MlnEPoRFCmnTMSBZ6tmr-Wyy9YW0,12190
7
+ bosdyn/mission/server_util.py,sha256=_ts77W8yGq9BXhgOWwtMCXaxDjUxoorEPk1-YooEUNA,1508
8
+ bosdyn/mission/util.py,sha256=30_LIam0ve6JTXZfXmZyza0Vey1FC3LHln81rUeAm_w,15616
9
+ bosdyn_mission-4.0.1.dist-info/METADATA,sha256=foyspudk4oRuRkFkE5T6MklXqahIP4E2_c9GTSx48Wo,1760
10
+ bosdyn_mission-4.0.1.dist-info/WHEEL,sha256=AtBG6SXL3KF_v0NxLf0ehyVOh0cold-JbJYXNGorC6Q,92
11
+ bosdyn_mission-4.0.1.dist-info/top_level.txt,sha256=an2OWgx1ej2jFjmBjPWNQ68ZglvUfKhmXWW-WhTtDmA,7
12
+ bosdyn_mission-4.0.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.40.0)
2
+ Generator: bdist_wheel (0.41.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,12 +0,0 @@
1
- bosdyn/__init__.py,sha256=CMQioQKK1NlMk3kZuY49b_Aw-JyvDeOtuqOCAul1I0s,330
2
- bosdyn/mission/__init__.py,sha256=_BpC0ZVGQ5yH5S8rt_DrTMQkAuxzTn5YlPvwDzeFXdQ,483
3
- bosdyn/mission/client.py,sha256=UeVysD0UBU3sV1DFBZF3K5dvfGbLqcDKWe9zjytqEec,20860
4
- bosdyn/mission/constants.py,sha256=oSsl0XR1-fNzHASGNqs541YEO8qi64eewvbY9ICKaxE,435
5
- bosdyn/mission/exceptions.py,sha256=UqGT0XK3zA6Bgwo_7KNC44yi_MvW9h3c8_pHKML8ELQ,3941
6
- bosdyn/mission/remote_client.py,sha256=rWMgI-Il8cZ-gGjUu7vHnfhyiNHTEk39NlDDK_5t-eg,12196
7
- bosdyn/mission/server_util.py,sha256=ytvamtXK_CzLmnAn-4ybJ7PNyGfpG-HGfJZFuARxHcs,1661
8
- bosdyn/mission/util.py,sha256=dO8zMy-zgp_rt-q9dAQfvnr_1OnJ7mUfhHBo2skZJyA,13577
9
- bosdyn_mission-3.3.2.dist-info/METADATA,sha256=4YmV_fDakosgaauANGxEozLC2P08YTD35ypD2O9SPRo,1782
10
- bosdyn_mission-3.3.2.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
11
- bosdyn_mission-3.3.2.dist-info/top_level.txt,sha256=an2OWgx1ej2jFjmBjPWNQ68ZglvUfKhmXWW-WhTtDmA,7
12
- bosdyn_mission-3.3.2.dist-info/RECORD,,