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
@@ -17,12 +17,20 @@ class StreamServiceBase(abc.ABC):
17
17
  async def AddStream(self, stream: 'grpclib.server.Stream[stream.v1.stream_pb2.AddStreamRequest, stream.v1.stream_pb2.AddStreamResponse]') -> None:
18
18
  pass
19
19
 
20
+ @abc.abstractmethod
21
+ async def GetStreamOptions(self, stream: 'grpclib.server.Stream[stream.v1.stream_pb2.GetStreamOptionsRequest, stream.v1.stream_pb2.GetStreamOptionsResponse]') -> None:
22
+ pass
23
+
24
+ @abc.abstractmethod
25
+ async def SetStreamOptions(self, stream: 'grpclib.server.Stream[stream.v1.stream_pb2.SetStreamOptionsRequest, stream.v1.stream_pb2.SetStreamOptionsResponse]') -> None:
26
+ pass
27
+
20
28
  @abc.abstractmethod
21
29
  async def RemoveStream(self, stream: 'grpclib.server.Stream[stream.v1.stream_pb2.RemoveStreamRequest, stream.v1.stream_pb2.RemoveStreamResponse]') -> None:
22
30
  pass
23
31
 
24
32
  def __mapping__(self) -> typing.Dict[str, grpclib.const.Handler]:
25
- return {'/proto.stream.v1.StreamService/ListStreams': grpclib.const.Handler(self.ListStreams, grpclib.const.Cardinality.UNARY_UNARY, stream.v1.stream_pb2.ListStreamsRequest, stream.v1.stream_pb2.ListStreamsResponse), '/proto.stream.v1.StreamService/AddStream': grpclib.const.Handler(self.AddStream, grpclib.const.Cardinality.UNARY_UNARY, stream.v1.stream_pb2.AddStreamRequest, stream.v1.stream_pb2.AddStreamResponse), '/proto.stream.v1.StreamService/RemoveStream': grpclib.const.Handler(self.RemoveStream, grpclib.const.Cardinality.UNARY_UNARY, stream.v1.stream_pb2.RemoveStreamRequest, stream.v1.stream_pb2.RemoveStreamResponse)}
33
+ return {'/proto.stream.v1.StreamService/ListStreams': grpclib.const.Handler(self.ListStreams, grpclib.const.Cardinality.UNARY_UNARY, stream.v1.stream_pb2.ListStreamsRequest, stream.v1.stream_pb2.ListStreamsResponse), '/proto.stream.v1.StreamService/AddStream': grpclib.const.Handler(self.AddStream, grpclib.const.Cardinality.UNARY_UNARY, stream.v1.stream_pb2.AddStreamRequest, stream.v1.stream_pb2.AddStreamResponse), '/proto.stream.v1.StreamService/GetStreamOptions': grpclib.const.Handler(self.GetStreamOptions, grpclib.const.Cardinality.UNARY_UNARY, stream.v1.stream_pb2.GetStreamOptionsRequest, stream.v1.stream_pb2.GetStreamOptionsResponse), '/proto.stream.v1.StreamService/SetStreamOptions': grpclib.const.Handler(self.SetStreamOptions, grpclib.const.Cardinality.UNARY_UNARY, stream.v1.stream_pb2.SetStreamOptionsRequest, stream.v1.stream_pb2.SetStreamOptionsResponse), '/proto.stream.v1.StreamService/RemoveStream': grpclib.const.Handler(self.RemoveStream, grpclib.const.Cardinality.UNARY_UNARY, stream.v1.stream_pb2.RemoveStreamRequest, stream.v1.stream_pb2.RemoveStreamResponse)}
26
34
 
27
35
  class UnimplementedStreamServiceBase(StreamServiceBase):
28
36
 
@@ -32,6 +40,12 @@ class UnimplementedStreamServiceBase(StreamServiceBase):
32
40
  async def AddStream(self, stream: 'grpclib.server.Stream[stream.v1.stream_pb2.AddStreamRequest, stream.v1.stream_pb2.AddStreamResponse]') -> None:
33
41
  raise grpclib.exceptions.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
34
42
 
