viam-sdk 0.45.2__py3-none-win_amd64.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.

Potentially problematic release.


This version of viam-sdk might be problematic. Click here for more details.

Files changed (476) hide show
  1. viam/__init__.py +71 -0
  2. viam/app/__init__.py +0 -0
  3. viam/app/_logs.py +34 -0
  4. viam/app/app_client.py +2525 -0
  5. viam/app/billing_client.py +143 -0
  6. viam/app/data_client.py +1715 -0
  7. viam/app/ml_training_client.py +251 -0
  8. viam/app/provisioning_client.py +95 -0
  9. viam/app/viam_client.py +260 -0
  10. viam/components/__init__.py +0 -0
  11. viam/components/arm/__init__.py +16 -0
  12. viam/components/arm/arm.py +223 -0
  13. viam/components/arm/client.py +124 -0
  14. viam/components/arm/service.py +123 -0
  15. viam/components/audio_input/__init__.py +18 -0
  16. viam/components/audio_input/audio_input.py +81 -0
  17. viam/components/audio_input/client.py +70 -0
  18. viam/components/audio_input/service.py +114 -0
  19. viam/components/base/__init__.py +13 -0
  20. viam/components/base/base.py +260 -0
  21. viam/components/base/client.py +153 -0
  22. viam/components/base/service.py +138 -0
  23. viam/components/board/__init__.py +9 -0
  24. viam/components/board/board.py +414 -0
  25. viam/components/board/client.py +241 -0
  26. viam/components/board/service.py +223 -0
  27. viam/components/button/__init__.py +10 -0
  28. viam/components/button/button.py +41 -0
  29. viam/components/button/client.py +52 -0
  30. viam/components/button/service.py +46 -0
  31. viam/components/camera/__init__.py +22 -0
  32. viam/components/camera/camera.py +138 -0
  33. viam/components/camera/client.py +98 -0
  34. viam/components/camera/service.py +105 -0
  35. viam/components/component_base.py +65 -0
  36. viam/components/encoder/__init__.py +18 -0
  37. viam/components/encoder/client.py +83 -0
  38. viam/components/encoder/encoder.py +118 -0
  39. viam/components/encoder/service.py +72 -0
  40. viam/components/gantry/__init__.py +11 -0
  41. viam/components/gantry/client.py +115 -0
  42. viam/components/gantry/gantry.py +156 -0
  43. viam/components/gantry/service.py +113 -0
  44. viam/components/generic/__init__.py +18 -0
  45. viam/components/generic/client.py +62 -0
  46. viam/components/generic/generic.py +76 -0
  47. viam/components/generic/service.py +40 -0
  48. viam/components/gripper/__init__.py +11 -0
  49. viam/components/gripper/client.py +85 -0
  50. viam/components/gripper/gripper.py +114 -0
  51. viam/components/gripper/service.py +81 -0
  52. viam/components/input/__init__.py +15 -0
  53. viam/components/input/client.py +194 -0
  54. viam/components/input/input.py +297 -0
  55. viam/components/input/service.py +175 -0
  56. viam/components/motor/__init__.py +11 -0
  57. viam/components/motor/client.py +168 -0
  58. viam/components/motor/motor.py +301 -0
  59. viam/components/motor/service.py +150 -0
  60. viam/components/movement_sensor/__init__.py +21 -0
  61. viam/components/movement_sensor/client.py +161 -0
  62. viam/components/movement_sensor/movement_sensor.py +253 -0
  63. viam/components/movement_sensor/service.py +146 -0
  64. viam/components/pose_tracker/__init__.py +17 -0
  65. viam/components/pose_tracker/client.py +50 -0
  66. viam/components/pose_tracker/pose_tracker.py +40 -0
  67. viam/components/pose_tracker/service.py +45 -0
  68. viam/components/power_sensor/__init__.py +17 -0
  69. viam/components/power_sensor/client.py +86 -0
  70. viam/components/power_sensor/power_sensor.py +104 -0
  71. viam/components/power_sensor/service.py +72 -0
  72. viam/components/sensor/__init__.py +18 -0
  73. viam/components/sensor/client.py +49 -0
  74. viam/components/sensor/sensor.py +48 -0
  75. viam/components/sensor/service.py +51 -0
  76. viam/components/servo/__init__.py +11 -0
  77. viam/components/servo/client.py +86 -0
  78. viam/components/servo/service.py +80 -0
  79. viam/components/servo/servo.py +114 -0
  80. viam/components/switch/__init__.py +10 -0
  81. viam/components/switch/client.py +83 -0
  82. viam/components/switch/service.py +72 -0
  83. viam/components/switch/switch.py +95 -0
  84. viam/errors.py +105 -0
  85. viam/gen/__init__.py +0 -0
  86. viam/gen/app/__init__.py +0 -0
  87. viam/gen/app/agent/__init__.py +0 -0
  88. viam/gen/app/agent/v1/__init__.py +0 -0
  89. viam/gen/app/agent/v1/agent_grpc.py +29 -0
  90. viam/gen/app/agent/v1/agent_pb2.py +47 -0
  91. viam/gen/app/agent/v1/agent_pb2.pyi +280 -0
  92. viam/gen/app/cloudslam/__init__.py +0 -0
  93. viam/gen/app/cloudslam/v1/__init__.py +0 -0
  94. viam/gen/app/cloudslam/v1/cloud_slam_grpc.py +70 -0
  95. viam/gen/app/cloudslam/v1/cloud_slam_pb2.py +54 -0
  96. viam/gen/app/cloudslam/v1/cloud_slam_pb2.pyi +384 -0
  97. viam/gen/app/data/__init__.py +0 -0
  98. viam/gen/app/data/v1/__init__.py +0 -0
  99. viam/gen/app/data/v1/data_grpc.py +206 -0
  100. viam/gen/app/data/v1/data_pb2.py +178 -0
  101. viam/gen/app/data/v1/data_pb2.pyi +1485 -0
  102. viam/gen/app/datapipelines/__init__.py +0 -0
  103. viam/gen/app/datapipelines/v1/__init__.py +0 -0
  104. viam/gen/app/datapipelines/v1/data_pipelines_grpc.py +84 -0
  105. viam/gen/app/datapipelines/v1/data_pipelines_pb2.py +56 -0
  106. viam/gen/app/datapipelines/v1/data_pipelines_pb2.pyi +370 -0
  107. viam/gen/app/dataset/__init__.py +0 -0
  108. viam/gen/app/dataset/v1/__init__.py +0 -0
  109. viam/gen/app/dataset/v1/dataset_grpc.py +60 -0
  110. viam/gen/app/dataset/v1/dataset_pb2.py +40 -0
  111. viam/gen/app/dataset/v1/dataset_pb2.pyi +179 -0
  112. viam/gen/app/datasync/__init__.py +0 -0
  113. viam/gen/app/datasync/v1/__init__.py +0 -0
  114. viam/gen/app/datasync/v1/data_sync_grpc.py +47 -0
  115. viam/gen/app/datasync/v1/data_sync_pb2.py +70 -0
  116. viam/gen/app/datasync/v1/data_sync_pb2.pyi +425 -0
  117. viam/gen/app/mlinference/__init__.py +0 -0
  118. viam/gen/app/mlinference/v1/__init__.py +0 -0
  119. viam/gen/app/mlinference/v1/ml_inference_grpc.py +28 -0
  120. viam/gen/app/mlinference/v1/ml_inference_pb2.py +23 -0
  121. viam/gen/app/mlinference/v1/ml_inference_pb2.pyi +63 -0
  122. viam/gen/app/mltraining/__init__.py +0 -0
  123. viam/gen/app/mltraining/v1/__init__.py +0 -0
  124. viam/gen/app/mltraining/v1/ml_training_grpc.py +78 -0
  125. viam/gen/app/mltraining/v1/ml_training_pb2.py +124 -0
  126. viam/gen/app/mltraining/v1/ml_training_pb2.pyi +415 -0
  127. viam/gen/app/packages/__init__.py +0 -0
  128. viam/gen/app/packages/v1/__init__.py +0 -0
  129. viam/gen/app/packages/v1/packages_grpc.py +54 -0
  130. viam/gen/app/packages/v1/packages_pb2.py +52 -0
  131. viam/gen/app/packages/v1/packages_pb2.pyi +311 -0
  132. viam/gen/app/v1/__init__.py +0 -0
  133. viam/gen/app/v1/app_grpc.py +863 -0
  134. viam/gen/app/v1/app_pb2.py +649 -0
  135. viam/gen/app/v1/app_pb2.pyi +5279 -0
  136. viam/gen/app/v1/billing_grpc.py +76 -0
  137. viam/gen/app/v1/billing_pb2.py +92 -0
  138. viam/gen/app/v1/billing_pb2.pyi +463 -0
  139. viam/gen/app/v1/end_user_grpc.py +59 -0
  140. viam/gen/app/v1/end_user_pb2.py +55 -0
  141. viam/gen/app/v1/end_user_pb2.pyi +181 -0
  142. viam/gen/app/v1/robot_grpc.py +55 -0
  143. viam/gen/app/v1/robot_pb2.py +127 -0
  144. viam/gen/app/v1/robot_pb2.pyi +1202 -0
  145. viam/gen/common/__init__.py +0 -0
  146. viam/gen/common/v1/__init__.py +0 -0
  147. viam/gen/common/v1/common_grpc.py +0 -0
  148. viam/gen/common/v1/common_pb2.py +78 -0
  149. viam/gen/common/v1/common_pb2.pyi +687 -0
  150. viam/gen/component/__init__.py +0 -0
  151. viam/gen/component/arm/__init__.py +0 -0
  152. viam/gen/component/arm/v1/__init__.py +0 -0
  153. viam/gen/component/arm/v1/arm_grpc.py +102 -0
  154. viam/gen/component/arm/v1/arm_pb2.py +74 -0
  155. viam/gen/component/arm/v1/arm_pb2.pyi +344 -0
  156. viam/gen/component/audioinput/__init__.py +0 -0
  157. viam/gen/component/audioinput/v1/__init__.py +0 -0
  158. viam/gen/component/audioinput/v1/audioinput_grpc.py +63 -0
  159. viam/gen/component/audioinput/v1/audioinput_pb2.py +45 -0
  160. viam/gen/component/audioinput/v1/audioinput_pb2.pyi +179 -0
  161. viam/gen/component/base/__init__.py +0 -0
  162. viam/gen/component/base/v1/__init__.py +0 -0
  163. viam/gen/component/base/v1/base_grpc.py +94 -0
  164. viam/gen/component/base/v1/base_pb2.py +66 -0
  165. viam/gen/component/base/v1/base_pb2.pyi +258 -0
  166. viam/gen/component/board/__init__.py +0 -0
  167. viam/gen/component/board/v1/__init__.py +0 -0
  168. viam/gen/component/board/v1/board_grpc.py +127 -0
  169. viam/gen/component/board/v1/board_pb2.py +103 -0
  170. viam/gen/component/board/v1/board_pb2.pyi +496 -0
  171. viam/gen/component/button/__init__.py +0 -0
  172. viam/gen/component/button/v1/__init__.py +0 -0
  173. viam/gen/component/button/v1/button_grpc.py +38 -0
  174. viam/gen/component/button/v1/button_pb2.py +28 -0
  175. viam/gen/component/button/v1/button_pb2.pyi +39 -0
  176. viam/gen/component/camera/__init__.py +0 -0
  177. viam/gen/component/camera/v1/__init__.py +0 -0
  178. viam/gen/component/camera/v1/camera_grpc.py +79 -0
  179. viam/gen/component/camera/v1/camera_pb2.py +67 -0
  180. viam/gen/component/camera/v1/camera_pb2.pyi +373 -0
  181. viam/gen/component/encoder/__init__.py +0 -0
  182. viam/gen/component/encoder/v1/__init__.py +0 -0
  183. viam/gen/component/encoder/v1/encoder_grpc.py +62 -0
  184. viam/gen/component/encoder/v1/encoder_pb2.py +44 -0
  185. viam/gen/component/encoder/v1/encoder_pb2.pyi +147 -0
  186. viam/gen/component/gantry/__init__.py +0 -0
  187. viam/gen/component/gantry/v1/__init__.py +0 -0
  188. viam/gen/component/gantry/v1/gantry_grpc.py +86 -0
  189. viam/gen/component/gantry/v1/gantry_pb2.py +62 -0
  190. viam/gen/component/gantry/v1/gantry_pb2.pyi +239 -0
  191. viam/gen/component/generic/__init__.py +0 -0
  192. viam/gen/component/generic/v1/__init__.py +0 -0
  193. viam/gen/component/generic/v1/generic_grpc.py +37 -0
  194. viam/gen/component/generic/v1/generic_pb2.py +23 -0
  195. viam/gen/component/generic/v1/generic_pb2.pyi +6 -0
  196. viam/gen/component/gripper/__init__.py +0 -0
  197. viam/gen/component/gripper/v1/__init__.py +0 -0
  198. viam/gen/component/gripper/v1/gripper_grpc.py +70 -0
  199. viam/gen/component/gripper/v1/gripper_pb2.py +48 -0
  200. viam/gen/component/gripper/v1/gripper_pb2.pyi +137 -0
  201. viam/gen/component/inputcontroller/__init__.py +0 -0
  202. viam/gen/component/inputcontroller/v1/__init__.py +0 -0
  203. viam/gen/component/inputcontroller/v1/input_controller_grpc.py +71 -0
  204. viam/gen/component/inputcontroller/v1/input_controller_pb2.py +55 -0
  205. viam/gen/component/inputcontroller/v1/input_controller_pb2.pyi +243 -0
  206. viam/gen/component/motor/__init__.py +0 -0
  207. viam/gen/component/motor/v1/__init__.py +0 -0
  208. viam/gen/component/motor/v1/motor_grpc.py +118 -0
  209. viam/gen/component/motor/v1/motor_pb2.py +86 -0
  210. viam/gen/component/motor/v1/motor_pb2.pyi +368 -0
  211. viam/gen/component/movementsensor/__init__.py +0 -0
  212. viam/gen/component/movementsensor/v1/__init__.py +0 -0
  213. viam/gen/component/movementsensor/v1/movementsensor_grpc.py +110 -0
  214. viam/gen/component/movementsensor/v1/movementsensor_pb2.py +78 -0
  215. viam/gen/component/movementsensor/v1/movementsensor_pb2.pyi +384 -0
  216. viam/gen/component/posetracker/__init__.py +0 -0
  217. viam/gen/component/posetracker/v1/__init__.py +0 -0
  218. viam/gen/component/posetracker/v1/pose_tracker_grpc.py +46 -0
  219. viam/gen/component/posetracker/v1/pose_tracker_pb2.py +34 -0
  220. viam/gen/component/posetracker/v1/pose_tracker_pb2.pyi +79 -0
  221. viam/gen/component/powersensor/__init__.py +0 -0
  222. viam/gen/component/powersensor/v1/__init__.py +0 -0
  223. viam/gen/component/powersensor/v1/powersensor_grpc.py +62 -0
  224. viam/gen/component/powersensor/v1/powersensor_pb2.py +42 -0
  225. viam/gen/component/powersensor/v1/powersensor_pb2.pyi +124 -0
  226. viam/gen/component/sensor/__init__.py +0 -0
  227. viam/gen/component/sensor/v1/__init__.py +0 -0
  228. viam/gen/component/sensor/v1/sensor_grpc.py +45 -0
  229. viam/gen/component/sensor/v1/sensor_pb2.py +25 -0
  230. viam/gen/component/sensor/v1/sensor_pb2.pyi +6 -0
  231. viam/gen/component/servo/__init__.py +0 -0
  232. viam/gen/component/servo/v1/__init__.py +0 -0
  233. viam/gen/component/servo/v1/servo_grpc.py +70 -0
  234. viam/gen/component/servo/v1/servo_pb2.py +50 -0
  235. viam/gen/component/servo/v1/servo_pb2.pyi +150 -0
  236. viam/gen/component/switch/__init__.py +0 -0
  237. viam/gen/component/switch/v1/__init__.py +0 -0
  238. viam/gen/component/switch/v1/switch_grpc.py +54 -0
  239. viam/gen/component/switch/v1/switch_pb2.py +40 -0
  240. viam/gen/component/switch/v1/switch_pb2.pyi +109 -0
  241. viam/gen/component/testecho/__init__.py +0 -0
  242. viam/gen/component/testecho/v1/__init__.py +0 -0
  243. viam/gen/component/testecho/v1/testecho_grpc.py +52 -0
  244. viam/gen/component/testecho/v1/testecho_pb2.py +36 -0
  245. viam/gen/component/testecho/v1/testecho_pb2.pyi +114 -0
  246. viam/gen/module/__init__.py +0 -0
  247. viam/gen/module/v1/__init__.py +0 -0
  248. viam/gen/module/v1/module_grpc.py +61 -0
  249. viam/gen/module/v1/module_pb2.py +43 -0
  250. viam/gen/module/v1/module_pb2.pyi +211 -0
  251. viam/gen/proto/__init__.py +0 -0
  252. viam/gen/proto/rpc/__init__.py +0 -0
  253. viam/gen/proto/rpc/examples/__init__.py +0 -0
  254. viam/gen/proto/rpc/examples/echo/__init__.py +0 -0
  255. viam/gen/proto/rpc/examples/echo/v1/__init__.py +0 -0
  256. viam/gen/proto/rpc/examples/echo/v1/echo_grpc.py +44 -0
  257. viam/gen/proto/rpc/examples/echo/v1/echo_pb2.py +32 -0
  258. viam/gen/proto/rpc/examples/echo/v1/echo_pb2.pyi +87 -0
  259. viam/gen/proto/rpc/examples/echoresource/__init__.py +0 -0
  260. viam/gen/proto/rpc/examples/echoresource/v1/__init__.py +0 -0
  261. viam/gen/proto/rpc/examples/echoresource/v1/echoresource_grpc.py +43 -0
  262. viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.py +29 -0
  263. viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.pyi +93 -0
  264. viam/gen/proto/rpc/v1/__init__.py +0 -0
  265. viam/gen/proto/rpc/v1/auth_grpc.py +47 -0
  266. viam/gen/proto/rpc/v1/auth_pb2.py +34 -0
  267. viam/gen/proto/rpc/v1/auth_pb2.pyi +92 -0
  268. viam/gen/proto/rpc/webrtc/__init__.py +0 -0
  269. viam/gen/proto/rpc/webrtc/v1/__init__.py +0 -0
  270. viam/gen/proto/rpc/webrtc/v1/grpc_grpc.py +0 -0
  271. viam/gen/proto/rpc/webrtc/v1/grpc_pb2.py +43 -0
  272. viam/gen/proto/rpc/webrtc/v1/grpc_pb2.pyi +304 -0
  273. viam/gen/proto/rpc/webrtc/v1/signaling_grpc.py +54 -0
  274. viam/gen/proto/rpc/webrtc/v1/signaling_pb2.py +70 -0
  275. viam/gen/proto/rpc/webrtc/v1/signaling_pb2.pyi +496 -0
  276. viam/gen/provisioning/__init__.py +0 -0
  277. viam/gen/provisioning/v1/__init__.py +0 -0
  278. viam/gen/provisioning/v1/provisioning_grpc.py +51 -0
  279. viam/gen/provisioning/v1/provisioning_pb2.py +39 -0
  280. viam/gen/provisioning/v1/provisioning_pb2.pyi +188 -0
  281. viam/gen/robot/__init__.py +0 -0
  282. viam/gen/robot/v1/__init__.py +0 -0
  283. viam/gen/robot/v1/robot_grpc.py +208 -0
  284. viam/gen/robot/v1/robot_pb2.py +188 -0
  285. viam/gen/robot/v1/robot_pb2.pyi +1020 -0
  286. viam/gen/service/__init__.py +0 -0
  287. viam/gen/service/datamanager/__init__.py +0 -0
  288. viam/gen/service/datamanager/v1/__init__.py +0 -0
  289. viam/gen/service/datamanager/v1/data_manager_grpc.py +38 -0
  290. viam/gen/service/datamanager/v1/data_manager_pb2.py +28 -0
  291. viam/gen/service/datamanager/v1/data_manager_pb2.pyi +39 -0
  292. viam/gen/service/discovery/__init__.py +0 -0
  293. viam/gen/service/discovery/v1/__init__.py +0 -0
  294. viam/gen/service/discovery/v1/discovery_grpc.py +39 -0
  295. viam/gen/service/discovery/v1/discovery_pb2.py +29 -0
  296. viam/gen/service/discovery/v1/discovery_pb2.pyi +51 -0
  297. viam/gen/service/generic/__init__.py +0 -0
  298. viam/gen/service/generic/v1/__init__.py +0 -0
  299. viam/gen/service/generic/v1/generic_grpc.py +29 -0
  300. viam/gen/service/generic/v1/generic_pb2.py +21 -0
  301. viam/gen/service/generic/v1/generic_pb2.pyi +6 -0
  302. viam/gen/service/mlmodel/__init__.py +0 -0
  303. viam/gen/service/mlmodel/v1/__init__.py +0 -0
  304. viam/gen/service/mlmodel/v1/mlmodel_grpc.py +37 -0
  305. viam/gen/service/mlmodel/v1/mlmodel_pb2.py +83 -0
  306. viam/gen/service/mlmodel/v1/mlmodel_pb2.pyi +480 -0
  307. viam/gen/service/motion/__init__.py +0 -0
  308. viam/gen/service/motion/v1/__init__.py +0 -0
  309. viam/gen/service/motion/v1/motion_grpc.py +87 -0
  310. viam/gen/service/motion/v1/motion_pb2.py +97 -0
  311. viam/gen/service/motion/v1/motion_pb2.pyi +838 -0
  312. viam/gen/service/navigation/__init__.py +0 -0
  313. viam/gen/service/navigation/v1/__init__.py +0 -0
  314. viam/gen/service/navigation/v1/navigation_grpc.py +102 -0
  315. viam/gen/service/navigation/v1/navigation_pb2.py +84 -0
  316. viam/gen/service/navigation/v1/navigation_pb2.pyi +419 -0
  317. viam/gen/service/sensors/__init__.py +0 -0
  318. viam/gen/service/sensors/v1/__init__.py +0 -0
  319. viam/gen/service/sensors/v1/sensors_grpc.py +46 -0
  320. viam/gen/service/sensors/v1/sensors_pb2.py +68 -0
  321. viam/gen/service/sensors/v1/sensors_pb2.pyi +137 -0
  322. viam/gen/service/shell/__init__.py +0 -0
  323. viam/gen/service/shell/v1/__init__.py +0 -0
  324. viam/gen/service/shell/v1/shell_grpc.py +55 -0
  325. viam/gen/service/shell/v1/shell_pb2.py +45 -0
  326. viam/gen/service/shell/v1/shell_pb2.pyi +307 -0
  327. viam/gen/service/slam/__init__.py +0 -0
  328. viam/gen/service/slam/v1/__init__.py +0 -0
  329. viam/gen/service/slam/v1/slam_grpc.py +61 -0
  330. viam/gen/service/slam/v1/slam_pb2.py +51 -0
  331. viam/gen/service/slam/v1/slam_pb2.pyi +213 -0
  332. viam/gen/service/vision/__init__.py +0 -0
  333. viam/gen/service/vision/v1/__init__.py +0 -0
  334. viam/gen/service/vision/v1/vision_grpc.py +87 -0
  335. viam/gen/service/vision/v1/vision_pb2.py +69 -0
  336. viam/gen/service/vision/v1/vision_pb2.pyi +454 -0
  337. viam/gen/stream/__init__.py +0 -0
  338. viam/gen/stream/v1/__init__.py +0 -0
  339. viam/gen/stream/v1/stream_grpc.py +59 -0
  340. viam/gen/stream/v1/stream_pb2.py +39 -0
  341. viam/gen/stream/v1/stream_pb2.pyi +161 -0
  342. viam/gen/tagger/__init__.py +0 -0
  343. viam/gen/tagger/v1/__init__.py +0 -0
  344. viam/gen/tagger/v1/tagger_grpc.py +0 -0
  345. viam/gen/tagger/v1/tagger_pb2.py +16 -0
  346. viam/gen/tagger/v1/tagger_pb2.pyi +15 -0
  347. viam/logging.py +216 -0
  348. viam/media/__init__.py +0 -0
  349. viam/media/audio.py +16 -0
  350. viam/media/utils/__init__.py +0 -0
  351. viam/media/utils/pil/__init__.py +51 -0
  352. viam/media/utils/pil/viam_rgba_plugin.py +73 -0
  353. viam/media/viam_rgba.py +10 -0
  354. viam/media/video.py +217 -0
  355. viam/module/__init__.py +5 -0
  356. viam/module/module.py +281 -0
  357. viam/module/service.py +66 -0
  358. viam/module/types.py +23 -0
  359. viam/operations.py +124 -0
  360. viam/proto/__init__.py +0 -0
  361. viam/proto/app/__init__.py +554 -0
  362. viam/proto/app/agent/__init__.py +28 -0
  363. viam/proto/app/billing.py +58 -0
  364. viam/proto/app/cloudslam/__init__.py +48 -0
  365. viam/proto/app/data/__init__.py +138 -0
  366. viam/proto/app/datapipelines/__init__.py +56 -0
  367. viam/proto/app/dataset/__init__.py +36 -0
  368. viam/proto/app/datasync/__init__.py +44 -0
  369. viam/proto/app/end_user.py +34 -0
  370. viam/proto/app/mlinference/__init__.py +15 -0
  371. viam/proto/app/mltraining/__init__.py +52 -0
  372. viam/proto/app/packages/__init__.py +38 -0
  373. viam/proto/app/robot.py +84 -0
  374. viam/proto/common/__init__.py +66 -0
  375. viam/proto/component/__init__.py +0 -0
  376. viam/proto/component/arm/__init__.py +48 -0
  377. viam/proto/component/audioinput/__init__.py +30 -0
  378. viam/proto/component/base/__init__.py +42 -0
  379. viam/proto/component/board/__init__.py +62 -0
  380. viam/proto/component/button/__init__.py +15 -0
  381. viam/proto/component/camera/__init__.py +46 -0
  382. viam/proto/component/encoder/__init__.py +28 -0
  383. viam/proto/component/gantry/__init__.py +40 -0
  384. viam/proto/component/generic/__init__.py +12 -0
  385. viam/proto/component/gripper/__init__.py +30 -0
  386. viam/proto/component/inputcontroller/__init__.py +38 -0
  387. viam/proto/component/motor/__init__.py +56 -0
  388. viam/proto/component/movementsensor/__init__.py +50 -0
  389. viam/proto/component/posetracker/__init__.py +19 -0
  390. viam/proto/component/powersensor/__init__.py +30 -0
  391. viam/proto/component/sensor/__init__.py +12 -0
  392. viam/proto/component/servo/__init__.py +32 -0
  393. viam/proto/component/switch/__init__.py +26 -0
  394. viam/proto/component/testecho/__init__.py +30 -0
  395. viam/proto/module/__init__.py +38 -0
  396. viam/proto/provisioning/__init__.py +36 -0
  397. viam/proto/robot/__init__.py +130 -0
  398. viam/proto/rpc/__init__.py +0 -0
  399. viam/proto/rpc/auth.py +34 -0
  400. viam/proto/rpc/examples/__init__.py +0 -0
  401. viam/proto/rpc/examples/echo/__init__.py +26 -0
  402. viam/proto/rpc/examples/echoresource/__init__.py +30 -0
  403. viam/proto/rpc/webrtc/__init__.py +0 -0
  404. viam/proto/rpc/webrtc/grpc.py +36 -0
  405. viam/proto/rpc/webrtc/signaling.py +58 -0
  406. viam/proto/service/__init__.py +0 -0
  407. viam/proto/service/datamanager/__init__.py +19 -0
  408. viam/proto/service/discovery/__init__.py +15 -0
  409. viam/proto/service/generic/__init__.py +12 -0
  410. viam/proto/service/mlmodel/__init__.py +54 -0
  411. viam/proto/service/motion/__init__.py +68 -0
  412. viam/proto/service/navigation/__init__.py +58 -0
  413. viam/proto/service/sensors/__init__.py +18 -0
  414. viam/proto/service/shell/__init__.py +36 -0
  415. viam/proto/service/slam/__init__.py +36 -0
  416. viam/proto/service/vision/__init__.py +46 -0
  417. viam/proto/stream/__init__.py +36 -0
  418. viam/proto/tagger/__init__.py +6 -0
  419. viam/py.typed +0 -0
  420. viam/resource/__init__.py +0 -0
  421. viam/resource/base.py +123 -0
  422. viam/resource/easy_resource.py +153 -0
  423. viam/resource/manager.py +126 -0
  424. viam/resource/registry.py +199 -0
  425. viam/resource/rpc_client_base.py +65 -0
  426. viam/resource/rpc_service_base.py +48 -0
  427. viam/resource/types.py +213 -0
  428. viam/robot/__init__.py +0 -0
  429. viam/robot/client.py +909 -0
  430. viam/robot/service.py +69 -0
  431. viam/rpc/__init__.py +0 -0
  432. viam/rpc/dial.py +420 -0
  433. viam/rpc/libviam_rust_utils.dll +0 -0
  434. viam/rpc/server.py +201 -0
  435. viam/rpc/signaling.py +29 -0
  436. viam/rpc/types.py +22 -0
  437. viam/services/__init__.py +0 -0
  438. viam/services/discovery/__init__.py +12 -0
  439. viam/services/discovery/client.py +55 -0
  440. viam/services/discovery/discovery.py +52 -0
  441. viam/services/discovery/service.py +43 -0
  442. viam/services/generic/__init__.py +18 -0
  443. viam/services/generic/client.py +58 -0
  444. viam/services/generic/generic.py +58 -0
  445. viam/services/generic/service.py +29 -0
  446. viam/services/mlmodel/__init__.py +24 -0
  447. viam/services/mlmodel/client.py +37 -0
  448. viam/services/mlmodel/mlmodel.py +78 -0
  449. viam/services/mlmodel/service.py +38 -0
  450. viam/services/mlmodel/utils.py +101 -0
  451. viam/services/motion/__init__.py +17 -0
  452. viam/services/motion/client.py +215 -0
  453. viam/services/motion/motion.py +378 -0
  454. viam/services/motion/service.py +132 -0
  455. viam/services/navigation/__init__.py +11 -0
  456. viam/services/navigation/client.py +99 -0
  457. viam/services/navigation/navigation.py +250 -0
  458. viam/services/navigation/service.py +137 -0
  459. viam/services/service_base.py +78 -0
  460. viam/services/service_client_base.py +46 -0
  461. viam/services/slam/__init__.py +17 -0
  462. viam/services/slam/client.py +62 -0
  463. viam/services/slam/service.py +75 -0
  464. viam/services/slam/slam.py +111 -0
  465. viam/services/vision/__init__.py +15 -0
  466. viam/services/vision/client.py +206 -0
  467. viam/services/vision/service.py +146 -0
  468. viam/services/vision/vision.py +315 -0
  469. viam/sessions_client.py +245 -0
  470. viam/streams.py +44 -0
  471. viam/utils.py +365 -0
  472. viam/version_metadata.py +4 -0
  473. viam_sdk-0.45.2.dist-info/METADATA +157 -0
  474. viam_sdk-0.45.2.dist-info/RECORD +476 -0
  475. viam_sdk-0.45.2.dist-info/WHEEL +4 -0
  476. viam_sdk-0.45.2.dist-info/licenses/LICENSE +202 -0
