standardbots 2.0.0.dev1758730305__tar.gz → 2.0.0.dev1763152552__tar.gz

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 (18) hide show
  1. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/PKG-INFO +1 -1
  2. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/setup.py +1 -1
  3. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/standardbots/auto_generated/apis.py +133 -0
  4. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/standardbots/auto_generated/models.py +309 -46
  5. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/standardbots.egg-info/PKG-INFO +1 -1
  6. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/tests/test_apis.py +19 -1
  7. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/README.md +0 -0
  8. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/setup.cfg +0 -0
  9. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/standardbots/__init__.py +0 -0
  10. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/standardbots/auto_generated/__init__.py +0 -0
  11. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/standardbots.egg-info/SOURCES.txt +0 -0
  12. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/standardbots.egg-info/dependency_links.txt +0 -0
  13. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/standardbots.egg-info/requires.txt +0 -0
  14. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/standardbots.egg-info/top_level.txt +0 -0
  15. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/tests/fixtures/__init__.py +0 -0
  16. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/tests/fixtures/client_fixt.py +0 -0
  17. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/tests/fixtures/robot_fixt.py +0 -0
  18. {standardbots-2.0.0.dev1758730305 → standardbots-2.0.0.dev1763152552}/tests/fixtures/routines_fixt.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: standardbots
3
- Version: 2.0.0.dev1758730305
3
+ Version: 2.0.0.dev1763152552
4
4
  Summary: Standard Bots RO1 Robotics API
5
5
  Home-page:
6
6
  Author: Standard Bots Support
@@ -13,7 +13,7 @@
13
13
  from setuptools import setup, find_packages # noqa: H301
14
14
 
15
15
  NAME = "standardbots"
16
- VERSION = "2.0.0-dev1758730305"
16
+ VERSION = "2.0.0-dev1763152552"
17
17
  # To install the library, run the following
18
18
  #
19
19
  # python setup.py install
@@ -833,6 +833,49 @@ class Default:
833
833
  self._request_manager = request_manager
834
834
 
835
835
 
