viam-sdk 0.25.2__py3-none-linux_armv7l.whl → 0.62.0__py3-none-linux_armv7l.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 (328) hide show
  1. viam/app/_logs.py +3 -6
  2. viam/app/app_client.py +606 -262
  3. viam/app/billing_client.py +60 -18
  4. viam/app/data_client.py +1086 -315
  5. viam/app/ml_training_client.py +51 -48
  6. viam/app/provisioning_client.py +3 -5
  7. viam/app/viam_client.py +105 -11
  8. viam/components/arm/__init__.py +1 -25
  9. viam/components/arm/arm.py +21 -22
  10. viam/components/arm/client.py +27 -30
  11. viam/components/arm/service.py +3 -3
  12. viam/components/audio_in/__init__.py +24 -0
  13. viam/components/audio_in/audio_in.py +74 -0
  14. viam/components/audio_in/client.py +76 -0
  15. viam/components/audio_in/service.py +83 -0
  16. viam/components/audio_input/__init__.py +1 -1
  17. viam/components/audio_input/audio_input.py +4 -3
  18. viam/components/audio_input/client.py +19 -8
  19. viam/components/audio_input/service.py +10 -0
  20. viam/components/audio_out/__init__.py +21 -0
  21. viam/components/audio_out/audio_out.py +72 -0
  22. viam/components/audio_out/client.py +67 -0
  23. viam/components/audio_out/service.py +63 -0
  24. viam/components/base/__init__.py +2 -10
  25. viam/components/base/base.py +20 -20
  26. viam/components/base/client.py +27 -30
  27. viam/components/board/__init__.py +2 -25
  28. viam/components/board/board.py +39 -77
  29. viam/components/board/client.py +39 -73
  30. viam/components/button/__init__.py +10 -0
  31. viam/components/button/button.py +41 -0
  32. viam/components/button/client.py +52 -0
  33. viam/components/button/service.py +46 -0
  34. viam/components/camera/__init__.py +1 -1
  35. viam/components/camera/camera.py +31 -22
  36. viam/components/camera/client.py +30 -20
  37. viam/components/camera/service.py +14 -12
  38. viam/components/component_base.py +10 -7
  39. viam/components/encoder/__init__.py +1 -1
  40. viam/components/encoder/client.py +15 -16
  41. viam/components/encoder/encoder.py +9 -9
  42. viam/components/gantry/__init__.py +1 -13
  43. viam/components/gantry/client.py +41 -28
  44. viam/components/gantry/gantry.py +48 -17
  45. viam/components/gantry/service.py +21 -5
  46. viam/components/generic/__init__.py +1 -1
  47. viam/components/generic/client.py +11 -7
  48. viam/components/generic/generic.py +3 -3
  49. viam/components/gripper/__init__.py +3 -12
  50. viam/components/gripper/client.py +43 -20
  51. viam/components/gripper/gripper.py +87 -12
  52. viam/components/gripper/service.py +32 -3
  53. viam/components/input/__init__.py +1 -14
  54. viam/components/input/client.py +22 -23
  55. viam/components/input/input.py +18 -12
  56. viam/components/motor/__init__.py +1 -21
  57. viam/components/motor/client.py +36 -42
  58. viam/components/motor/motor.py +24 -24
  59. viam/components/movement_sensor/__init__.py +1 -1
  60. viam/components/movement_sensor/client.py +33 -40
  61. viam/components/movement_sensor/movement_sensor.py +12 -12
  62. viam/components/pose_tracker/__init__.py +1 -1
  63. viam/components/pose_tracker/client.py +9 -8
  64. viam/components/pose_tracker/pose_tracker.py +2 -2
  65. viam/components/power_sensor/__init__.py +1 -1
  66. viam/components/power_sensor/client.py +15 -18
  67. viam/components/power_sensor/power_sensor.py +12 -12
  68. viam/components/sensor/__init__.py +1 -1
  69. viam/components/sensor/client.py +9 -8
  70. viam/components/sensor/sensor.py +5 -5
  71. viam/components/servo/__init__.py +1 -13
  72. viam/components/servo/client.py +18 -18
  73. viam/components/servo/servo.py +12 -12
  74. viam/components/switch/__init__.py +10 -0
  75. viam/components/switch/client.py +83 -0
  76. viam/components/switch/service.py +72 -0
  77. viam/components/switch/switch.py +95 -0
  78. viam/gen/app/agent/v1/agent_pb2.py +40 -29
  79. viam/gen/app/agent/v1/agent_pb2.pyi +73 -11
  80. viam/gen/app/cloudslam/v1/cloud_slam_pb2.py +45 -42
  81. viam/gen/app/data/v1/data_grpc.py +98 -2
  82. viam/gen/app/data/v1/data_pb2.py +238 -119
  83. viam/gen/app/data/v1/data_pb2.pyi +804 -34
  84. viam/gen/app/datapipelines/v1/data_pipelines_grpc.py +84 -0
  85. viam/gen/app/datapipelines/v1/data_pipelines_pb2.py +57 -0
  86. viam/gen/app/datapipelines/v1/data_pipelines_pb2.pyi +387 -0
  87. viam/gen/app/dataset/v1/dataset_grpc.py +10 -2
  88. viam/gen/app/dataset/v1/dataset_pb2.py +38 -31
  89. viam/gen/app/dataset/v1/dataset_pb2.pyi +36 -1
  90. viam/gen/app/datasync/v1/data_sync_grpc.py +1 -1
  91. viam/gen/app/datasync/v1/data_sync_pb2.py +61 -51
  92. viam/gen/app/datasync/v1/data_sync_pb2.pyi +52 -12
  93. viam/gen/app/mlinference/__init__.py +0 -0
  94. viam/gen/app/mlinference/v1/__init__.py +0 -0
  95. viam/gen/app/mlinference/v1/ml_inference_grpc.py +28 -0
  96. viam/gen/app/mlinference/v1/ml_inference_pb2.py +23 -0
  97. viam/gen/app/mlinference/v1/ml_inference_pb2.pyi +63 -0
  98. viam/gen/app/mltraining/v1/ml_training_grpc.py +18 -2
  99. viam/gen/app/mltraining/v1/ml_training_pb2.py +134 -101
  100. viam/gen/app/mltraining/v1/ml_training_pb2.pyi +193 -7
  101. viam/gen/app/packages/v1/packages_pb2.py +43 -40
  102. viam/gen/app/v1/app_grpc.py +290 -2
  103. viam/gen/app/v1/app_pb2.py +670 -453
  104. viam/gen/app/v1/app_pb2.pyi +3133 -947
  105. viam/gen/app/v1/billing_grpc.py +34 -2
  106. viam/gen/app/v1/billing_pb2.py +94 -35
  107. viam/gen/app/v1/billing_pb2.pyi +314 -61
  108. viam/gen/app/v1/end_user_pb2.py +50 -29
  109. viam/gen/app/v1/robot_pb2.py +120 -111
  110. viam/gen/app/v1/robot_pb2.pyi +137 -15
  111. viam/gen/common/v1/common_pb2.py +86 -66
  112. viam/gen/common/v1/common_pb2.pyi +184 -8
  113. viam/gen/component/arm/v1/arm_grpc.py +18 -2
  114. viam/gen/component/arm/v1/arm_pb2.py +68 -55
  115. viam/gen/component/arm/v1/arm_pb2.pyi +73 -3
  116. viam/gen/component/audioin/__init__.py +0 -0
  117. viam/gen/component/audioin/v1/__init__.py +0 -0
  118. viam/gen/component/audioin/v1/audioin_grpc.py +54 -0
  119. viam/gen/component/audioin/v1/audioin_pb2.py +34 -0
  120. viam/gen/component/audioin/v1/audioin_pb2.pyi +94 -0
  121. viam/gen/component/audioinput/v1/audioinput_pb2.py +35 -32
  122. viam/gen/component/audioout/__init__.py +0 -0
  123. viam/gen/component/audioout/v1/__init__.py +0 -0
  124. viam/gen/component/audioout/v1/audioout_grpc.py +54 -0
  125. viam/gen/component/audioout/v1/audioout_pb2.py +32 -0
  126. viam/gen/component/audioout/v1/audioout_pb2.pyi +47 -0
  127. viam/gen/component/base/v1/base_pb2.py +57 -54
  128. viam/gen/component/board/v1/board_pb2.py +93 -90
  129. viam/gen/component/button/__init__.py +0 -0
  130. viam/gen/component/button/v1/__init__.py +0 -0
  131. viam/gen/component/button/v1/button_grpc.py +38 -0
  132. viam/gen/component/button/v1/button_pb2.py +28 -0
  133. viam/gen/component/button/v1/button_pb2.pyi +39 -0
  134. viam/gen/component/camera/v1/camera_pb2.py +58 -55
  135. viam/gen/component/camera/v1/camera_pb2.pyi +31 -7
  136. viam/gen/component/encoder/v1/encoder_pb2.py +35 -32
  137. viam/gen/component/gantry/v1/gantry_grpc.py +9 -1
  138. viam/gen/component/gantry/v1/gantry_pb2.py +56 -51
  139. viam/gen/component/generic/v1/generic_pb2.py +15 -12
  140. viam/gen/component/gripper/v1/gripper_grpc.py +18 -2
  141. viam/gen/component/gripper/v1/gripper_pb2.py +48 -37
  142. viam/gen/component/gripper/v1/gripper_pb2.pyi +43 -1
  143. viam/gen/component/inputcontroller/v1/input_controller_pb2.py +45 -42
  144. viam/gen/component/motor/v1/motor_pb2.py +77 -74
  145. viam/gen/component/movementsensor/v1/movementsensor_pb2.py +69 -66
  146. viam/gen/component/posetracker/v1/pose_tracker_pb2.py +25 -22
  147. viam/gen/component/powersensor/v1/powersensor_pb2.py +33 -30
  148. viam/gen/component/sensor/v1/sensor_pb2.py +17 -14
  149. viam/gen/component/servo/v1/servo_pb2.py +41 -38
  150. viam/gen/component/switch/__init__.py +0 -0
  151. viam/gen/component/switch/v1/__init__.py +0 -0
  152. viam/gen/component/switch/v1/switch_grpc.py +54 -0
  153. viam/gen/component/switch/v1/switch_pb2.py +40 -0
  154. viam/gen/component/switch/v1/switch_pb2.pyi +116 -0
  155. viam/gen/component/testecho/v1/testecho_pb2.py +29 -26
  156. viam/gen/module/v1/module_pb2.py +36 -33
  157. viam/gen/module/v1/module_pb2.pyi +7 -2
  158. viam/gen/proto/rpc/examples/echo/v1/echo_pb2.py +26 -23
  159. viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.py +23 -20
  160. viam/gen/proto/rpc/v1/auth_pb2.py +27 -24
  161. viam/gen/proto/rpc/webrtc/v1/grpc_pb2.py +35 -32
  162. viam/gen/proto/rpc/webrtc/v1/signaling_pb2.py +62 -57
  163. viam/gen/proto/rpc/webrtc/v1/signaling_pb2.pyi +18 -4
  164. viam/gen/provisioning/v1/provisioning_grpc.py +10 -2
  165. viam/gen/provisioning/v1/provisioning_pb2.py +38 -31
  166. viam/gen/provisioning/v1/provisioning_pb2.pyi +20 -2
  167. viam/gen/robot/v1/robot_grpc.py +61 -29
  168. viam/gen/robot/v1/robot_pb2.py +186 -155
  169. viam/gen/robot/v1/robot_pb2.pyi +278 -59
  170. viam/gen/service/datamanager/v1/data_manager_grpc.py +11 -2
  171. viam/gen/service/datamanager/v1/data_manager_pb2.py +27 -17
  172. viam/gen/service/datamanager/v1/data_manager_pb2.pyi +47 -1
  173. viam/gen/service/discovery/__init__.py +0 -0
  174. viam/gen/service/discovery/v1/__init__.py +0 -0
  175. viam/gen/service/discovery/v1/discovery_grpc.py +39 -0
  176. viam/gen/service/discovery/v1/discovery_pb2.py +29 -0
  177. viam/gen/service/discovery/v1/discovery_pb2.pyi +51 -0
  178. viam/gen/service/generic/v1/generic_pb2.py +13 -10
  179. viam/gen/service/mlmodel/v1/mlmodel_pb2.py +75 -72
  180. viam/gen/service/motion/v1/motion_pb2.py +118 -85
  181. viam/gen/service/motion/v1/motion_pb2.pyi +130 -68
  182. viam/gen/service/navigation/v1/navigation_pb2.py +75 -72
  183. viam/gen/service/sensors/v1/sensors_pb2.py +59 -56
  184. viam/gen/service/shell/v1/shell_pb2.py +35 -32
  185. viam/gen/service/slam/v1/slam_pb2.py +43 -40
  186. viam/gen/service/slam/v1/slam_pb2.pyi +1 -1
  187. viam/gen/service/video/__init__.py +0 -0
  188. viam/gen/service/video/v1/__init__.py +0 -0
  189. viam/gen/service/video/v1/video_grpc.py +39 -0
  190. viam/gen/service/video/v1/video_pb2.py +29 -0
  191. viam/gen/service/video/v1/video_pb2.pyi +72 -0
  192. viam/gen/service/vision/v1/vision_pb2.py +60 -57
  193. viam/gen/service/vision/v1/vision_pb2.pyi +28 -3
  194. viam/gen/service/worldstatestore/__init__.py +0 -0
  195. viam/gen/service/worldstatestore/v1/__init__.py +0 -0
  196. viam/gen/service/worldstatestore/v1/world_state_store_grpc.py +55 -0
  197. viam/gen/service/worldstatestore/v1/world_state_store_pb2.py +39 -0
  198. viam/gen/service/worldstatestore/v1/world_state_store_pb2.pyi +171 -0
  199. viam/gen/stream/v1/stream_grpc.py +17 -1
  200. viam/gen/stream/v1/stream_pb2.py +34 -21
  201. viam/gen/stream/v1/stream_pb2.pyi +79 -1
  202. viam/gen/tagger/v1/tagger_pb2.py +9 -8
  203. viam/logging.py +77 -18
  204. viam/media/audio.py +28 -0
  205. viam/media/utils/pil/__init__.py +7 -3
  206. viam/media/video.py +80 -17
  207. viam/module/module.py +111 -38
  208. viam/module/resource_data_consumer.py +41 -0
  209. viam/module/service.py +9 -1
  210. viam/module/types.py +2 -4
  211. viam/proto/app/__init__.py +199 -0
  212. viam/proto/app/agent/__init__.py +5 -2
  213. viam/proto/app/billing.py +31 -4
  214. viam/proto/app/cloudslam/__init__.py +1 -0
  215. viam/proto/app/data/__init__.py +63 -0
  216. viam/proto/app/datapipelines/__init__.py +56 -0
  217. viam/proto/app/dataset/__init__.py +5 -0
  218. viam/proto/app/datasync/__init__.py +3 -0
  219. viam/proto/app/end_user.py +1 -0
  220. viam/proto/app/mlinference/__init__.py +15 -0
  221. viam/proto/app/mltraining/__init__.py +13 -0
  222. viam/proto/app/packages/__init__.py +1 -0
  223. viam/proto/app/robot.py +7 -0
  224. viam/proto/common/__init__.py +15 -0
  225. viam/proto/component/arm/__init__.py +7 -0
  226. viam/proto/component/audioin/__init__.py +16 -0
  227. viam/proto/component/audioinput/__init__.py +1 -0
  228. viam/proto/component/audioout/__init__.py +15 -0
  229. viam/proto/component/base/__init__.py +1 -0
  230. viam/proto/component/board/__init__.py +1 -0
  231. viam/proto/component/button/__init__.py +15 -0
  232. viam/proto/component/camera/__init__.py +1 -0
  233. viam/proto/component/encoder/__init__.py +1 -0
  234. viam/proto/component/gantry/__init__.py +1 -0
  235. viam/proto/component/generic/__init__.py +1 -0
  236. viam/proto/component/gripper/__init__.py +5 -0
  237. viam/proto/component/inputcontroller/__init__.py +1 -0
  238. viam/proto/component/motor/__init__.py +1 -0
  239. viam/proto/component/movementsensor/__init__.py +1 -0
  240. viam/proto/component/posetracker/__init__.py +1 -0
  241. viam/proto/component/powersensor/__init__.py +1 -0
  242. viam/proto/component/sensor/__init__.py +1 -0
  243. viam/proto/component/servo/__init__.py +1 -0
  244. viam/proto/component/switch/__init__.py +26 -0
  245. viam/proto/component/testecho/__init__.py +1 -0
  246. viam/proto/module/__init__.py +1 -0
  247. viam/proto/provisioning/__init__.py +5 -0
  248. viam/proto/robot/__init__.py +29 -8
  249. viam/proto/rpc/auth.py +1 -0
  250. viam/proto/rpc/examples/echo/__init__.py +1 -0
  251. viam/proto/rpc/examples/echoresource/__init__.py +1 -0
  252. viam/proto/rpc/webrtc/grpc.py +1 -0
  253. viam/proto/rpc/webrtc/signaling.py +3 -0
  254. viam/proto/service/datamanager/__init__.py +9 -1
  255. viam/proto/service/discovery/__init__.py +15 -0
  256. viam/proto/service/generic/__init__.py +1 -0
  257. viam/proto/service/mlmodel/__init__.py +1 -0
  258. viam/proto/service/motion/__init__.py +3 -0
  259. viam/proto/service/navigation/__init__.py +1 -0
  260. viam/proto/service/sensors/__init__.py +1 -0
  261. viam/proto/service/shell/__init__.py +1 -0
  262. viam/proto/service/slam/__init__.py +1 -0
  263. viam/proto/service/video/__init__.py +15 -0
  264. viam/proto/service/vision/__init__.py +1 -0
  265. viam/proto/service/worldstatestore/__init__.py +32 -0
  266. viam/proto/stream/__init__.py +11 -0
  267. viam/py.typed +0 -0
  268. viam/resource/base.py +12 -8
  269. viam/resource/easy_resource.py +24 -13
  270. viam/resource/manager.py +6 -5
  271. viam/resource/registry.py +39 -51
  272. viam/resource/rpc_client_base.py +33 -1
  273. viam/resource/types.py +13 -14
  274. viam/robot/client.py +190 -122
  275. viam/robot/service.py +2 -50
  276. viam/rpc/dial.py +54 -4
  277. viam/rpc/libviam_rust_utils.so +0 -0
  278. viam/rpc/server.py +25 -11
  279. viam/rpc/types.py +2 -4
  280. viam/services/discovery/__init__.py +12 -0
  281. viam/services/discovery/client.py +55 -0
  282. viam/services/discovery/discovery.py +52 -0
  283. viam/services/discovery/service.py +43 -0
  284. viam/services/generic/__init__.py +1 -1
  285. viam/services/generic/client.py +8 -5
  286. viam/services/generic/generic.py +2 -2
  287. viam/services/mlmodel/__init__.py +1 -1
  288. viam/services/mlmodel/client.py +17 -7
  289. viam/services/mlmodel/mlmodel.py +23 -12
  290. viam/services/mlmodel/service.py +5 -2
  291. viam/services/mlmodel/utils.py +11 -1
  292. viam/services/motion/__init__.py +2 -2
  293. viam/services/motion/client.py +32 -32
  294. viam/services/motion/motion.py +66 -62
  295. viam/services/navigation/__init__.py +1 -1
  296. viam/services/navigation/client.py +30 -20
  297. viam/services/navigation/navigation.py +23 -23
  298. viam/services/service_base.py +13 -9
  299. viam/services/service_client_base.py +3 -3
  300. viam/services/slam/__init__.py +1 -1
  301. viam/services/slam/client.py +15 -10
  302. viam/services/slam/slam.py +11 -11
  303. viam/services/vision/__init__.py +1 -1
  304. viam/services/vision/client.py +31 -24
  305. viam/services/vision/service.py +8 -8
  306. viam/services/vision/vision.py +36 -53
  307. viam/services/worldstatestore/__init__.py +18 -0
  308. viam/services/worldstatestore/client.py +94 -0
  309. viam/services/worldstatestore/service.py +55 -0
  310. viam/services/worldstatestore/worldstatestore.py +90 -0
  311. viam/sessions_client.py +115 -46
  312. viam/streams.py +3 -6
  313. viam/utils.py +44 -14
  314. viam/version_metadata.py +4 -0
  315. {viam_sdk-0.25.2.dist-info → viam_sdk-0.62.0.dist-info}/METADATA +27 -28
  316. viam_sdk-0.62.0.dist-info/RECORD +514 -0
  317. {viam_sdk-0.25.2.dist-info → viam_sdk-0.62.0.dist-info}/WHEEL +1 -1
  318. viam/gen/proto/rpc/examples/fileupload/v1/fileupload_grpc.py +0 -27
  319. viam/gen/proto/rpc/examples/fileupload/v1/fileupload_pb2.py +0 -18
  320. viam/gen/proto/rpc/examples/fileupload/v1/fileupload_pb2.pyi +0 -45
  321. viam/proto/rpc/examples/fileupload/__init__.py +0 -18
  322. viam/services/sensors/__init__.py +0 -5
  323. viam/services/sensors/client.py +0 -65
  324. viam_sdk-0.25.2.dist-info/LICENSE +0 -202
  325. viam_sdk-0.25.2.dist-info/RECORD +0 -442
  326. /viam/gen/{proto/rpc/examples/fileupload → app/datapipelines}/__init__.py +0 -0
  327. /viam/gen/{proto/rpc/examples/fileupload → app/datapipelines}/v1/__init__.py +0 -0
  328. /LICENSE → /viam_sdk-0.62.0.dist-info/licenses/LICENSE +0 -0