43
+ async def GetStreamOptions(self, stream: 'grpclib.server.Stream[stream.v1.stream_pb2.GetStreamOptionsRequest, stream.v1.stream_pb2.GetStreamOptionsResponse]') -> None:
44
+ raise grpclib.exceptions.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
45
+
46
+ async def SetStreamOptions(self, stream: 'grpclib.server.Stream[stream.v1.stream_pb2.SetStreamOptionsRequest, stream.v1.stream_pb2.SetStreamOptionsResponse]') -> None:
47
+ raise grpclib.exceptions.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
48
+
35
49
  async def RemoveStream(self, stream: 'grpclib.server.Stream[stream.v1.stream_pb2.RemoveStreamRequest, stream.v1.stream_pb2.RemoveStreamResponse]') -> None:
36
50
  raise grpclib.exceptions.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
37
51
 
@@ -40,4 +54,6 @@ class StreamServiceStub:
40
54
  def __init__(self, channel: grpclib.client.Channel) -> None:
41
55
  self.ListStreams = grpclib.client.UnaryUnaryMethod(channel, '/proto.stream.v1.StreamService/ListStreams', stream.v1.stream_pb2.ListStreamsRequest, stream.v1.stream_pb2.ListStreamsResponse)
42
56
  self.AddStream = grpclib.client.UnaryUnaryMethod(channel, '/proto.stream.v1.StreamService/AddStream', stream.v1.stream_pb2.AddStreamRequest, stream.v1.stream_pb2.AddStreamResponse)
57
+ self.GetStreamOptions = grpclib.client.UnaryUnaryMethod(channel, '/proto.stream.v1.StreamService/GetStreamOptions', stream.v1.stream_pb2.GetStreamOptionsRequest, stream.v1.stream_pb2.GetStreamOptionsResponse)
58
+ self.SetStreamOptions = grpclib.client.UnaryUnaryMethod(channel, '/proto.stream.v1.StreamService/SetStreamOptions', stream.v1.stream_pb2.SetStreamOptionsRequest, stream.v1.stream_pb2.SetStreamOptionsResponse)
43
59
  self.RemoveStream = grpclib.client.UnaryUnaryMethod(channel, '/proto.stream.v1.StreamService/RemoveStream', stream.v1.stream_pb2.RemoveStreamRequest, stream.v1.stream_pb2.RemoveStreamResponse)
@@ -1,26 +1,39 @@
1
1
  """Generated protocol buffer code."""
2
- from google.protobuf.internal import builder as _builder
3
2
  from google.protobuf import descriptor as _descriptor
4
3
  from google.protobuf import descriptor_pool as _descriptor_pool
4
+ from google.protobuf import runtime_version as _runtime_version
5
5
  from google.protobuf import symbol_database as _symbol_database
6
+ from google.protobuf.internal import builder as _builder
7
+ _runtime_version.ValidateProtobufRuntimeVersion(_runtime_version.Domain.PUBLIC, 5, 29, 2, '', 'stream/v1/stream.proto')
6
8
  _sym_db = _symbol_database.Default()