836
+ def list_global_spaces(
837
+ self,
838
+ ) -> Response[
839
+ Union[
840
+ models.SpacesPaginatedResponse,
841
+ models.ErrorResponse,
842
+ None
843
+ ],
844
+ models.SpacesPaginatedResponse
845
+ ]:
846
+ """
847
+ List Global Spaces
848
+ """
849
+ path = "/api/v1/space/globals"
850
+ try:
851
+ response = self._request_manager.request(
852
+ "GET",
853
+ path,
854
+ headers=self._request_manager.json_headers(),
855
+ )
856
+ parsed = None
857
+ if response.status == 200:
858
+ parsed = models.parse_spaces_paginated_response(json.loads(response.data))
859
+
860
+ is_user_error = response.status >= 400 and response.status <= 500
861
+ is_unavailable = response.status == 503
862
+ if parsed is None and (is_user_error or is_unavailable):
863
+ parsed = models.parse_error_response(json.loads(response.data))
864
+
865
+ return Response(
866
+ parsed,
867
+ response.status,
868
+ response
869
+ )
870
+ except urllib3.exceptions.MaxRetryError:
871
+ return Response(
872
+ models.ErrorResponse(
873
+ error=models.ErrorEnum.InternalServerError,
874
+ message="Connection Refused"
875
+ ),
876
+ 503,
877
+ None
878
+ )
836
879
  def list_planes(
837
880
  self,
838
881
  limit: int,
@@ -1137,6 +1180,96 @@ class Default:
1137
1180
  if parsed is None and (is_user_error or is_unavailable):
1138
1181
  parsed = models.parse_error_response(json.loads(response.data))
1139
1182
 
1183
+ return Response(
1184
+ parsed,
1185
+ response.status,
1186
+ response
1187
+ )
1188
+ except urllib3.exceptions.MaxRetryError:
1189
+ return Response(
1190
+ models.ErrorResponse(
1191
+ error=models.ErrorEnum.InternalServerError,
1192
+ message="Connection Refused"
1193
+ ),
1194
+ 503,
1195
+ None
1196
+ )
1197
+ def set_gripper_bounds(
1198
+ self,
1199
+ body: models.SetGripperBoundsRequest,
1200
+ ) -> Response[
1201
+ Union[
1202
+ models.TeleopState,
1203
+ models.ErrorResponse,
1204
+ None
1205
+ ],
1206
+ models.TeleopState
1207
+ ]:
1208
+ """
1209
+ Set gripper bounds for primary and secondary bots
1210
+ """
1211
+ path = "/api/v1/teleop/set-gripper-bounds"
1212
+ try:
1213
+ response = self._request_manager.request(
1214
+ "POST",
1215
+ path,
1216
+ headers=self._request_manager.json_headers(),
1217
+ body=json.dumps(models.serialize_set_gripper_bounds_request(body)),
1218
+ )
1219
+ parsed = None
1220
+ if response.status == 200:
1221
+ parsed = models.parse_teleop_state(json.loads(response.data))
1222
+
1223
+ is_user_error = response.status >= 400 and response.status <= 500
1224
+ is_unavailable = response.status == 503
1225
+ if parsed is None and (is_user_error or is_unavailable):
1226
+ parsed = models.parse_error_response(json.loads(response.data))
1227
+
1228
+ return Response(
1229
+ parsed,
1230
+ response.status,
1231
+ response
1232
+ )
1233
+ except urllib3.exceptions.MaxRetryError:
1234
+ return Response(
1235
+ models.ErrorResponse(
1236
+ error=models.ErrorEnum.InternalServerError,
1237
+ message="Connection Refused"
1238
+ ),
1239
+ 503,
1240
+ None
1241
+ )
1242
+ def set_robot_frame(
1243
+ self,
1244
+ body: models.SetRobotFrameRequest,
1245
+ ) -> Response[
1246
+ Union[
1247
+ models.TeleopState,
1248
+ models.ErrorResponse,
1249
+ None
1250
+ ],
1251
+ models.TeleopState
1252
+ ]:
1253
+ """
1254
+ Set robot frame
1255
+ """
1256
+ path = "/api/v1/teleop/set-robot-frame"
1257
+ try:
1258
+ response = self._request_manager.request(
1259
+ "POST",
1260
+ path,
1261
+ headers=self._request_manager.json_headers(),
1262
+ body=json.dumps(models.serialize_set_robot_frame_request(body)),
1263
+ )
1264
+ parsed = None
1265
+ if response.status == 200:
1266
+ parsed = models.parse_teleop_state(json.loads(response.data))
1267
+
1268
+ is_user_error = response.status >= 400 and response.status <= 500
1269
+ is_unavailable = response.status == 503
1270
+ if parsed is None and (is_user_error or is_unavailable):
1271
+ parsed = models.parse_error_response(json.loads(response.data))
1272
+
1140
1273
  return Response(
1141
1274
  parsed,
1142
1275
  response.status,
@@ -1337,6 +1337,8 @@ class ErrorEnum(Enum):
1337
1337
  """Cannot change ROS state"""
1338
1338
  IoSafeguardError = "io_safeguard_error"
1339
1339
  """Cannot change IO state because of safeguard"""
1340
+ RobotOutOfComplianceBounds = "robot_out_of_compliance_bounds"
1341
+ """Cannot initiate compliance control: Robot is outside compliance bounds"""
1340
1342
 
1341
1343
  def parse_error_enum(data: object) -> ErrorEnum:
1342
1344
  return ErrorEnum(data)
@@ -1470,6 +1472,51 @@ def parse_force_unit_kind(data: object) -> ForceUnitKind:
1470
1472
  def serialize_force_unit_kind(data: Union[ForceUnitKind, str]) -> object:
1471
1473
  return ForceUnitKind(data).value
1472
1474
 
1475
+ @dataclass
1476
+ class GripperBounds:
1477
+ """Gripper bounds configuration"""
1478
+ min: Union[float, None] = None
1479
+ max: Union[float, None] = None
1480
+
1481
+ def validate_min(self, value: float) -> Tuple[bool, str]:
1482
+ if value is None:
1483
+ return [False, "min is required for GripperBounds"]
1484
+
1485
+ if not isinstance(value, float):
1486
+ return [False, "min must be of type float for GripperBounds, got " + type(value).__name__]
1487
+
1488
+ return [True, ""]
1489
+
1490
+ def validate_max(self, value: float) -> Tuple[bool, str]:
1491
+ if value is None:
1492
+ return [False, "max is required for GripperBounds"]
1493
+
1494
+ if not isinstance(value, float):
1495
+ return [False, "max must be of type float for GripperBounds, got " + type(value).__name__]
1496
+
1497
+ return [True, ""]
1498
+
1499
+ def __post_init__(self):
1500
+ # Type check incoming model - raise error if invalid (required or wrong type)
1501
+ is_valid, error_str = self.validate_min(self.min)
1502
+ if not is_valid:
1503
+ raise TypeError(error_str)
1504
+ is_valid, error_str = self.validate_max(self.max)
1505
+ if not is_valid:
1506
+ raise TypeError(error_str)
1507
+
1508
+ def parse_gripper_bounds(data: object):
1509
+ return GripperBounds(
1510
+ min=parse_f_64(data["min"]) if "min" in data and data.get("min") is not None else None,
1511
+ max=parse_f_64(data["max"]) if "max" in data and data.get("max") is not None else None,
1512
+ )
1513
+
1514
+ def serialize_gripper_bounds(data: GripperBounds) -> object:
1515
+ return {
1516
+ "min": serialize_f_64(data.min),
1517
+ "max": serialize_f_64(data.max),
1518
+ }
1519
+
1473
1520
  class GripperKindEnum(Enum):
1474
1521
  Onrobot2Fg7 = "onrobot_2fg7"
1475
1522
  """An OnRobot 2FG7 Gripper is connected"""
@@ -2660,6 +2707,18 @@ def parse_robot_control_mode_enum(data: object) -> RobotControlModeEnum:
2660
2707
  def serialize_robot_control_mode_enum(data: Union[RobotControlModeEnum, str]) -> object:
2661
2708
  return RobotControlModeEnum(data).value
2662
2709
 
2710
+ class RobotFrame(Enum):
2711
+ World = "world"
2712
+ """Enum World = `world`"""
2713
+ Tooltip = "tooltip"
2714
+ """Enum Tooltip = `tooltip`"""
2715
+
2716
+ def parse_robot_frame(data: object) -> RobotFrame:
2717
+ return RobotFrame(data)
2718
+
2719
+ def serialize_robot_frame(data: Union[RobotFrame, str]) -> object:
2720
+ return RobotFrame(data).value
2721
+
2663
2722
  class RobotStatusEnum(Enum):
2664
2723
  Idle = "Idle"
2665
2724
  """Enum Idle = `Idle`"""
@@ -3341,36 +3400,6 @@ def serialize_status_version_data(data: StatusVersionData) -> object:
3341
3400
  "name": None if data.name is None else serialize_str(data.name),
3342
3401
  }
3343
3402
 
3344
- @dataclass
3345
- class StopRecordingRequest:
3346
- """Request to stop recording movement and camera data"""
3347
- delete: Union[bool, None] = None
3348
-
3349
- def validate_delete(self, value: bool) -> Tuple[bool, str]:
3350
- if value is None:
3351
- return [True, ""]
3352
-
3353
- if not isinstance(value, bool):
3354
- return [False, "delete must be of type bool for StopRecordingRequest, got " + type(value).__name__]
3355
-
3356
- return [True, ""]
3357
-
3358
- def __post_init__(self):
3359
- # Type check incoming model - raise error if invalid (required or wrong type)
3360
- is_valid, error_str = self.validate_delete(self.delete)
3361
- if not is_valid:
3362
- raise TypeError(error_str)
3363
-
3364
- def parse_stop_recording_request(data: object):
3365
- return StopRecordingRequest(
3366
- delete=parse_bool(data["delete"]) if "delete" in data and data.get("delete") is not None else None,
3367
- )
3368
-
3369
- def serialize_stop_recording_request(data: StopRecordingRequest) -> object:
3370
- return {
3371
- "delete": None if data.delete is None else serialize_bool(data.delete),
3372
- }
3373
-
3374
3403
  StringArray = List[str]
3375
3404
 
3376
3405
  def parse_string_array(data: object) -> StringArray:
@@ -4242,7 +4271,7 @@ class ErrorResponse:
4242
4271
  if value is None:
4243
4272
  return [False, "error is required for ErrorResponse"]
4244
4273
 
4245
- if not ((isinstance(value, str) and ErrorEnum in ['authorization_required', 'routine_must_be_running', 'api_control_required', 'robot_brakes_disengage_failed', 'robot_brakes_engage_failed', 'request_failed_validation', 'robot_not_idle', 'brakes_must_be_engaged', 'brakes_must_be_disengaged', 'equipment_no_matching', 'service_initializing', 'camera_disconnected', 'settings_validation_error', 'settings_timeout', 'internal_server_error', 'recovery_error', 'not_found', 'invalid_space_specified', 'invalid_parameters', 'routine_does_not_exist', 'cannot_play_routine', 'routine_must_be_playing', 'cannot_change_ros_state', 'io_safeguard_error']) or isinstance(value, ErrorEnum)):
4274
+ if not ((isinstance(value, str) and ErrorEnum in ['authorization_required', 'routine_must_be_running', 'api_control_required', 'robot_brakes_disengage_failed', 'robot_brakes_engage_failed', 'request_failed_validation', 'robot_not_idle', 'brakes_must_be_engaged', 'brakes_must_be_disengaged', 'equipment_no_matching', 'service_initializing', 'camera_disconnected', 'settings_validation_error', 'settings_timeout', 'internal_server_error', 'recovery_error', 'not_found', 'invalid_space_specified', 'invalid_parameters', 'routine_does_not_exist', 'cannot_play_routine', 'routine_must_be_playing', 'cannot_change_ros_state', 'io_safeguard_error', 'robot_out_of_compliance_bounds']) or isinstance(value, ErrorEnum)):
4246
4275
  return [False, "error must be of type ErrorEnum for ErrorResponse, got " + type(value).__name__]
4247
4276
 
4248
4277
  return [True, ""]
@@ -4579,6 +4608,18 @@ def serialize_force_unit(data: ForceUnit) -> object:
4579
4608
  "value": None if data.value is None else serialize_f_64(data.value),
4580
4609
  }
