Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions docs/data-ai/ai/act.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,21 +192,22 @@ For the safe arm example, you also need to get the name of the existing arm reso
{{% tablestep %}}
**Initialize all variables.**

`viam-server` calls the `reconfigure` method whenever the module starts or a configuration change occurs.
`viam-server` calls the `new` method whenever the module starts or a configuration change occurs.
Use this method to initialize the vision service and camera name, as well as any other resources you plan to use.
The dependencies parameter contains all the resources this component can access.
By using `cast`, you tell Python the type of the resource.

Update the `reconfigure` method to initialize all the variables:
Update the `new` method to initialize all the variables:

{{< tabs >}}
{{% tab name="Python" %}}

```python {class="line-numbers linkable-line-numbers" data-start="79" }
def reconfigure(
self, config: ComponentConfig,
dependencies: Mapping[ResourceName, ResourceBase]
):
@classmethod
def new(
cls, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]
) -> Self:
obj = super().new(config, dependencies)
camera_name = config.attributes.fields["camera_name"].string_value
vision_name = config.attributes.fields["vision_name"].string_value

Expand All @@ -221,10 +222,10 @@ Update the `reconfigure` method to initialize all the variables:
f"{list(dependencies.keys())}")

vision_resource = dependencies[vision_resource_name]
self.vision_service = cast(VisionClient, vision_resource)
self.camera_name = camera_name
obj.vision_service = cast(VisionClient, vision_resource)
obj.camera_name = camera_name

return super().reconfigure(config, dependencies)
return obj
```

{{% /tab %}}
Expand All @@ -236,10 +237,11 @@ Update the `reconfigure` method to initialize all the variables:
{{% tab name="Python" %}}

```python {class="line-numbers linkable-line-numbers" data-start="79" }
def reconfigure(
self, config: ComponentConfig,
dependencies: Mapping[ResourceName, ResourceBase]
):
@classmethod
def new(
cls, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]
) -> Self:
obj = super().new(config, dependencies)
# ...
arm_name = config.attributes.fields["arm_name"].string_value
arm_resource_name = Arm.get_resource_name(arm_name)
Expand All @@ -250,9 +252,9 @@ Update the `reconfigure` method to initialize all the variables:
f"{list(dependencies.keys())}")

arm_resource = dependencies[arm_resource_name]
self.arm = cast(Arm, arm_resource)
obj.arm = cast(Arm, arm_resource)

return super().reconfigure(config, dependencies)
return obj
```

{{% /tab %}}
Expand Down
6 changes: 6 additions & 0 deletions docs/dev/reference/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ date: "2024-09-18"
# updated: "" # When the content was last entirely checked
---

{{% changelog color="changed" title="Use new() instead of reconfigure() in Python modules" date="2025-12-05" %}}

The Python module `reconfigure()` method has been removed in favour of using `new()`.

{{% /changelog %}}

{{% changelog color="changed" title="GetImages replaced GetImage" date="2025-10-31" %}}