7
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16stream/v1/stream.proto\x12\x0fproto.stream.v1"\x14\n\x12ListStreamsRequest"+\n\x13ListStreamsResponse\x12\x14\n\x05names\x18\x01 \x03(\tR\x05names"&\n\x10AddStreamRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name"\x13\n\x11AddStreamResponse")\n\x13RemoveStreamRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name"\x16\n\x14RemoveStreamResponse2\x9a\x02\n\rStreamService\x12X\n\x0bListStreams\x12#.proto.stream.v1.ListStreamsRequest\x1a$.proto.stream.v1.ListStreamsResponse\x12R\n\tAddStream\x12!.proto.stream.v1.AddStreamRequest\x1a".proto.stream.v1.AddStreamResponse\x12[\n\x0cRemoveStream\x12$.proto.stream.v1.RemoveStreamRequest\x1a%.proto.stream.v1.RemoveStreamResponseB.Z,github.com/edaniels/gostream/proto/stream/v1b\x06proto3')
8
- _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
9
- _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'stream.v1.stream_pb2', globals())
10
- if _descriptor._USE_C_DESCRIPTORS == False:
11
- DESCRIPTOR._options = None
12
- DESCRIPTOR._serialized_options = b'Z,github.com/edaniels/gostream/proto/stream/v1'
13
- _LISTSTREAMSREQUEST._serialized_start = 43
14
- _LISTSTREAMSREQUEST._serialized_end = 63
15
- _LISTSTREAMSRESPONSE._serialized_start = 65
16
- _LISTSTREAMSRESPONSE._serialized_end = 108
17
- _ADDSTREAMREQUEST._serialized_start = 110
18
- _ADDSTREAMREQUEST._serialized_end = 148
19
- _ADDSTREAMRESPONSE._serialized_start = 150
20
- _ADDSTREAMRESPONSE._serialized_end = 169
21
- _REMOVESTREAMREQUEST._serialized_start = 171
22
- _REMOVESTREAMREQUEST._serialized_end = 212
23
- _REMOVESTREAMRESPONSE._serialized_start = 214
24
- _REMOVESTREAMRESPONSE._serialized_end = 236
25
- _STREAMSERVICE._serialized_start = 239
26
- _STREAMSERVICE._serialized_end = 521
9
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16stream/v1/stream.proto\x12\x0fproto.stream.v1"\x14\n\x12ListStreamsRequest"+\n\x13ListStreamsResponse\x12\x14\n\x05names\x18\x01 \x03(\tR\x05names"&\n\x10AddStreamRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name"\x13\n\x11AddStreamResponse")\n\x13RemoveStreamRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name"\x16\n\x14RemoveStreamResponse":\n\nResolution\x12\x14\n\x05width\x18\x01 \x01(\x05R\x05width\x12\x16\n\x06height\x18\x02 \x01(\x05R\x06height"-\n\x17GetStreamOptionsRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name"Y\n\x18GetStreamOptionsResponse\x12=\n\x0bresolutions\x18\x01 \x03(\x0b2\x1b.proto.stream.v1.ResolutionR\x0bresolutions"j\n\x17SetStreamOptionsRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12;\n\nresolution\x18\x02 \x01(\x0b2\x1b.proto.stream.v1.ResolutionR\nresolution"\x1a\n\x18SetStreamOptionsResponse2\xec\x03\n\rStreamService\x12X\n\x0bListStreams\x12#.proto.stream.v1.ListStreamsRequest\x1a$.proto.stream.v1.ListStreamsResponse\x12R\n\tAddStream\x12!.proto.stream.v1.AddStreamRequest\x1a".proto.stream.v1.AddStreamResponse\x12g\n\x10GetStreamOptions\x12(.proto.stream.v1.GetStreamOptionsRequest\x1a).proto.stream.v1.GetStreamOptionsResponse\x12g\n\x10SetStreamOptions\x12(.proto.stream.v1.SetStreamOptionsRequest\x1a).proto.stream.v1.SetStreamOptionsResponse\x12[\n\x0cRemoveStream\x12$.proto.stream.v1.RemoveStreamRequest\x1a%.proto.stream.v1.RemoveStreamResponseB.Z,github.com/edaniels/gostream/proto/stream/v1b\x06proto3')
10
+ _globals = globals()
11
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
12
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'stream.v1.stream_pb2', _globals)
13
+ if not _descriptor._USE_C_DESCRIPTORS:
14
+ _globals['DESCRIPTOR']._loaded_options = None
15
+ _globals['DESCRIPTOR']._serialized_options = b'Z,github.com/edaniels/gostream/proto/stream/v1'
16
+ _globals['_LISTSTREAMSREQUEST']._serialized_start = 43
17
+ _globals['_LISTSTREAMSREQUEST']._serialized_end = 63
18
+ _globals['_LISTSTREAMSRESPONSE']._serialized_start = 65
19
+ _globals['_LISTSTREAMSRESPONSE']._serialized_end = 108
20
+ _globals['_ADDSTREAMREQUEST']._serialized_start = 110
21
+ _globals['_ADDSTREAMREQUEST']._serialized_end = 148
22
+ _globals['_ADDSTREAMRESPONSE']._serialized_start = 150
23
+ _globals['_ADDSTREAMRESPONSE']._serialized_end = 169
24
+ _globals['_REMOVESTREAMREQUEST']._serialized_start = 171
25
+ _globals['_REMOVESTREAMREQUEST']._serialized_end = 212
26
+ _globals['_REMOVESTREAMRESPONSE']._serialized_start = 214
27
+ _globals['_REMOVESTREAMRESPONSE']._serialized_end = 236
28
+ _globals['_RESOLUTION']._serialized_start = 238
29
+ _globals['_RESOLUTION']._serialized_end = 296
30
+ _globals['_GETSTREAMOPTIONSREQUEST']._serialized_start = 298
31
+ _globals['_GETSTREAMOPTIONSREQUEST']._serialized_end = 343
32
+ _globals['_GETSTREAMOPTIONSRESPONSE']._serialized_start = 345
33
+ _globals['_GETSTREAMOPTIONSRESPONSE']._serialized_end = 434
34
+ _globals['_SETSTREAMOPTIONSREQUEST']._serialized_start = 436
35
+ _globals['_SETSTREAMOPTIONSREQUEST']._serialized_end = 542
36
+ _globals['_SETSTREAMOPTIONSRESPONSE']._serialized_start = 544
37
+ _globals['_SETSTREAMOPTIONSRESPONSE']._serialized_end = 570
38
+ _globals['_STREAMSERVICE']._serialized_start = 573
39
+ _globals['_STREAMSERVICE']._serialized_end = 1065
@@ -80,4 +80,82 @@ class RemoveStreamResponse(google.protobuf.message.Message):
80
80
 
81
81
  def __init__(self) -> None:
82
82
  ...
83
- global___RemoveStreamResponse = RemoveStreamResponse
83
+ global___RemoveStreamResponse = RemoveStreamResponse
84
+
85
+ @typing.final
86
+ class Resolution(google.protobuf.message.Message):
87
+ """Resolution details the width and height of a stream."""
88
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
89
+ WIDTH_FIELD_NUMBER: builtins.int
90
+ HEIGHT_FIELD_NUMBER: builtins.int
91
+ width: builtins.int
92
+ height: builtins.int
93
+
94
+ def __init__(self, *, width: builtins.int=..., height: builtins.int=...) -> None:
95
+ ...
96
+
97
+ def ClearField(self, field_name: typing.Literal['height', b'height', 'width', b'width']) -> None:
98
+ ...
99
+ global___Resolution = Resolution
100
+
101
+ @typing.final
102
+ class GetStreamOptionsRequest(google.protobuf.message.Message):
103
+ """GetStreamOptionsRequest requests the options for a particular stream."""
104
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
105
+ NAME_FIELD_NUMBER: builtins.int
106
+ name: builtins.str
107
+
108
+ def __init__(self, *, name: builtins.str=...) -> None:
109
+ ...
110
+
111
+ def ClearField(self, field_name: typing.Literal['name', b'name']) -> None:
112
+ ...
113
+ global___GetStreamOptionsRequest = GetStreamOptionsRequest
114
+
115
+ @typing.final
116
+ class GetStreamOptionsResponse(google.protobuf.message.Message):
117
+ """GetStreamOptionsResponse details the options for a particular stream."""
118
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
119
+ RESOLUTIONS_FIELD_NUMBER: builtins.int
120
+
121
+ @property
122
+ def resolutions(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Resolution]:
123
+ ...
124
+
125
+ def __init__(self, *, resolutions: collections.abc.Iterable[global___Resolution] | None=...) -> None:
126
+ ...
127
+
128
+ def ClearField(self, field_name: typing.Literal['resolutions', b'resolutions']) -> None:
129
+ ...
130
+ global___GetStreamOptionsResponse = GetStreamOptionsResponse
131
+
132
+ @typing.final
133
+ class SetStreamOptionsRequest(google.protobuf.message.Message):
134
+ """SetStreamOptionsRequest sets the options for a particular stream."""
135
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
136
+ NAME_FIELD_NUMBER: builtins.int
137
+ RESOLUTION_FIELD_NUMBER: builtins.int
138
+ name: builtins.str
139
+
140
+ @property
141
+ def resolution(self) -> global___Resolution:
142
+ ...
143
+
144
+ def __init__(self, *, name: builtins.str=..., resolution: global___Resolution | None=...) -> None:
145
+ ...
146
+
147
+ def HasField(self, field_name: typing.Literal['resolution', b'resolution']) -> builtins.bool:
148
+ ...
149
+
150
+ def ClearField(self, field_name: typing.Literal['name', b'name', 'resolution', b'resolution']) -> None:
151
+ ...
152
+ global___SetStreamOptionsRequest = SetStreamOptionsRequest
153
+
154
+ @typing.final
155
+ class SetStreamOptionsResponse(google.protobuf.message.Message):
156
+ """SetStreamOptionsResponse is returned after a successful SetStreamOptionsRequest."""
157
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
158
+
159
+ def __init__(self) -> None:
160
+ ...
161
+ global___SetStreamOptionsResponse = SetStreamOptionsResponse
@@ -1,15 +1,16 @@
1
1
  """Generated protocol buffer code."""
2
- from google.protobuf.internal import builder as _builder
3
2
  from google.protobuf import descriptor as _descriptor
4
3
  from google.protobuf import descriptor_pool as _descriptor_pool
4
+ from google.protobuf import runtime_version as _runtime_version
5
5
  from google.protobuf import symbol_database as _symbol_database
6
+ from google.protobuf.internal import builder as _builder
7
+ _runtime_version.ValidateProtobufRuntimeVersion(_runtime_version.Domain.PUBLIC, 5, 29, 2, '', 'tagger/v1/tagger.proto')
6
8
  _sym_db = _symbol_database.Default()
7
9
  from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
8
10
  DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16tagger/v1/tagger.proto\x12\ttagger.v1\x1a google/protobuf/descriptor.proto:3\n\x04tags\x12\x1d.google.protobuf.FieldOptions\x18\xc3\xe03 \x01(\tR\x04tags:>\n\noneof_tags\x12\x1d.google.protobuf.OneofOptions\x18\xc3\xe03 \x01(\tR\toneofTagsB4Z2github.com/srikrsna/protoc-gen-gotag/tagger;taggerb\x06proto3')
9
- _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
10
- _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tagger.v1.tagger_pb2', globals())
11
- if _descriptor._USE_C_DESCRIPTORS == False:
12
- google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(tags)
13
- google_dot_protobuf_dot_descriptor__pb2.OneofOptions.RegisterExtension(oneof_tags)
14
- DESCRIPTOR._options = None
15
- DESCRIPTOR._serialized_options = b'Z2github.com/srikrsna/protoc-gen-gotag/tagger;tagger'
11
+ _globals = globals()
12
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
13
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'tagger.v1.tagger_pb2', _globals)
14
+ if not _descriptor._USE_C_DESCRIPTORS:
15
+ _globals['DESCRIPTOR']._loaded_options = None
16
+ _globals['DESCRIPTOR']._serialized_options = b'Z2github.com/srikrsna/protoc-gen-gotag/tagger;tagger'
viam/logging.py CHANGED
@@ -4,6 +4,7 @@ import sys
4
4
  from copy import copy
5
5
  from datetime import datetime
6
6
  from logging import DEBUG, ERROR, FATAL, INFO, WARN, WARNING # noqa: F401
7
+ from threading import Event, Lock, Thread
7
8
  from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Union
8
9
 
9
10
  from grpclib.exceptions import StreamTerminatedError
@@ -19,22 +20,63 @@ LOGGERS: Dict[str, logging.Logger] = {}
19
20
  _MODULE_PARENT: Optional["RobotClient"] = None
20
21
 
21
22
 
23
+ class _SingletonEventLoopThread:
24
+ _instance = None
25
+ _lock = Lock()
26
+ # We use a threading.Event instead of an asyncio.Event because the latter are not thread safe,
27
+ # and this is set in a separate thread than it is waited on.
28
+ _ready_event = Event()
29
+ _loop: asyncio.AbstractEventLoop
30
+ _thread: Thread
31
+
32
+ def __new__(cls):
33
+ # Ensure singleton precondition
34
+ if cls._instance is None:
35
+ with cls._lock:
36
+ if cls._instance is None:
37
+ cls._instance = super(_SingletonEventLoopThread, cls).__new__(cls)
38
+ cls._instance._loop = asyncio.new_event_loop()
39
+ cls._instance._thread = Thread(target=cls._instance._run)
40
+ cls._instance._thread.start()
41
+ return cls._instance
42
+
43
+ def _run(self):
44
+ asyncio.set_event_loop(self._loop)
45
+ self._ready_event.set()
46
+ self._loop.run_forever()
47
+
48
+ def stop(self):
49
+ if self._loop is not None:
50
+ self._loop.call_soon_threadsafe(self._loop.stop)
51
+ self._thread.join()
52
+
53
+ def get_loop(self):
54
+ if self._loop is None:
55
+ raise RuntimeError("Event loop is None. Did you call .start() and .wait_until_ready()?")
56
+ return self._loop
57
+
58
+ def wait_until_ready(self):
59
+ self._ready_event.wait()
60
+
61
+
22
62
  class _ModuleHandler(logging.Handler):
23
63
  _parent: "RobotClient"
24
64
  _logger: logging.Logger
65
+ _worker: _SingletonEventLoopThread
25
66
 
26
67
  def __init__(self, parent: "RobotClient"):
68
+ super().__init__()
27
69
  self._parent = parent
28
70
  self._logger = logging.getLogger("ModuleLogger")
29
71
  addHandlers(self._logger, True)
30
- super().__init__()
31
72
  self._logger.setLevel(self.level)
73
+ self._worker = _SingletonEventLoopThread()
32
74
 
33
75
  def setLevel(self, level: Union[int, str]) -> None:
34
76
  self._logger.setLevel(level)
35
77
  return super().setLevel(level)
36
78
 
37
- def handle_task_result(self, task: asyncio.Task):
79
+ async def handle_task_result(self, task: asyncio.Task):
38
80
  try:
39
81
  _ = task.result()
40
82
  except (asyncio.CancelledError, asyncio.InvalidStateError, StreamTerminatedError):
@@ -42,30 +84,35 @@ class _ModuleHandler(logging.Handler):
42
84
 
43
85
  def emit(self, record: logging.LogRecord):
44
86
  assert isinstance(record, logging.LogRecord)
45
- name = record.name.split(".")[-1]
87
+ # Fully qualified name of form "{API triplet}/{name}", e.g. "rdk:component:arm/myarm"
88
+ name = record.name.replace(".", "/")
46
89
  message = f"{record.filename}:{record.lineno}\t{record.getMessage()}"
47
90
  stack = f"exc_info: {record.exc_info}, exc_text: {record.exc_text}, stack_info: {record.stack_info}"
48
91
  time = datetime.fromtimestamp(record.created)
49
92
 
50
93
  try:
51
- assert self._parent is not None
52
- try:
53
- loop = asyncio.get_event_loop()
54
- loop.create_task(
55
- self._parent.log(name, record.levelname, time, message, stack), name=f"{viam._TASK_PREFIX}-LOG-{record.created}"
56
- ).add_done_callback(self.handle_task_result)
57
- except RuntimeError:
58
- # If the log is coming from a thread that doesn't have an event loop, create and set a new one.
59
- loop = asyncio.new_event_loop()
60
- asyncio.set_event_loop(loop)
61
- loop.create_task(
62
- self._parent.log(name, record.levelname, time, message, stack), name=f"{viam._TASK_PREFIX}-LOG-{record.created}"
63
- ).add_done_callback(self.handle_task_result)
94
+ loop = self._worker.get_loop()
95
+ asyncio.run_coroutine_threadsafe(
96
+ self._asynchronously_emit(record, name, message, stack, time),
97
+ loop,
98
+ )
64
99
  except Exception as err:
65
100
  # If the module log fails, log using stdout/stderr handlers
66
101
  self._logger.error(f"ModuleLogger failed for {record.name} - {err}")
67
102
  self._logger.log(record.levelno, message)
68
103
 
104
+ async def _asynchronously_emit(self, record: logging.LogRecord, name: str, message: str, stack: str, time: datetime):
105
+ self._worker.wait_until_ready()
106
+ task = self._worker.get_loop().create_task(
107
+ self._parent.log(name, record.levelname, time, message, stack),
108
+ name=f"{viam._TASK_PREFIX}-LOG-{record.created}",
109
+ )
110
+ task.add_done_callback(lambda t: asyncio.run_coroutine_threadsafe(self.handle_task_result(t), self._worker.get_loop()))
111
+
112
+ def close(self):
113
+ self._worker.stop()
114
+ super().close()
115
+
69
116
 
70
117
  class _ColorFormatter(logging.Formatter):
71
118
  MAPPING = {
@@ -76,8 +123,8 @@ class _ColorFormatter(logging.Formatter):
76
123
  "CRITICAL": 41, # white on red bg
77
124
  }
78
125
 
79
- def __init__(self, patern):
80
- logging.Formatter.__init__(self, patern)
126
+ def __init__(self, pattern):
127
+ logging.Formatter.__init__(self, pattern)
81
128
 
82
129
  def format(self, record):
83
130
  colored_record = copy(record)
@@ -106,6 +153,14 @@ def addHandlers(logger: logging.Logger, use_default_handlers=False):
106
153
  _addHandlers([logger], use_default_handlers)
107
154
 
108
155
 
156
+ def update_log_level(logger: logging.Logger, level: Union[int, str]):
157
+ if level == "":
158
+ level = LOG_LEVEL
159
+ logger.setLevel(level)
160
+ for handler in logger.handlers:
161
+ handler.setLevel(level)
162
+
163
+
109
164
  def _addHandlers(loggers: Iterable[logging.Logger], use_default_handlers=False):
110
165
  format = _ColorFormatter("%(asctime)s\t\t" + "%(levelname)s\t" + "%(name)s (%(filename)s:%(lineno)d)\t" + "%(message)s\t")
111
166
 
@@ -156,3 +211,7 @@ def setLevel(level: int):
156
211
 
157
212
  def silence():
158
213
  setLevel(FATAL + 1)
214
+
215
+
216
+ def shutdown():
217
+ logging.shutdown()
viam/media/audio.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from dataclasses import dataclass
2
+ from enum import Enum
2
3
 
3
4
  from viam.proto.component.audioinput import AudioChunk, AudioChunkInfo
4
5
  from viam.streams import Stream, StreamReader
@@ -14,3 +15,30 @@ class Audio:
14
15
 
15
16
  AudioReader = StreamReader[Audio]
16
17
  AudioStream = Stream[Audio]
18
+
19
+
20
+ class AudioCodec(str, Enum):
21
+ """Common audio codec identifiers.
22
+
23
+ These constants represent commonly supported audio codecs
24
+ for audioin and audioout components.
25
+
26
+ Example::
27
+
28
+ from viam.components.codecs import AudioCodec
29
+ from viam.proto.common import AudioInfo
30
+
31
+ audio_info = AudioInfo(
32
+ codec=AudioCodec.PCM16,
33
+ sample_rate_hz=44100,
34
+ num_channels=2
35
+ )
36
+ """
37
+
38
+ PCM16 = "pcm16"
39
+ PCM32 = "pcm32"
40
+ PCM32_FLOAT = "pcm32_float"
41
+ MP3 = "mp3"
42
+ AAC = "aac"
43
+ OPUS = "opus"
44
+ FLAC = "flac"
@@ -14,7 +14,7 @@ def viam_to_pil_image(image: ViamImage) -> Image.Image:
14
14
  Convert a ViamImage to a PIL.Image.
15
15
 
16
16
  In order to use this function, Pillow must be installed.
17
- https://python-pillow.org/
17
+ https://pillow.readthedocs.io/
18
18
 
19
19
  Args:
20
20
  image (ViamImage): The image to convert.
@@ -30,7 +30,7 @@ def pil_to_viam_image(image: Image.Image, mime_type: CameraMimeType) -> ViamImag
30
30
  Convert a PIL.Image to a ViamImage.
31
31
 
32
32
  In order to use this function, Pillow must be installed.
33
- https://python-pillow.org/
33
+ https://pillow.readthedocs.io/
34
34
 
35
35
  Args:
36
36
  image (Image.Image): The image to convert.
@@ -39,6 +39,10 @@ def pil_to_viam_image(image: Image.Image, mime_type: CameraMimeType) -> ViamImag
39
39
  Returns:
40
40
  ViamImage: The resulting ViamImage
41
41
  """
42
+ # Make sure at runtime the mime_type string is actually a CameraMimeType
43
+ if not isinstance(mime_type, CameraMimeType):
44
+ raise ValueError(f"Cannot encode to unsupported mimetype: {mime_type}")
45
+
42
46
  if mime_type.name in LIBRARY_SUPPORTED_FORMATS:
43
47
  buf = BytesIO()
44
48
  if image.mode == "RGBA" and mime_type == CameraMimeType.JPEG:
@@ -46,6 +50,6 @@ def pil_to_viam_image(image: Image.Image, mime_type: CameraMimeType) -> ViamImag
46
50
  image.save(buf, format=mime_type.name)
47
51
  data = buf.getvalue()
48
52
  else:
49
- raise ValueError(f"Cannot encode image to {mime_type}")
53
+ raise ValueError(f"Cannot encode to unsupported mimetype: {mime_type}")
50
54
 
51
55
  return ViamImage(data, mime_type)
viam/media/video.py CHANGED
@@ -1,8 +1,7 @@
1
1
  from array import array
2
- from enum import Enum
3
- from typing import List, Optional, Tuple
2
+ from typing import Any, List, Optional, Tuple
4
3
 
5
- from typing_extensions import Self
4
+ from typing_extensions import ClassVar, Self
6
5
 
7
6
  from viam.errors import NotSupportedError
8
7
  from viam.proto.component.camera import Format
@@ -10,19 +9,69 @@ from viam.proto.component.camera import Format
10
9
  from .viam_rgba import RGBA_HEADER_LENGTH, RGBA_MAGIC_NUMBER
11
10
 
12
11
 
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"
12
+ class _FrozenClassAttributesMeta(type):
13
+ """
14
+ A metaclass that prevents the reassignment of existing class attributes.
15
+ """
16
+
17
+ def __setattr__(cls, name: str, value: Any):
18
+ # Check if the attribute `name` already exists on the class
19
+ if name in cls.__dict__:
20
+ # If it exists, raise an error to prevent overwriting
21
+ raise AttributeError(f"Cannot reassign constant '{name}'")
22
+ # If it's a new attribute, allow it to be set
23
+ super().__setattr__(name, value)
24
+
25
+
26
+ class CameraMimeType(str, metaclass=_FrozenClassAttributesMeta):
27
+ """
28
+ The compatible mime-types for cameras and vision services.
29
+
30
+ You can use the `CameraMimeType.CUSTOM(...)` method to use an unlisted mime-type.
31
+ """
32
+
33
+ VIAM_RGBA: ClassVar[Self]
34
+ VIAM_RAW_DEPTH: ClassVar[Self]
35
+ JPEG: ClassVar[Self]
36
+ PNG: ClassVar[Self]
37
+ PCD: ClassVar[Self]
38
+
39
+ @property
40
+ def name(self) -> str:
41
+ for key, value in self.__class__.__dict__.items():
42
+ if value == self:
43
+ return key
44
+ return "CUSTOM"
45
+
46
+ @property
47
+ def value(self) -> str:
48
+ return self
49
+
50
+ @classmethod
51
+ def CUSTOM(cls, mime_type: str) -> Self:
52
+ """
53
+ Create a custom mime type.
54
+
55
+ Args:
56
+ mime_type (str): The mimetype as a string
57
+ """
58
+ return cls.from_string(mime_type)
19
59
 
20
60
  @classmethod
21
61
  def from_string(cls, value: str) -> Self:
22
- return cls(value)
62
+ """Return the mimetype from a string.
63
+
64
+ Args:
65
+ value (str): The mimetype as a string
66
+
67
+ Returns:
68
+ Self: The mimetype
69
+ """
70
+ value_mime = value[:-5] if value.endswith("+lazy") else value # ViamImage lazy encodes by default
71
+ return cls(value_mime)
23
72
 
24
73
  @classmethod
25
- def from_proto(cls, format: Format.ValueType) -> "CameraMimeType":
74
+ def from_proto(cls, format: Format.ValueType) -> Self:
26
75
  """Returns the mimetype from a proto enum.
27
76
 
28
77
  Args:
@@ -32,14 +81,15 @@ class CameraMimeType(str, Enum):
32
81
  Self: The mimetype.
33
82
  """
34
83
  mimetypes = {
35
- Format.FORMAT_RAW_RGBA: CameraMimeType.VIAM_RGBA,
36
- Format.FORMAT_RAW_DEPTH: CameraMimeType.VIAM_RAW_DEPTH,
37
- Format.FORMAT_JPEG: CameraMimeType.JPEG,
38
- Format.FORMAT_PNG: CameraMimeType.PNG,
84
+ Format.FORMAT_RAW_RGBA: cls.VIAM_RGBA,
85
+ Format.FORMAT_RAW_DEPTH: cls.VIAM_RAW_DEPTH,
86
+ Format.FORMAT_JPEG: cls.JPEG,
87
+ Format.FORMAT_PNG: cls.PNG,
39
88
  }
40
- return mimetypes.get(format, CameraMimeType.JPEG)
89
+ return cls(mimetypes.get(format, cls.JPEG))
41
90
 
42
- def to_proto(self) -> Format.ValueType:
91
+ @property
92
+ def proto(self) -> Format.ValueType:
43
93
  """Returns the mimetype in a proto enum.
44
94
 
45
95
  Returns:
@@ -53,6 +103,19 @@ class CameraMimeType(str, Enum):
53
103
  }
54
104
  return formats.get(self, Format.FORMAT_UNSPECIFIED)
55
105
 
106
+ def to_proto(self) -> Format.ValueType:
107
+ """
108
+ DEPRECATED: Use `CameraMimeType.proto`
109
+ """
110
+ return self.proto
111
+
112
+
113
+ CameraMimeType.VIAM_RGBA = CameraMimeType.from_string("image/vnd.viam.rgba")
114
+ CameraMimeType.VIAM_RAW_DEPTH = CameraMimeType.from_string("image/vnd.viam.dep")
115
+ CameraMimeType.JPEG = CameraMimeType.from_string("image/jpeg")
116
+ CameraMimeType.PNG = CameraMimeType.from_string("image/png")
117
+ CameraMimeType.PCD = CameraMimeType.from_string("pointcloud/pcd")
118
+
56
119
 
57
120
  class ViamImage:
58
121
  """A native implementation of an image.