4581
4610
 
4611
+ SecondaryBotGripperBounds = Dict[str, GripperBounds]
4612
+
4613
+ def parse_secondary_bot_gripper_bounds(data: object) -> SecondaryBotGripperBounds:
4614
+ return {
4615
+ parse_str(key): parse_gripper_bounds(value) for key, value in data.items()
4616
+ }
4617
+
4618
+ def serialize_secondary_bot_gripper_bounds(data: SecondaryBotGripperBounds) -> object:
4619
+ return {
4620
+ serialize_str(key): serialize_gripper_bounds(value) for key, value in data.items()
4621
+ }
4622
+
4582
4623
  @dataclass
4583
4624
  class IOStateResponse:
4584
4625
  """Response to a query for the current state of I/O."""
@@ -6082,6 +6123,18 @@ def serialize_robot_control_mode(data: RobotControlMode) -> object:
6082
6123
  "kind": None if data.kind is None else serialize_robot_control_mode_enum(data.kind),
6083
6124
  }
6084
6125
 
6126
+ SecondaryBotRobotFrame = Dict[str, RobotFrame]
6127
+
6128
+ def parse_secondary_bot_robot_frame(data: object) -> SecondaryBotRobotFrame:
6129
+ return {
6130
+ parse_str(key): parse_robot_frame(value) for key, value in data.items()
6131
+ }
6132
+
6133
+ def serialize_secondary_bot_robot_frame(data: SecondaryBotRobotFrame) -> object:
6134
+ return {
6135
+ serialize_str(key): serialize_robot_frame(value) for key, value in data.items()
6136
+ }
6137
+
6085
6138
  @dataclass