viam/media/video.py ADDED
@@ -0,0 +1,217 @@
1
+ from array import array
2
+ from enum import Enum
3
+ from typing import List, Optional, Tuple
4
+
5
+ from typing_extensions import Self
6
+
7
+ from viam.errors import NotSupportedError
8
+ from viam.proto.component.camera import Format
9
+
10
+ from .viam_rgba import RGBA_HEADER_LENGTH, RGBA_MAGIC_NUMBER
11
+
12
+
13
+ class CameraMimeType(str, Enum):
14
+ VIAM_RGBA = "image/vnd.viam.rgba"
15
+ VIAM_RAW_DEPTH = "image/vnd.viam.dep"
16
+ JPEG = "image/jpeg"
17
+ PNG = "image/png"
18
+ PCD = "pointcloud/pcd"
19
+
20
+ @classmethod
21
+ def from_string(cls, value: str) -> Self:
22
+ """Return the mimetype from a string.
23
+
24
+ Args:
25
+ value (str): The mimetype as a string
26
+
27
+ Returns:
28
+ Self: The mimetype
29
+ """
30
+ value_mime = value[:-5] if value.endswith("+lazy") else value # ViamImage lazy encodes by default
31
+ return cls(value_mime)
32
+
33
+ @classmethod
34
+ def from_proto(cls, format: Format.ValueType) -> "CameraMimeType":
35
+ """Returns the mimetype from a proto enum.
36
+
37
+ Args:
38
+ format (Format.ValueType): The mimetype in a proto enum.
39
+
40
+ Returns:
41
+ Self: The mimetype.
42
+ """
43
+ mimetypes = {
44
+ Format.FORMAT_RAW_RGBA: CameraMimeType.VIAM_RGBA,
45
+ Format.FORMAT_RAW_DEPTH: CameraMimeType.VIAM_RAW_DEPTH,
46
+ Format.FORMAT_JPEG: CameraMimeType.JPEG,
47
+ Format.FORMAT_PNG: CameraMimeType.PNG,
48
+ }
49
+ return mimetypes.get(format, CameraMimeType.JPEG)
50
+
51
+ def to_proto(self) -> Format.ValueType:
52
+ """Returns the mimetype in a proto enum.
53
+
54
+ Returns:
55
+ Format.ValueType: The mimetype in a proto enum.
56
+ """
57
+ formats = {
58
+ self.VIAM_RGBA: Format.FORMAT_RAW_RGBA,
59
+ self.VIAM_RAW_DEPTH: Format.FORMAT_RAW_DEPTH,
60
+ self.JPEG: Format.FORMAT_JPEG,
61
+ self.PNG: Format.FORMAT_PNG,
62
+ }
63
+ return formats.get(self, Format.FORMAT_UNSPECIFIED)
64
+
65
+
66
+ class ViamImage:
67
+ """A native implementation of an image.
68
+
69
+ Provides the raw data and the mime type.
70
+ """
71
+
72
+ _data: bytes
73
+ _mime_type: CameraMimeType
74
+ _height: Optional[int] = None
75
+ _width: Optional[int] = None
76
+
77
+ def __init__(self, data: bytes, mime_type: CameraMimeType) -> None:
78
+ self._data = data
79
+ self._mime_type = mime_type
80
+ self._width, self._height = _getDimensions(data, mime_type)
81
+
82
+ @property
83
+ def data(self) -> bytes:
84
+ """The raw bytes of the image"""
85
+ return self._data
86
+
87
+ @property
88
+ def mime_type(self) -> CameraMimeType:
89
+ """The mime type of the image"""
90
+ return self._mime_type
91
+
92
+ @property
93
+ def width(self) -> Optional[int]:
94
+ """The width of the image"""
95
+ return self._width
96
+
97
+ @property
98
+ def height(self) -> Optional[int]:
99
+ """The height of the image"""
100
+ return self._height
101
+
102
+ def bytes_to_depth_array(self) -> List[List[int]]:
103
+ """
104
+ Decode the data of an image that has the custom depth MIME type ``image/vnd.viam.dep`` into a standard representation.
105
+
106
+ Raises:
107
+ NotSupportedError: Raised if the image is not of MIME type `image/vnd.viam.dep`.
108
+
109
+ Returns:
110
+ List[List[int]]: The standard representation of the image.
111
+ """
112
+ if self.mime_type != CameraMimeType.VIAM_RAW_DEPTH:
113
+ raise NotSupportedError("Type must be `image/vnd.viam.dep` to use bytes_to_depth_array()")
114
+
115
+ self._width = int.from_bytes(self.data[8:16], "big")
116
+ self._height = int.from_bytes(self.data[16:24], "big")
117
+ depth_arr = array("H", self.data[24:])
118
+ depth_arr.byteswap()
119
+
120
+ depth_arr_2d = [[depth_arr[row * self._width + col] for col in range(self._width)] for row in range(self._height)]
121
+ return depth_arr_2d
122
+
123
+
124
+ class NamedImage(ViamImage):
125
+ """An implementation of ViamImage that contains a name attribute."""
126
+
127
+ name: str
128
+ """The name of the image
129
+ """
130
+
131
+ def __init__(self, name: str, data: bytes, mime_type: CameraMimeType) -> None:
132
+ self.name = name
133
+ super().__init__(data, mime_type)
134
+
135
+
136
+ def _getDimensions(image: bytes, mime_type: CameraMimeType) -> Tuple[Optional[int], Optional[int]]:
137
+ try:
138
+ if mime_type == CameraMimeType.JPEG:
139
+ return _getDimensionsFromJPEG(image)
140
+ if mime_type == CameraMimeType.PNG:
141
+ return _getDimensionsFromPNG(image)
142
+ if mime_type == CameraMimeType.VIAM_RGBA:
143
+ return _getDimensionsFromRGBA(image)
144
+ except ValueError:
145
+ return (None, None)
146
+ return (None, None)
147
+
148
+
149
+ def _getDimensionsFromJPEG(image: bytes) -> Tuple[int, int]:
150
+ # JPEG Specification: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
151
+ # Specification for markers: Table B.1
152
+
153
+ offset = 0
154
+ while offset < len(image):
155
+ while image[offset] == 0xFF:
156
+ # Skip all 0xFF bytes
157
+ offset += 1
158
+
159
+ marker = image[offset]
160
+ offset += 1
161
+ if marker == 0x01:
162
+ # Temporary/private use marker
163
+ offset += 1
164
+ continue
165
+ if marker in range(0xD0, 0xD7):
166
+ # Restart (RST) marker
167
+ offset += 1
168
+ continue
169
+ if marker == 0xD8:
170
+ # Start of image (SOI) marker
171
+ offset += 1
172
+ continue
173
+ if marker == 0xD9:
174
+ # End of image (EOI) marker
175
+ break
176
+
177
+ length = int.from_bytes(image[offset : offset + 1], byteorder="big") # length of section
178
+ if marker == 0xC0 or marker == 0xC2:
179
+ height = int.from_bytes(image[offset + 3 : offset + 5], byteorder="big")
180
+ width = int.from_bytes(image[offset + 5 : offset + 7], byteorder="big")
181
+ return (width, height)
182
+
183
+ offset += length
184
+
185
+ raise ValueError("Invalid JPEG: Could not extract dimensions")
186
+
187
+
188
+ def _getDimensionsFromPNG(image: bytes) -> Tuple[int, int]:
189
+ # PNG Specification: https://www.w3.org/TR/png/
190
+
191
+ # PNG will always start with this signature
192
+ signature = image[:8]
193
+ if signature != [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]:
194
+ ValueError("Invalid PNG: Invalid signature")
195
+
196
+ header = image[12:24]
197
+ chunk_type = header[:4].decode()
198
+ if chunk_type != "IHDR":
199
+ ValueError("Invalid PNG: Invalid headers")
200
+
201
+ width = int.from_bytes(header[4:8], byteorder="big")
202
+ height = int.from_bytes(header[8:], byteorder="big")
203
+ return (width, height)
204
+
205
+
206
+ def _getDimensionsFromRGBA(image: bytes) -> Tuple[int, int]:
207
+ # Viam RGBA header comes in 3 4-byte chunks:
208
+ # * Magic Number/Signature
209
+ # * Width
210
+ # * Height
211
+ header = image[:RGBA_HEADER_LENGTH]
212
+ if header[:4] != RGBA_MAGIC_NUMBER:
213
+ raise ValueError("Invalid Viam RGBA: Invalid headers")
214
+
215
+ width = int.from_bytes(header[4:8], byteorder="big")
216
+ height = int.from_bytes(header[8:], byteorder="big")
217
+ return (width, height)
@@ -0,0 +1,5 @@
1
+ from .module import Module
2
+
3
+ __all__ = [
4
+ "Module",
5
+ ]
viam/module/module.py ADDED
@@ -0,0 +1,281 @@
1
+ import argparse
2
+ import io
3
+ import logging as pylogging
4
+ import os
5
+ import sys
6
+ from inspect import iscoroutinefunction
7
+ from threading import Lock
8
+ from typing import List, Mapping, Optional, Sequence, Tuple
9
+
10
+ from grpclib.metadata import Deadline
11
+ from grpclib.utils import _service_name
12
+ from typing_extensions import Self
13
+
14
+ from viam import logging
15
+ from viam.errors import ResourceNotFoundError, ValidationError
16
+ from viam.logging import update_log_level
17
+ from viam.proto.app.robot import ComponentConfig
18
+ from viam.proto.module import (
19
+ AddResourceRequest,
20
+ HandlerDefinition,
21
+ HandlerMap,
22
+ ReadyRequest,
23
+ ReadyResponse,
24
+ ReconfigureResourceRequest,
25
+ RemoveResourceRequest,
26
+ ValidateConfigRequest,
27
+ ValidateConfigResponse,
28
+ )
29
+ from viam.proto.robot import ResourceRPCSubtype
30
+ from viam.resource.base import ResourceBase
31
+ from viam.resource.registry import Registry
32
+ from viam.resource.types import API, RESOURCE_TYPE_COMPONENT, RESOURCE_TYPE_SERVICE, Model, ResourceName, resource_name_from_string
33
+ from viam.robot.client import RobotClient
34
+ from viam.rpc.dial import DialOptions
35
+ from viam.rpc.server import Server
36
+
37
+ from .service import ModuleRPCService
38
+ from .types import Reconfigurable, Stoppable
39
+
40
+
41
+ def _parse_module_args() -> argparse.Namespace:
42
+ """
43
+ Parse command-line args. Used by the various `Module` entrypoints.
44
+ """
45
+ p = argparse.ArgumentParser(description="Start this viam python module")
46
+ p.add_argument("socket_path", help="path where this module will serve a unix socket")
47
+ p.add_argument("--log-level", type=lambda name: pylogging._nameToLevel[name.upper()], default=logging.INFO)
48
+ return p.parse_args()
49
+
50
+
51
+ class Module:
52
+ _address: str
53
+ _parent_address: Optional[str] = None
54
+ _ready: bool
55
+ _log_level: int
56
+ _lock: Lock
57
+ parent: Optional[RobotClient] = None
58
+ server: Server
59
+ logger: pylogging.Logger
60
+
61
+ @classmethod
62
+ def from_args(cls) -> Self:
63
+ """Create a new Module with the args provided in the command line. The first argument after the command must be
64
+ the socket path. If the second argument after the command is "--log-level=debug", the Module's logger will be
65
+ DEBUG level. Otherwise, it will be INFO level. See LogLevel documentation in the RDK for more information on how
66
+ to start modules with a "log-level" commandline argument.
67
+
68
+ Raises:
69
+ Exception: If there is no socket path provided in the command line argument
70
+
71
+ Returns:
72
+ Module: a new Module instance
73
+ """
74
+ args = _parse_module_args()
75
+ return cls(args.socket_path, log_level=args.log_level)
76
+
77
+ @classmethod
78
+ async def run_with_models(cls, *models: ResourceBase):
79
+ """
80
+ Module entrypoint that takes a list of ResourceBase implementations.
81
+ In most cases you'll want to use run_from_registry instead (see below).
82
+ """
83
+ module = cls.from_args()
84
+ for model in models:
85
+ if not hasattr(model, "MODEL"):
86
+ raise TypeError(f"missing MODEL field on {model}. Resource implementations must define MODEL")
87
+ module.add_model_from_registry(model.API, model.MODEL) # pyright: ignore [reportAttributeAccessIssue]
88
+ await module.start()
89
+
90
+ @classmethod
91
+ async def run_from_registry(cls):
92
+ """
93
+ Module entrypoint that automatically includes all the resources you've created in your program.
94
+
95
+ Example:
96
+
97
+ if __name__ == '__main__':
98
+ asyncio.run(Module.run_from_registry())
99
+
100
+ Full example at examples/easy_resource/main.py.
101
+ """
102
+ module = cls.from_args()
103
+ for key in Registry.REGISTERED_RESOURCE_CREATORS().keys():
104
+ module.add_model_from_registry(*key.split("/")) # pyright: ignore [reportArgumentType]
105
+ await module.start()
106
+
107
+ def __init__(self, address: str, *, log_level: int = logging.INFO) -> None:
108
+ # When a module is launched by viam-server, its stdout is not connected to a tty. In
109
+ # response, python disables line buffering, which prevents `print` statements from being
110
+ # immediately flushed to viam-server. This behavior can be confusing, interfere with
111
+ # debugging, and is non-standard when compared to other languages. Here, stdout and stderr
112
+ # are reconfigured to immediately flush.
113
+ if isinstance(sys.stdout, io.TextIOWrapper):
114
+ sys.stdout.reconfigure(line_buffering=True)
115
+ if isinstance(sys.stderr, io.TextIOWrapper):
116
+ sys.stderr.reconfigure(line_buffering=True)
117
+ self._address = address
118
+ self.server = Server(resources=[], module_service=ModuleRPCService(self))
119
+ self._log_level = log_level
120
+
121
+ module_name = os.environ.get("VIAM_MODULE_NAME")
122
+ # this can happen if the user is running an old version of viam-server that doesn't set `VIAM_MODULE_NAME`
123
+ if module_name is None:
124
+ module_name = __name__
125
+ self.logger = logging.getLogger(module_name)
126
+ self._ready = True
127
+ self._lock = Lock()
128
+
129
+ async def _connect_to_parent(self):
130
+ if self.parent is None:
131
+ if self._parent_address is None:
132
+ raise ValueError("Parent address not found")
133
+ self.parent = await RobotClient.at_address(
134
+ self._parent_address,
135
+ RobotClient.Options(
136
+ dial_options=DialOptions(disable_webrtc=True, insecure=True),
137
+ log_level=self._log_level,
138
+ ),
139
+ )
140
+ self.logger.debug("Starting module logging")
141
+ logging.setParent(self.parent)
142
+
143
+ async def _get_resource(self, name: ResourceName) -> ResourceBase:
144
+ await self._connect_to_parent()
145
+ assert self.parent is not None
146
+ await self.parent.refresh()
147
+ if name.type == RESOURCE_TYPE_COMPONENT:
148
+ return self.parent.get_component(name)
149
+ elif name.type == RESOURCE_TYPE_SERVICE:
150
+ return self.parent.get_service(name)
151
+ raise ValueError("Dependency does not describe a component nor a service")
152
+
153
+ async def _get_dependencies(self, dependencies: Sequence[str]) -> Mapping[ResourceName, ResourceBase]:
154
+ deps: Mapping[ResourceName, ResourceBase] = {}
155
+ for dep in dependencies:
156
+ rn = resource_name_from_string(dep)
157
+ deps[rn] = await self._get_resource(rn)
158
+ return deps
159
+
160
+ async def start(self):
161
+ """Start the module service and gRPC server"""
162
+ try:
163
+ await self.server.serve(log_level=self._log_level, path=self._address)
164
+ finally:
165
+ await self.stop()
166
+
167
+ async def stop(self):
168
+ """Stop the module service and gRPC server"""
169
+ self.logger.debug("Shutting down module")
170
+ try:
171
+ logging.shutdown()
172
+ if self.parent is not None:
173
+ await self.parent.close()
174
+ except Exception as e:
175
+ self.logger.error("Encountered error while shutting down module", exc_info=e)
176
+
177
+ def set_ready(self, ready: bool):
178
+ """Set the module's ready state. The module automatically sets to READY on load. Setting to False can be useful
179
+ in instances where the module is not instantly ready (for example waiting on hardware)
180
+
181
+ Args:
182
+ ready (bool): Whether the module is ready
183
+ """
184
+ with self._lock:
185
+ self._ready = ready
186
+
187
+ async def add_resource(self, request: AddResourceRequest, *, deadline: Optional[Deadline] = None):
188
+ dependencies = await self._get_dependencies(request.dependencies)
189
+ config: ComponentConfig = request.config
190
+ api = API.from_string(config.api)
191
+ model = Model.from_string(config.model, ignore_errors=True)
192
+ creator = Registry.lookup_resource_creator(api, model)
193
+ resource = creator(config, dependencies)
194
+ if deadline is not None and deadline.time_remaining() <= 0:
195
+ raise TimeoutError("Deadline expired")
196
+ update_log_level(resource.logger, config.log_configuration.level.upper())
197
+ self.server.register(resource)
198
+
199
+ async def reconfigure_resource(self, request: ReconfigureResourceRequest):
200
+ dependencies = await self._get_dependencies(request.dependencies)
201
+ config: ComponentConfig = request.config
202
+ api = API.from_string(config.api)
203
+ name = config.name
204
+ rn = ResourceName(namespace=api.namespace, type=api.resource_type, subtype=api.resource_subtype, name=name)
205
+ resource = self.server.get_resource(ResourceBase, rn)
206
+ if isinstance(resource, Reconfigurable):
207
+ resource.reconfigure(config, dependencies)
208
+ else:
209
+ if isinstance(resource, Stoppable):
210
+ if iscoroutinefunction(resource.stop):
211
+ await resource.stop()
212
+ else:
213
+ resource.stop()
214
+ add_request = AddResourceRequest(config=request.config, dependencies=request.dependencies)
215
+ await self.server.remove_resource(rn)
216
+ await self.add_resource(add_request)
217
+
218
+ async def remove_resource(self, request: RemoveResourceRequest):
219
+ rn = resource_name_from_string(request.name)
220
+ resource = self.server.get_resource(ResourceBase, rn)
221
+ if isinstance(resource, Stoppable):
222
+ if iscoroutinefunction(resource.stop):
223
+ await resource.stop()
224
+ else:
225
+ resource.stop()
226
+ await self.server.remove_resource(rn)
227
+
228
+ async def ready(self, request: ReadyRequest) -> ReadyResponse:
229
+ self._parent_address = request.parent_address
230
+ await self._connect_to_parent()
231
+
232
+ svcname_to_models: Mapping[Tuple[str, API], List[Model]] = {}
233
+ for api_model_str in Registry.REGISTERED_RESOURCE_CREATORS().keys():
234
+ api_str, model_str = api_model_str.split("/")
235
+ api = API.from_string(api_str)
236
+ model = Model.from_string(model_str)
237
+
238
+ registration = Registry.lookup_api(api)
239
+ service = registration.rpc_service(self.server)
240
+ service_name = _service_name(service)
241
+
242
+ models = svcname_to_models.get((service_name, api), [])
243
+ models.append(model)
244
+ svcname_to_models[(service_name, api)] = models
245
+
246
+ handlers: List[HandlerDefinition] = []
247
+ for key, value in svcname_to_models.items():
248
+ svc_name, api = key
249
+ rpc_subtype = ResourceRPCSubtype(
250
+ subtype=ResourceName(
251
+ namespace=api.namespace,
252
+ type=api.resource_type,
253
+ subtype=api.resource_subtype,
254
+ name="",
255
+ ),
256
+ proto_service=svc_name,
257
+ )
258
+ handler_def = HandlerDefinition(subtype=rpc_subtype, models=[str(model) for model in value])
259
+ handlers.append(handler_def)
260
+
261
+ return ReadyResponse(ready=self._ready, handlermap=HandlerMap(handlers=handlers))
262
+
263
+ def add_model_from_registry(self, api: API, model: Model):
264
+ """Add a pre-registered model to this Module"""
265
+
266
+ # All we need to do is double check that the model has already been registered
267
+ try:
268
+ Registry.lookup_resource_creator(api, model)
269
+ except ResourceNotFoundError:
270
+ raise ValueError(f"Cannot add model because it has not been registered. API: {api}. Model: {model}")
271
+
272
+ async def validate_config(self, request: ValidateConfigRequest) -> ValidateConfigResponse:
273
+ config: ComponentConfig = request.config
274
+ api = API.from_string(config.api)
275
+ model = Model.from_string(config.model)
276
+ validator = Registry.lookup_validator(api, model)
277
+ try:
278
+ dependencies = validator(config)
279
+ return ValidateConfigResponse(dependencies=dependencies)
280
+ except Exception as e:
281
+ raise ValidationError(f"{type(Exception)}: {e}").grpc_error
viam/module/service.py ADDED
@@ -0,0 +1,66 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from grpclib import Status
4
+ from grpclib.server import Stream
5
+
6
+ from viam.errors import ViamGRPCError
7
+ from viam.proto.module import (
8
+ AddResourceRequest,
9
+ AddResourceResponse,
10
+ ModuleServiceBase,
11
+ ReadyRequest,
12
+ ReadyResponse,
13
+ ReconfigureResourceRequest,
14
+ ReconfigureResourceResponse,
15
+ RemoveResourceRequest,
16
+ RemoveResourceResponse,
17
+ ValidateConfigRequest,
18
+ ValidateConfigResponse,
19
+ )
20
+
21
+ if TYPE_CHECKING:
22
+ from .module import Module
23
+
24
+
25
+ class ModuleRPCService(ModuleServiceBase):
26
+ _module: "Module"
27
+
28
+ def __init__(self, module: "Module") -> None:
29
+ self._module = module
30
+
31
+ async def AddResource(self, stream: Stream[AddResourceRequest, AddResourceResponse]) -> None:
32
+ request = await stream.recv_message()
33
+ assert request is not None
34
+ try:
35
+ await self._module.add_resource(request, deadline=stream.deadline)
36
+ except TimeoutError:
37
+ raise ViamGRPCError(
38
+ message="Timeout while adding resource",
39
+ grpc_code=Status.DEADLINE_EXCEEDED,
40
+ )
41
+ await stream.send_message(AddResourceResponse())
42
+
43
+ async def ReconfigureResource(self, stream: Stream[ReconfigureResourceRequest, ReconfigureResourceResponse]) -> None:
44
+ request = await stream.recv_message()
45
+ assert request is not None
46
+ await self._module.reconfigure_resource(request)
47
+ await stream.send_message(ReconfigureResourceResponse())
48
+
49
+ async def RemoveResource(self, stream: Stream[RemoveResourceRequest, RemoveResourceResponse]) -> None:
50
+ request = await stream.recv_message()
51
+ assert request is not None
52
+ await self._module.remove_resource(request)
53
+ await stream.send_message(RemoveResourceResponse())
54
+
55
+ async def Ready(self, stream: Stream[ReadyRequest, ReadyResponse]) -> None:
56
+ request = await stream.recv_message()
57
+ assert request is not None
58
+ response = await self._module.ready(request)
59
+ await stream.send_message(response)
60
+
61
+ async def ValidateConfig(self, stream: Stream[ValidateConfigRequest, ValidateConfigResponse]) -> None:
62
+ request = await stream.recv_message()
63
+ assert request is not None
64
+ response = await self._module.validate_config(request)
65
+ if response is not None:
66
+ await stream.send_message(response)
viam/module/types.py ADDED
@@ -0,0 +1,23 @@
1
+ from typing import Any, Mapping, Optional, Protocol, runtime_checkable
2
+
3
+ from viam.proto.app.robot import ComponentConfig
4
+ from viam.proto.common import ResourceName
5
+ from viam.resource.base import ResourceBase
6
+
7
+
8
+ @runtime_checkable
9
+ class Reconfigurable(Protocol):
10
+ """The Reconfigurable protocol defines the requirements for making a resource Reconfigurable"""
11
+
12
+ def reconfigure(self, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]): ...
13
+
14
+
15
+ @runtime_checkable
16
+ class Stoppable(Protocol):
17
+ """
18
+ The Stoppable protocol defines the requirements for making a resource Stoppable.
19
+
20
+ All resources that physically move should be Stoppable.
21
+ """
22
+
23
+ def stop(self, *, extra: Optional[Mapping[str, Any]] = None, timeout: Optional[float] = None, **kwargs): ...