viam/app/data_client.py CHANGED
@@ -2,10 +2,12 @@ import warnings
2
2
  from dataclasses import dataclass
3
3
  from datetime import datetime
4
4
  from pathlib import Path
5
- from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple
5
+ from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple, Union, cast
6
6
 
7
+ import bson
7
8
  from google.protobuf.struct_pb2 import Struct
8
9
  from grpclib.client import Channel, Stream
10
+ from typing_extensions import Self
9
11
 
10
12
  from viam import logging
11
13
  from viam.proto.app.data import (
@@ -22,19 +24,32 @@ from viam.proto.app.data import (
22
24
  BinaryID,
23
25
  BoundingBoxLabelsByFilterRequest,
24
26
  BoundingBoxLabelsByFilterResponse,
27
+ CaptureInterval,
25
28
  CaptureMetadata,
26
29
  ConfigureDatabaseUserRequest,
30
+ CreateBinaryDataSignedURLRequest,
31
+ CreateBinaryDataSignedURLResponse,
32
+ CreateIndexRequest,
27
33
  DataRequest,
28
34
  DataServiceStub,
29
35
  DeleteBinaryDataByFilterRequest,
30
36
  DeleteBinaryDataByFilterResponse,
31
37
  DeleteBinaryDataByIDsRequest,
32
38
  DeleteBinaryDataByIDsResponse,
39
+ DeleteIndexRequest,
33
40
  DeleteTabularDataRequest,
34
41
  DeleteTabularDataResponse,
42
+ ExportTabularDataRequest,
43
+ ExportTabularDataResponse,
35
44
  Filter,
36
45
  GetDatabaseConnectionRequest,
37
46
  GetDatabaseConnectionResponse,
47
+ GetLatestTabularDataRequest,
48
+ GetLatestTabularDataResponse,
49
+ Index,
50
+ IndexableCollection,
51
+ ListIndexesRequest,
52
+ ListIndexesResponse,
38
53
  Order,
39
54
  RemoveBinaryDataFromDatasetByIDsRequest,
40
55
  RemoveBoundingBoxFromImageByIDRequest,
@@ -48,9 +63,31 @@ from viam.proto.app.data import (
48
63
  TabularDataByMQLResponse,
49
64
  TabularDataBySQLRequest,
50
65
  TabularDataBySQLResponse,
66
+ TabularDataSource,
67
+ TabularDataSourceType,
51
68
  TagsByFilterRequest,
52
69
  TagsByFilterResponse,
53
70
  )
71
+ from viam.proto.app.datapipelines import (
72
+ CreateDataPipelineRequest,
73
+ CreateDataPipelineResponse,
74
+ DataPipelineRunStatus,
75
+ DataPipelinesServiceStub,
76
+ DeleteDataPipelineRequest,
77
+ GetDataPipelineRequest,
78
+ GetDataPipelineResponse,
79
+ ListDataPipelineRunsRequest,
80
+ ListDataPipelineRunsResponse,
81
+ ListDataPipelinesRequest,
82
+ ListDataPipelinesResponse,
83
+ RenameDataPipelineRequest,
84
+ )
85
+ from viam.proto.app.datapipelines import (
86
+ DataPipeline as ProtoDataPipeline,
87
+ )
88
+ from viam.proto.app.datapipelines import (
89
+ DataPipelineRun as ProtoDataPipelineRun,
90
+ )
54
91
  from viam.proto.app.dataset import (
55
92
  CreateDatasetRequest,
56
93
  CreateDatasetResponse,
@@ -61,6 +98,8 @@ from viam.proto.app.dataset import (
61
98
  ListDatasetsByIDsResponse,
62
99
  ListDatasetsByOrganizationIDRequest,
63
100
  ListDatasetsByOrganizationIDResponse,
101
+ MergeDatasetsRequest,
102
+ MergeDatasetsResponse,
64
103
  RenameDatasetRequest,
65
104
  )
66
105
  from viam.proto.app.datasync import (
@@ -78,7 +117,7 @@ from viam.proto.app.datasync import (
78
117
  StreamingDataCaptureUploadResponse,
79
118
  UploadMetadata,
80
119
  )
81
- from viam.utils import ValueTypes, create_filter, datetime_to_timestamp, struct_to_dict
120
+ from viam.utils import ValueTypes, _alias_param, create_filter, datetime_to_timestamp, dict_to_struct, struct_to_dict
82
121
 
83
122
  LOGGER = logging.getLogger(__name__)
84
123
 
@@ -86,10 +125,10 @@ LOGGER = logging.getLogger(__name__)
86
125
  class DataClient:
87
126
  """gRPC client for uploading and retrieving data from app.
88
127
 
89
- Constructor is used by `ViamClient` to instantiate relevant service stubs. Calls to `DataClient` methods should be made through
90
- `ViamClient`.
128
+ This class's constructor instantiates relevant service stubs. Always make :class:`DataClient` method calls through an instance of
129
+ :class:`ViamClient`.
91
130
 
92
- Establish a Connection::
131
+ Establish a connection::
93
132
 
94
133
  import asyncio
95
134
 
@@ -105,17 +144,15 @@ class DataClient:
105
144
 
106
145
  async def main():
107
146
  # Make a ViamClient
108
- viam_client = await connect()
109
- # Instantiate a DataClient to run data client API methods on
110
- data_client = viam_client.data_client
111
-
112
- viam_client.close()
147
+ async with await connect() as viam_client:
148
+ # Instantiate a DataClient to run data client API methods on
149
+ data_client = viam_client.data_client
113
150
 
114
151
  if __name__ == '__main__':
115
152
  asyncio.run(main())
116
153
 
117
154
 
118
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
155
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/>`_.
119
156
  """
120
157
 
121
158
  @dataclass
@@ -142,8 +179,203 @@ class DataClient:
142
179
  return str(self) == str(other)
143
180
  return False
144
181
 
182
+ @dataclass
183
+ class TabularDataPoint:
184
+ """Represents a tabular data point and its associated metadata."""
185
+
186
+ part_id: str
187
+ """The robot part ID"""
188
+
189
+ resource_name: str
190
+ """The resource name"""
191
+
192
+ resource_api: str
193
+ """The resource API. For example, rdk:component:sensor"""
194
+
195
+ method_name: str
196
+ """The method used for data capture. For example, Readings"""
197
+
198
+ time_captured: datetime
199
+ """The time at which the data point was captured"""
200
+
201
+ organization_id: str
202
+ """The organization ID"""
203
+
204
+ location_id: str
205
+ """The location ID"""
206
+
207
+ robot_name: str
208
+ """The robot name"""
209
+
210
+ robot_id: str
211
+ """The robot ID"""
212
+
213
+ part_name: str
214
+ """The robot part name"""
215
+
216
+ method_parameters: Mapping[str, ValueTypes]
217
+ """Additional parameters associated with the data capture method"""
218
+
219
+ tags: List[str]
220
+ """A list of tags associated with the data point"""
221
+
222
+ payload: Mapping[str, ValueTypes]
223
+ """The captured data"""
224
+
225
+ def __str__(self) -> str:
226
+ return (
227
+ f"TabularDataPoint("
228
+ f"robot='{self.robot_name}' (id={self.robot_id}), "
229
+ f"part='{self.part_name}' (id={self.part_id}), "
230
+ f"resource='{self.resource_name}' ({self.resource_api}), "
231
+ f"method='{self.method_name}', "
232
+ f"org={self.organization_id}, "
233
+ f"location={self.location_id}, "
234
+ f"time='{self.time_captured.isoformat()}', "
235
+ f"params={self.method_parameters}, "
236
+ f"tags={self.tags}, "
237
+ f"payload={self.payload})"
238
+ )
239
+
240
+ def __eq__(self, other: object) -> bool:
241
+ if isinstance(other, DataClient.TabularDataPoint):
242
+ return str(self) == str(other)
243
+ return False
244
+
245
+ @property
246
+ def resource_subtype(self) -> str:
247
+ warnings.warn(
248
+ "`TabularDataPoint.resource_subtype` is deprecated. Use `TabularDataPoint.resource_api` instead.",
249
+ DeprecationWarning,
250
+ stacklevel=2,
251
+ )
252
+ return self.resource_api
253
+
254
+ @dataclass
255
+ class DataPipeline:
256
+ """Represents a data pipeline and its associated metadata."""
257
+
258
+ id: str
259
+ """The ID of the data pipeline"""
260
+
261
+ organization_id: str
262
+ """The organization ID"""
263
+
264
+ name: str
265
+ """The name of the data pipeline"""
266
+
267
+ mql_binary: List[Dict[str, Any]]
268
+ """The MQL binary of the data pipeline"""
269
+
270
+ schedule: str
271
+ """The schedule of the data pipeline"""
272
+
273
+ created_on: datetime
274
+ """The time the data pipeline was created"""
275
+
276
+ updated_at: datetime
277
+ """The time the data pipeline was last updated"""
278
+
279
+ enabled: bool
280
+ """Whether the data pipeline is enabled"""
281
+
282
+ data_source_type: TabularDataSourceType.ValueType
283
+ """The type of data source for the data pipeline"""
284
+
285
+ @classmethod
286
+ def from_proto(cls, data_pipeline: ProtoDataPipeline) -> Self:
287
+ return cls(
288
+ id=data_pipeline.id,
289
+ organization_id=data_pipeline.organization_id,
290
+ name=data_pipeline.name,
291
+ mql_binary=[bson.decode(bson_bytes) for bson_bytes in data_pipeline.mql_binary],
292
+ schedule=data_pipeline.schedule,
293
+ created_on=data_pipeline.created_on.ToDatetime(),
294
+ updated_at=data_pipeline.updated_at.ToDatetime(),
295
+ enabled=data_pipeline.enabled,
296
+ data_source_type=data_pipeline.data_source_type,
297
+ )
298
+
299
+ @dataclass
300
+ class DataPipelineRun:
301
+ """Represents a data pipeline run and its associated metadata."""
302
+
303
+ id: str
304
+ """The ID of the data pipeline run"""
305
+
306
+ status: DataPipelineRunStatus.ValueType
307
+ """The status of the data pipeline run"""
308
+
309
+ start_time: datetime
310
+ """The time the data pipeline run started"""
311
+
312
+ end_time: datetime
313
+ """The time the data pipeline run ended"""
314
+
315
+ data_start_time: datetime
316
+ """The start time of the data that was processed in the run."""
317
+ data_end_time: datetime
318
+ """The end time of the data that was processed in the run."""
319
+
320
+ error_message: str
321
+ """The error message of the data pipeline run. Only set if the run failed."""
322
+
323
+ @classmethod
324
+ def from_proto(cls, data_pipeline_run: ProtoDataPipelineRun) -> Self:
325
+ return cls(
326
+ id=data_pipeline_run.id,
327
+ status=data_pipeline_run.status,
328
+ start_time=data_pipeline_run.start_time.ToDatetime(),
329
+ end_time=data_pipeline_run.end_time.ToDatetime(),
330
+ data_start_time=data_pipeline_run.data_start_time.ToDatetime(),
331
+ data_end_time=data_pipeline_run.data_end_time.ToDatetime(),
332
+ error_message=data_pipeline_run.error_message,
333
+ )
334
+
335
+ @dataclass
336
+ class DataPipelineRunsPage:
337
+ """Represents a page of data pipeline runs and provides pagination functionality."""
338
+
339
+ _client: "DataClient"
340
+ """The data client used to make API calls"""
341
+
342
+ pipeline_id: str
343
+ """The ID of the pipeline these runs belong to"""
344
+
345
+ page_size: int
346
+ """The number of runs per page"""
347
+
348
+ runs: List["DataClient.DataPipelineRun"]
349
+ """The list of runs in this page"""
350
+
351
+ next_page_token: str
352
+ """The token to use to get the next page of results"""
353
+
354
+ async def next_page(self) -> "DataClient.DataPipelineRunsPage":
355
+ """Get the next page of data pipeline runs.
356
+
357
+ Returns:
358
+ DataPipelineRunsPage: The next page of runs, or an empty page if there are no more runs
359
+ """
360
+ if not self.next_page_token:
361
+ # no token, return empty next page
362
+ return DataClient.DataPipelineRunsPage(
363
+ _client=self._client, pipeline_id=self.pipeline_id, page_size=self.page_size, runs=[], next_page_token=""
364
+ )
365
+ return await self._client._list_data_pipeline_runs(self.pipeline_id, self.page_size, self.next_page_token)
366
+
367
+ @classmethod
368
+ def from_proto(cls, data_pipeline_runs_page: ListDataPipelineRunsResponse, client: "DataClient", page_size: int) -> Self:
369
+ return cls(
370
+ _client=client,
371
+ pipeline_id=data_pipeline_runs_page.pipeline_id,
372
+ page_size=page_size,
373
+ runs=[DataClient.DataPipelineRun.from_proto(run) for run in data_pipeline_runs_page.runs],
374
+ next_page_token=data_pipeline_runs_page.next_page_token,
375
+ )
376
+
145
377
  def __init__(self, channel: Channel, metadata: Mapping[str, str]):
146
- """Create a `DataClient` that maintains a connection to app.
378
+ """Create a :class:`DataClient` that maintains a connection to app.
147
379
 
148
380
  Args:
149
381
  channel (grpclib.client.Channel): Connection to app.
@@ -153,11 +385,13 @@ class DataClient:
153
385
  self._data_client = DataServiceStub(channel)
154
386
  self._data_sync_client = DataSyncServiceStub(channel)
155
387
  self._dataset_client = DatasetServiceStub(channel)
388
+ self._data_pipelines_client = DataPipelinesServiceStub(channel)
156
389
  self._channel = channel
157
390
 
158
391
  _data_client: DataServiceStub
159
392
  _data_sync_client: DataSyncServiceStub
160
393
  _dataset_client: DatasetServiceStub
394
+ _data_pipelines_client: DataPipelinesServiceStub
161
395
  _metadata: Mapping[str, str]
162
396
  _channel: Channel
163
397
 
@@ -171,44 +405,44 @@ class DataClient:
171
405
  include_internal_data: bool = False,
172
406
  dest: Optional[str] = None,
173
407
  ) -> Tuple[List[TabularData], int, str]:
174
- """Filter and download tabular data. The data will be paginated into pages of `limit` items, and the pagination ID will be included
175
- in the returned tuple. If a destination is provided, the data will be saved to that file.
176
- If the file is not empty, it will be overwritten.
408
+ """Filter and download tabular data. The data will be paginated into pages of ``limit`` items; the returned tuple will include
409
+ the pagination ID. If a destination is provided, this method saves returned data to that file, overwriting any existing file content.
177
410
 
178
411
  ::
179
412
 
180
413
  from viam.utils import create_filter
181
414
 
182
415
  my_data = []
416
+ my_filter = create_filter(component_name="motor-1")
183
417
  last = None
184
- my_filter = create_filter(component_name="left_motor")
185
418
  while True:
186
- tabular_data, count, last = await data_client.tabular_data_by_filter(my_filter, last)
419
+ tabular_data, count, last = await data_client.tabular_data_by_filter(my_filter, last=last)
187
420
  if not tabular_data:
188
421
  break
189
422
  my_data.extend(tabular_data)
190
423
 
424
+ print(f"My data: {my_data}")
191
425
 
192
426
  Args:
193
- filter (viam.proto.app.data.Filter): Optional `Filter` specifying tabular data to retrieve. No `Filter` implies all tabular
194
- data.
427
+ filter (~viam.proto.app.data.Filter): Optional, specifies tabular data to retrieve. If missing, matches all tabular data.
195
428
  limit (int): The maximum number of entries to include in a page. Defaults to 50 if unspecified.
196
- sort_order (viam.proto.app.data.Order): The desired sort order of the data.
429
+ sort_order (~viam.proto.app.data.Order): The desired sort order of the data.
197
430
  last (str): Optional string indicating the object identifier of the last-returned data.
198
- This object identifier is returned by calls to `TabularDataByFilter` as the `last` value.
199
- If provided, the server will return the next data entries after the last object identifier.
431
+ Returned by calls to :class:`TabularDataByFilter` as the ``last`` value.
432
+ If provided, the server returns the next data entries after the last object identifier.
200
433
  count_only (bool): Whether to return only the total count of entries.
201
434
  include_internal_data (bool): Whether to return the internal data. Internal data is used for Viam-specific data ingestion,
202
- like cloud SLAM. Defaults to `False`.
435
+ like cloud SLAM. Defaults to ``False``.
203
436
  dest (str): Optional filepath for writing retrieved data.
204
437
 
205
438
  Returns:
206
439
  Tuple[List[TabularData], int, str]: A tuple containing the following:
207
- List[TabularData]: The tabular data,
208
- int: The count (number of entries),
209
- str: The last-returned page ID.
210
440
 
211
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
441
+ - ``tabular_data`` (*List[TabularData]*): The tabular data.
442
+ - ``count`` (*int*): The count (number of entries).
443
+ - ``last`` (*str*): The last-returned page ID.
444
+
445
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#tabulardatabyfilter>`_.
212
446
  """
213
447
  filter = filter if filter else Filter()
214
448
 
@@ -240,62 +474,218 @@ class DataClient:
240
474
  LOGGER.error(f"Failed to write tabular data to file {dest}", exc_info=e)
241
475
  return data, response.count, response.last
242
476
 
243
- async def tabular_data_by_sql(self, organization_id: str, sql_query: str) -> List[Dict[str, ValueTypes]]:
477
+ async def tabular_data_by_sql(self, organization_id: str, sql_query: str) -> List[Dict[str, Union[ValueTypes, datetime]]]:
244
478
  """Obtain unified tabular data and metadata, queried with SQL.
479
+ Make sure your API key has permissions at the organization level in order to use this.
245
480
 
246
481
  ::
247
482
 
248
- data = await data_client.tabular_data_by_sql(org_id="<your-org-id>", sql_query="SELECT * FROM readings LIMIT 5")
249
-
483
+ data = await data_client.tabular_data_by_sql(
484
+ organization_id="<YOUR-ORG-ID>",
485
+ sql_query="SELECT * FROM readings LIMIT 5"
486
+ )
250
487
 
251
488
  Args:
252
489
  organization_id (str): The ID of the organization that owns the data.
253
- You can obtain your organization ID from the Viam app's organization settings page.
490
+ To find your organization ID, visit the organization settings page.
254
491
  sql_query (str): The SQL query to run.
255
492
 
256
493
  Returns:
257
- List[Dict[str, ValueTypes]]: An array of data objects.
494
+ List[Dict[str, Union[ValueTypes, datetime]]]: An array of decoded BSON data objects.
258
495
 
259
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
496
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#tabulardatabysql>`_.
260
497
  """
261
498
  request = TabularDataBySQLRequest(organization_id=organization_id, sql_query=sql_query)
262
499
  response: TabularDataBySQLResponse = await self._data_client.TabularDataBySQL(request, metadata=self._metadata)
263
- return [struct_to_dict(struct) for struct in response.data]
500
+ return [bson.decode(bson_bytes) for bson_bytes in response.raw_data]
264
501
 
265
- async def tabular_data_by_mql(self, organization_id: str, mql_binary: List[bytes]) -> List[Dict[str, ValueTypes]]:
502
+ @_alias_param("query", param_alias="mql_binary")
503
+ async def tabular_data_by_mql(
504
+ self,
505
+ organization_id: str,
506
+ query: Union[List[bytes], List[Dict[str, Any]]],
507
+ use_recent_data: Optional[bool] = None,
508
+ tabular_data_source_type: TabularDataSourceType.ValueType = TabularDataSourceType.TABULAR_DATA_SOURCE_TYPE_STANDARD,
509
+ pipeline_id: Optional[str] = None,
510
+ query_prefix_name: Optional[str] = None,
511
+ ) -> List[Dict[str, Union[ValueTypes, datetime]]]:
266
512
  """Obtain unified tabular data and metadata, queried with MQL.
267
513
 
268
514
  ::
269
515
 
270
- # using bson
271
516
  import bson
272
- tabular_data = await data_client.tabular_data_by_mql(org_id="<your-org-id>", mql_binary=[
273
- bson.dumps({ '$match': { 'location_id': '<location-id>' } }),
274
- bson.dumps({ "$limit": 5 })
275
- ])
276
517
 
277
- # using pymongo
278
- import bson
279
- tabular_data = await data_client.tabular_data_by_mql(org_id="<your-org-id>", mql_binary=[
280
- bson.encode({ '$match': { 'location_id': '<location-id>' } }),
281
- bson.encode({ "$limit": 5 })
518
+ tabular_data = await data_client.tabular_data_by_mql(organization_id="<YOUR-ORG-ID>", query=[
519
+ { '$match': { 'location_id': '<YOUR-LOCATION-ID>' } },
520
+ { "$limit": 5 }
282
521
  ])
283
522
 
523
+ print(f"Tabular Data: {tabular_data}")
284
524
 
285
525
  Args:
286
526
  organization_id (str): The ID of the organization that owns the data.
287
- You can obtain your organization ID from the Viam app's organization settings page.
288
- mql_binary (List[bytes]): The MQL query to run as a list of BSON queries. You can encode your bson queries using a library like
289
- `pymongo` or `bson`.
527
+ To find your organization ID, visit the organization settings page.
528
+ query (Union[List[bytes], List[Dict[str, Any]]]): The MQL query to run, as a list of MongoDB aggregation pipeline stages.
529
+ Each stage can be provided as either a dictionary or raw BSON bytes, but support for bytes will be removed in the
530
+ future, so prefer the dictionary option.
531
+ use_recent_data (bool): Whether to query blob storage or your recent data store. Defaults to ``False``..
532
+ Deprecated, use `tabular_data_source_type` instead.
533
+ tabular_data_source_type (viam.proto.app.data.TabularDataSourceType): The data source to query.
534
+ Defaults to `TABULAR_DATA_SOURCE_TYPE_STANDARD`.
535
+ pipeline_id (str): The ID of the data pipeline to query. Defaults to `None`.
536
+ Required if `tabular_data_source_type` is `TABULAR_DATA_SOURCE_TYPE_PIPELINE_SINK`.
537
+ query_prefix_name (str): Optional field that can be used to specify a saved query to run.
290
538
 
291
539
  Returns:
292
- List[Dict[str, ValueTypes]]: An array of data objects.
540
+ List[Dict[str, Union[ValueTypes, datetime]]]: An array of decoded BSON data objects.
293
541
 
294
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
542
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#tabulardatabymql>`_.
295
543
  """
296
- request = TabularDataByMQLRequest(organization_id=organization_id, mql_binary=mql_binary)
544
+ binary: List[bytes] = [bson.encode(query) for query in query] if isinstance(query[0], dict) else query # type: ignore
545
+ data_source = TabularDataSource(type=tabular_data_source_type, pipeline_id=pipeline_id)
546
+ if use_recent_data:
547
+ data_source.type = TabularDataSourceType.TABULAR_DATA_SOURCE_TYPE_HOT_STORAGE
548
+ request = TabularDataByMQLRequest(
549
+ organization_id=organization_id,
550
+ mql_binary=binary,
551
+ data_source=data_source,
552
+ query_prefix_name=query_prefix_name,
553
+ )
297
554
  response: TabularDataByMQLResponse = await self._data_client.TabularDataByMQL(request, metadata=self._metadata)
298
- return [struct_to_dict(struct) for struct in response.data]
555
+ return [bson.decode(bson_bytes) for bson_bytes in response.raw_data]
556
+
557
+ @_alias_param("resource_api", param_alias="resource_subtype")
558
+ async def get_latest_tabular_data(
559
+ self,
560
+ part_id: str,
561
+ resource_name: str,
562
+ resource_api: str,
563
+ method_name: str,
564
+ additional_params: Optional[Mapping[str, ValueTypes]] = None,
565
+ ) -> Optional[Tuple[datetime, datetime, Dict[str, ValueTypes]]]:
566
+ """Gets the most recent tabular data captured from the specified data source, as long as it was synced within the last year.
567
+
568
+ ::
569
+
570
+ tabular_data = await data_client.get_latest_tabular_data(
571
+ part_id="77ae3145-7b91-123a-a234-e567cdca8910",
572
+ resource_name="camera-1",
573
+ resource_api="rdk:component:camera",
574
+ method_name="GetImage",
575
+ additional_params={"docommand_input": {"test": "test"}}
576
+ )
577
+
578
+ if tabular_data:
579
+ time_captured, time_synced, payload = tabular_data
580
+ print(f"Time Captured: {time_captured}")
581
+ print(f"Time Synced: {time_synced}")
582
+ print(f"Payload: {payload}")
583
+ else:
584
+ print(f"No data returned: {tabular_data}")
585
+
586
+ Args:
587
+ part_id (str): The ID of the part that owns the data.
588
+ resource_name (str): The name of the requested resource that captured the data. For example, "my-sensor".
589
+ resource_api (str): The API of the requested resource that captured the data. For example, "rdk:component:sensor".
590
+ method_name (str): The data capture method name. For exampe, "Readings".
591
+ additional_params (dict): Optional additional parameters of the resource that captured the data.
592
+
593
+ Returns:
594
+ Optional[Tuple[datetime, datetime, Dict[str, ValueTypes]]]:
595
+ A return value of ``None`` means that this data source
596
+ has not synced data in the last year. Otherwise, the data source has synced some data in the last year, so the returned
597
+ tuple contains the following:
598
+
599
+ - ``time_captured`` (*datetime*): The time captured.
600
+ - ``time_synced`` (*datetime*): The time synced.
601
+ - ``payload`` (*Dict[str, ValueTypes]*): The latest tabular data captured from the specified data source.
602
+
603
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#getlatesttabulardata>`_.
604
+ """
605
+
606
+ request = GetLatestTabularDataRequest(
607
+ part_id=part_id,
608
+ resource_name=resource_name,
609
+ resource_subtype=resource_api,
610
+ method_name=method_name,
611
+ additional_parameters=dict_to_struct(additional_params) if additional_params is not None else None,
612
+ )
613
+ response: GetLatestTabularDataResponse = await self._data_client.GetLatestTabularData(request, metadata=self._metadata)
614
+ if not response.payload:
615
+ return None
616
+ return response.time_captured.ToDatetime(), response.time_synced.ToDatetime(), struct_to_dict(response.payload)
617
+
618
+ @_alias_param("resource_api", param_alias="resource_subtype")
619
+ async def export_tabular_data(
620
+ self,
621
+ part_id: str,
622
+ resource_name: str,
623
+ resource_api: str,
624
+ method_name: str,
625
+ start_time: Optional[datetime] = None,
626
+ end_time: Optional[datetime] = None,
627
+ additional_params: Optional[Mapping[str, ValueTypes]] = None,
628
+ ) -> List[TabularDataPoint]:
629
+ """Obtain unified tabular data and metadata from the specified data source.
630
+
631
+ ::
632
+
633
+ tabular_data = await data_client.export_tabular_data(
634
+ part_id="<PART-ID>",
635
+ resource_name="<RESOURCE-NAME>",
636
+ resource_api="<RESOURCE-API>",
637
+ method_name="<METHOD-NAME>",
638
+ start_time="<START_TIME>"
639
+ end_time="<END_TIME>"
640
+ additional_params="<ADDITIONAL_PARAMETERS>"
641
+ )
642
+
643
+ print(f"My data: {tabular_data}")
644
+
645
+ Args:
646
+ part_id (str): The ID of the part that owns the data.
647
+ resource_name (str): The name of the requested resource that captured the data.
648
+ resource_api (str): The API of the requested resource that captured the data.
649
+ method_name (str): The data capture method name.
650
+ start_time (datetime): Optional start time for requesting a specific range of data.
651
+ end_time (datetime): Optional end time for requesting a specific range of data.
652
+ additional_params (dict): Optional additional parameters of the resource that captured the data.
653
+
654
+ Returns:
655
+ List[TabularDataPoint]: The unified tabular data and metadata.
656
+
657
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#exporttabulardata>`_.
658
+ """
659
+
660
+ interval = CaptureInterval(start=datetime_to_timestamp(start_time), end=datetime_to_timestamp(end_time))
661
+ request = ExportTabularDataRequest(
662
+ part_id=part_id,
663
+ resource_name=resource_name,
664
+ resource_subtype=resource_api,
665
+ method_name=method_name,
666
+ interval=interval,
667
+ additional_parameters=dict_to_struct(additional_params) if additional_params is not None else None,
668
+ )
669
+ response: List[ExportTabularDataResponse] = await self._data_client.ExportTabularData(request, metadata=self._metadata)
670
+
671
+ return [
672
+ DataClient.TabularDataPoint(
673
+ part_id=resp.part_id,
674
+ resource_name=resp.resource_name,
675
+ resource_api=resp.resource_subtype,
676
+ method_name=resp.method_name,
677
+ time_captured=resp.time_captured.ToDatetime(),
678
+ organization_id=resp.organization_id,
679
+ location_id=resp.location_id,
680
+ robot_name=resp.robot_name,
681
+ robot_id=resp.robot_id,
682
+ part_name=resp.part_name,
683
+ method_parameters=struct_to_dict(resp.method_parameters),
684
+ tags=list(resp.tags),
685
+ payload=struct_to_dict(resp.payload),
686
+ )
687
+ for resp in response
688
+ ]
299
689
 
300
690
  async def binary_data_by_filter(
301
691
  self,
@@ -308,46 +698,68 @@ class DataClient:
308
698
  include_internal_data: bool = False,
309
699
  dest: Optional[str] = None,
310
700
  ) -> Tuple[List[BinaryData], int, str]:
311
- """Filter and download binary data. The data will be paginated into pages of `limit` items, and the pagination ID will be included
312
- in the returned tuple. If a destination is provided, the data will be saved to that file.
313
- If the file is not empty, it will be overwritten.
701
+ """Filter and download binary data. The data will be paginated into pages of ``limit`` items, and the pagination ID will be included
702
+ in the returned tuple as ``last``. If a destination is provided, this method saves returned data to that file,
703
+ overwriting any existing file content.
314
704
 
315
705
  ::
316
706
 
317
707
  from viam.utils import create_filter
708
+ from viam.proto.app.data import Filter, TagsFilter, TagsFilterType
318
709
 
319
-
710
+ # Get data captured from camera components
320
711
  my_data = []
321
712
  last = None
322
- my_filter = create_filter(component_name="camera")
713
+ my_filter = create_filter(component_name="camera-1")
714
+
323
715
  while True:
324
- data, count, last = await data_client.binary_data_by_filter(my_filter, last)
716
+ data, count, last = await data_client.binary_data_by_filter(
717
+ my_filter, limit=1, last=last)
325
718
  if not data:
326
719
  break
327
720
  my_data.extend(data)
328
721
 
722
+ print(f"My data: {my_data}")
723
+
724
+ # Get untagged data from a dataset
725
+
726
+ my_untagged_data = []
727
+ last = None
728
+ tags_filter = TagsFilter(type=TagsFilterType.TAGS_FILTER_TYPE_UNTAGGED)
729
+ my_filter = Filter(
730
+ dataset_id="66db6fe7d93d1ade24cd1dc3",
731
+ tags_filter=tags_filter
732
+ )
733
+
734
+ while True:
735
+ data, count, last = await data_client.binary_data_by_filter(
736
+ my_filter, last=last, include_binary_data=False)
737
+ if not data:
738
+ break
739
+ my_untagged_data.extend(data)
740
+
329
741
  Args:
330
- filter (viam.proto.app.data.Filter): Optional `Filter` specifying tabular data to retrieve. No `Filter` implies all binary
331
- data.
742
+ filter (~viam.proto.app.data.Filter): Optional, specifies tabular data to retrieve. An empty filter matches all binary data.
332
743
  limit (int): The maximum number of entries to include in a page. Defaults to 50 if unspecified.
333
- sort_order (viam.proto.app.data.Order): The desired sort order of the data.
744
+ sort_order (~viam.proto.app.data.Order): The desired sort order of the data.
334
745
  last (str): Optional string indicating the object identifier of the last-returned data.
335
- This object identifier is returned by calls to `BinaryDataByFilter` as the `last` value.
336
- If provided, the server will return the next data entries after the last object identifier.
746
+ This object identifier is returned by calls to :meth:`binary_data_by_filter` as the ``last`` value.
747
+ If provided, the server will return the next data entries after the last object identifier.
337
748
  include_binary_data (bool): Boolean specifying whether to actually include the binary file data with each retrieved file.
338
- Defaults to true (that is, both the files' data and metadata are returned).
749
+ Defaults to true (that is, both the files' data and metadata are returned).
339
750
  count_only (bool): Whether to return only the total count of entries.
340
751
  include_internal_data (bool): Whether to return the internal data. Internal data is used for Viam-specific data ingestion,
341
- like cloud SLAM. Defaults to `False`.
752
+ like cloud SLAM. Defaults to ``False``.
342
753
  dest (str): Optional filepath for writing retrieved data.
343
754
 
344
755
  Returns:
345
- Tuple[List[viam.proto.app.data.BinaryData], int, str]: A tuple containing the following:
346
- List[viam.proto.app.data.BinaryData]: The binary data,
347
- int: The count (number of entries),
348
- str: The last-returned page ID.
756
+ Tuple[List[~viam.proto.app.data.BinaryData], int, str]: A tuple containing the following:
757
+
758
+ - ``data`` (*List[* :class:`~viam.proto.app.data.BinaryData` *]*): The binary data.
759
+ - ``count`` (*int*): The count (number of entries).
760
+ - ``last`` (*str*): The last-returned page ID.
349
761
 
350
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
762
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#binarydatabyfilter>`_.
351
763
  """
352
764
 
353
765
  data_request = DataRequest(filter=filter)
@@ -377,45 +789,46 @@ class DataClient:
377
789
 
378
790
  async def binary_data_by_ids(
379
791
  self,
380
- binary_ids: List[BinaryID],
792
+ binary_ids: Union[List[BinaryID], List[str]],
381
793
  dest: Optional[str] = None,
382
794
  ) -> List[BinaryData]:
383
795
  """Filter and download binary data.
384
796
 
385
797
  ::
386
798
 
387
- from viam.proto.app.data import BinaryID
388
-
389
- binary_metadata = await data_client.binary_data_by_filter(
390
- include_file_data=False
799
+ binary_metadata, count, last = await data_client.binary_data_by_filter(
800
+ include_binary_data=False
391
801
  )
392
802
 
393
803
  my_ids = []
394
804
 
395
805
  for obj in binary_metadata:
396
- my_ids.append(
397
- BinaryID(
398
- file_id=obj.metadata.id,
399
- organization_id=obj.metadata.capture_metadata.organization_id,
400
- location_id=obj.metadata.capture_metadata.location_id
401
- )
402
- )
806
+ my_ids.append(obj.metadata.binary_data_id)
403
807
 
404
808
  binary_data = await data_client.binary_data_by_ids(my_ids)
405
809
 
406
810
  Args:
407
- binary_ids (List[viam.proto.app.data.BinaryID]): `BinaryID` objects specifying the desired data. Must be non-empty.
811
+ binary_ids (Union[List[~viam.proto.app.data.BinaryID], List[str]]): Binary data ID strings specifying the desired data or
812
+ :class:`BinaryID` objects. Must be non-empty.
813
+ *DEPRECATED:* :class:`BinaryID` *is deprecated and will be removed in a future release. Instead, pass binary data IDs as a
814
+ list of strings.*
408
815
  dest (str): Optional filepath for writing retrieved data.
409
816
 
410
817
  Raises:
411
- GRPCError: If no `BinaryID` objects are provided.
818
+ GRPCError: If no binary data ID strings or :class:`BinaryID` objects are provided.
412
819
 
413
820
  Returns:
414
- List[viam.proto.app.data.BinaryData]: The binary data.
821
+ List[~viam.proto.app.data.BinaryData]: The binary data.
415
822
 
416
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
823
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#binarydatabyids>`_.
417
824
  """
418
- request = BinaryDataByIDsRequest(binary_ids=binary_ids, include_binary=True)
825
+ request = BinaryDataByIDsRequest()
826
+ if len(binary_ids) > 0 and isinstance(binary_ids[0], str):
827
+ binary_data_ids = cast(List[str], binary_ids)
828
+ request = BinaryDataByIDsRequest(binary_data_ids=binary_data_ids, include_binary=True)
829
+ else:
830
+ bin_ids = cast(List[BinaryID], binary_ids)
831
+ request = BinaryDataByIDsRequest(binary_ids=bin_ids, include_binary=True)
419
832
  response: BinaryDataByIDsResponse = await self._data_client.BinaryDataByIDs(request, metadata=self._metadata)
420
833
  if dest:
421
834
  try:
@@ -431,30 +844,28 @@ class DataClient:
431
844
 
432
845
  ::
433
846
 
434
- from viam.utils import create_filter
435
-
436
- my_filter = create_filter(component_name="left_motor")
437
- days_of_data_to_delete = 10
438
847
  tabular_data = await data_client.delete_tabular_data(
439
- org_id="a12b3c4e-1234-1abc-ab1c-ab1c2d345abc", days_of_data_to_delete)
848
+ organization_id="<YOUR-ORG-ID>",
849
+ delete_older_than_days=150
850
+ )
440
851
 
441
852
  Args:
442
- organization_id (str): ID of organization to delete data from.
443
- You can obtain your organization ID from the Viam app's organization settings page.
444
- delete_older_than_days (int): Delete data that was captured up to this many days ago. For example if `delete_older_than_days`
445
- is 10, this deletes any data that was captured up to 10 days ago. If it is 0, all existing data is deleted.
853
+ organization_id (str): The ID of the organization to delete the data from.
854
+ To find your organization ID, visit the organization settings page.
855
+ delete_older_than_days (int): Delete data that was captured up to *this many* days ago. For example, a value of
856
+ 10 deletes any data that was captured up to 10 days ago. A value of 0 deletes *all* existing data.
446
857
 
447
858
  Returns:
448
859
  int: The number of items deleted.
449
860
 
450
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
861
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#deletetabulardata>`_.
451
862
  """
452
863
  request = DeleteTabularDataRequest(organization_id=organization_id, delete_older_than_days=delete_older_than_days)
453
864
  response: DeleteTabularDataResponse = await self._data_client.DeleteTabularData(request, metadata=self._metadata)
454
865
  return response.deleted_count
455
866
 
456
867
  async def delete_tabular_data_by_filter(self, filter: Optional[Filter]) -> int:
457
- """Deprecated: use delete_tabular_data instead."""
868
+ """Deprecated: use :meth:`delete_tabular_data` instead."""
458
869
  raise NotImplementedError()
459
870
 
460
871
  async def delete_binary_data_by_filter(self, filter: Optional[Filter]) -> int:
@@ -464,98 +875,118 @@ class DataClient:
464
875
 
465
876
  from viam.utils import create_filter
466
877
 
467
- my_filter = create_filter(component_name="left_motor")
878
+ my_filter = create_filter(component_name="left_motor", organization_ids=["<YOUR-ORG-ID>"])
879
+
468
880
  res = await data_client.delete_binary_data_by_filter(my_filter)
469
881
 
470
882
  Args:
471
- filter (viam.proto.app.data.Filter): Optional `Filter` specifying binary data to delete. Passing an empty `Filter` will lead to
472
- all data being deleted. Exercise caution when using this option.
883
+ filter (~viam.proto.app.data.Filter): Optional, specifies binary data to delete.
884
+ **CAUTION: Passing an empty** ``Filter`` **deletes all binary data!**
885
+ You must specify an organization ID with ``organization_ids`` when using this option.
886
+ To find your organization ID, visit the organization settings page.
473
887
 
474
888
  Returns:
475
889
  int: The number of items deleted.
476
890
 
477
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
891
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#deletebinarydatabyfilter>`_.
478
892
  """
479
893
  filter = filter if filter else Filter()
480
894
  request = DeleteBinaryDataByFilterRequest(filter=filter)
481
895
  response: DeleteBinaryDataByFilterResponse = await self._data_client.DeleteBinaryDataByFilter(request, metadata=self._metadata)
482
896
  return response.deleted_count
483
897
 
484
- async def delete_binary_data_by_ids(self, binary_ids: List[BinaryID]) -> int:
898
+ async def delete_binary_data_by_ids(self, binary_ids: Union[List[BinaryID], List[str]]) -> int:
485
899
  """Filter and delete binary data.
486
900
 
487
901
  ::
488
902
 
489
903
  from viam.proto.app.data import BinaryID
904
+ from viam.utils import create_filter
490
905
 
491
- binary_metadata = await data_client.binary_data_by_filter(
492
- include_file_data=False
906
+ my_filter = create_filter(component_name="camera-1", organization_ids=["<YOUR-ORG-ID>"])
907
+ binary_metadata, count, last = await data_client.binary_data_by_filter(
908
+ filter=my_filter,
909
+ limit=20,
910
+ include_binary_data=False
493
911
  )
494
912
 
495
913
  my_ids = []
496
914
 
497
915
  for obj in binary_metadata:
498
916
  my_ids.append(
499
- BinaryID(
500
- file_id=obj.metadata.id,
501
- organization_id=obj.metadata.capture_metadata.organization_id,
502
- location_id=obj.metadata.capture_metadata.location_id
503
- )
917
+ obj.metadata.binary_data_id
504
918
  )
505
919
 
506
920
  binary_data = await data_client.delete_binary_data_by_ids(my_ids)
507
921
 
508
922
  Args:
509
- binary_ids (List[viam.proto.app.data.BinaryID]): `BinaryID` objects specifying the data to be deleted. Must be non-empty.
923
+ binary_ids (Union[List[~viam.proto.app.data.BinaryID], List[str]]): Binary data ID strings specifying the data to be deleted or
924
+ :class:`BinaryID` objects. Must be non-empty.
925
+ *DEPRECATED:* :class:`BinaryID` *is deprecated and will be removed in a future release. Instead, pass binary data IDs as a
926
+ list of strings.*
510
927
 
511
928
  Raises:
512
- GRPCError: If no `BinaryID` objects are provided.
929
+ GRPCError: If no binary data ID strings or :class:`BinaryID` objects are provided.
513
930
 
514
931
  Returns:
515
932
  int: The number of items deleted.
516
933
 
517
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
934
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#deletebinarydatabyids>`_.
518
935
  """
519
- request = DeleteBinaryDataByIDsRequest(binary_ids=binary_ids)
936
+ request = DeleteBinaryDataByIDsRequest()
937
+ if len(binary_ids) > 0 and isinstance(binary_ids[0], str):
938
+ binary_data_ids = cast(List[str], binary_ids)
939
+ request = DeleteBinaryDataByIDsRequest(binary_data_ids=binary_data_ids)
940
+ else:
941
+ bin_ids = cast(List[BinaryID], binary_ids)
942
+ request = DeleteBinaryDataByIDsRequest(binary_ids=bin_ids)
520
943
  response: DeleteBinaryDataByIDsResponse = await self._data_client.DeleteBinaryDataByIDs(request, metadata=self._metadata)
521
944
  return response.deleted_count
522
945
 
523
- async def add_tags_to_binary_data_by_ids(self, tags: List[str], binary_ids: List[BinaryID]) -> None:
946
+ async def add_tags_to_binary_data_by_ids(self, tags: List[str], binary_ids: Union[List[BinaryID], List[str]]) -> None:
524
947
  """Add tags to binary data.
525
948
 
526
949
  ::
527
950
 
528
- from viam.proto.app.data import BinaryID
951
+ from viam.utils import create_filter
529
952
 
530
953
  tags = ["tag1", "tag2"]
531
954
 
532
- binary_metadata = await data_client.binary_data_by_filter(
533
- include_file_data=False
955
+ my_filter = create_filter(component_name="camera-1", organization_ids=["<YOUR-ORG-ID>"])
956
+ binary_metadata, count, last = await data_client.binary_data_by_filter(
957
+ filter=my_filter,
958
+ limit=20,
959
+ include_binary_data=False
534
960
  )
535
961
 
536
962
  my_ids = []
537
963
 
538
964
  for obj in binary_metadata:
539
965
  my_ids.append(
540
- BinaryID(
541
- file_id=obj.metadata.id,
542
- organization_id=obj.metadata.capture_metadata.organization_id,
543
- location_id=obj.metadata.capture_metadata.location_id
544
- )
966
+ obj.metadata.binary_data_id
545
967
  )
546
968
 
547
969
  binary_data = await data_client.add_tags_to_binary_data_by_ids(tags, my_ids)
548
970
 
549
971
  Args:
550
972
  tags (List[str]): List of tags to add to specified binary data. Must be non-empty.
551
- binary_ids (List[viam.app.proto.BinaryID]): List of `BinaryID` objects specifying binary data to tag. Must be non-empty.
973
+ binary_ids (Union[List[~viam.proto.app.data.BinaryID], List[str]]): Binary data ID strings specifying the data to be tagged or
974
+ :class:`BinaryID` objects. Must be non-empty.
975
+ *DEPRECATED:* :class:`BinaryID` *is deprecated and will be removed in a future release. Instead, pass binary data IDs as a
976
+ list of strings.*
552
977
 
553
978
  Raises:
554
- GRPCError: If no `BinaryID` objects or tags are provided.
979
+ GRPCError: If no binary data ID strings or :class:`BinaryID` objects are provided.
555
980
 
556
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
981
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#addtagstobinarydatabyids>`_.
557
982
  """
558
- request = AddTagsToBinaryDataByIDsRequest(binary_ids=binary_ids, tags=tags)
983
+ request = AddTagsToBinaryDataByIDsRequest()
984
+ if len(binary_ids) > 0 and isinstance(binary_ids[0], str):
985
+ binary_data_ids = cast(List[str], binary_ids)
986
+ request = AddTagsToBinaryDataByIDsRequest(binary_data_ids=binary_data_ids, tags=tags)
987
+ else:
988
+ bin_ids = cast(List[BinaryID], binary_ids)
989
+ request = AddTagsToBinaryDataByIDsRequest(binary_ids=bin_ids, tags=tags)
559
990
  await self._data_client.AddTagsToBinaryDataByIDs(request, metadata=self._metadata)
560
991
 
561
992
  async def add_tags_to_binary_data_by_filter(self, tags: List[str], filter: Optional[Filter] = None) -> None:
@@ -567,44 +998,43 @@ class DataClient:
567
998
 
568
999
  my_filter = create_filter(component_name="my_camera")
569
1000
  tags = ["tag1", "tag2"]
570
- res = await data_client.add_tags_to_binary_data_by_filter(tags, my_filter)
1001
+ await data_client.add_tags_to_binary_data_by_filter(tags, my_filter)
571
1002
 
572
1003
  Args:
573
1004
  tags (List[str]): List of tags to add to specified binary data. Must be non-empty.
574
- filter (viam.proto.app.data.Filter): `Filter` specifying binary data to tag. If no `Filter` is provided, all data will be
575
- tagged.
1005
+ filter (~viam.proto.app.data.Filter): Specifies binary data to tag. If none is provided, tags all data.
576
1006
 
577
1007
  Raises:
578
1008
  GRPCError: If no tags are provided.
579
1009
 
580
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1010
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#addtagstobinarydatabyfilter>`_.
581
1011
  """
582
1012
  filter = filter if filter else Filter()
583
1013
  request = AddTagsToBinaryDataByFilterRequest(filter=filter, tags=tags)
584
1014
  await self._data_client.AddTagsToBinaryDataByFilter(request, metadata=self._metadata)
585
1015
 
586
- async def remove_tags_from_binary_data_by_ids(self, tags: List[str], binary_ids: List[BinaryID]) -> int:
1016
+ async def remove_tags_from_binary_data_by_ids(self, tags: List[str], binary_ids: Union[List[BinaryID], List[str]]) -> int:
587
1017
  """Remove tags from binary data by IDs.
588
1018
 
589
1019
  ::
590
1020
 
591
- from viam.proto.app.data import BinaryID
1021
+ from viam.utils import create_filter
592
1022
 
593
1023
  tags = ["tag1", "tag2"]
594
1024
 
595
- binary_metadata = await data_client.binary_data_by_filter(
596
- include_file_data=False
1025
+ my_filter = create_filter(component_name="camera-1")
1026
+
1027
+ binary_metadata, count, last = await data_client.binary_data_by_filter(
1028
+ filter=my_filter,
1029
+ limit=50,
1030
+ include_binary_data=False
597
1031
  )
598
1032
 
599
1033
  my_ids = []
600
1034
 
601
1035
  for obj in binary_metadata:
602
1036
  my_ids.append(
603
- BinaryID(
604
- file_id=obj.metadata.id,
605
- organization_id=obj.metadata.capture_metadata.organization_id,
606
- location_id=obj.metadata.capture_metadata.location_id
607
- )
1037
+ obj.metadata.binary_data_id
608
1038
  )
609
1039
 
610
1040
  binary_data = await data_client.remove_tags_from_binary_data_by_ids(
@@ -612,17 +1042,26 @@ class DataClient:
612
1042
 
613
1043
  Args:
614
1044
  tags (List[str]): List of tags to remove from specified binary data. Must be non-empty.
615
- binary_ids (List[BinaryID]): List of `BinaryID` objects specifying binary data to untag. Must be non-empty.
1045
+ binary_ids (Union[List[~viam.proto.app.data.BinaryID], List[str]]): Binary data ID strings specifying the data to be untagged
1046
+ or `BinaryID` objects. Must be non-empty.
1047
+ *DEPRECATED:* :class:`BinaryID` *is deprecated and will be removed in a future release. Instead, pass binary data IDs as a
1048
+ list of strings.*
616
1049
 
617
1050
  Raises:
618
- GRPCError: If no binary_ids or tags are provided.
1051
+ GRPCError: If no binary data ID strings, :class:`BinaryID` objects, or tags are provided.
619
1052
 
620
1053
  Returns:
621
1054
  int: The number of tags removed.
622
1055
 
623
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1056
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#removetagsfrombinarydatabyids>`_.
624
1057
  """
625
- request = RemoveTagsFromBinaryDataByIDsRequest(binary_ids=binary_ids, tags=tags)
1058
+ request = RemoveTagsFromBinaryDataByIDsRequest(tags=tags)
1059
+ if len(binary_ids) > 0 and isinstance(binary_ids[0], str):
1060
+ binary_data_ids = cast(List[str], binary_ids)
1061
+ request = RemoveTagsFromBinaryDataByIDsRequest(binary_data_ids=binary_data_ids, tags=tags)
1062
+ else:
1063
+ bin_ids = cast(List[BinaryID], binary_ids)
1064
+ request = RemoveTagsFromBinaryDataByIDsRequest(binary_ids=bin_ids, tags=tags)
626
1065
  response: RemoveTagsFromBinaryDataByIDsResponse = await self._data_client.RemoveTagsFromBinaryDataByIDs(
627
1066
  request, metadata=self._metadata
628
1067
  )
@@ -641,8 +1080,7 @@ class DataClient:
641
1080
 
642
1081
  Args:
643
1082
  tags (List[str]): List of tags to remove from specified binary data.
644
- filter (viam.proto.app.data.Filter): `Filter` specifying binary data to untag. If no `Filter` is provided, all data will be
645
- untagged.
1083
+ filter (~viam.proto.app.data.Filter): Specifies binary data to untag. If none is provided, removes tags from all data.
646
1084
 
647
1085
  Raises:
648
1086
  GRPCError: If no tags are provided.
@@ -650,7 +1088,7 @@ class DataClient:
650
1088
  Returns:
651
1089
  int: The number of tags removed.
652
1090
 
653
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1091
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#removetagsfrombinarydatabyfilter>`_.
654
1092
  """
655
1093
  filter = filter if filter else Filter()
656
1094
  request = RemoveTagsFromBinaryDataByFilterRequest(filter=filter, tags=tags)
@@ -670,13 +1108,12 @@ class DataClient:
670
1108
  tags = await data_client.tags_by_filter(my_filter)
671
1109
 
672
1110
  Args:
673
- filter (viam.proto.app.data.Filter): `Filter` specifying data to retrieve from. If no `Filter` is provided, all data tags will
674
- return.
1111
+ filter (~viam.proto.app.data.Filter): Specifies subset ofdata to retrieve tags from. If none is provided, returns all tags.
675
1112
 
676
1113
  Returns:
677
1114
  List[str]: The list of tags.
678
1115
 
679
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1116
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#tagsbyfilter>`_.
680
1117
  """
681
1118
  filter = filter if filter else Filter()
682
1119
  request = TagsByFilterRequest(filter=filter)
@@ -685,7 +1122,7 @@ class DataClient:
685
1122
 
686
1123
  async def add_bounding_box_to_image_by_id(
687
1124
  self,
688
- binary_id: BinaryID,
1125
+ binary_id: Union[BinaryID, str],
689
1126
  label: str,
690
1127
  x_min_normalized: float,
691
1128
  y_min_normalized: float,
@@ -696,16 +1133,8 @@ class DataClient:
696
1133
 
697
1134
  ::
698
1135
 
699
- from viam.proto.app.data import BinaryID
700
-
701
- MY_BINARY_ID = BinaryID(
702
- file_id=your-file_id,
703
- organization_id=your-org-id,
704
- location_id=your-location-id
705
- )
706
-
707
- bbox_label = await data_client.add_bounding_box_to_image_by_id(
708
- binary_id=MY_BINARY_ID,
1136
+ bbox_id = await data_client.add_bounding_box_to_image_by_id(
1137
+ binary_id="<YOUR-BINARY-DATA-ID>",
709
1138
  label="label",
710
1139
  x_min_normalized=0,
711
1140
  y_min_normalized=.1,
@@ -713,10 +1142,12 @@ class DataClient:
713
1142
  y_max_normalized=.3
714
1143
  )
715
1144
 
716
- print(bbox_label)
1145
+ print(bbox_id)
717
1146
 
718
1147
  Args:
719
- binary_id (viam.proto.app.data.BinaryID): The ID of the image to add the bounding box to.
1148
+ binary_id (Union[~viam.proto.app.data.BinaryID, str]): The binary data ID or :class:`BinaryID` of the image to add the bounding
1149
+ box to. *DEPRECATED:* :class:`BinaryID` *is deprecated and will be removed in a future release. Instead, pass binary data IDs as a
1150
+ list of strings.*
720
1151
  label (str): A label for the bounding box.
721
1152
  x_min_normalized (float): Min X value of the bounding box normalized from 0 to 1.
722
1153
  y_min_normalized (float): Min Y value of the bounding box normalized from 0 to 1.
@@ -729,44 +1160,55 @@ class DataClient:
729
1160
  Returns:
730
1161
  str: The bounding box ID.
731
1162
 
732
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1163
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#addboundingboxtoimagebyid>`_.
733
1164
  """
734
- request = AddBoundingBoxToImageByIDRequest(
735
- label=label,
736
- binary_id=binary_id,
737
- x_max_normalized=x_max_normalized,
738
- x_min_normalized=x_min_normalized,
739
- y_max_normalized=y_max_normalized,
740
- y_min_normalized=y_min_normalized,
741
- )
1165
+ request = AddBoundingBoxToImageByIDRequest()
1166
+ if isinstance(binary_id, str):
1167
+ request = AddBoundingBoxToImageByIDRequest(
1168
+ binary_data_id=binary_id,
1169
+ label=label,
1170
+ x_max_normalized=x_max_normalized,
1171
+ x_min_normalized=x_min_normalized,
1172
+ y_max_normalized=y_max_normalized,
1173
+ y_min_normalized=y_min_normalized,
1174
+ )
1175
+ else:
1176
+ request = AddBoundingBoxToImageByIDRequest(
1177
+ binary_id=binary_id,
1178
+ label=label,
1179
+ x_max_normalized=x_max_normalized,
1180
+ x_min_normalized=x_min_normalized,
1181
+ y_max_normalized=y_max_normalized,
1182
+ y_min_normalized=y_min_normalized,
1183
+ )
742
1184
  response: AddBoundingBoxToImageByIDResponse = await self._data_client.AddBoundingBoxToImageByID(request, metadata=self._metadata)
743
1185
  return response.bbox_id
744
1186
 
745
- async def remove_bounding_box_from_image_by_id(self, bbox_id: str, binary_id: BinaryID) -> None:
1187
+ async def remove_bounding_box_from_image_by_id(self, bbox_id: str, binary_id: Union[BinaryID, str]) -> None:
746
1188
  """Removes a bounding box from an image.
747
1189
 
748
1190
  ::
749
1191
 
750
- from viam.proto.app.data import BinaryID
751
-
752
- MY_BINARY_ID = BinaryID(
753
- file_id=your-file_id,
754
- organization_id=your-org-id,
755
- location_id=your-location-id
756
- )
757
-
758
1192
  await data_client.remove_bounding_box_from_image_by_id(
759
- binary_id=MY_BINARY_ID,
1193
+ binary_id="<YOUR-BINARY-DATA-ID>",
760
1194
  bbox_id="your-bounding-box-id-to-delete"
761
1195
  )
762
1196
 
763
1197
  Args:
764
1198
  bbox_id (str): The ID of the bounding box to remove.
765
- binary_id (viam.proto.arr.data.BinaryID): Binary ID of the image to to remove the bounding box from.
1199
+ binary_id (Union[~viam.proto.app.data.BinaryID, str]): The binary data ID or :class:`BinaryID` of the image to remove the
1200
+ bounding box from.
1201
+ *DEPRECATED:* :class:`BinaryID` *is deprecated and will be removed in a future release. Instead, pass binary data IDs as a
1202
+ list of strings.*
766
1203
 
767
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1204
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#removeboundingboxfromimagebyid>`_.
768
1205
  """
769
- request = RemoveBoundingBoxFromImageByIDRequest(bbox_id=bbox_id, binary_id=binary_id)
1206
+ request = RemoveBoundingBoxFromImageByIDRequest()
1207
+ if isinstance(binary_id, str):
1208
+ request = RemoveBoundingBoxFromImageByIDRequest(binary_data_id=binary_id, bbox_id=bbox_id)
1209
+ else:
1210
+ request = RemoveBoundingBoxFromImageByIDRequest(binary_id=binary_id, bbox_id=bbox_id)
1211
+
770
1212
  await self._data_client.RemoveBoundingBoxFromImageByID(request, metadata=self._metadata)
771
1213
 
772
1214
  async def bounding_box_labels_by_filter(self, filter: Optional[Filter] = None) -> List[str]:
@@ -780,14 +1222,16 @@ class DataClient:
780
1222
  bounding_box_labels = await data_client.bounding_box_labels_by_filter(
781
1223
  my_filter)
782
1224
 
1225
+ print(bounding_box_labels)
1226
+
783
1227
  Args:
784
- filter (viam.proto.app.data.Filter): `Filter` specifying data to retrieve from. If no `Filter` is provided, all labels will
785
- return.
1228
+ filter (~viam.proto.app.data.Filter): Specifies data to retrieve bounding box labels from. If none is provided, returns labels
1229
+ from all data.
786
1230
 
787
1231
  Returns:
788
1232
  List[str]: The list of bounding box labels.
789
1233
 
790
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1234
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#boundingboxlabelsbyfilter>`_.
791
1235
  """
792
1236
  filter = filter if filter else Filter()
793
1237
  request = BoundingBoxLabelsByFilterRequest(filter=filter)
@@ -799,16 +1243,16 @@ class DataClient:
799
1243
 
800
1244
  ::
801
1245
 
802
- data_client.get_database_connection(org_id="a12b3c4e-1234-1abc-ab1c-ab1c2d345abc")
1246
+ hostname = await data_client.get_database_connection(organization_id="<YOUR-ORG-ID>")
803
1247
 
804
1248
  Args:
805
- organization_id (str): Organization to retrieve the connection for.
806
- You can obtain your organization ID from the Viam app's organization settings page.
1249
+ organization_id (str): The ID of the organization you'd like to connect to.
1250
+ To find your organization ID, visit the organization settings page.
807
1251
 
808
1252
  Returns:
809
1253
  str: The hostname of the federated database.
810
1254
 
811
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1255
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#getdatabaseconnection>`_.
812
1256
  """
813
1257
  request = GetDatabaseConnectionRequest(organization_id=organization_id)
814
1258
  response: GetDatabaseConnectionResponse = await self._data_client.GetDatabaseConnection(request, metadata=self._metadata)
@@ -821,16 +1265,16 @@ class DataClient:
821
1265
  ::
822
1266
 
823
1267
  await data_client.configure_database_user(
824
- organization_id="<your-org-id>",
825
- password="your_password"
1268
+ organization_id="<YOUR-ORG-ID>",
1269
+ password="Your_Password@1234"
826
1270
  )
827
1271
 
828
1272
  Args:
829
- organization_id (str): The ID of the organization.
830
- You can obtain your organization ID from the Viam app's organization settings page.
1273
+ organization_id (str): The ID of the organization you'd like to configure a database user for.
1274
+ To find your organization ID, visit the organization settings page.
831
1275
  password (str): The password of the user.
832
1276
 
833
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1277
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#configuredatabaseuser>`_.
834
1278
  """
835
1279
  request = ConfigureDatabaseUserRequest(organization_id=organization_id, password=password)
836
1280
  await self._data_client.ConfigureDatabaseUser(request, metadata=self._metadata)
@@ -840,45 +1284,74 @@ class DataClient:
840
1284
 
841
1285
  ::
842
1286
 
843
- name = await data_client.create_dataset(
844
- name="<dataset-name>",
845
- organization_id="<your-org-id>"
1287
+ dataset_id = await data_client.create_dataset(
1288
+ name="<DATASET-NAME>",
1289
+ organization_id="<YOUR-ORG-ID>"
846
1290
  )
847
- print(name)
1291
+ print(dataset_id)
848
1292
 
849
1293
  Args:
850
1294
  name (str): The name of the dataset being created.
851
1295
  organization_id (str): The ID of the organization where the dataset is being created.
852
- You can obtain your organization ID from the Viam app's organization settings page.
1296
+ To find your organization ID, visit the organization settings page.
853
1297
 
854
1298
  Returns:
855
1299
  str: The dataset ID of the created dataset.
856
1300
 
857
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1301
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#createdataset>`_.
858
1302
  """
859
1303
  request = CreateDatasetRequest(name=name, organization_id=organization_id)
860
1304
  response: CreateDatasetResponse = await self._dataset_client.CreateDataset(request, metadata=self._metadata)
861
1305
  return response.id
862
1306
 
1307
+ async def merge_datasets(self, name: str, organization_id: str, dataset_ids: List[str]) -> str:
1308
+ """Merge multiple datasets into a new dataset.
1309
+
1310
+ ::
1311
+
1312
+ dataset_id = await data_client.merge_datasets(
1313
+ name="<DATASET-NAME>",
1314
+ organization_id="<YOUR-ORG-ID>",
1315
+ dataset_ids=["<YOUR-DATASET-ID-1>", "<YOUR-DATASET-ID-2>"]
1316
+ )
1317
+ print(dataset_id)
1318
+
1319
+ Args:
1320
+ name (str): The name of the dataset being created.
1321
+ organization_id (str): The ID of the organization where the dataset is being created.
1322
+ To find your organization ID, visit the organization settings page.
1323
+ dataset_ids (List[str]): The IDs of the datasets that you would like to merge.
1324
+ Returns:
1325
+ str: The dataset ID of the created dataset.
1326
+
1327
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#mergedatasets>`_.
1328
+ """
1329
+ request = MergeDatasetsRequest(name=name, organization_id=organization_id, dataset_ids=dataset_ids)
1330
+ response: MergeDatasetsResponse = await self._dataset_client.MergeDatasets(request, metadata=self._metadata)
1331
+ return response.dataset_id
1332
+
863
1333
  async def list_dataset_by_ids(self, ids: List[str]) -> Sequence[Dataset]:
864
1334
  """Get a list of datasets using their IDs.
865
1335
 
866
1336
  ::
867
1337
 
868
1338
  datasets = await data_client.list_dataset_by_ids(
869
- ids=["abcd-1234xyz-8765z-123abc"]
1339
+ ids=["<YOUR-DATASET-ID-1>, <YOUR-DATASET-ID-2>"]
870
1340
  )
871
1341
  print(datasets)
872
1342
 
873
1343
  Args:
874
- ids (List[str]): The IDs of the datasets being called for. To retrieve these IDs,
875
- navigate to your dataset's page in the Viam app,
876
- click **...** in the left-hand menu, and click **Copy dataset ID**.
1344
+ ids (List[str]): The IDs of the datasets that you would like to retrieve information about. To retrieve a dataset ID:
1345
+
1346
+ - Navigate to the **DATASETS** tab of the **DATA** page.
1347
+ - Click on the dataset.
1348
+ - Click the **...** menu.
1349
+ - Select **Copy dataset ID**.
877
1350
 
878
1351
  Returns:
879
1352
  Sequence[Dataset]: The list of datasets.
880
1353
 
881
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1354
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#listdatasetsbyids>`_.
882
1355
  """
883
1356
  request = ListDatasetsByIDsRequest(ids=ids)
884
1357
  response: ListDatasetsByIDsResponse = await self._dataset_client.ListDatasetsByIDs(request, metadata=self._metadata)
@@ -890,19 +1363,19 @@ class DataClient:
890
1363
 
891
1364
  ::
892
1365
 
893
- datasets = await data_client.list_dataset_by_organization_id(
894
- organization_id=[""a12b3c4e-1234-1abc-ab1c-ab1c2d345abc""]
1366
+ datasets = await data_client.list_datasets_by_organization_id(
1367
+ organization_id="<YOUR-ORG-ID>"
895
1368
  )
896
1369
  print(datasets)
897
1370
 
898
1371
  Args:
899
- organization_id (str): The ID of the organization.
900
- You can obtain your organization ID from the Viam app's organization settings page.
1372
+ organization_id (str): The ID of the organization you'd like to retrieve datasets from.
1373
+ To find your organization ID, visit the organization settings page.
901
1374
 
902
1375
  Returns:
903
1376
  Sequence[Dataset]: The list of datasets in the organization.
904
1377
 
905
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1378
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#listdatasetsbyorganizationid>`_.
906
1379
  """
907
1380
  request = ListDatasetsByOrganizationIDRequest(organization_id=organization_id)
908
1381
  response: ListDatasetsByOrganizationIDResponse = await self._dataset_client.ListDatasetsByOrganizationID(
@@ -917,15 +1390,20 @@ class DataClient:
917
1390
  ::
918
1391
 
919
1392
  await data_client.rename_dataset(
920
- id="abcd-1234xyz-8765z-123abc",
921
- name="<dataset-name>"
1393
+ id="<YOUR-DATASET-ID>",
1394
+ name="MyDataset"
922
1395
  )
923
1396
 
924
1397
  Args:
925
- id (str): The ID of the dataset.
1398
+ id (str): The ID of the dataset. To retrieve the dataset ID:
1399
+
1400
+ - Navigate to the **DATASETS** tab of the **DATA** page.
1401
+ - Click on the dataset.
1402
+ - Click the **...** menu.
1403
+ - Select **Copy dataset ID**.
926
1404
  name (str): The new name of the dataset.
927
1405
 
928
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1406
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#renamedataset>`_.
929
1407
  """
930
1408
  request = RenameDatasetRequest(id=id, name=name)
931
1409
  await self._dataset_client.RenameDataset(request, metadata=self._metadata)
@@ -936,95 +1414,110 @@ class DataClient:
936
1414
  ::
937
1415
 
938
1416
  await data_client.delete_dataset(
939
- id="abcd-1234xyz-8765z-123abc"
1417
+ id="<YOUR-DATASET-ID>"
940
1418
  )
941
1419
 
942
1420
  Args:
943
- id (str): The ID of the dataset.
1421
+ id (str): The ID of the dataset. To retrieve the dataset ID:
944
1422
 
945
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1423
+ - Navigate to the **DATASETS** tab of the **DATA** page.
1424
+ - Click on the dataset.
1425
+ - Click the **...** menu.
1426
+ - Select **Copy dataset ID**.
1427
+
1428
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#deletedataset>`_.
946
1429
  """
947
1430
  request = DeleteDatasetRequest(id=id)
948
1431
  await self._dataset_client.DeleteDataset(request, metadata=self._metadata)
949
1432
 
950
- async def add_binary_data_to_dataset_by_ids(self, binary_ids: List[BinaryID], dataset_id: str) -> None:
1433
+ async def add_binary_data_to_dataset_by_ids(self, binary_ids: Union[List[BinaryID], List[str]], dataset_id: str) -> None:
951
1434
  """Add the BinaryData to the provided dataset.
952
1435
 
953
1436
  This BinaryData will be tagged with the VIAM_DATASET_{id} label.
954
1437
 
955
1438
  ::
956
1439
 
957
- from viam.proto.app.data import BinaryID
958
-
959
- binary_metadata = await data_client.binary_data_by_filter(
960
- include_file_data=False
1440
+ binary_metadata, count, last = await data_client.binary_data_by_filter(
1441
+ include_binary_data=False
961
1442
  )
962
1443
 
963
- my_binary_ids = []
1444
+ my_binary_data_ids = []
964
1445
 
965
1446
  for obj in binary_metadata:
966
- my_binary_ids.append(
967
- BinaryID(
968
- file_id=obj.metadata.id,
969
- organization_id=obj.metadata.capture_metadata.organization_id,
970
- location_id=obj.metadata.capture_metadata.location_id
971
- )
1447
+ my_binary_data_ids.append(
1448
+ obj.metadata.binary_data_id
972
1449
  )
973
1450
 
974
1451
  await data_client.add_binary_data_to_dataset_by_ids(
975
- binary_ids=my_binary_ids,
1452
+ binary_ids=my_binary_data_ids,
976
1453
  dataset_id="abcd-1234xyz-8765z-123abc"
977
1454
  )
978
1455
 
979
1456
  Args:
980
- binary_ids (List[BinaryID]): The IDs of binary data to add to dataset. To retrieve these IDs,
981
- navigate to your dataset's page in the Viam app,
982
- click **...** in the left-hand menu, and click **Copy dataset ID**.
983
- dataset_id (str): The ID of the dataset to be added to.
1457
+ binary_ids (List[~viam.proto.app.data.BinaryID]): Unique identifiers for binary data to add to the dataset. To retrieve these IDs,
1458
+ navigate to the DATA page, click on an image, and copy its Binary Data ID from the details tab.
1459
+ dataset_id (str): The ID of the dataset to be added to. To retrieve the dataset ID:
984
1460
 
985
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1461
+ - Navigate to the **DATASETS** tab of the **DATA** page.
1462
+ - Click on the dataset.
1463
+ - Click the **...** menu.
1464
+ - Select **Copy dataset ID**.
1465
+
1466
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#addbinarydatatodatasetbyids>`_.
986
1467
  """
987
- request = AddBinaryDataToDatasetByIDsRequest(binary_ids=binary_ids, dataset_id=dataset_id)
1468
+ request = AddBinaryDataToDatasetByIDsRequest()
1469
+ if len(binary_ids) > 0 and isinstance(binary_ids[0], str):
1470
+ binary_data_ids = cast(List[str], binary_ids)
1471
+ request = AddBinaryDataToDatasetByIDsRequest(binary_data_ids=binary_data_ids, dataset_id=dataset_id)
1472
+ else:
1473
+ bin_ids = cast(List[BinaryID], binary_ids)
1474
+ request = AddBinaryDataToDatasetByIDsRequest(binary_ids=bin_ids, dataset_id=dataset_id)
988
1475
  await self._data_client.AddBinaryDataToDatasetByIDs(request, metadata=self._metadata)
989
1476
 
990
- async def remove_binary_data_from_dataset_by_ids(self, binary_ids: List[BinaryID], dataset_id: str) -> None:
1477
+ async def remove_binary_data_from_dataset_by_ids(self, binary_ids: Union[List[BinaryID], List[str]], dataset_id: str) -> None:
991
1478
  """Remove the BinaryData from the provided dataset.
992
1479
 
993
1480
  This BinaryData will lose the VIAM_DATASET_{id} tag.
994
1481
 
995
1482
  ::
996
1483
 
997
- from viam.proto.app.data import BinaryID
998
-
999
- binary_metadata = await data_client.binary_data_by_filter(
1000
- include_file_data=False
1484
+ binary_metadata, count, last = await data_client.binary_data_by_filter(
1485
+ include_binary_data=False
1001
1486
  )
1002
1487
 
1003
- my_binary_ids = []
1488
+ my_binary_data_ids = []
1004
1489
 
1005
1490
  for obj in binary_metadata:
1006
- my_binary_ids.append(
1007
- BinaryID(
1008
- file_id=obj.metadata.id,
1009
- organization_id=obj.metadata.capture_metadata.organization_id,
1010
- location_id=obj.metadata.capture_metadata.location_id
1011
- )
1491
+ my_binary_data_ids.append(
1492
+ obj.metadata.binary_data_id
1012
1493
  )
1013
1494
 
1014
1495
  await data_client.remove_binary_data_from_dataset_by_ids(
1015
- binary_ids=my_binary_ids,
1496
+ binary_ids=my_binary_data_ids,
1016
1497
  dataset_id="abcd-1234xyz-8765z-123abc"
1017
1498
  )
1018
1499
 
1019
1500
  Args:
1020
- binary_ids (List[BinaryID]): The IDs of binary data to remove from dataset. To retrieve these IDs,
1021
- navigate to your dataset's page in the Viam app,
1022
- click **...** in the left-hand menu, and click **Copy dataset ID**.
1023
- dataset_id (str): The ID of the dataset to be removed from.
1024
-
1025
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1501
+ binary_ids (Union[List[~viam.proto.app.data.BinaryID], List[str]]): Unique identifiers for the binary data to remove from the dataset. To retrieve these IDs,
1502
+ navigate to the DATA page, click on an image and copy its Binary Data ID from the details tab.
1503
+ *DEPRECATED:* :class:`BinaryID` *is deprecated and will be removed in a future release. Instead, pass binary data IDs as a
1504
+ list of strings.*
1505
+ dataset_id (str): The ID of the dataset to be removed from. To retrieve the dataset ID:
1506
+
1507
+ - Navigate to the **DATASETS** tab of the **DATA** page.
1508
+ - Click on the dataset.
1509
+ - Click the **...** menu.
1510
+ - Select **Copy dataset ID**.
1511
+
1512
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#removebinarydatafromdatasetbyids>`_.
1026
1513
  """
1027
- request = RemoveBinaryDataFromDatasetByIDsRequest(binary_ids=binary_ids, dataset_id=dataset_id)
1514
+ request = RemoveBinaryDataFromDatasetByIDsRequest()
1515
+ if len(binary_ids) > 0 and isinstance(binary_ids[0], str):
1516
+ binary_data_ids = cast(List[str], binary_ids)
1517
+ request = RemoveBinaryDataFromDatasetByIDsRequest(binary_data_ids=binary_data_ids, dataset_id=dataset_id)
1518
+ else:
1519
+ bin_ids = cast(List[BinaryID], binary_ids)
1520
+ request = RemoveBinaryDataFromDatasetByIDsRequest(binary_ids=bin_ids, dataset_id=dataset_id)
1028
1521
  await self._data_client.RemoveBinaryDataFromDatasetByIDs(request, metadata=self._metadata)
1029
1522
 
1030
1523
  async def binary_data_capture_upload(
@@ -1037,12 +1530,13 @@ class DataClient:
1037
1530
  file_extension: str,
1038
1531
  method_parameters: Optional[Mapping[str, Any]] = None,
1039
1532
  tags: Optional[List[str]] = None,
1533
+ dataset_ids: Optional[List[str]] = None,
1040
1534
  data_request_times: Optional[Tuple[datetime, datetime]] = None,
1041
1535
  ) -> str:
1042
1536
  """Upload binary sensor data.
1043
1537
 
1044
- Upload binary data collected on a robot through a specific component (for example, a motor) along with the relevant metadata to
1045
- app.viam.com. Binary data can be found under the "Files" subtab of the Data tab on app.viam.com.
1538
+ Upload binary data collected on a robot through a specific component (for example, a motor), along with the relevant metadata.
1539
+ Binary data can be found on the **DATA** page.
1046
1540
 
1047
1541
  ::
1048
1542
 
@@ -1058,7 +1552,8 @@ class DataClient:
1058
1552
  tags=["tag_1", "tag_2"],
1059
1553
  data_request_times=[time_requested, time_received],
1060
1554
  file_extension=".jpg",
1061
- binary_data=b"Encoded image bytes"
1555
+ binary_data=b"Encoded image bytes",
1556
+ dataset_ids=["dataset_1", "dataset_2"]
1062
1557
  )
1063
1558
 
1064
1559
  Args:
@@ -1067,21 +1562,22 @@ class DataClient:
1067
1562
  component_type (str): Type of the component used to capture the data (for example, "movement_sensor").
1068
1563
  component_name (str): Name of the component used to capture the data.
1069
1564
  method_name (str): Name of the method used to capture the data.
1070
- file_extension (str): The file extension of binary data including the period, for example .jpg, .png, .pcd.
1071
- The backend will route the binary to its corresponding mime type based on this extension. Files with a .jpeg, .jpg,
1072
- or .png extension will be saved to the images tab.
1565
+ file_extension (str): The file extension of binary data, *including the period*, for example ``.jpg``, ``.png``, ``.pcd``.
1566
+ The backend routes the binary to its corresponding mime type based on this extension. Files with a ``.jpeg``, ``.jpg``,
1567
+ or ``.png`` extension will appear in the **Images** tab.
1073
1568
  method_parameters (Optional[Mapping[str, Any]]): Optional dictionary of method parameters. No longer in active use.
1074
1569
  tags (Optional[List[str]]): Optional list of tags to allow for tag-based data filtering when retrieving data.
1570
+ dataset_ids (Optional[List[str]]): Optional list of datasets to add the data to.
1075
1571
  data_request_times (Optional[Tuple[datetime.datetime, datetime.datetime]]): Optional tuple containing datetime objects
1076
- denoting the times this data was requested[0] by the robot and received[1] from the appropriate sensor.
1572
+ denoting the times this data was requested ``[0]`` by the robot and received ``[1]`` from the appropriate sensor.
1077
1573
 
1078
1574
  Raises:
1079
1575
  GRPCError: If an invalid part ID is passed.
1080
1576
 
1081
1577
  Returns:
1082
- str: The file_id of the uploaded data.
1578
+ str: The binary data ID of the uploaded data.
1083
1579
 
1084
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1580
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#binarydatacaptureupload>`_.
1085
1581
  """
1086
1582
  sensor_contents = SensorData(
1087
1583
  metadata=(
@@ -1103,11 +1599,12 @@ class DataClient:
1103
1599
  type=DataType.DATA_TYPE_BINARY_SENSOR,
1104
1600
  method_parameters=method_parameters,
1105
1601
  tags=tags,
1602
+ dataset_ids=dataset_ids,
1106
1603
  )
1107
1604
  if file_extension:
1108
1605
  metadata.file_extension = file_extension if file_extension[0] == "." else f".{file_extension}"
1109
1606
  response = await self._data_capture_upload(metadata=metadata, sensor_contents=[sensor_contents])
1110
- return response.file_id
1607
+ return response.binary_data_id
1111
1608
 
1112
1609
  async def tabular_data_capture_upload(
1113
1610
  self,
@@ -1116,57 +1613,62 @@ class DataClient:
1116
1613
  component_type: str,
1117
1614
  component_name: str,
1118
1615
  method_name: str,
1616
+ data_request_times: List[Tuple[datetime, datetime]],
1119
1617
  method_parameters: Optional[Mapping[str, Any]] = None,
1120
1618
  tags: Optional[List[str]] = None,
1121
- data_request_times: Optional[List[Tuple[datetime, datetime]]] = None,
1122
1619
  ) -> str:
1123
1620
  """Upload tabular sensor data.
1124
1621
 
1125
- Upload tabular data collected on a robot through a specific component (for example, a motor) along with the relevant metadata to
1126
- app.viam.com. Tabular data can be found under the "Sensors" subtab of the Data tab on app.viam.com.
1622
+ Upload tabular data collected on a robot through a specific component (for example, a motor), along with the relevant metadata.
1623
+ Tabular data can be found under the **Sensors** tab of the **DATA** page.
1127
1624
 
1128
1625
  ::
1129
1626
 
1627
+ from datetime import datetime
1628
+
1130
1629
  time_requested = datetime(2023, 6, 5, 11)
1131
1630
  time_received = datetime(2023, 6, 5, 11, 0, 3)
1132
-
1133
1631
  file_id = await data_client.tabular_data_capture_upload(
1134
1632
  part_id="INSERT YOUR PART ID",
1135
- component_type='motor',
1136
- component_name='left_motor',
1137
- method_name='IsPowered',
1138
- tags=["tag_1", "tag_2"],
1633
+ component_type='rdk:component:movement_sensor',
1634
+ component_name='my_movement_sensor',
1635
+ method_name='Readings',
1636
+ tags=["sensor_data"],
1139
1637
  data_request_times=[(time_requested, time_received)],
1140
- tabular_data=[{'PowerPCT': 0, 'IsPowered': False}]
1638
+ tabular_data=[{
1639
+ 'readings': {
1640
+ 'linear_velocity': {'x': 0.5, 'y': 0.0, 'z': 0.0},
1641
+ 'angular_velocity': {'x': 0.0, 'y': 0.0, 'z': 0.1}
1642
+ }
1643
+ }]
1141
1644
  )
1142
1645
 
1143
1646
  Args:
1144
1647
  tabular_data (List[Mapping[str, Any]]): List of the data to be uploaded, represented tabularly as a collection of dictionaries.
1648
+ Must include the key ``readings`` for sensors.
1145
1649
  part_id (str): Part ID of the component used to capture the data.
1146
- component_type (str): Type of the component used to capture the data (for example, "movement_sensor").
1650
+ component_type (str): Type of the component used to capture the data (for example, ``rdk:component:movement_sensor``).
1147
1651
  component_name (str): Name of the component used to capture the data.
1148
1652
  method_name (str): Name of the method used to capture the data.
1653
+ data_request_times (List[Tuple[datetime.datetime, datetime.datetime]]): List of tuples, each containing ``datetime`` objects
1654
+ denoting the times this data was requested ``[0]`` by the robot and received ``[1]`` from the appropriate sensor.
1655
+ Pass a list of tabular data and timestamps with length ``n > 1`` to upload ``n`` datapoints, all with the same metadata.
1149
1656
  method_parameters (Optional[Mapping[str, Any]]): Optional dictionary of method parameters. No longer in active use.
1150
1657
  tags (Optional[List[str]]): Optional list of tags to allow for tag-based data filtering when retrieving data.
1151
- data_request_times (Optional[List[Tuple[datetime.datetime, datetime.datetime]]]): Optional list of tuples, each containing
1152
- `datetime` objects denoting the times this data was requested[0] by the robot and received[1] from the appropriate sensor.
1153
- Passing a list of tabular data and Timestamps with length n > 1 will result in n datapoints being uploaded, all tied to the
1154
- same metadata.
1155
1658
 
1156
1659
  Raises:
1157
1660
  GRPCError: If an invalid part ID is passed.
1158
- ValueError: If a list of `Timestamp` objects is provided and its length does not match the length of the list of tabular
1661
+ ValueError: If the provided list of `Timestamp` objects has a length that does not match the length of the list of tabular
1159
1662
  data.
1160
1663
 
1161
1664
  Returns:
1162
- str: The file_id of the uploaded data.
1665
+ str: The file ID of the uploaded data.
1163
1666
 
1164
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1667
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#tabulardatacaptureupload>`_.
1165
1668
  """
1166
1669
  sensor_contents = []
1167
- if data_request_times:
1168
- if len(data_request_times) != len(tabular_data):
1169
- raise ValueError("data_request_times and tabular_data lengths must be equal.")
1670
+ if len(data_request_times) != len(tabular_data):
1671
+ raise ValueError("data_request_times and tabular_data lengths must be equal.")
1170
1672
 
1171
1673
  for idx, tab in enumerate(tabular_data):
1172
1674
  s = Struct()
@@ -1215,6 +1717,7 @@ class DataClient:
1215
1717
  method_parameters: Optional[Mapping[str, Any]] = None,
1216
1718
  data_request_times: Optional[Tuple[datetime, datetime]] = None,
1217
1719
  tags: Optional[List[str]] = None,
1720
+ dataset_ids: Optional[List[str]] = None,
1218
1721
  ) -> str:
1219
1722
  """Uploads the metadata and contents of streaming binary data.
1220
1723
 
@@ -1230,29 +1733,31 @@ class DataClient:
1230
1733
  component_type='motor',
1231
1734
  component_name='left_motor',
1232
1735
  method_name='IsPowered',
1233
- data_request_times=[(time_requested, time_received)],
1234
- tags=["tag_1", "tag_2"]
1736
+ data_request_times=[time_requested, time_received],
1737
+ tags=["tag_1", "tag_2"],
1738
+ dataset_ids=["dataset_1", "dataset_2"]
1235
1739
  )
1236
1740
 
1237
1741
  Args:
1238
- data (bytes): the data to be uploaded.
1742
+ data (bytes): The data to be uploaded.
1239
1743
  part_id (str): Part ID of the resource associated with the file.
1240
- file_ext (str): file extension type for the data. required for determining MIME type.
1744
+ file_ext (str): File extension type for the data. required for determining MIME type.
1241
1745
  component_type (Optional[str]): Optional type of the component associated with the file (for example, "movement_sensor").
1242
1746
  component_name (Optional[str]): Optional name of the component associated with the file.
1243
1747
  method_name (Optional[str]): Optional name of the method associated with the file.
1244
1748
  method_parameters (Optional[str]): Optional dictionary of the method parameters. No longer in active use.
1245
1749
  data_request_times (Optional[Tuple[datetime.datetime, datetime.datetime]]): Optional tuple containing datetime objects
1246
- denoting the times this data was requested[0] by the robot and received[1] from the appropriate sensor.
1750
+ denoting the times this data was requested ``[0]`` by the robot and received ``[1]`` from the appropriate sensor.
1247
1751
  tags (Optional[List[str]]): Optional list of tags to allow for tag-based filtering when retrieving data.
1752
+ dataset_ids (Optional[List[str]]): Optional list of datasets to add the data to.
1248
1753
 
1249
1754
  Raises:
1250
1755
  GRPCError: If an invalid part ID is passed.
1251
1756
 
1252
1757
  Returns:
1253
- str: The file_id of the uploaded data.
1758
+ str: The binary data ID of the uploaded data.
1254
1759
 
1255
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1760
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#streamingdatacaptureupload>`_.
1256
1761
  """
1257
1762
 
1258
1763
  upload_metadata = UploadMetadata(
@@ -1264,6 +1769,7 @@ class DataClient:
1264
1769
  type=DataType.DATA_TYPE_BINARY_SENSOR,
1265
1770
  file_extension=file_ext if file_ext[0] == "." else f".{file_ext}",
1266
1771
  tags=tags,
1772
+ dataset_ids=dataset_ids,
1267
1773
  )
1268
1774
  sensor_metadata = SensorMetadata(
1269
1775
  time_requested=datetime_to_timestamp(data_request_times[0]) if data_request_times else None,
@@ -1279,7 +1785,7 @@ class DataClient:
1279
1785
  if not response:
1280
1786
  await stream.recv_trailing_metadata() # causes us to throw appropriate gRPC error
1281
1787
  raise TypeError("Response cannot be empty")
1282
- return response.file_id
1788
+ return response.binary_data_id
1283
1789
 
1284
1790
  async def file_upload(
1285
1791
  self,
@@ -1292,11 +1798,12 @@ class DataClient:
1292
1798
  method_parameters: Optional[Mapping[str, Any]] = None,
1293
1799
  file_extension: Optional[str] = None,
1294
1800
  tags: Optional[List[str]] = None,
1801
+ dataset_ids: Optional[List[str]] = None,
1295
1802
  ) -> str:
1296
1803
  """Upload arbitrary file data.
1297
1804
 
1298
- Upload file data that may be stored on a robot along with the relevant metadata to app.viam.com. File data can be found under the
1299
- "Files" subtab of the Data tab on app.viam.com.
1805
+ Upload file data that may be stored on a robot along with the relevant metadata. File data can be found in the
1806
+ **Files** tab of the **DATA** page.
1300
1807
 
1301
1808
  ::
1302
1809
 
@@ -1305,7 +1812,8 @@ class DataClient:
1305
1812
  part_id="INSERT YOUR PART ID",
1306
1813
  tags=["tag_1", "tag_2"],
1307
1814
  file_name="your-file",
1308
- file_extension=".txt"
1815
+ file_extension=".txt",
1816
+ dataset_ids=["dataset_1", "dataset_2"]
1309
1817
  )
1310
1818
 
1311
1819
  Args:
@@ -1314,20 +1822,21 @@ class DataClient:
1314
1822
  component_type (Optional[str]): Optional type of the component associated with the file (for example, "movement_sensor").
1315
1823
  component_name (Optional[str]): Optional name of the component associated with the file.
1316
1824
  method_name (Optional[str]): Optional name of the method associated with the file.
1317
- file_name (Optional[str]): Optional name of the file. The empty string "" will be assigned as the file name if one isn't
1825
+ file_name (Optional[str]): Optional name of the file. The empty string ``""`` will be assigned as the file name if one isn't
1318
1826
  provided.
1319
1827
  method_parameters (Optional[str]): Optional dictionary of the method parameters. No longer in active use.
1320
- file_extension (Optional[str]): Optional file extension. The empty string "" will be assigned as the file extension if one isn't
1321
- provided. Files with a .jpeg, .jpg, or .png extension will be saved to the images tab.
1828
+ file_extension (Optional[str]): Optional file extension. The empty string ``""`` will be assigned as the file extension if one
1829
+ isn't provided. Files with a ``.jpeg``, ``.jpg``, or ``.png`` extension will be saved to the **Images** tab.
1322
1830
  tags (Optional[List[str]]): Optional list of tags to allow for tag-based filtering when retrieving data.
1831
+ dataset_ids (Optional[List[str]]): Optional list of datasets to add the data to.
1323
1832
 
1324
1833
  Raises:
1325
1834
  GRPCError: If an invalid part ID is passed.
1326
1835
 
1327
1836
  Returns:
1328
- str: ID of the new file.
1837
+ str: Binary data ID of the new file.
1329
1838
 
1330
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1839
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#fileupload>`_.
1331
1840
  """
1332
1841
  metadata = UploadMetadata(
1333
1842
  part_id=part_id,
@@ -1339,9 +1848,10 @@ class DataClient:
1339
1848
  method_parameters=method_parameters,
1340
1849
  file_extension=file_extension if file_extension else "",
1341
1850
  tags=tags,
1851
+ dataset_ids=dataset_ids,
1342
1852
  )
1343
1853
  response: FileUploadResponse = await self._file_upload(metadata=metadata, file_contents=FileData(data=data))
1344
- return response.file_id
1854
+ return response.binary_data_id
1345
1855
 
1346
1856
  async def file_upload_from_path(
1347
1857
  self,
@@ -1352,17 +1862,19 @@ class DataClient:
1352
1862
  method_name: Optional[str] = None,
1353
1863
  method_parameters: Optional[Mapping[str, Any]] = None,
1354
1864
  tags: Optional[List[str]] = None,
1865
+ dataset_ids: Optional[List[str]] = None,
1355
1866
  ) -> str:
1356
1867
  """Upload arbitrary file data.
1357
1868
 
1358
- Upload file data that may be stored on a robot along with the relevant metadata to app.viam.com. File data can be found under the
1359
- "Files" subtab of the Data tab on app.viam.com.
1869
+ Upload file data that may be stored on a robot along with the relevant metadata. File data can be found in the
1870
+ **Files** tab of the **DATA** page.
1360
1871
 
1361
1872
  ::
1362
1873
 
1363
1874
  file_id = await data_client.file_upload_from_path(
1364
1875
  part_id="INSERT YOUR PART ID",
1365
1876
  tags=["tag_1", "tag_2"],
1877
+ dataset_ids=["dataset_1", "dataset_2"],
1366
1878
  filepath="/Users/<your-username>/<your-directory>/<your-file.txt>"
1367
1879
  )
1368
1880
 
@@ -1374,23 +1886,22 @@ class DataClient:
1374
1886
  method_name (Optional[str]): Optional name of the method associated with the file.
1375
1887
  method_parameters (Optional[str]): Optional dictionary of the method parameters. No longer in active use.
1376
1888
  tags (Optional[List[str]]): Optional list of tags to allow for tag-based filtering when retrieving data.
1377
-
1889
+ dataset_ids (Optional[List[str]]): Optional list of datasets to add the data to.
1378
1890
 
1379
1891
  Raises:
1380
1892
  GRPCError: If an invalid part ID is passed.
1381
1893
  FileNotFoundError: If the provided filepath is not found.
1382
1894
 
1383
1895
  Returns:
1384
- str: ID of the new file.
1896
+ str: Binary data ID of the new file.
1385
1897
 
1386
- For more information, see `Data Client API <https://docs.viam.com/appendix/apis/data-client/>`_.
1898
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#fileuploadfrompath>`_.
1387
1899
  """
1388
1900
  path = Path(filepath)
1389
1901
  file_name = path.stem
1390
1902
  file_extension = path.suffix if path.suffix != "" else None
1391
- f = open(filepath, "rb")
1392
- data = f.read()
1393
- f.close()
1903
+ with open(filepath, "rb") as f:
1904
+ data = f.read()
1394
1905
 
1395
1906
  metadata = UploadMetadata(
1396
1907
  part_id=part_id,
@@ -1402,9 +1913,10 @@ class DataClient:
1402
1913
  method_parameters=method_parameters,
1403
1914
  file_extension=file_extension if file_extension else "",
1404
1915
  tags=tags,
1916
+ dataset_ids=dataset_ids,
1405
1917
  )
1406
1918
  response: FileUploadResponse = await self._file_upload(metadata=metadata, file_contents=FileData(data=data if data else bytes()))
1407
- return response.file_id
1919
+ return response.binary_data_id
1408
1920
 
1409
1921
  async def _file_upload(self, metadata: UploadMetadata, file_contents: FileData) -> FileUploadResponse:
1410
1922
  request_metadata = FileUploadRequest(metadata=metadata)
@@ -1419,6 +1931,265 @@ class DataClient:
1419
1931
  raise TypeError("Response cannot be empty")
1420
1932
  return response
1421
1933
 
1934
+ async def get_data_pipeline(self, id: str) -> DataPipeline:
1935
+ """Get a data pipeline by its ID.
1936
+
1937
+ ::
1938
+
1939
+ data_pipeline = await data_client.get_data_pipeline(id="<YOUR-DATA-PIPELINE-ID>")
1940
+
1941
+ Args:
1942
+ id (str): The ID of the data pipeline to get.
1943
+
1944
+ Returns:
1945
+ DataPipeline: The data pipeline with the given ID.
1946
+ """
1947
+ request = GetDataPipelineRequest(id=id)
1948
+ response: GetDataPipelineResponse = await self._data_pipelines_client.GetDataPipeline(request, metadata=self._metadata)
1949
+ return DataClient.DataPipeline.from_proto(response.data_pipeline)
1950
+
1951
+ async def list_data_pipelines(self, organization_id: str) -> List[DataPipeline]:
1952
+ """List all of the data pipelines for an organization.
1953
+
1954
+ ::
1955
+
1956
+ data_pipelines = await data_client.list_data_pipelines(organization_id="<YOUR-ORGANIZATION-ID>")
1957
+
1958
+ Args:
1959
+ organization_id (str): The ID of the organization that owns the pipelines.
1960
+ You can obtain your organization ID from the organization settings page.
1961
+
1962
+ Returns:
1963
+ List[DataPipeline]: A list of all of the data pipelines for the given organization.
1964
+ """
1965
+ request = ListDataPipelinesRequest(organization_id=organization_id)
1966
+ response: ListDataPipelinesResponse = await self._data_pipelines_client.ListDataPipelines(request, metadata=self._metadata)
1967
+ return [DataClient.DataPipeline.from_proto(pipeline) for pipeline in response.data_pipelines]
1968
+
1969
+ async def create_data_pipeline(
1970
+ self,
1971
+ organization_id: str,
1972
+ name: str,
1973
+ mql_binary: List[Dict[str, Any]],
1974
+ schedule: str,
1975
+ enable_backfill: bool,
1976
+ data_source_type: TabularDataSourceType.ValueType = TabularDataSourceType.TABULAR_DATA_SOURCE_TYPE_STANDARD,
1977
+ ) -> str:
1978
+ """Create a new data pipeline.
1979
+
1980
+ ::
1981
+
1982
+ data_pipeline_id = await data_client.create_data_pipeline(
1983
+ organization_id="<YOUR-ORGANIZATION-ID>",
1984
+ name="<YOUR-PIPELINE-NAME>",
1985
+ mql_binary=[<YOUR-MQL-PIPELINE-AGGREGATION>],
1986
+ schedule="<YOUR-SCHEDULE>",
1987
+ enable_backfill=False,
1988
+ data_source_type=TabularDataSourceType.TABULAR_DATA_SOURCE_TYPE_STANDARD,
1989
+ )
1990
+
1991
+ Args:
1992
+ organization_id (str): The ID of the organization that will own the pipeline.
1993
+ You can obtain your organization ID from the organization settings page.
1994
+ name (str): The name of the pipeline.
1995
+ mql_binary (List[Dict[str, Any]]):The MQL pipeline to run, as a list of MongoDB aggregation pipeline stages.
1996
+ schedule (str): A cron expression representing the expected execution schedule in UTC (note this also
1997
+ defines the input time window; an hourly schedule would process 1 hour of data at a time).
1998
+ enable_backfill (bool): When true, pipeline runs will be scheduled for the organization's past data.
1999
+ data_source_type (TabularDataSourceType): The type of data source to use for the pipeline.
2000
+ Defaults to TabularDataSourceType.TABULAR_DATA_SOURCE_TYPE_STANDARD.
2001
+
2002
+ Returns:
2003
+ str: The ID of the newly created pipeline.
2004
+ """
2005
+ binary: List[bytes] = [bson.encode(query) for query in mql_binary]
2006
+ request = CreateDataPipelineRequest(
2007
+ organization_id=organization_id,
2008
+ name=name,
2009
+ mql_binary=binary,
2010
+ schedule=schedule,
2011
+ enable_backfill=enable_backfill,
2012
+ data_source_type=data_source_type,
2013
+ )
2014
+ response: CreateDataPipelineResponse = await self._data_pipelines_client.CreateDataPipeline(request, metadata=self._metadata)
2015
+ return response.id
2016
+
2017
+ async def rename_data_pipeline(self, id: str, name: str) -> None:
2018
+ """Rename a data pipeline by its ID.
2019
+ ::
2020
+
2021
+ await data_client.rename_data_pipeline(id="<YOUR-DATA-PIPELINE-ID>", name="<YOUR-NEW-NAME>")
2022
+
2023
+ Args:
2024
+ id (str): The ID of the data pipeline to rename.
2025
+ name (str): The new name of the data pipeline.
2026
+ """
2027
+ if not id or not name:
2028
+ raise ValueError("id and name are required")
2029
+ request = RenameDataPipelineRequest(id=id, name=name)
2030
+ await self._data_pipelines_client.RenameDataPipeline(request, metadata=self._metadata)
2031
+
2032
+ async def delete_data_pipeline(self, id: str) -> None:
2033
+ """Delete a data pipeline by its ID.
2034
+
2035
+ ::
2036
+
2037
+ await data_client.delete_data_pipeline(id="<YOUR-DATA-PIPELINE-ID>")
2038
+
2039
+ Args:
2040
+ id (str): The ID of the data pipeline to delete.
2041
+ """
2042
+ request = DeleteDataPipelineRequest(id=id)
2043
+ await self._data_pipelines_client.DeleteDataPipeline(request, metadata=self._metadata)
2044
+
2045
+ async def list_data_pipeline_runs(self, id: str, page_size: int = 10) -> DataPipelineRunsPage:
2046
+ """List all of the data pipeline runs for a data pipeline.
2047
+
2048
+ ::
2049
+
2050
+ data_pipeline_runs = await data_client.list_data_pipeline_runs(id="<YOUR-DATA-PIPELINE-ID>")
2051
+ while len(data_pipeline_runs.runs) > 0:
2052
+ data_pipeline_runs = await data_pipeline_runs.next_page()
2053
+
2054
+ Args:
2055
+ id (str): The ID of the pipeline to list runs for
2056
+ page_size (int): The number of runs to return per page. Defaults to 10.
2057
+
2058
+ Returns:
2059
+ DataPipelineRunsPage: A page of data pipeline runs with pagination support
2060
+ """
2061
+ return await self._list_data_pipeline_runs(id, page_size)
2062
+
2063
+ async def _list_data_pipeline_runs(self, id: str, page_size: int, page_token: str = "") -> DataPipelineRunsPage:
2064
+ """Internal method to list data pipeline runs with pagination.
2065
+
2066
+ Args:
2067
+ id (str): The ID of the pipeline to list runs for
2068
+ page_size (int): The number of runs to return per page
2069
+ page_token (str): The token to use to get the next page of results
2070
+
2071
+ Returns:
2072
+ DataPipelineRunsPage: A page of data pipeline runs with pagination support
2073
+ """
2074
+ request = ListDataPipelineRunsRequest(id=id, page_size=page_size, page_token=page_token)
2075
+ response: ListDataPipelineRunsResponse = await self._data_pipelines_client.ListDataPipelineRuns(request, metadata=self._metadata)
2076
+ return DataClient.DataPipelineRunsPage.from_proto(response, self, page_size)
2077
+
2078
+ async def create_index(
2079
+ self,
2080
+ organization_id: str,
2081
+ collection_type: IndexableCollection.ValueType,
2082
+ index_spec: Dict[str, Any],
2083
+ pipeline_name: Optional[str] = None,
2084
+ ) -> None:
2085
+ """Starts a custom index build.
2086
+
2087
+ Args:
2088
+ organization_id (str): The ID of the organization that owns the data.
2089
+ To find your organization ID, visit the organization settings page.
2090
+ collection_type (IndexableCollection.ValueType): The type of collection the index is on.
2091
+ index_spec (List[Dict[str, Any]]): The MongoDB index specification defined in JSON format.
2092
+ pipeline_name (Optional[str]): The name of the pipeline if the collection type is PIPELINE_SINK.
2093
+
2094
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#createindex>`_.
2095
+ """
2096
+ index_spec_bytes = [bson.encode(index_spec)]
2097
+ request = CreateIndexRequest(
2098
+ organization_id=organization_id,
2099
+ collection_type=collection_type,
2100
+ index_spec=index_spec_bytes,
2101
+ pipeline_name=pipeline_name,
2102
+ )
2103
+ await self._data_client.CreateIndex(request, metadata=self._metadata)
2104
+
2105
+ async def list_indexes(
2106
+ self,
2107
+ organization_id: str,
2108
+ collection_type: IndexableCollection.ValueType,
2109
+ pipeline_name: Optional[str] = None,
2110
+ ) -> Sequence[Index]:
2111
+ """Returns all the indexes for a given collection.
2112
+
2113
+ Args:
2114
+ organization_id (str): The ID of the organization that owns the data.
2115
+ To find your organization ID, visit the organization settings page.
2116
+ collection_type (IndexableCollection.ValueType): The type of collection the index is on.
2117
+ pipeline_name (Optional[str]): The name of the pipeline if the collection type is PIPELINE_SINK.
2118
+
2119
+ Returns:
2120
+ List[Index]: A list of indexes.
2121
+
2122
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#listindexes>`_.
2123
+ """
2124
+ request = ListIndexesRequest(
2125
+ organization_id=organization_id,
2126
+ collection_type=collection_type,
2127
+ pipeline_name=pipeline_name,
2128
+ )
2129
+ response: ListIndexesResponse = await self._data_client.ListIndexes(request, metadata=self._metadata)
2130
+ return response.indexes
2131
+
2132
+ async def delete_index(
2133
+ self,
2134
+ organization_id: str,
2135
+ collection_type: IndexableCollection.ValueType,
2136
+ index_name: str,
2137
+ pipeline_name: Optional[str] = None,
2138
+ ) -> None:
2139
+ """Drops the specified custom index from a collection.
2140
+
2141
+ Args:
2142
+ organization_id (str): The ID of the organization that owns the data.
2143
+ To find your organization ID, visit the organization settings page.
2144
+ collection_type (IndexableCollection.ValueType): The type of collection the index is on.
2145
+ index_name (str): The name of the index to delete.
2146
+ pipeline_name (Optional[str]): The name of the pipeline if the collection type is PIPELINE_SINK.
2147
+
2148
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#deleteindex>`_.
2149
+ """
2150
+ request = DeleteIndexRequest(
2151
+ organization_id=organization_id,
2152
+ collection_type=collection_type,
2153
+ index_name=index_name,
2154
+ pipeline_name=pipeline_name,
2155
+ )
2156
+ await self._data_client.DeleteIndex(request, metadata=self._metadata)
2157
+
2158
+ async def create_binary_data_signed_url(
2159
+ self,
2160
+ binary_data_id: str,
2161
+ expiration_minutes: Optional[int] = None,
2162
+ ) -> Tuple[str, datetime]:
2163
+ """Create a signed URL for binary data.
2164
+
2165
+ ::
2166
+
2167
+ signed_url, expires_at = await data_client.create_binary_data_signed_url(
2168
+ binary_data_id="<YOUR-BINARY-DATA-ID>",
2169
+ expiration_minutes=60
2170
+ )
2171
+
2172
+ print(f"Signed URL: {signed_url}")
2173
+ print(f"Expires at: {expires_at}")
2174
+
2175
+ Args:
2176
+ binary_data_id (str): The binary data ID of the file to create a signed URL for.
2177
+ expiration_minutes (Optional[int]): Expiration time in minutes. Defaults to 15 minutes if not specified.
2178
+ Maximum allowed is 10080 minutes (7 days).
2179
+
2180
+ Returns:
2181
+ Tuple[str, datetime]: A tuple containing:
2182
+ - ``signed_url`` (*str*): The signed URL for the binary data file.
2183
+ - ``expires_at`` (*datetime*): The expiration time of the signed URL token.
2184
+
2185
+ For more information, see `Data Client API <https://docs.viam.com/dev/reference/apis/data-client/#createbinarydatasignedurl>`_.
2186
+ """
2187
+ request = CreateBinaryDataSignedURLRequest(binary_data_id=binary_data_id)
2188
+ if expiration_minutes is not None:
2189
+ request.expiration_minutes = expiration_minutes
2190
+ response: CreateBinaryDataSignedURLResponse = await self._data_client.CreateBinaryDataSignedURL(request, metadata=self._metadata)
2191
+ return response.signed_url, response.expires_at.ToDatetime()
2192
+
1422
2193
  @staticmethod
1423
2194
  def create_filter(
1424
2195
  component_name: Optional[str] = None,