6086
6139
  class PlayRoutineResponse:
6087
6140
  """Status response informs user of of robot state"""
@@ -6593,6 +6646,51 @@ def serialize_save_recording_response(data: SaveRecordingResponse) -> object:
6593
6646
  "errors": None if data.errors is None else serialize_string_array(data.errors),
6594
6647
  }
6595
6648
 
6649
+ @dataclass
6650
+ class StopRecordingRequest:
6651
+ """Request to stop recording movement and camera data"""
6652
+ delete: Union[bool, None] = None
6653
+ tags: Union[StringArray, None] = None
6654
+
6655
+ def validate_delete(self, value: bool) -> Tuple[bool, str]:
6656
+ if value is None:
6657
+ return [True, ""]
6658
+
6659
+ if not isinstance(value, bool):
6660
+ return [False, "delete must be of type bool for StopRecordingRequest, got " + type(value).__name__]
6661
+
6662
+ return [True, ""]
6663
+
6664
+ def validate_tags(self, value: StringArray) -> Tuple[bool, str]:
6665
+ if value is None:
6666
+ return [True, ""]
6667
+
6668
+ if not (isinstance(value, list) and all(isinstance(x, str) for x in value)):
6669
+ return [False, "tags must be of type StringArray for StopRecordingRequest, got " + type(value).__name__]
6670
+
6671
+ return [True, ""]
6672
+
6673
+ def __post_init__(self):
6674
+ # Type check incoming model - raise error if invalid (required or wrong type)
6675
+ is_valid, error_str = self.validate_delete(self.delete)
6676
+ if not is_valid:
6677
+ raise TypeError(error_str)
6678
+ is_valid, error_str = self.validate_tags(self.tags)
6679
+ if not is_valid:
6680
+ raise TypeError(error_str)
6681
+
6682
+ def parse_stop_recording_request(data: object):
6683
+ return StopRecordingRequest(
6684
+ delete=parse_bool(data["delete"]) if "delete" in data and data.get("delete") is not None else None,
6685
+ tags=parse_string_array(data["tags"]) if "tags" in data and data.get("tags") is not None else None,
6686
+ )
6687
+
6688
+ def serialize_stop_recording_request(data: StopRecordingRequest) -> object:
6689
+ return {
6690
+ "delete": None if data.delete is None else serialize_bool(data.delete),
6691
+ "tags": None if data.tags is None else serialize_string_array(data.tags),
6692
+ }
6693
+
6596
6694
  @dataclass
6597
6695
  class BotTeleopDetails:
6598
6696
  """Details of the bot"""
@@ -6604,6 +6702,8 @@ class BotTeleopDetails:
6604
6702
  isEnabled: Union[bool, None] = None
6605
6703
  status: Union[TeleopStatus, None] = None
6606
6704
  errors: Union[TeleopErrorArray, None] = None
6705
+ gripperBounds: Union[GripperBounds, None] = None
6706
+ robotFrame: Union[RobotFrame, None] = None
6607
6707
 
6608
6708
  def validate_botId(self, value: str) -> Tuple[bool, str]:
6609
6709
  if value is None:
@@ -6677,6 +6777,24 @@ class BotTeleopDetails:
6677
6777
 
6678
6778
  return [True, ""]
6679
6779
 
6780
+ def validate_gripperBounds(self, value: GripperBounds) -> Tuple[bool, str]:
6781
+ if value is None:
6782
+ return [True, ""]
6783
+
6784
+ if not isinstance(value, GripperBounds):
6785
+ return [False, "gripperBounds must be of type GripperBounds for BotTeleopDetails, got " + type(value).__name__]
6786
+
6787
+ return [True, ""]
6788
+
6789
+ def validate_robotFrame(self, value: RobotFrame) -> Tuple[bool, str]:
6790
+ if value is None:
6791
+ return [True, ""]
6792
+
6793
+ if not ((isinstance(value, str) and RobotFrame in ['world', 'tooltip']) or isinstance(value, RobotFrame)):
6794
+ return [False, "robotFrame must be of type RobotFrame for BotTeleopDetails, got " + type(value).__name__]
6795
+
6796
+ return [True, ""]
6797
+
6680
6798
  def __post_init__(self):
6681
6799
  # Type check incoming model - raise error if invalid (required or wrong type)
6682
6800
  is_valid, error_str = self.validate_botId(self.botId)
@@ -6703,6 +6821,12 @@ class BotTeleopDetails:
6703
6821
  is_valid, error_str = self.validate_errors(self.errors)
6704
6822
  if not is_valid:
6705
6823
  raise TypeError(error_str)
6824
+ is_valid, error_str = self.validate_gripperBounds(self.gripperBounds)
6825
+ if not is_valid:
6826
+ raise TypeError(error_str)
6827
+ is_valid, error_str = self.validate_robotFrame(self.robotFrame)
6828
+ if not is_valid:
6829
+ raise TypeError(error_str)
6706
6830
 
6707
6831
  def parse_bot_teleop_details(data: object):
