From 71031015a98340da63b46fe2573f4403c129d1e1 Mon Sep 17 00:00:00 2001 From: Alden Hsu Date: Tue, 17 Mar 2026 12:27:22 -0400 Subject: [PATCH 1/3] remove reconfigure --- examples/complex_module/src/base/my_base.py | 3 +- examples/complex_module/src/gizmo/my_gizmo.py | 3 +- .../src/summation/my_summation.py | 3 +- examples/optionaldepsmodule/module.py | 3 +- src/viam/module/module.py | 22 +++++------- src/viam/module/types.py | 6 ---- tests/mocks/module/gizmo/my_gizmo.py | 3 +- tests/mocks/module/summation/my_summation.py | 3 +- tests/test_module.py | 34 ------------------- 9 files changed, 15 insertions(+), 65 deletions(-) diff --git a/examples/complex_module/src/base/my_base.py b/examples/complex_module/src/base/my_base.py index dd2a6699d8..2e36741c13 100644 --- a/examples/complex_module/src/base/my_base.py +++ b/examples/complex_module/src/base/my_base.py @@ -4,7 +4,6 @@ from viam.components.base import Base from viam.components.motor import Motor -from viam.module.types import Reconfigurable from viam.proto.app.robot import ComponentConfig from viam.resource.base import ResourceBase from viam.proto.common import Geometry, Vector3, ResourceName @@ -13,7 +12,7 @@ from viam.utils import ValueTypes, struct_to_dict -class MyBase(Base, Reconfigurable): +class MyBase(Base): """ MyBase implements a base that only supports set_power (basic forward/back/turn controls), is_moving (check if in motion), and stop (stop all motion). diff --git a/examples/complex_module/src/gizmo/my_gizmo.py b/examples/complex_module/src/gizmo/my_gizmo.py index 2f2bc49054..d6e2c7215a 100644 --- a/examples/complex_module/src/gizmo/my_gizmo.py +++ b/examples/complex_module/src/gizmo/my_gizmo.py @@ -4,7 +4,6 @@ from viam.logging import getLogger from viam.utils import ValueTypes -from viam.module.types import Reconfigurable from viam.proto.app.robot import ComponentConfig from viam.proto.common import ResourceName from viam.resource.base import ResourceBase @@ -16,7 +15,7 @@ LOGGER = getLogger(__name__) -class MyGizmo(Gizmo, Reconfigurable): +class MyGizmo(Gizmo): """This is the specific implementation of a ``Gizmo`` (defined in api.py). It inherits from Gizmo, as well conforms to the ``Reconfigurable`` protocol, which signifies that this component can be reconfigured. diff --git a/examples/complex_module/src/summation/my_summation.py b/examples/complex_module/src/summation/my_summation.py index 47b9594635..a1a84dc234 100644 --- a/examples/complex_module/src/summation/my_summation.py +++ b/examples/complex_module/src/summation/my_summation.py @@ -2,7 +2,6 @@ from typing_extensions import Self -from viam.module.types import Reconfigurable from viam.utils import ValueTypes from viam.proto.app.robot import ComponentConfig from viam.proto.common import ResourceName @@ -13,7 +12,7 @@ from ..summation.api import SummationService -class MySummationService(SummationService, Reconfigurable): +class MySummationService(SummationService): """This is the specific implementation of a ``SummationService`` (defined in api.py) It inherits from SummationService, as well as conforms to the ``Reconfigurable`` protocol, which signifies that this component can be diff --git a/examples/optionaldepsmodule/module.py b/examples/optionaldepsmodule/module.py index 27093d3716..20af9664de 100644 --- a/examples/optionaldepsmodule/module.py +++ b/examples/optionaldepsmodule/module.py @@ -4,7 +4,6 @@ from viam.components.generic import Generic from viam.components.motor import Motor -from viam.module.types import Reconfigurable from viam.proto.app.robot import ComponentConfig from viam.resource.base import ResourceBase from viam.proto.common import ResourceName @@ -15,7 +14,7 @@ import asyncio -class Foo(Generic, Reconfigurable): +class Foo(Generic): MODEL: ClassVar[Model] = Model(ModelFamily("acme", "demo"), "foo") def __init__(self, name: str): diff --git a/src/viam/module/module.py b/src/viam/module/module.py index 463986c782..ae96b105e5 100644 --- a/src/viam/module/module.py +++ b/src/viam/module/module.py @@ -60,7 +60,7 @@ from ..services.slam import SLAM # noqa: F401 from ..services.vision import Vision # noqa: F401 from .service import ModuleRPCService -from .types import Reconfigurable, Stoppable +from .types import Stoppable NO_MODULE_PARENT = os.environ.get("VIAM_NO_MODULE_PARENT", "").lower() == "true" @@ -233,23 +233,19 @@ async def add_resource(self, request: AddResourceRequest, *, deadline: Optional[ self.server.register(resource) async def reconfigure_resource(self, request: ReconfigureResourceRequest): - dependencies = await self._get_dependencies(request.dependencies) config: ComponentConfig = request.config api = API.from_string(config.api) name = config.name rn = ResourceName(namespace=api.namespace, type=api.resource_type, subtype=api.resource_subtype, name=name) resource = self.server.get_resource(ResourceBase, rn) - if isinstance(resource, Reconfigurable): - resource.reconfigure(config, dependencies) - else: - if isinstance(resource, Stoppable): - if iscoroutinefunction(resource.stop): - await resource.stop() - else: - resource.stop() - add_request = AddResourceRequest(config=request.config, dependencies=request.dependencies) - await self.server.remove_resource(rn) - await self.add_resource(add_request) + if isinstance(resource, Stoppable): + if iscoroutinefunction(resource.stop): + await resource.stop() + else: + resource.stop() + add_request = AddResourceRequest(config=request.config, dependencies=request.dependencies) + await self.server.remove_resource(rn) + await self.add_resource(add_request) async def remove_resource(self, request: RemoveResourceRequest): rn = resource_name_from_string(request.name) diff --git a/src/viam/module/types.py b/src/viam/module/types.py index b1cd3ea73b..4930653426 100644 --- a/src/viam/module/types.py +++ b/src/viam/module/types.py @@ -1,16 +1,10 @@ from typing import Any, Mapping, Optional, Protocol, runtime_checkable -from viam.proto.app.robot import ComponentConfig -from viam.proto.common import ResourceName -from viam.resource.base import ResourceBase - @runtime_checkable class Reconfigurable(Protocol): """The Reconfigurable protocol defines the requirements for making a resource Reconfigurable""" - def reconfigure(self, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]): ... - @runtime_checkable class Stoppable(Protocol): diff --git a/tests/mocks/module/gizmo/my_gizmo.py b/tests/mocks/module/gizmo/my_gizmo.py index 5ae932630b..3ab3f67bf0 100644 --- a/tests/mocks/module/gizmo/my_gizmo.py +++ b/tests/mocks/module/gizmo/my_gizmo.py @@ -3,7 +3,6 @@ from typing_extensions import Self from viam.components.component_base import ComponentBase -from viam.module.types import Reconfigurable from viam.proto.app.robot import ComponentConfig from viam.proto.common import ResourceName from viam.resource.base import ResourceBase @@ -12,7 +11,7 @@ from ..gizmo.api import Gizmo -class MyGizmo(Gizmo, Reconfigurable): +class MyGizmo(Gizmo): MODEL: ClassVar[Model] = Model(ModelFamily("acme", "demo"), "mygizmo") my_arg: str closed: bool = False diff --git a/tests/mocks/module/summation/my_summation.py b/tests/mocks/module/summation/my_summation.py index f613d3885e..97a9fa4802 100644 --- a/tests/mocks/module/summation/my_summation.py +++ b/tests/mocks/module/summation/my_summation.py @@ -2,7 +2,6 @@ from typing_extensions import Self -from viam.module.types import Reconfigurable from viam.proto.app.robot import ComponentConfig from viam.proto.common import ResourceName from viam.resource.base import ResourceBase @@ -11,7 +10,7 @@ from ..summation.api import SummationService -class MySummationService(SummationService, Reconfigurable): +class MySummationService(SummationService): MODEL: ClassVar[Model] = Model.from_string("acme:demo:mysum") subtract: bool diff --git a/tests/test_module.py b/tests/test_module.py index d629bd82f6..8bacfa5705 100644 --- a/tests/test_module.py +++ b/tests/test_module.py @@ -30,7 +30,6 @@ from .mocks.module.gizmo.api import Gizmo from .mocks.module.gizmo.my_gizmo import MyGizmo from .mocks.module.summation.api import SummationService -from .mocks.module.summation.my_summation import MySummationService from .test_robot import service as robot_service # noqa: F401 @@ -108,39 +107,6 @@ async def test_add_resource(self, module: Module): await module.add_resource(req) assert SummationService.get_resource_name("mysum1") in module.server.resources - async def test_reconfigure_resource(self, module: Module): - await self.test_add_resource(module) - - gizmo = module.server.get_resource(MyGizmo, Gizmo.get_resource_name("gizmo1")) - assert gizmo.my_arg == "arg1" - req = ReconfigureResourceRequest( - config=ComponentConfig( - name="gizmo1", - namespace="acme", - type="gizmo", - model="acme:demo:mygizmo", - attributes=dict_to_struct({"arg1": "arg2", "motor": "motor1"}), - api="acme:component:gizmo", - ) - ) - await module.reconfigure_resource(req) - assert gizmo.my_arg == "arg2" - - summer = module.server.get_resource(MySummationService, SummationService.get_resource_name("mysum1")) - assert summer.subtract is False - req = ReconfigureResourceRequest( - config=ComponentConfig( - name="mysum1", - namespace="acme", - type="summation", - model="acme:demo:mysum", - attributes=dict_to_struct({"subtract": True}), - api="acme:service:summation", - ) - ) - await module.reconfigure_resource(req) - assert summer.subtract is True - async def test_add_resource_with_deps(self, robot_service: RobotService, module: Module): # noqa: F811 async with ChannelFor([robot_service]) as channel: _ = mock.patch("viam.module.module.Module._connect_to_parent") From 9da487d4b6ab49a62dd079dd0121555a42981320 Mon Sep 17 00:00:00 2001 From: Alden Hsu Date: Tue, 17 Mar 2026 14:52:43 -0400 Subject: [PATCH 2/3] DeprecationWarning when subclassing Reconfigurable --- src/viam/module/types.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/viam/module/types.py b/src/viam/module/types.py index 4930653426..3ac0e77067 100644 --- a/src/viam/module/types.py +++ b/src/viam/module/types.py @@ -1,9 +1,12 @@ from typing import Any, Mapping, Optional, Protocol, runtime_checkable +import warnings @runtime_checkable class Reconfigurable(Protocol): """The Reconfigurable protocol defines the requirements for making a resource Reconfigurable""" + def __init_subclass__(*args, **kwargs): + warnings.warn("Reconfigure is deprecated, and resources will always rebuild. It is not necessary to implement Reconfigurable.", DeprecationWarning, stacklevel=2) @runtime_checkable From f78397cb378b83451a84d6ec982f1f37da85eb6b Mon Sep 17 00:00:00 2001 From: Alden Hsu Date: Wed, 20 May 2026 13:54:39 -0400 Subject: [PATCH 3/3] remove "reconfigure" from example notebook --- docs/examples/example.ipynb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/examples/example.ipynb b/docs/examples/example.ipynb index a00d2ef07e..090358396c 100644 --- a/docs/examples/example.ipynb +++ b/docs/examples/example.ipynb @@ -288,15 +288,13 @@ "\n", "Click [here](https://github.com/viamrobotics/viam-python-sdk/blob/main/docs/examples/module_step2.py) to see the file with its new `MODEL` variable, creator function, and `main()` function.\n", "\n", - "#### Optional Validator and Reconfiguration Functions\n", - "Modules also have support for validator and reconfiguration functions.\n", + "#### Optional Validator Function\n", + "Modules also have support for validator functions.\n", "\n", "Custom validation can be done by specifying a validate function. Validate functions can raise errors that will be returned to the parent through gRPC. Validate functions return two sequences of strings: the first represents the implicit required dependencies and the second represents the optional dependencies. If there are none for either, return an empty sequence `[]` (if there are no required dependencies and no optional dependencies, return `[], []`) .\n", "\n", "For example, let's say `MySensor` had a `multiplier` argument that is used to multiply the returned readings in `get_readings()`. The validation function can check if a multiplier attribute was provided and prevent erroneous resource start ups.\n", "\n", - "Reconfiguration specifies what values can change based on a new configuration. To allow this, add a `reconfigure()` function to the `MySensor` class. A good pattern is to call `reconfigure()` within `new()`, since initialization and reconfiguration are usually very similar.\n", - "\n", "```python\n", "# ADD `Sequence` and `Tuple` FROM `typing`.\n", "from typing import Sequence, Tuple\n", @@ -348,7 +346,7 @@ " async def main():\n", " Registry.register_resource_creator(Sensor.SUBTYPE, MySensor.MODEL, ResourceCreatorRegistration(MySensor.new, MySensor.validate_config))\n", "```\n", - "Click [here](https://github.com/viamrobotics/viam-python-sdk/blob/main/docs/examples/module_step2_optional.py) to see the new `wifi_sensor_module.py` with the optional validator and reconfiguration functions." + "Click [here](https://github.com/viamrobotics/viam-python-sdk/blob/main/docs/examples/module_step2_optional.py) to see the new `wifi_sensor_module.py` with the optional validator function." ] }, {