[`GetImage`](/dev/reference/apis/components/camera/#getimage) is deprecated.
Expand Down
33 changes: 17 additions & 16 deletions docs/operate/hello-world/tutorial-desk-safari.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ Your game needs to know which camera and vision service to use.
While you could hardcode these names, you'll get them from the button's configuration. This makes your game flexible if you change component names later.

To get parameters from the configuration object, you use the `validate_config` method.
`viam-server` calls the `validate_config` method before calling `reconfigure` to:
`viam-server` calls the `validate_config` method before calling `new` to:

1. Ensure the expected fields are in the config and have the right type.
This method makes sure the camera name and vision service name are present and raises errors if they are not provided.
Expand Down Expand Up @@ -444,9 +444,9 @@ In the <FILE>hello-world-game-py/src/models/game_logic.py</FILE> file, find the
**Initialize all variables.**

Unlike class attributes, instance attributes are unique to a single instance of the button running on your machine.
You use them to initialize instance parameters, like `self.new_game`, in the `reconfigure` method.
`viam-server` calls the `reconfigure` method whenever the module starts or a configuration change occurs.
Whenever you change the config of the button, the parameters get set to the values assigned in the reconfigure method.
You use them to initialize instance parameters, like `self.new_game`, in the `new` method.
`viam-server` calls the `new` method whenever the module starts or a configuration change occurs.
Whenever you change the config of the button, the parameters get set to the values assigned in the `new` method.

You must initialize all variables that can and may be accessed before they are assigned elsewhere in the code.
For the Desk Safari game, you'll initialize the following game state variables:
Expand All @@ -460,18 +460,19 @@ On top of game state variables, you also need to initialize the vision service a
The dependencies parameter contains all the resources this component can access.
By using `cast` you tell Python that the vision resource is specifically a VisionClient.

Update the `reconfigure` method to initialize all the variables:
Update the `new` method to initialize all the variables:

```python {class="line-numbers linkable-line-numbers" data-start="79" }
def reconfigure(
self, config: ComponentConfig,
dependencies: Mapping[ResourceName, ResourceBase]
):
@classmethod
def new(
cls, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]
) -> Self:
obj = super().new(config, dependencies)
# Game state
self.new_game: bool = False
self.score: int = 0
self.time_round_start: Optional[datetime] = None
self.item_to_detect: str = ""
obj.new_game: bool = False
obj.score: int = 0
obj.time_round_start: Optional[datetime] = None
obj.item_to_detect: str = ""

camera_name = config.attributes.fields["camera_name"].string_value
detector_name = config.attributes.fields["detector_name"].string_value
Expand All @@ -487,10 +488,10 @@ Update the `reconfigure` method to initialize all the variables:
f"{list(dependencies.keys())}")

vision_resource = dependencies[vision_resource_name]
self.detector = cast(VisionClient, vision_resource)
self.camera_name = camera_name
obj.detector = cast(VisionClient, vision_resource)
obj.camera_name = camera_name

return super().reconfigure(config, dependencies)
return obj
```

{{% /tab %}}
Expand Down
35 changes: 19 additions & 16 deletions docs/operate/modules/advanced/dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,39 +161,41 @@ Accessing dependencies from the resource works differently for different program
{{< tabs >}}
{{% tab name="Python" %}}

To be able to access the dependencies, use the `reconfigure` method to:
To be able to access the dependencies, use the `new` method to:

- Access the dependency by using its name as a key in the `dependencies` mapping.
- Cast the dependency to the correct type and store it.

```python {class="line-numbers linkable-line-numbers"}
def reconfigure(
self, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]
):
@classmethod
def new(
cls, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]
) -> Self:
obj = super().new(config, dependencies)
camera_name = config.attributes.fields["camera_name"].string_value
camera_resource = dependencies[Camera.get_resource_name(camera_name)]
self.camera = cast(Camera, camera_resource)
obj.camera = cast(Camera, camera_resource)

# If you need to use the camera name in your module,
# for example to pass it to a vision service method,
# you can store it in an instance variable.
self.camera_name = camera_name
obj.camera_name = camera_name

sensor_name = config.attributes.fields["sensor_name"].string_value
sensor_resource = dependencies[Sensor.get_resource_name(sensor_name)]
self.sensor = cast(Sensor, sensor_resource)
obj.sensor = cast(Sensor, sensor_resource)

# Optional dependencies may not be present in the config
self.vision_svc = None
obj.vision_svc = None
if "vision_name" in config.attributes.fields:
vision_name = config.attributes.fields["vision_name"].string_value

# For optional dependencies, use .get() and handle None
vision_resource = dependencies.get(VisionClient.get_resource_name(vision_name))
if vision_resource is not None:
self.vision_svc = cast(VisionClient, vision_resource)
obj.vision_svc = cast(VisionClient, vision_resource)

return super().reconfigure(config, dependencies)
return obj
```

{{% /tab %}}
Expand Down Expand Up @@ -429,14 +431,15 @@ def validate_config(


# Get and store motion service instance
def reconfigure(
self, config: ComponentConfig, dependencies: Mapping[
ResourceName, ResourceBase]
):
@classmethod
def new(
cls, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]
) -> Self:
obj = super().new(config, dependencies)
motion_resource = dependencies[MotionClient.get_resource_name("builtin")]
self.motion_service = cast(MotionClient, motion_resource)
obj.motion_service = cast(MotionClient, motion_resource)

return super().reconfigure(config, dependencies)
return obj
```

{{% /tab %}}
Expand Down
4 changes: 2 additions & 2 deletions docs/operate/modules/control-logic.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ The following example shows how you might implement logic that toggles an LED on

Any resources that you wish to access from your control logic need to be identified and instantiated.
To keep your code loosely coupled, we recommend passing the resource names in the configuration attributes of the control logic.
We must modify the `validate_config` method to ensure all required values are passed in correctly and then instantiate the resource in the `reconfigure` method.
We must modify the `validate_config` method to ensure all required values are passed in correctly and then instantiate the resource in the `new` method.

{{< table >}}
{{% tablestep start=1 %}}
Expand Down Expand Up @@ -162,7 +162,7 @@ from viam.components.board import Board

The `new` method gets called whenever the control logic module starts or when a configuration change occurs for the resource itself.

If this is a problem, consider writing state to a file on disk and adding logic to handle subsequent calls to the reconfigure method gracefully.
If this is a problem, consider writing state to a file on disk and adding logic to handle subsequent calls to the `new` method gracefully.

{{% /tablestep %}}
{{% tablestep %}}
Expand Down
2 changes: 1 addition & 1 deletion docs/operate/modules/lifecycle-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The lifecycle of a module and the resources it provides are as follows:
If a required dependency is not found or fails to start, `viam-server` does not start the resource that depends on it.

1. `viam-server` calls the resource's constructor to build the resource based on its configuration.
Typically, the constructor calls the `reconfigure` function.
Typically, the constructor calls the `new` method.

1. Modular resources can fail to start for various reasons:

Expand Down
18 changes: 10 additions & 8 deletions docs/operate/modules/support-hardware/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -597,31 +597,33 @@ For the sensor model, you do not need to edit any of the validation or configura
{{% tablestep %}}
**Reconfiguration**

`viam-server` calls the `reconfigure` method when the user adds the model or changes its configuration.
`viam-server` calls the `new` method when the user adds the model or changes its configuration.

The reconfiguration step serves two purposes:

- Use the configuration attributes and dependencies to set attributes on the model for usage within the API methods.
- Obtain access to dependencies.
For information on how to use dependencies, see [Module dependencies](/operate/modules/advanced/dependencies/).

**Example module**: For the camera model, the reconfigure method serves to set the image path for use in API methods.
**Example module**: For the camera model, the `new` method serves to set the image path for use in API methods.

{{< tabs >}}
{{% tab name="Python" %}}

1. Open <file>/src/models/hello_camera.py</file>.

2. Edit the `reconfigure` function to:
2. Edit the `new` function to:

```python {class="line-numbers" data-start="51" data-line="4-5"}
def reconfigure(
self, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]
):
@classmethod
def new(
cls, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]
) -> Self:
obj = super().new(config, dependencies)
attrs = struct_to_dict(config.attributes)
self.image_path = str(attrs.get("image_path"))
obj.image_path = str(attrs.get("image_path"))

return super().reconfigure(config, dependencies)
return obj
```

3. Add the following import to the top of the file:
Expand Down
11 changes: 6 additions & 5 deletions docs/operate/reference/services/motion/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,17 @@ For example:
return req_deps, []
```

1. Edit your `reconfigure` function to add the motion service as an instance variable so that you can use it in your module:
1. Edit your `new` function to add the motion service as an instance variable so that you can use it in your module:

```python {class="line-numbers linkable-line-numbers"}
def reconfigure(
self, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]
):
def new(
cls, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]
) -> Self:
obj = super().new(config, dependencies)
motion_resource = dependencies[Motion.get_resource_name("builtin")]
self.motion_service = cast(MotionClient, motion_resource)

return super().reconfigure(config, dependencies)
return obj
```

1. You can now use the motion service in your module, for example:
Expand Down
Loading