6708
6832
  return BotTeleopDetails(
@@ -6714,6 +6838,8 @@ def parse_bot_teleop_details(data: object):
6714
6838
  isEnabled=parse_bool(data["isEnabled"]) if "isEnabled" in data and data.get("isEnabled") is not None else None,
6715
6839
  status=parse_teleop_status(data["status"]) if "status" in data and data.get("status") is not None else None,
6716
6840
  errors=parse_teleop_error_array(data["errors"]) if "errors" in data and data.get("errors") is not None else None,
6841
+ gripperBounds=parse_gripper_bounds(data["gripperBounds"]) if "gripperBounds" in data and data.get("gripperBounds") is not None else None,
6842
+ robotFrame=parse_robot_frame(data["robotFrame"]) if "robotFrame" in data and data.get("robotFrame") is not None else None,
6717
6843
  )
6718
6844
 
6719
6845
  def serialize_bot_teleop_details(data: BotTeleopDetails) -> object:
@@ -6726,6 +6852,8 @@ def serialize_bot_teleop_details(data: BotTeleopDetails) -> object:
6726
6852
  "isEnabled": None if data.isEnabled is None else serialize_bool(data.isEnabled),
6727
6853
  "status": None if data.status is None else serialize_teleop_status(data.status),
6728
6854
  "errors": None if data.errors is None else serialize_teleop_error_array(data.errors),
6855
+ "gripperBounds": None if data.gripperBounds is None else serialize_gripper_bounds(data.gripperBounds),
6856
+ "robotFrame": None if data.robotFrame is None else serialize_robot_frame(data.robotFrame),
6729
6857
  }
6730
6858
 
6731
6859
  @dataclass
@@ -6918,6 +7046,51 @@ def serialize_calibration_data(data: CalibrationData) -> object:
6918
7046
  "urdfParameters": serialize_urdf_parameters(data.urdfParameters),
6919
7047
  }
6920
7048
 
7049
+ @dataclass
7050
+ class SetGripperBoundsRequest:
7051
+ """Request to set gripper bounds for primary and secondary bots"""
7052
+ primary: Union[GripperBounds, None] = None
7053
+ secondary: Union[SecondaryBotGripperBounds, None] = None
7054
+
7055
+ def validate_primary(self, value: GripperBounds) -> Tuple[bool, str]:
7056
+ if value is None:
7057
+ return [False, "primary is required for SetGripperBoundsRequest"]
7058
+
7059
+ if not isinstance(value, GripperBounds):
7060
+ return [False, "primary must be of type GripperBounds for SetGripperBoundsRequest, got " + type(value).__name__]
7061
+
7062
+ return [True, ""]
7063
+
7064
+ def validate_secondary(self, value: SecondaryBotGripperBounds) -> Tuple[bool, str]:
7065
+ if value is None:
7066
+ return [True, ""]
7067
+
7068
+ if not (isinstance(value, dict) and all((isinstance(k, str) and isinstance(val, GripperBounds)) for k, val in value.items())):
7069
+ return [False, "secondary must be of type SecondaryBotGripperBounds for SetGripperBoundsRequest, got " + type(value).__name__]
7070
+
7071
+ return [True, ""]
7072
+
7073
+ def __post_init__(self):
7074
+ # Type check incoming model - raise error if invalid (required or wrong type)
7075
+ is_valid, error_str = self.validate_primary(self.primary)
7076
+ if not is_valid:
7077
+ raise TypeError(error_str)
7078
+ is_valid, error_str = self.validate_secondary(self.secondary)
7079
+ if not is_valid:
7080
+ raise TypeError(error_str)
7081
+
7082
+ def parse_set_gripper_bounds_request(data: object):
7083
+ return SetGripperBoundsRequest(
7084
+ primary=parse_gripper_bounds(data["primary"]) if "primary" in data and data.get("primary") is not None else None,
7085
+ secondary=parse_secondary_bot_gripper_bounds(data["secondary"]) if "secondary" in data and data.get("secondary") is not None else None,
7086
+ )
7087
+
7088
+ def serialize_set_gripper_bounds_request(data: SetGripperBoundsRequest) -> object:
7089
+ return {
7090
+ "primary": serialize_gripper_bounds(data.primary),
7091
+ "secondary": None if data.secondary is None else serialize_secondary_bot_gripper_bounds(data.secondary),
7092
+ }
7093
+
6921
7094
  ArmJointRotationsList = List[ArmJointRotations]
6922
7095
 
6923
7096
  def parse_arm_joint_rotations_list(data: object) -> ArmJointRotationsList:
@@ -7688,6 +7861,51 @@ def serialize_failure_state_response(data: FailureStateResponse) -> object:
7688
7861
  "failure": None if data.failure is None else serialize_failure_state_details(data.failure),
7689
7862
  }
7690
7863
 
