viam-sdk 0.41.1__py3-none-linux_armv6l.whl → 0.66.0__py3-none-linux_armv6l.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 (225) hide show
  1. viam/app/app_client.py +225 -51
  2. viam/app/billing_client.py +47 -5
  3. viam/app/data_client.py +771 -234
  4. viam/app/ml_training_client.py +3 -5
  5. viam/app/provisioning_client.py +3 -5
  6. viam/app/viam_client.py +58 -11
  7. viam/components/arm/arm.py +1 -1
  8. viam/components/arm/service.py +1 -1
  9. viam/components/audio_in/__init__.py +24 -0
  10. viam/components/audio_in/audio_in.py +74 -0
  11. viam/components/audio_in/client.py +76 -0
  12. viam/components/audio_in/service.py +83 -0
  13. viam/components/audio_out/__init__.py +21 -0
  14. viam/components/audio_out/audio_out.py +72 -0
  15. viam/components/audio_out/client.py +67 -0
  16. viam/components/audio_out/service.py +63 -0
  17. viam/components/base/base.py +1 -1
  18. viam/components/board/board.py +8 -2
  19. viam/components/board/client.py +2 -1
  20. viam/components/board/service.py +1 -0
  21. viam/components/button/__init__.py +10 -0
  22. viam/components/button/button.py +41 -0
  23. viam/components/button/client.py +52 -0
  24. viam/components/button/service.py +46 -0
  25. viam/components/camera/camera.py +15 -30
  26. viam/components/camera/client.py +10 -21
  27. viam/components/camera/service.py +15 -28
  28. viam/components/component_base.py +2 -2
  29. viam/components/gantry/client.py +17 -2
  30. viam/components/gantry/gantry.py +32 -1
  31. viam/components/gantry/service.py +21 -5
  32. viam/components/gripper/__init__.py +2 -0
  33. viam/components/gripper/client.py +25 -2
  34. viam/components/gripper/gripper.py +76 -1
  35. viam/components/gripper/service.py +32 -3
  36. viam/components/input/input.py +1 -1
  37. viam/components/motor/motor.py +1 -1
  38. viam/components/power_sensor/power_sensor.py +1 -1
  39. viam/components/switch/__init__.py +10 -0
  40. viam/components/switch/client.py +83 -0
  41. viam/components/switch/service.py +72 -0
  42. viam/components/switch/switch.py +98 -0
  43. viam/gen/app/agent/v1/agent_pb2.py +1 -1
  44. viam/gen/app/cloudslam/v1/cloud_slam_pb2.py +1 -1
  45. viam/gen/app/data/v1/data_grpc.py +74 -2
  46. viam/gen/app/data/v1/data_pb2.py +198 -104
  47. viam/gen/app/data/v1/data_pb2.pyi +563 -31
  48. viam/gen/app/datapipelines/__init__.py +0 -0
  49. viam/gen/app/datapipelines/v1/__init__.py +0 -0
  50. viam/gen/app/datapipelines/v1/data_pipelines_grpc.py +84 -0
  51. viam/gen/app/datapipelines/v1/data_pipelines_pb2.py +57 -0
  52. viam/gen/app/datapipelines/v1/data_pipelines_pb2.pyi +387 -0
  53. viam/gen/app/dataset/v1/dataset_grpc.py +10 -2
  54. viam/gen/app/dataset/v1/dataset_pb2.py +8 -4
  55. viam/gen/app/dataset/v1/dataset_pb2.pyi +36 -1
  56. viam/gen/app/datasync/v1/data_sync_pb2.py +39 -35
  57. viam/gen/app/datasync/v1/data_sync_pb2.pyi +21 -8
  58. viam/gen/app/mlinference/v1/ml_inference_pb2.py +7 -7
  59. viam/gen/app/mlinference/v1/ml_inference_pb2.pyi +4 -2
  60. viam/gen/app/mltraining/v1/ml_training_grpc.py +10 -2
  61. viam/gen/app/mltraining/v1/ml_training_pb2.py +63 -43
  62. viam/gen/app/mltraining/v1/ml_training_pb2.pyi +112 -7
  63. viam/gen/app/packages/v1/packages_pb2.py +1 -1
  64. viam/gen/app/v1/app_grpc.py +74 -3
  65. viam/gen/app/v1/app_pb2.py +600 -545
  66. viam/gen/app/v1/app_pb2.pyi +1108 -258
  67. viam/gen/app/v1/billing_grpc.py +26 -2
  68. viam/gen/app/v1/billing_pb2.py +52 -36
  69. viam/gen/app/v1/billing_pb2.pyi +158 -4
  70. viam/gen/app/v1/end_user_pb2.py +1 -1
  71. viam/gen/app/v1/robot_pb2.py +95 -89
  72. viam/gen/app/v1/robot_pb2.pyi +121 -9
  73. viam/gen/common/v1/common_pb2.py +76 -58
  74. viam/gen/common/v1/common_pb2.pyi +186 -17
  75. viam/gen/component/arm/v1/arm_grpc.py +10 -2
  76. viam/gen/component/arm/v1/arm_pb2.py +5 -3
  77. viam/gen/component/audioin/__init__.py +0 -0
  78. viam/gen/component/audioin/v1/__init__.py +0 -0
  79. viam/gen/component/audioin/v1/audioin_grpc.py +54 -0
  80. viam/gen/component/audioin/v1/audioin_pb2.py +34 -0
  81. viam/gen/component/audioin/v1/audioin_pb2.pyi +94 -0
  82. viam/gen/component/audioinput/v1/audioinput_pb2.py +1 -1
  83. viam/gen/component/audioout/__init__.py +0 -0
  84. viam/gen/component/audioout/v1/__init__.py +0 -0
  85. viam/gen/component/audioout/v1/audioout_grpc.py +54 -0
  86. viam/gen/component/audioout/v1/audioout_pb2.py +32 -0
  87. viam/gen/component/audioout/v1/audioout_pb2.pyi +47 -0
  88. viam/gen/component/base/v1/base_pb2.py +1 -1
  89. viam/gen/component/board/v1/board_pb2.py +1 -1
  90. viam/gen/component/button/v1/button_pb2.py +1 -1
  91. viam/gen/component/camera/v1/camera_grpc.py +1 -0
  92. viam/gen/component/camera/v1/camera_pb2.py +37 -36
  93. viam/gen/component/camera/v1/camera_pb2.pyi +31 -4
  94. viam/gen/component/encoder/v1/encoder_pb2.py +1 -1
  95. viam/gen/component/gantry/v1/gantry_grpc.py +9 -1
  96. viam/gen/component/gantry/v1/gantry_pb2.py +5 -3
  97. viam/gen/component/generic/v1/generic_pb2.py +1 -1
  98. viam/gen/component/gripper/v1/gripper_grpc.py +18 -2
  99. viam/gen/component/gripper/v1/gripper_pb2.py +12 -4
  100. viam/gen/component/gripper/v1/gripper_pb2.pyi +43 -1
  101. viam/gen/component/inputcontroller/v1/input_controller_pb2.py +1 -1
  102. viam/gen/component/motor/v1/motor_pb2.py +1 -1
  103. viam/gen/component/movementsensor/v1/movementsensor_pb2.py +1 -1
  104. viam/gen/component/posetracker/v1/pose_tracker_pb2.py +1 -1
  105. viam/gen/component/powersensor/v1/powersensor_pb2.py +1 -1
  106. viam/gen/component/sensor/v1/sensor_pb2.py +1 -1
  107. viam/gen/component/servo/v1/servo_pb2.py +1 -1
  108. viam/gen/component/switch/v1/switch_pb2.py +5 -5
  109. viam/gen/component/switch/v1/switch_pb2.pyi +9 -2
  110. viam/gen/component/testecho/v1/testecho_pb2.py +1 -1
  111. viam/gen/module/v1/module_pb2.py +5 -5
  112. viam/gen/module/v1/module_pb2.pyi +7 -2
  113. viam/gen/opentelemetry/__init__.py +0 -0
  114. viam/gen/opentelemetry/proto/__init__.py +0 -0
  115. viam/gen/opentelemetry/proto/common/__init__.py +0 -0
  116. viam/gen/opentelemetry/proto/common/v1/__init__.py +0 -0
  117. viam/gen/opentelemetry/proto/common/v1/common_grpc.py +0 -0
  118. viam/gen/opentelemetry/proto/common/v1/common_pb2.py +27 -0
  119. viam/gen/opentelemetry/proto/common/v1/common_pb2.pyi +208 -0
  120. viam/gen/opentelemetry/proto/resource/__init__.py +0 -0
  121. viam/gen/opentelemetry/proto/resource/v1/__init__.py +0 -0
  122. viam/gen/opentelemetry/proto/resource/v1/resource_grpc.py +0 -0
  123. viam/gen/opentelemetry/proto/resource/v1/resource_pb2.py +18 -0
  124. viam/gen/opentelemetry/proto/resource/v1/resource_pb2.pyi +59 -0
  125. viam/gen/opentelemetry/proto/trace/__init__.py +0 -0
  126. viam/gen/opentelemetry/proto/trace/v1/__init__.py +0 -0
  127. viam/gen/opentelemetry/proto/trace/v1/trace_grpc.py +0 -0
  128. viam/gen/opentelemetry/proto/trace/v1/trace_pb2.py +37 -0
  129. viam/gen/opentelemetry/proto/trace/v1/trace_pb2.pyi +402 -0
  130. viam/gen/proto/rpc/examples/echo/v1/echo_pb2.py +1 -1
  131. viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.py +1 -1
  132. viam/gen/proto/rpc/v1/auth_pb2.py +1 -1
  133. viam/gen/proto/rpc/webrtc/v1/grpc_pb2.py +1 -1
  134. viam/gen/proto/rpc/webrtc/v1/signaling_pb2.py +1 -1
  135. viam/gen/provisioning/v1/provisioning_grpc.py +10 -2
  136. viam/gen/provisioning/v1/provisioning_pb2.py +32 -26
  137. viam/gen/provisioning/v1/provisioning_pb2.pyi +46 -5
  138. viam/gen/robot/v1/robot_grpc.py +51 -34
  139. viam/gen/robot/v1/robot_pb2.py +147 -142
  140. viam/gen/robot/v1/robot_pb2.pyi +153 -86
  141. viam/gen/service/datamanager/v1/data_manager_grpc.py +11 -2
  142. viam/gen/service/datamanager/v1/data_manager_pb2.py +15 -8
  143. viam/gen/service/datamanager/v1/data_manager_pb2.pyi +47 -1
  144. viam/gen/service/discovery/v1/discovery_pb2.py +1 -1
  145. viam/gen/service/generic/v1/generic_pb2.py +1 -1
  146. viam/gen/service/mlmodel/v1/mlmodel_pb2.py +1 -1
  147. viam/gen/service/motion/v1/motion_pb2.py +92 -62
  148. viam/gen/service/motion/v1/motion_pb2.pyi +130 -68
  149. viam/gen/service/navigation/v1/navigation_pb2.py +1 -1
  150. viam/gen/service/sensors/v1/sensors_pb2.py +1 -1
  151. viam/gen/service/shell/v1/shell_pb2.py +1 -1
  152. viam/gen/service/slam/v1/slam_pb2.py +1 -1
  153. viam/gen/service/slam/v1/slam_pb2.pyi +1 -1
  154. viam/gen/service/video/__init__.py +0 -0
  155. viam/gen/service/video/v1/__init__.py +0 -0
  156. viam/gen/service/video/v1/video_grpc.py +39 -0
  157. viam/gen/service/video/v1/video_pb2.py +29 -0
  158. viam/gen/service/video/v1/video_pb2.pyi +72 -0
  159. viam/gen/service/vision/v1/vision_pb2.py +27 -27
  160. viam/gen/service/vision/v1/vision_pb2.pyi +28 -3
  161. viam/gen/service/worldstatestore/__init__.py +0 -0
  162. viam/gen/service/worldstatestore/v1/__init__.py +0 -0
  163. viam/gen/service/worldstatestore/v1/world_state_store_grpc.py +55 -0
  164. viam/gen/service/worldstatestore/v1/world_state_store_pb2.py +39 -0
  165. viam/gen/service/worldstatestore/v1/world_state_store_pb2.pyi +171 -0
  166. viam/gen/stream/v1/stream_pb2.py +1 -1
  167. viam/gen/tagger/v1/tagger_pb2.py +1 -1
  168. viam/logging.py +9 -8
  169. viam/media/audio.py +22 -10
  170. viam/media/utils/pil/__init__.py +5 -1
  171. viam/media/video.py +54 -40
  172. viam/module/module.py +85 -16
  173. viam/module/resource_data_consumer.py +41 -0
  174. viam/module/service.py +9 -1
  175. viam/proto/app/__init__.py +68 -0
  176. viam/proto/app/billing.py +16 -0
  177. viam/proto/app/data/__init__.py +48 -0
  178. viam/proto/app/datapipelines/__init__.py +56 -0
  179. viam/proto/app/dataset/__init__.py +4 -0
  180. viam/proto/app/mltraining/__init__.py +6 -0
  181. viam/proto/app/robot.py +6 -0
  182. viam/proto/common/__init__.py +14 -0
  183. viam/proto/component/audioin/__init__.py +16 -0
  184. viam/proto/component/audioout/__init__.py +15 -0
  185. viam/proto/component/camera/__init__.py +0 -2
  186. viam/proto/component/gripper/__init__.py +4 -0
  187. viam/proto/opentelemetry/__init__.py +0 -0
  188. viam/proto/opentelemetry/proto/__init__.py +0 -0
  189. viam/proto/opentelemetry/proto/common/__init__.py +15 -0
  190. viam/proto/opentelemetry/proto/resource/__init__.py +10 -0
  191. viam/proto/opentelemetry/proto/trace/__init__.py +15 -0
  192. viam/proto/provisioning/__init__.py +6 -0
  193. viam/proto/robot/__init__.py +16 -8
  194. viam/proto/service/datamanager/__init__.py +8 -1
  195. viam/proto/service/motion/__init__.py +2 -0
  196. viam/proto/service/video/__init__.py +15 -0
  197. viam/proto/service/worldstatestore/__init__.py +32 -0
  198. viam/resource/easy_resource.py +5 -9
  199. viam/resource/manager.py +4 -3
  200. viam/resource/registry.py +2 -2
  201. viam/resource/types.py +2 -2
  202. viam/robot/client.py +38 -59
  203. viam/rpc/dial.py +48 -5
  204. viam/rpc/libviam_rust_utils.so +0 -0
  205. viam/rpc/server.py +24 -10
  206. viam/services/motion/client.py +8 -9
  207. viam/services/motion/motion.py +48 -46
  208. viam/services/navigation/navigation.py +2 -2
  209. viam/services/vision/client.py +1 -1
  210. viam/services/vision/service.py +5 -8
  211. viam/services/vision/vision.py +5 -3
  212. viam/services/worldstatestore/__init__.py +18 -0
  213. viam/services/worldstatestore/client.py +94 -0
  214. viam/services/worldstatestore/service.py +55 -0
  215. viam/services/worldstatestore/worldstatestore.py +90 -0
  216. viam/sessions_client.py +115 -46
  217. viam/version_metadata.py +2 -2
  218. {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/METADATA +10 -6
  219. {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/RECORD +221 -152
  220. {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/WHEEL +1 -1
  221. viam/components/audio_input/__init__.py +0 -18
  222. viam/components/audio_input/audio_input.py +0 -81
  223. viam/components/audio_input/client.py +0 -70
  224. viam/components/audio_input/service.py +0 -114
  225. {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/licenses/LICENSE +0 -0
@@ -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,21 +1,60 @@
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
- from viam.proto.component.camera import Format
9
7
 
10
8
  from .viam_rgba import RGBA_HEADER_LENGTH, RGBA_MAGIC_NUMBER
11
9
 
12
10
 
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"
11
+ class _FrozenClassAttributesMeta(type):
12
+ """
13
+ A metaclass that prevents the reassignment of existing class attributes.
14
+ """
15
+
16
+ def __setattr__(cls, name: str, value: Any):
17
+ # Check if the attribute `name` already exists on the class
18
+ if name in cls.__dict__:
19
+ # If it exists, raise an error to prevent overwriting
20
+ raise AttributeError(f"Cannot reassign constant '{name}'")
21
+ # If it's a new attribute, allow it to be set
22
+ super().__setattr__(name, value)
23
+
24
+
25
+ class CameraMimeType(str, metaclass=_FrozenClassAttributesMeta):
26
+ """
27
+ The compatible mime-types for cameras and vision services.
28
+
29
+ You can use the `CameraMimeType.CUSTOM(...)` method to use an unlisted mime-type.
30
+ """
31
+
32
+ VIAM_RGBA: ClassVar[Self]
33
+ VIAM_RAW_DEPTH: ClassVar[Self]
34
+ JPEG: ClassVar[Self]
35
+ PNG: ClassVar[Self]
36
+ PCD: ClassVar[Self]
37
+
38
+ @property
39
+ def name(self) -> str:
40
+ for key, value in self.__class__.__dict__.items():
41
+ if value == self:
42
+ return key
43
+ return "CUSTOM"
44
+
45
+ @property
46
+ def value(self) -> str:
47
+ return self
48
+
49
+ @classmethod
50
+ def CUSTOM(cls, mime_type: str) -> Self:
51
+ """
52
+ Create a custom mime type.
53
+
54
+ Args:
55
+ mime_type (str): The mimetype as a string
56
+ """
57
+ return cls.from_string(mime_type)
19
58
 
20
59
  @classmethod
21
60
  def from_string(cls, value: str) -> Self:
@@ -30,37 +69,12 @@ class CameraMimeType(str, Enum):
30
69
  value_mime = value[:-5] if value.endswith("+lazy") else value # ViamImage lazy encodes by default
31
70
  return cls(value_mime)
32
71
 
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
72
 
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)
73
+ CameraMimeType.VIAM_RGBA = CameraMimeType.from_string("image/vnd.viam.rgba")
74
+ CameraMimeType.VIAM_RAW_DEPTH = CameraMimeType.from_string("image/vnd.viam.dep")
75
+ CameraMimeType.JPEG = CameraMimeType.from_string("image/jpeg")
76
+ CameraMimeType.PNG = CameraMimeType.from_string("image/png")
77
+ CameraMimeType.PCD = CameraMimeType.from_string("pointcloud/pcd")
64
78
 
65
79
 
66
80
  class ViamImage:
viam/module/module.py CHANGED
@@ -1,11 +1,14 @@
1
1
  import argparse
2
2
  import io
3
3
  import logging as pylogging
4
+ import os
4
5
  import sys
6
+ from collections.abc import Iterable
5
7
  from inspect import iscoroutinefunction
6
8
  from threading import Lock
7
9
  from typing import List, Mapping, Optional, Sequence, Tuple
8
10
 
11
+ from grpclib.metadata import Deadline
9
12
  from grpclib.utils import _service_name
10
13
  from typing_extensions import Self
11
14
 
@@ -29,13 +32,37 @@ from viam.resource.base import ResourceBase
29
32
  from viam.resource.registry import Registry
30
33
  from viam.resource.types import API, RESOURCE_TYPE_COMPONENT, RESOURCE_TYPE_SERVICE, Model, ResourceName, resource_name_from_string
31
34
  from viam.robot.client import RobotClient
32
- from viam.rpc.dial import DialOptions
35
+ from viam.rpc.dial import DialOptions, _host_port_from_url
33
36
  from viam.rpc.server import Server
34
37
 
38
+ # These imports are required to register built-in resources with the registry
39
+ from ..components.arm import Arm # noqa: F401
40
+ from ..components.base import Base # noqa: F401
41
+ from ..components.board import Board # noqa: F401
42
+ from ..components.button import Button # noqa: F401
43
+ from ..components.camera import Camera # noqa: F401
44
+ from ..components.encoder import Encoder # noqa: F401
45
+ from ..components.gantry import Gantry # noqa: F401
46
+ from ..components.generic import Generic as GenericComponent # noqa: F401
47
+ from ..components.gripper import Gripper # noqa: F401
48
+ from ..components.input import Controller # noqa: F401
49
+ from ..components.motor import Motor # noqa: F401
50
+ from ..components.movement_sensor import MovementSensor # noqa: F401
51
+ from ..components.pose_tracker import PoseTracker # noqa: F401
52
+ from ..components.power_sensor import PowerSensor # noqa: F401
53
+ from ..components.sensor import Sensor # noqa: F401
54
+ from ..components.servo import Servo # noqa: F401
55
+ from ..components.switch import Switch # noqa: F401
56
+ from ..services.discovery import Discovery # noqa: F401
57
+ from ..services.generic import Generic as GenericService # noqa: F401
58
+ from ..services.motion import Motion # noqa: F401
59
+ from ..services.navigation import Navigation # noqa: F401
60
+ from ..services.slam import SLAM # noqa: F401
61
+ from ..services.vision import Vision # noqa: F401
35
62
  from .service import ModuleRPCService
36
63
  from .types import Reconfigurable, Stoppable
37
64
 
38
- LOGGER = logging.getLogger(__name__)
65
+ NO_MODULE_PARENT = os.environ.get("VIAM_NO_MODULE_PARENT", "").lower() == "true"
39
66
 
40
67
 
41
68
  def _parse_module_args() -> argparse.Namespace:
@@ -45,7 +72,8 @@ def _parse_module_args() -> argparse.Namespace:
45
72
  p = argparse.ArgumentParser(description="Start this viam python module")
46
73
  p.add_argument("socket_path", help="path where this module will serve a unix socket")
47
74
  p.add_argument("--log-level", type=lambda name: pylogging._nameToLevel[name.upper()], default=logging.INFO)
48
- return p.parse_args()
75
+ p.add_argument("--tcp-mode", action="store_true")
76
+ return p.parse_known_args()[0]
49
77
 
50
78
 
51
79
  class Module:
@@ -54,8 +82,10 @@ class Module:
54
82
  _ready: bool
55
83
  _log_level: int
56
84
  _lock: Lock
85
+ _tcp_mode: bool
57
86
  parent: Optional[RobotClient] = None
58
87
  server: Server
88
+ logger: pylogging.Logger
59
89
 
60
90
  @classmethod
61
91
  def from_args(cls) -> Self:
@@ -71,7 +101,7 @@ class Module:
71
101
  Module: a new Module instance
72
102
  """
73
103
  args = _parse_module_args()
74
- return cls(args.socket_path, log_level=args.log_level)
104
+ return cls(args.socket_path, log_level=args.log_level, tcp_mode=args.tcp_mode)
75
105
 
76
106
  @classmethod
77
107
  async def run_with_models(cls, *models: ResourceBase):
@@ -103,7 +133,7 @@ class Module:
103
133
  module.add_model_from_registry(*key.split("/")) # pyright: ignore [reportArgumentType]
104
134
  await module.start()
105
135
 
106
- def __init__(self, address: str, *, log_level: int = logging.INFO) -> None:
136
+ def __init__(self, address: str, *, log_level: int = logging.INFO, tcp_mode: bool = False) -> None:
107
137
  # When a module is launched by viam-server, its stdout is not connected to a tty. In
108
138
  # response, python disables line buffering, which prevents `print` statements from being
109
139
  # immediately flushed to viam-server. This behavior can be confusing, interfere with
@@ -114,12 +144,21 @@ class Module:
114
144
  if isinstance(sys.stderr, io.TextIOWrapper):
115
145
  sys.stderr.reconfigure(line_buffering=True)
116
146
  self._address = address
147
+ self._tcp_mode = tcp_mode
117
148
  self.server = Server(resources=[], module_service=ModuleRPCService(self))
118
149
  self._log_level = log_level
150
+
151
+ module_name = os.environ.get("VIAM_MODULE_NAME")
152
+ # this can happen if the user is running an old version of viam-server that doesn't set `VIAM_MODULE_NAME`
153
+ if module_name is None:
154
+ module_name = __name__
155
+ self.logger = logging.getLogger(module_name)
119
156
  self._ready = True
120
157
  self._lock = Lock()
121
158
 
122
159
  async def _connect_to_parent(self):
160
+ if NO_MODULE_PARENT:
161
+ return
123
162
  if self.parent is None:
124
163
  if self._parent_address is None:
125
164
  raise ValueError("Parent address not found")
@@ -130,7 +169,7 @@ class Module:
130
169
  log_level=self._log_level,
131
170
  ),
132
171
  )
133
- LOGGER.debug("Starting module logging")
172
+ self.logger.debug("Starting module logging")
134
173
  logging.setParent(self.parent)
135
174
 
136
175
  async def _get_resource(self, name: ResourceName) -> ResourceBase:
@@ -153,19 +192,23 @@ class Module:
153
192
  async def start(self):
154
193
  """Start the module service and gRPC server"""
155
194
  try:
156
- await self.server.serve(log_level=self._log_level, path=self._address)
195
+ if self._tcp_mode:
196
+ host, port = _host_port_from_url(self._address)
197
+ await self.server.serve(log_level=self._log_level, host=host, port=port)
198
+ else:
199
+ await self.server.serve(log_level=self._log_level, path=self._address)
157
200
  finally:
158
201
  await self.stop()
159
202
 
160
203
  async def stop(self):
161
204
  """Stop the module service and gRPC server"""
162
- LOGGER.debug("Shutting down module")
205
+ self.logger.debug("Shutting down module")
163
206
  try:
164
207
  logging.shutdown()
165
208
  if self.parent is not None:
166
209
  await self.parent.close()
167
210
  except Exception as e:
168
- LOGGER.error("Encountered error while shutting down module", exc_info=e)
211
+ self.logger.error("Encountered error while shutting down module", exc_info=e)
169
212
 
170
213
  def set_ready(self, ready: bool):
171
214
  """Set the module's ready state. The module automatically sets to READY on load. Setting to False can be useful
@@ -177,13 +220,15 @@ class Module:
177
220
  with self._lock:
178
221
  self._ready = ready
179
222
 
180
- async def add_resource(self, request: AddResourceRequest):
223
+ async def add_resource(self, request: AddResourceRequest, *, deadline: Optional[Deadline] = None):
181
224
  dependencies = await self._get_dependencies(request.dependencies)
182
225
  config: ComponentConfig = request.config
183
226
  api = API.from_string(config.api)
184
227
  model = Model.from_string(config.model, ignore_errors=True)
185
228
  creator = Registry.lookup_resource_creator(api, model)
186
229
  resource = creator(config, dependencies)
230
+ if deadline is not None and deadline.time_remaining() <= 0:
231
+ raise TimeoutError("Deadline expired")
187
232
  update_log_level(resource.logger, config.log_configuration.level.upper())
188
233
  self.server.register(resource)
189
234
 
@@ -210,10 +255,13 @@ class Module:
210
255
  rn = resource_name_from_string(request.name)
211
256
  resource = self.server.get_resource(ResourceBase, rn)
212
257
  if isinstance(resource, Stoppable):
213
- if iscoroutinefunction(resource.stop):
214
- await resource.stop()
215
- else:
216
- resource.stop()
258
+ try:
259
+ if iscoroutinefunction(resource.stop):
260
+ await resource.stop()
261
+ else:
262
+ resource.stop()
263
+ except Exception as e:
264
+ self.logger.warning(f"Could not remove resource named {resource.name}", exc_info=e)
217
265
  await self.server.remove_resource(rn)
218
266
 
219
267
  async def ready(self, request: ReadyRequest) -> ReadyResponse:
@@ -266,7 +314,28 @@ class Module:
266
314
  model = Model.from_string(config.model)
267
315
  validator = Registry.lookup_validator(api, model)
268
316
  try:
269
- dependencies = validator(config)
270
- return ValidateConfigResponse(dependencies=dependencies)
317
+ # backwards compatibility. Support both ([], []) or [] with deprecation warning.
318
+ # If user's validate returns [str], it will be treated as required dependencies only.
319
+ # Incorect formats, e.g. int, will raise ValidationError.
320
+ _validator_return_test = validator(config)
321
+ if not (isinstance(_validator_return_test, tuple) and len(_validator_return_test) == 2):
322
+ msg = f"Your validate function {validator.__name__} did not return \
323
+ type tuple[Sequence[str], Sequence[str]]. Got {_validator_return_test}."
324
+ self.logger.warning(msg)
325
+ if (isinstance(_validator_return_test, Iterable) and not isinstance(_validator_return_test, str)) and all(
326
+ isinstance(e, str)
327
+ for e in _validator_return_test # type: ignore
328
+ ):
329
+ self.logger.warning(
330
+ f"Detected deprecated validate function signature. \
331
+ Treating all dependencies {_validator_return_test} as required dependencies. \
332
+ Please update to new signature Tuple[Sequence[str], Sequence[str]] soon."
333
+ )
334
+ return ValidateConfigResponse(dependencies=_validator_return_test)
335
+ else:
336
+ raise ValidationError(msg)
337
+
338
+ dependencies, optional_dependencies = _validator_return_test
339
+ return ValidateConfigResponse(dependencies=dependencies, optional_dependencies=optional_dependencies)
271
340
  except Exception as e:
272
341
  raise ValidationError(f"{type(Exception)}: {e}").grpc_error
@@ -0,0 +1,41 @@
1
+ import datetime
2
+ import os
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ from viam.app.viam_client import ViamClient
6
+
7
+
8
+ class ResourceDataConsumer:
9
+ """Client for retrieving historical module data from app.
10
+
11
+ Inherit from this class in a module to get access to historical module data.
12
+ """
13
+
14
+ @classmethod
15
+ def construct_query(cls, part_id: str, resource_name: str, time_back: datetime.timedelta) -> List[Dict[str, Any]]:
16
+ return [
17
+ {
18
+ "$match": {
19
+ "part_id": part_id,
20
+ "component_name": resource_name,
21
+ "time_received": {"$gte": datetime.datetime.now() - time_back},
22
+ }
23
+ }
24
+ ]
25
+
26
+ @classmethod
27
+ async def query_tabular_data(
28
+ cls, resource_name: str, time_back: datetime.timedelta, additional_stages: Optional[List[Dict[str, Any]]] = None, **kwargs
29
+ ) -> List[Dict[str, Any]]:
30
+ """Return historical data for this module, queried with MQL."""
31
+ viam_client = await ViamClient.create_from_env_vars()
32
+
33
+ org_id = os.environ["VIAM_PRIMARY_ORG_ID"]
34
+ part_id = os.environ["VIAM_MACHINE_PART_ID"]
35
+
36
+ query = cls.construct_query(part_id=part_id, resource_name=resource_name, time_back=time_back)
37
+
38
+ if additional_stages is not None:
39
+ query += additional_stages
40
+
41
+ return await viam_client.data_client.tabular_data_by_mql(org_id, query)
viam/module/service.py CHANGED
@@ -1,7 +1,9 @@
1
1
  from typing import TYPE_CHECKING
2
2
 
3
+ from grpclib import Status
3
4
  from grpclib.server import Stream
4
5
 
6
+ from viam.errors import ViamGRPCError
5
7
  from viam.proto.module import (
6
8
  AddResourceRequest,
7
9
  AddResourceResponse,
@@ -29,7 +31,13 @@ class ModuleRPCService(ModuleServiceBase):
29
31
  async def AddResource(self, stream: Stream[AddResourceRequest, AddResourceResponse]) -> None:
30
32
  request = await stream.recv_message()
31
33
  assert request is not None
32
- await self._module.add_resource(request)
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
+ )
33
41
  await stream.send_message(AddResourceResponse())
34
42
 
35
43
  async def ReconfigureResource(self, stream: Stream[ReconfigureResourceRequest, ReconfigureResourceResponse]) -> None:
@@ -11,6 +11,9 @@ from ...gen.app.v1.app_pb2 import (
11
11
  AddRoleResponse,
12
12
  APIKey,
13
13
  APIKeyWithAuthorizations,
14
+ App,
15
+ AppCustomizations,
16
+ AppType,
14
17
  AuthenticationType,
15
18
  AuthenticatorInfo,
16
19
  Authorization,
@@ -83,10 +86,17 @@ from ...gen.app.v1.app_pb2 import (
83
86
  FragmentError,
84
87
  FragmentErrorType,
85
88
  FragmentHistoryEntry,
89
+ FragmentImport,
90
+ FragmentImportList,
86
91
  FragmentRevision,
92
+ FragmentSummary,
87
93
  FragmentTag,
88
94
  FragmentUsage,
89
95
  FragmentVisibility,
96
+ GetAppBrandingRequest,
97
+ GetAppBrandingResponse,
98
+ GetAppContentRequest,
99
+ GetAppContentResponse,
90
100
  GetBillingServiceConfigRequest,
91
101
  GetBillingServiceConfigResponse,
92
102
  GetFragmentHistoryRequest,
@@ -115,6 +125,8 @@ from ...gen.app.v1.app_pb2 import (
115
125
  GetRobotAPIKeysResponse,
116
126
  GetRobotMetadataRequest,
117
127
  GetRobotMetadataResponse,
128
+ GetRobotPartByNameAndLocationRequest,
129
+ GetRobotPartByNameAndLocationResponse,
118
130
  GetRobotPartHistoryRequest,
119
131
  GetRobotPartHistoryResponse,
120
132
  GetRobotPartLogsRequest,
@@ -141,8 +153,12 @@ from ...gen.app.v1.app_pb2 import (
141
153
  ListLocationsResponse,
142
154
  ListMachineFragmentsRequest,
143
155
  ListMachineFragmentsResponse,
156
+ ListMachineSummariesRequest,
157
+ ListMachineSummariesResponse,
144
158
  ListModulesRequest,
145
159
  ListModulesResponse,
160
+ ListNestedFragmentsRequest,
161
+ ListNestedFragmentsResponse,
146
162
  ListOAuthAppsRequest,
147
163
  ListOAuthAppsResponse,
148
164
  ListOrganizationMembersRequest,
@@ -153,6 +169,10 @@ from ...gen.app.v1.app_pb2 import (
153
169
  ListOrganizationsResponse,
154
170
  ListRegistryItemsRequest,
155
171
  ListRegistryItemsResponse,
172
+ ListRobotsForLocationsRequest,
173
+ ListRobotsForLocationsResponse,
174
+ ListRobotsForOrgRequest,
175
+ ListRobotsForOrgResponse,
156
176
  ListRobotsRequest,
157
177
  ListRobotsResponse,
158
178
  Location,
@@ -160,6 +180,9 @@ from ...gen.app.v1.app_pb2 import (
160
180
  LocationAuthRequest,
161
181
  LocationAuthResponse,
162
182
  LocationOrganization,
183
+ LocationSummary,
184
+ MachinePickerCustomizations,
185
+ MachineSummary,
163
186
  MarkPartAsMainRequest,
164
187
  MarkPartAsMainResponse,
165
188
  MarkPartForRestartRequest,
@@ -170,13 +193,16 @@ from ...gen.app.v1.app_pb2 import (
170
193
  Model,
171
194
  Module,
172
195
  ModuleFileInfo,
196
+ ModuleLanguage,
173
197
  ModuleMetadata,
198
+ ModuleSourceType,
174
199
  ModuleVersion,
175
200
  NewRobotPartRequest,
176
201
  NewRobotPartResponse,
177
202
  NewRobotRequest,
178
203
  NewRobotResponse,
179
204
  OAuthConfig,
205
+ OnlineState,
180
206
  Organization,
181
207
  OrganizationGetLogoRequest,
182
208
  OrganizationGetLogoResponse,
@@ -190,6 +216,7 @@ from ...gen.app.v1.app_pb2 import (
190
216
  OrganizationSetSupportEmailRequest,
191
217
  OrganizationSetSupportEmailResponse,
192
218
  OrgDetails,
219
+ PartSummary,
193
220
  ReadOAuthAppRequest,
194
221
  ReadOAuthAppResponse,
195
222
  RegistryItem,
@@ -198,6 +225,8 @@ from ...gen.app.v1.app_pb2 import (
198
225
  RemoveRoleResponse,
199
226
  RenameKeyRequest,
200
227
  RenameKeyResponse,
228
+ RenameRegistryItemRequest,
229
+ RenameRegistryItemResponse,
201
230
  ResendOrganizationInviteRequest,
202
231
  ResendOrganizationInviteResponse,
203
232
  ResolvedFragment,
@@ -217,6 +246,7 @@ from ...gen.app.v1.app_pb2 import (
217
246
  StorageConfig,
218
247
  TailRobotPartLogsRequest,
219
248
  TailRobotPartLogsResponse,
249
+ TextOverrides,
220
250
  TransferRegistryItemRequest,
221
251
  TransferRegistryItemResponse,
222
252
  UnshareLocationRequest,
@@ -240,6 +270,8 @@ from ...gen.app.v1.app_pb2 import (
240
270
  UpdateOrganizationInviteAuthorizationsResponse,
241
271
  UpdateOrganizationMetadataRequest,
242
272
  UpdateOrganizationMetadataResponse,
273
+ UpdateOrganizationNamespaceRequest,
274
+ UpdateOrganizationNamespaceResponse,
243
275
  UpdateOrganizationRequest,
244
276
  UpdateOrganizationResponse,
245
277
  UpdateRegistryItemRequest,
@@ -257,6 +289,8 @@ from ...gen.app.v1.app_pb2 import (
257
289
  Uploads,
258
290
  URLValidation,
259
291
  VersionHistory,
292
+ ViamAgentVersion,
293
+ ViamServerVersion,
260
294
  Visibility,
261
295
  )
262
296
 
@@ -269,6 +303,9 @@ __all__ = [
269
303
  "AddRoleRequest",
270
304
  "AddRoleResponse",
271
305
  "AdditionalFragment",
306
+ "App",
307
+ "AppCustomizations",
308
+ "AppType",
272
309
  "AuthenticationType",
273
310
  "AuthenticatorInfo",
274
311
  "Authorization",
@@ -341,10 +378,17 @@ __all__ = [
341
378
  "FragmentError",
342
379
  "FragmentErrorType",
343
380
  "FragmentHistoryEntry",
381
+ "FragmentImport",
382
+ "FragmentImportList",
344
383
  "FragmentRevision",
384
+ "FragmentSummary",
345
385
  "FragmentTag",
346
386
  "FragmentUsage",
347
387
  "FragmentVisibility",
388
+ "GetAppBrandingRequest",
389
+ "GetAppBrandingResponse",
390
+ "GetAppContentRequest",
391
+ "GetAppContentResponse",
348
392
  "GetBillingServiceConfigRequest",
349
393
  "GetBillingServiceConfigResponse",
350
394
  "GetFragmentHistoryRequest",
@@ -373,6 +417,8 @@ __all__ = [
373
417
  "GetRobotAPIKeysResponse",
374
418
  "GetRobotMetadataRequest",
375
419
  "GetRobotMetadataResponse",
420
+ "GetRobotPartByNameAndLocationRequest",
421
+ "GetRobotPartByNameAndLocationResponse",
376
422
  "GetRobotPartHistoryRequest",
377
423
  "GetRobotPartHistoryResponse",
378
424
  "GetRobotPartLogsRequest",
@@ -399,8 +445,12 @@ __all__ = [
399
445
  "ListLocationsResponse",
400
446
  "ListMachineFragmentsRequest",
401
447
  "ListMachineFragmentsResponse",
448
+ "ListMachineSummariesRequest",
449
+ "ListMachineSummariesResponse",
402
450
  "ListModulesRequest",
403
451
  "ListModulesResponse",
452
+ "ListNestedFragmentsRequest",
453
+ "ListNestedFragmentsResponse",
404
454
  "ListOAuthAppsRequest",
405
455
  "ListOAuthAppsResponse",
406
456
  "ListOrganizationMembersRequest",
@@ -411,6 +461,10 @@ __all__ = [
411
461
  "ListOrganizationsResponse",
412
462
  "ListRegistryItemsRequest",
413
463
  "ListRegistryItemsResponse",
464
+ "ListRobotsForLocationsRequest",
465
+ "ListRobotsForLocationsResponse",
466
+ "ListRobotsForOrgRequest",
467
+ "ListRobotsForOrgResponse",
414
468
  "ListRobotsRequest",
415
469
  "ListRobotsResponse",
416
470
  "Location",
@@ -418,9 +472,12 @@ __all__ = [
418
472
  "LocationAuthRequest",
419
473
  "LocationAuthResponse",
420
474
  "LocationOrganization",
475
+ "LocationSummary",
421
476
  "MLModelMetadata",
422
477
  "MLTrainingMetadata",
423
478
  "MLTrainingVersion",
479
+ "MachinePickerCustomizations",
480
+ "MachineSummary",
424
481
  "MarkPartAsMainRequest",
425
482
  "MarkPartAsMainResponse",
426
483
  "MarkPartForRestartRequest",
@@ -428,13 +485,16 @@ __all__ = [
428
485
  "Model",
429
486
  "Module",
430
487
  "ModuleFileInfo",
488
+ "ModuleLanguage",
431
489
  "ModuleMetadata",
490
+ "ModuleSourceType",
432
491
  "ModuleVersion",
433
492
  "NewRobotPartRequest",
434
493
  "NewRobotPartResponse",
435
494
  "NewRobotRequest",
436
495
  "NewRobotResponse",
437
496
  "OAuthConfig",
497
+ "OnlineState",
438
498
  "OrgDetails",
439
499
  "Organization",
440
500
  "OrganizationGetLogoRequest",
@@ -449,6 +509,7 @@ __all__ = [
449
509
  "OrganizationSetSupportEmailRequest",
450
510
  "OrganizationSetSupportEmailResponse",
451
511
  "PKCE",
512
+ "PartSummary",
452
513
  "ReadOAuthAppRequest",
453
514
  "ReadOAuthAppResponse",
454
515
  "RegistryItem",
@@ -457,6 +518,8 @@ __all__ = [
457
518
  "RemoveRoleResponse",
458
519
  "RenameKeyRequest",
459
520
  "RenameKeyResponse",
521
+ "RenameRegistryItemRequest",
522
+ "RenameRegistryItemResponse",
460
523
  "ResendOrganizationInviteRequest",
461
524
  "ResendOrganizationInviteResponse",
462
525
  "ResolvedFragment",
@@ -476,6 +539,7 @@ __all__ = [
476
539
  "StorageConfig",
477
540
  "TailRobotPartLogsRequest",
478
541
  "TailRobotPartLogsResponse",
542
+ "TextOverrides",
479
543
  "TransferRegistryItemRequest",
480
544
  "TransferRegistryItemResponse",
481
545
  "URLValidation",
@@ -500,6 +564,8 @@ __all__ = [
500
564
  "UpdateOrganizationInviteAuthorizationsResponse",
501
565
  "UpdateOrganizationMetadataRequest",
502
566
  "UpdateOrganizationMetadataResponse",
567
+ "UpdateOrganizationNamespaceRequest",
568
+ "UpdateOrganizationNamespaceResponse",
503
569
  "UpdateOrganizationRequest",
504
570
  "UpdateOrganizationResponse",
505
571
  "UpdateRegistryItemRequest",
@@ -516,5 +582,7 @@ __all__ = [
516
582
  "UploadModuleFileResponse",
517
583
  "Uploads",
518
584
  "VersionHistory",
585
+ "ViamAgentVersion",
586
+ "ViamServerVersion",
519
587
  "Visibility",
520
588
  ]