7864
+ @dataclass
7865
+ class SetRobotFrameRequest:
7866
+ """Request to set robot frame"""
7867
+ primary: Union[RobotFrame, None] = None
7868
+ secondary: Union[SecondaryBotRobotFrame, None] = None
7869
+
7870
+ def validate_primary(self, value: RobotFrame) -> Tuple[bool, str]:
7871
+ if value is None:
7872
+ return [False, "primary is required for SetRobotFrameRequest"]
7873
+
7874
+ if not ((isinstance(value, str) and RobotFrame in ['world', 'tooltip']) or isinstance(value, RobotFrame)):
7875
+ return [False, "primary must be of type RobotFrame for SetRobotFrameRequest, got " + type(value).__name__]
7876
+
7877
+ return [True, ""]
7878
+
7879
+ def validate_secondary(self, value: SecondaryBotRobotFrame) -> Tuple[bool, str]:
7880
+ if value is None:
7881
+ return [True, ""]
7882
+
7883
+ if not (isinstance(value, dict) and all((isinstance(k, str) and ((isinstance(val, str) and RobotFrame in ['world', 'tooltip']) or isinstance(val, RobotFrame))) for k, val in value.items())):
7884
+ return [False, "secondary must be of type SecondaryBotRobotFrame for SetRobotFrameRequest, got " + type(value).__name__]
7885
+
7886
+ return [True, ""]
7887
+
7888
+ def __post_init__(self):
7889
+ # Type check incoming model - raise error if invalid (required or wrong type)
7890
+ is_valid, error_str = self.validate_primary(self.primary)
7891
+ if not is_valid:
7892
+ raise TypeError(error_str)
7893
+ is_valid, error_str = self.validate_secondary(self.secondary)
7894
+ if not is_valid:
7895
+ raise TypeError(error_str)
7896
+
7897
+ def parse_set_robot_frame_request(data: object):
7898
+ return SetRobotFrameRequest(
7899
+ primary=parse_robot_frame(data["primary"]) if "primary" in data and data.get("primary") is not None else None,
7900
+ secondary=parse_secondary_bot_robot_frame(data["secondary"]) if "secondary" in data and data.get("secondary") is not None else None,
7901
+ )
7902
+
7903
+ def serialize_set_robot_frame_request(data: SetRobotFrameRequest) -> object:
7904
+ return {
7905
+ "primary": serialize_robot_frame(data.primary),
7906
+ "secondary": None if data.secondary is None else serialize_secondary_bot_robot_frame(data.secondary),
7907
+ }
7908
+
7691
7909
  @dataclass
7692
7910
  class SensorsConfiguration:
7693
7911
  """Configuration of all sensors defined in custom equipment"""
@@ -8244,13 +8462,13 @@ def serialize_get_messages_response(data: GetMessagesResponse) -> object:
8244
8462
  class RecorderConfig:
8245
8463
  """Config of the recorder"""
8246
8464
  isSecondary: Union[bool, None] = None
8247
- isInference: Union[bool, None] = None
8248
8465
  userId: Union[str, None] = None
8249
8466
  taskId: Union[str, None] = None
8250
8467
  bots: Union[RecorderBotDetailsList, None] = None
8251
8468
  offset: Union[OffsetConfig, None] = None
8252
8469
  sensors: Union[SensorConfigList, None] = None
8253
8470
  equipmentKeyAssignments: Union[EquipmentKeyAssignments, None] = None
8471
+ tags: Union[StringArray, None] = None
8254
8472
 
8255
8473
  def validate_isSecondary(self, value: bool) -> Tuple[bool, str]:
8256
8474
  if value is None:
@@ -8261,15 +8479,6 @@ class RecorderConfig:
8261
8479
 
8262
8480
  return [True, ""]
8263
8481
 
8264
- def validate_isInference(self, value: bool) -> Tuple[bool, str]:
8265
- if value is None:
8266
- return [True, ""]
8267
-
8268
- if not isinstance(value, bool):
8269
- return [False, "isInference must be of type bool for RecorderConfig, got " + type(value).__name__]
8270
-
8271
- return [True, ""]
8272
-
8273
8482
  def validate_userId(self, value: str) -> Tuple[bool, str]:
8274
8483
  if value is None:
8275
8484
  return [True, ""]
@@ -8324,12 +8533,18 @@ class RecorderConfig:
8324
8533
 
8325
8534
  return [True, ""]
8326
8535
 
8536
+ def validate_tags(self, value: StringArray) -> Tuple[bool, str]:
8537
+ if value is None:
8538
+ return [True, ""]
8539
+
8540
+ if not (isinstance(value, list) and all(isinstance(x, str) for x in value)):
8541
+ return [False, "tags must be of type StringArray for RecorderConfig, got " + type(value).__name__]
8542
+
8543
+ return [True, ""]
8544
+
8327
8545
  def __post_init__(self):
8328
8546
  # Type check incoming model - raise error if invalid (required or wrong type)
8329
8547
  is_valid, error_str = self.validate_isSecondary(self.isSecondary)
8330
- if not is_valid:
8331
- raise TypeError(error_str)
8332
- is_valid, error_str = self.validate_isInference(self.isInference)
8333
8548
  if not is_valid:
8334
8549
  raise TypeError(error_str)
8335
8550
  is_valid, error_str = self.validate_userId(self.userId)
@@ -8350,29 +8565,32 @@ class RecorderConfig:
8350
8565
  is_valid, error_str = self.validate_equipmentKeyAssignments(self.equipmentKeyAssignments)
8351
8566
  if not is_valid:
8352
8567
  raise TypeError(error_str)
8568
+ is_valid, error_str = self.validate_tags(self.tags)
8569
+ if not is_valid:
8570
+ raise TypeError(error_str)
8353
8571
 
8354
8572
  def parse_recorder_config(data: object):
8355
8573
  return RecorderConfig(
8356
8574
  isSecondary=parse_bool(data["isSecondary"]) if "isSecondary" in data and data.get("isSecondary") is not None else None,
8357
- isInference=parse_bool(data["isInference"]) if "isInference" in data and data.get("isInference") is not None else None,
8358
8575
  userId=parse_str(data["userId"]) if "userId" in data and data.get("userId") is not None else None,
8359
8576
  taskId=parse_str(data["taskId"]) if "taskId" in data and data.get("taskId") is not None else None,
8360
8577
  bots=parse_recorder_bot_details_list(data["bots"]) if "bots" in data and data.get("bots") is not None else None,
8361
8578
  offset=parse_offset_config(data["offset"]) if "offset" in data and data.get("offset") is not None else None,
8362
8579
  sensors=parse_sensor_config_list(data["sensors"]) if "sensors" in data and data.get("sensors") is not None else None,
8363
8580
  equipmentKeyAssignments=parse_equipment_key_assignments(data["equipmentKeyAssignments"]) if "equipmentKeyAssignments" in data and data.get("equipmentKeyAssignments") is not None else None,
8581
+ tags=parse_string_array(data["tags"]) if "tags" in data and data.get("tags") is not None else None,
8364
8582
  )
8365
8583
 
8366
8584
  def serialize_recorder_config(data: RecorderConfig) -> object:
8367
8585
  return {
8368
8586
  "isSecondary": None if data.isSecondary is None else serialize_bool(data.isSecondary),
8369
- "isInference": None if data.isInference is None else serialize_bool(data.isInference),
8370
8587
  "userId": None if data.userId is None else serialize_str(data.userId),
8371
8588
  "taskId": None if data.taskId is None else serialize_str(data.taskId),
8372
8589
  "bots": None if data.bots is None else serialize_recorder_bot_details_list(data.bots),
8373
8590
  "offset": None if data.offset is None else serialize_offset_config(data.offset),
8374
8591
  "sensors": None if data.sensors is None else serialize_sensor_config_list(data.sensors),
8375
8592
  "equipmentKeyAssignments": None if data.equipmentKeyAssignments is None else serialize_equipment_key_assignments(data.equipmentKeyAssignments),
8593
+ "tags": None if data.tags is None else serialize_string_array(data.tags),
8376
8594
  }
8377
8595
 
8378
8596
  @dataclass
@@ -8915,6 +9133,8 @@ class TeleopState:
8915
9133
  status: Union[TeleopStatus, None] = None
8916
9134
  botsInSync: Union[bool, None] = None
8917
9135
  errors: Union[TeleopErrorArray, None] = None
9136
+ gripperBounds: Union[GripperBounds, None] = None
9137
+ robotFrame: Union[RobotFrame, None] = None
8918
9138
 
8919
9139
  def validate_config(self, value: TeleopConfig) -> Tuple[bool, str]:
8920
9140
  if value is None:
@@ -8952,6 +9172,24 @@ class TeleopState:
8952
9172
 
8953
9173
  return [True, ""]
8954
9174
 
9175
+ def validate_gripperBounds(self, value: GripperBounds) -> Tuple[bool, str]:
9176
+ if value is None:
9177
+ return [True, ""]
9178
+
9179
+ if not isinstance(value, GripperBounds):
9180
+ return [False, "gripperBounds must be of type GripperBounds for TeleopState, got " + type(value).__name__]
9181
+
9182
+ return [True, ""]
9183
+
9184
+ def validate_robotFrame(self, value: RobotFrame) -> Tuple[bool, str]:
9185
+ if value is None:
9186
+ return [True, ""]
9187
+
9188
+ if not ((isinstance(value, str) and RobotFrame in ['world', 'tooltip']) or isinstance(value, RobotFrame)):
9189
+ return [False, "robotFrame must be of type RobotFrame for TeleopState, got " + type(value).__name__]
9190
+
9191
+ return [True, ""]
9192
+
8955
9193
  def __post_init__(self):
8956
9194
  # Type check incoming model - raise error if invalid (required or wrong type)
8957
9195
  is_valid, error_str = self.validate_config(self.config)
@@ -8966,6 +9204,12 @@ class TeleopState:
8966
9204
  is_valid, error_str = self.validate_errors(self.errors)
8967
9205
  if not is_valid:
8968
9206
  raise TypeError(error_str)
9207
+ is_valid, error_str = self.validate_gripperBounds(self.gripperBounds)
9208
+ if not is_valid:
9209
+ raise TypeError(error_str)
9210
+ is_valid, error_str = self.validate_robotFrame(self.robotFrame)
9211
+ if not is_valid:
9212
+ raise TypeError(error_str)
8969
9213
 
8970
9214
  def parse_teleop_state(data: object):
8971
9215
  return TeleopState(
@@ -8973,6 +9217,8 @@ def parse_teleop_state(data: object):
8973
9217
  status=parse_teleop_status(data["status"]) if "status" in data and data.get("status") is not None else None,
8974
9218
  botsInSync=parse_bool(data["botsInSync"]) if "botsInSync" in data and data.get("botsInSync") is not None else None,
8975
9219
  errors=parse_teleop_error_array(data["errors"]) if "errors" in data and data.get("errors") is not None else None,
9220
+ gripperBounds=parse_gripper_bounds(data["gripperBounds"]) if "gripperBounds" in data and data.get("gripperBounds") is not None else None,
9221
+ robotFrame=parse_robot_frame(data["robotFrame"]) if "robotFrame" in data and data.get("robotFrame") is not None else None,
8976
9222
  )
8977
9223
 
8978
9224
  def serialize_teleop_state(data: TeleopState) -> object:
@@ -8981,6 +9227,8 @@ def serialize_teleop_state(data: TeleopState) -> object:
8981
9227
  "status": None if data.status is None else serialize_teleop_status(data.status),
8982
9228
  "botsInSync": None if data.botsInSync is None else serialize_bool(data.botsInSync),
8983
9229
  "errors": None if data.errors is None else serialize_teleop_error_array(data.errors),
9230
+ "gripperBounds": None if data.gripperBounds is None else serialize_gripper_bounds(data.gripperBounds),
9231
+ "robotFrame": None if data.robotFrame is None else serialize_robot_frame(data.robotFrame),
8984
9232
  }
8985
9233
 
8986
9234
  @dataclass
@@ -9162,6 +9410,7 @@ class StopRecordingResponse:
9162
9410
  state: Union[RecorderState, None] = None
9163
9411
  startTimestamp: Union[str, None] = None
9164
9412
  endTimestamp: Union[str, None] = None
9413
+ status: Union[RecorderStatus, None] = None
9165
9414
 
9166
9415
  def validate_state(self, value: RecorderState) -> Tuple[bool, str]:
9167
9416
  if value is None:
@@ -9190,6 +9439,15 @@ class StopRecordingResponse:
9190
9439
 
9191
9440
  return [True, ""]
9192
9441
 
9442
+ def validate_status(self, value: RecorderStatus) -> Tuple[bool, str]:
9443
+ if value is None:
9444
+ return [True, ""]
9445
+
9446
+ if not ((isinstance(value, str) and RecorderStatus in ['not_recording', 'recording', 'error', 'complete', 'initializing']) or isinstance(value, RecorderStatus)):
9447
+ return [False, "status must be of type RecorderStatus for StopRecordingResponse, got " + type(value).__name__]
9448
+
9449
+ return [True, ""]
9450
+
9193
9451
  def __post_init__(self):
9194
9452
  # Type check incoming model - raise error if invalid (required or wrong type)
9195
9453
  is_valid, error_str = self.validate_state(self.state)
@@ -9201,12 +9459,16 @@ class StopRecordingResponse:
9201
9459
  is_valid, error_str = self.validate_endTimestamp(self.endTimestamp)
9202
9460
  if not is_valid:
9203
9461
  raise TypeError(error_str)
9462
+ is_valid, error_str = self.validate_status(self.status)
9463
+ if not is_valid:
9464
+ raise TypeError(error_str)
9204
9465
 
9205
9466
  def parse_stop_recording_response(data: object):
9206
9467
  return StopRecordingResponse(
9207
9468
  state=parse_recorder_state(data["state"]) if "state" in data and data.get("state") is not None else None,
9208
9469
  startTimestamp=parse_str(data["startTimestamp"]) if "startTimestamp" in data and data.get("startTimestamp") is not None else None,
9209
9470
  endTimestamp=parse_str(data["endTimestamp"]) if "endTimestamp" in data and data.get("endTimestamp") is not None else None,
9471
+ status=parse_recorder_status(data["status"]) if "status" in data and data.get("status") is not None else None,
9210
9472
  )
9211
9473
 
9212
9474
  def serialize_stop_recording_response(data: StopRecordingResponse) -> object:
@@ -9214,6 +9476,7 @@ def serialize_stop_recording_response(data: StopRecordingResponse) -> object:
9214
9476
  "state": None if data.state is None else serialize_recorder_state(data.state),
9215
9477
  "startTimestamp": None if data.startTimestamp is None else serialize_str(data.startTimestamp),
9216
9478
  "endTimestamp": None if data.endTimestamp is None else serialize_str(data.endTimestamp),
9479
+ "status": None if data.status is None else serialize_recorder_status(data.status),
9217
9480
  }
9218
9481
 
9219
9482
  @dataclass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: standardbots
3
- Version: 2.0.0.dev1758730305
3
+ Version: 2.0.0.dev1763152552
4
4
  Summary: Standard Bots RO1 Robotics API
5
5
  Home-page:
6
6
  Author: Standard Bots Support
@@ -2442,6 +2442,21 @@ class TestGetStatusHealthHealth:
2442
2442
  assert res.health == models.StatusHealthEnum.Ok
2443
2443
 
2444
2444
 
2445
+ class TestGetSpaceGlobalSpaces:
2446
+ """Tests: [GET] `/api/v1/space/globals`"""
2447
+
2448
+ def test_basic(self, client_live: StandardBotsRobot) -> None:
2449
+ """Basic test"""
2450
+ client = client_live
2451
+ with client.connection():
2452
+ res = client.space.list_global_spaces()
2453
+ assert not res.isNotOk()
2454
+ data = res.data
2455
+ assert isinstance(data, models.SpacesPaginatedResponse)
2456
+ # Implied by test bed requirements
2457
+ assert len(data.items) >= 0
2458
+
2459
+
2445
2460
  class TestGetSpacePlanes:
2446
2461
  """Tests: [GET] `/api/v1/space/planes`"""
2447
2462
 
@@ -3323,7 +3338,10 @@ class TestPostMovementPositionArmControlled:
3323
3338
  assert heartbeat_data.event is not None
3324
3339
  assert heartbeat_data.event.kind == models.ArmPositionUpdateKindEnum.Failure
3325
3340
  assert heartbeat_data.event.failure is not None
3326
- assert heartbeat_data.event.failure.reason == "Failed to generate a motion plan"
3341
+ assert (
3342
+ heartbeat_data.event.failure.reason
3343
+ == "Failed to generate a motion plan"
3344
+ )
3327
3345
 
3328
3346
  def test_move_then_stop_heartbeat(
3329
3347
  self,