Skip to content

Commit bb8a644

Browse files
committed
Deprecate explicit deps and change wording to optional or required
1 parent 06fd06c commit bb8a644

File tree

2 files changed

+62
-49
lines changed

2 files changed

+62
-49
lines changed

docs/operate/get-started/other-hardware/_index.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ Edit the generated files to add your logic:
176176
1. **Edit the `validate_config` function** to do the following:
177177

178178
- Check that the user has configured required attributes and return errors if they are missing.
179-
- Return a map of any implicit dependencies.
179+
- Return a map of any dependencies.
180180
- For more information, see [Module dependencies](/operate/get-started/other-hardware/dependencies/).
181181

182182
1. **Edit the `reconfigure` function**, which gets called when the user changes the configuration.
@@ -235,7 +235,7 @@ class meteo_PM(Sensor, EasyResource):
235235
@classmethod
236236
def validate_config(cls, config: ComponentConfig) -> Sequence[str]:
237237
"""This method allows you to validate the configuration object
238-
received from the machine, as well as to return any implicit
238+
received from the machine, as well as to return any
239239
dependencies based on that `config`.
240240
"""
241241
fields = config.attributes.fields
@@ -381,7 +381,7 @@ This error doesn't exist in the other SDKs, so `AlwaysRebuild` is not supported
381381
1. **Edit the `Validate` function** to do the following:
382382

383383
- Check that the user has configured required attributes and return errors if they are missing.
384-
- Return any implicit dependencies.
384+
- Return any dependencies.
385385
- For more information, see [Module dependencies](/operate/get-started/other-hardware/dependencies/).<br><br>
386386

387387
1. **(Optional) Create and edit a `Reconfigure` function**:

docs/operate/get-started/other-hardware/dependencies.md

+59-46
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,27 @@ type: "docs"
77
description: "Handle dependencies in your custom modular resource."
88
---
99

10-
Dependencies are other {{< glossary_tooltip term_id="resource" text="resources" >}} that your modular resource needs to access in order to function.
11-
For example, a vision service might depend on a camera component, meaning that the camera is a dependency of that vision service.
12-
13-
When [`viam-server` builds all the resources on a machine](/operate/get-started/other-hardware/#how-and-where-do-modules-run), it builds the dependencies first.
14-
15-
## Implicit versus explicit dependencies
10+
## What are dependencies?
1611

17-
- **Implicit dependencies** require users to configure a named attribute (for example `"left-motor": "motor1"`).
12+
Dependencies are other {{< glossary_tooltip term_id="resource" text="resources" >}} that your modular resource needs to access in order to function.
1813

19-
- Recommended when dependencies are required, because implicit dependencies:
20-
- Make it more clear what needs to be configured.
21-
- Eliminate the need for users to configure the same resource name twice.
22-
- Make debugging easier.
23-
- Your module code must access the dependency using its attribute name and return it in the list of dependencies from the `validate` function.
14+
For example, you could write a sensor component that requires a camera component, meaning that the camera is a dependency of that sensor.
2415

25-
- **Explicit dependencies** require that a user list the names of dependencies in the `depends_on` field of the resource's configuration.
16+
```json {class="line-numbers linkable-line-numbers" data-line="6"}
17+
{
18+
"name": "mime-type-sensor",
19+
"api": "rdk:component:sensor",
20+
"model": "jessamy:my-module:my-sensor",
21+
"attributes": {
22+
"camera_name": "camera-1"
23+
}
24+
}
25+
```
2626

27-
- Useful when dependencies are optional.
28-
- Depending on how you write your module, especially if your resources use multiple explicit dependencies, you may need users to configure the dependency both in the `depends_on` field and as an attribute so that your code can determine which dependency is which.
29-
For example:
27+
Dependencies are configured just like any other resource attribute.
28+
The difference is that dependencies represent other resources that must be built before the resource that depends on them.
3029

31-
```json {class="line-numbers linkable-line-numbers"}
32-
{
33-
"name": "mime-type-sensor",
34-
"api": "rdk:component:sensor",
35-
"model": "jessamy:my-module:my-sensor",
36-
"attributes": {
37-
"camera_name": "camera-1"
38-
},
39-
"depends_on": ["camera-1"]
40-
}
41-
```
30+
When [`viam-server` builds all the resources on a machine](/operate/get-started/other-hardware/#how-and-where-do-modules-run), it builds the dependencies first.
4231

4332
## Use dependencies
4433

@@ -47,8 +36,7 @@ For example, you cannot call `Camera.from_robot()` to get a camera resource.
4736

4837
Instead, you must access dependencies by writing your module code as follows:
4938

50-
{{< tabs >}}
51-
{{% tab name="Use implicit dependencies" %}}
39+
### Required dependencies
5240

5341
{{< tabs >}}
5442
{{% tab name="Python" %}}
@@ -185,54 +173,79 @@ If you need to maintain the state of your resource, see [(Optional) Create and e
185173
{{% /tab %}}
186174
{{< /tabs >}}
187175

188-
{{% /tab %}}
189-
{{% tab name="Use explicit dependencies" %}}
176+
### Optional dependencies
190177

191178
{{< tabs >}}
192179
{{% tab name="Python" %}}
193180

194-
If you prefer to use explicit dependencies (for example, for an optional dependency), the steps are the same as for implicit dependencies, except that you do not need to return the dependency from the `validate_config` method and can instead return an empty list:
181+
If your module has optional dependencies, the steps are the same as for required dependencies, except that your `validate_config` method can treat the dependency as optional by returning an empty list if the dependency is not configured:
195182

196183
```python {class="line-numbers linkable-line-numbers"}
197184
@classmethod
198185
def validate_config(cls, config: ComponentConfig) -> Sequence[str]:
186+
deps = []
199187
fields = config.attributes.fields
200-
if "camera_name" in fields and not fields[
201-
"camera_name"].HasField("string_value"):
202-
raise Exception("camera_name must be a string")
203188
if "camera_name" not in fields:
204189
self.logger.info(
205-
"camera_name not configured,using empty string and no camera")
206-
return []
190+
"camera_name not configured, using no camera")
191+
else:
192+
if not fields["camera_name"].HasField("string_value"):
193+
raise Exception("camera_name must be a string")
194+
deps.append(fields["camera_name"].string_value)
195+
return deps
207196
```
208197

198+
Be sure to handle the case where the dependency is not configured in your API implementation as well.
199+
209200
{{% /tab %}}
210201
{{% tab name="Go" %}}
211202

212-
If you prefer to use explicit dependencies (for example, for an optional dependency), the steps are the same as for implicit dependencies, except that you do not need to return the dependency from the `Validate` method and can instead return `nil`:
203+
If your module has optional dependencies, the steps are the same as for required dependencies, except that your `Validate` method can treat the dependency as optional by returning an empty list if the dependency is not configured:
213204

214205
```go {class="line-numbers linkable-line-numbers"}
215206
func (cfg *Config) Validate(path string) ([]string, error) {
216-
if cfg.CameraName != "" && reflect.TypeOf(cfg.CameraName).Kind() != reflect.String {
217-
return nil, errors.New("camera_name must be a string")
218-
}
207+
var deps []string
219208
if cfg.CameraName == "" {
220-
logger.Info("camera_name not configured, using empty string and no camera")
209+
logger.Info("camera_name not configured, using no camera")
210+
return nil, nil
211+
}
212+
if reflect.TypeOf(cfg.CameraName).Kind() != reflect.String {
213+
return nil, errors.New("camera_name must be a string")
221214
}
222-
return nil, nil
215+
deps = append(deps, cfg.CameraName)
216+
return deps, nil
223217
}
224218
```
225219

226-
{{% /tab %}}
227-
{{< /tabs >}}
220+
Be sure to handle the case where the dependency is not configured in your API implementation as well.
228221

229222
{{% /tab %}}
230223
{{< /tabs >}}
231224

232225
{{% hiddencontent %}}
233-
There is not currently an SDK method to access configuration attributes of dependencies in Python or Go, but in Python it is possible to use `get_robot_part` to return information including the whole configuration of a machine part, and then access the configuration attributes of the dependency from there.
226+
There is not currently an SDK method to directly access configuration attributes of dependencies in Python or Go, but in Python it is possible to use `get_robot_part` to return information including the whole configuration of a machine part, and then access the configuration attributes of the dependency from there.
227+
You must access the API key module environment variables to establish the app client connection.
234228
{{% /hiddencontent %}}
235229

230+
### Explicit dependencies (deprecated)
231+
232+
Some older modules use explicit dependencies, which require users to list the names of dependencies in the `depends_on` field of the resource's configuration, for example:
233+
234+
```json {class="line-numbers linkable-line-numbers"}
235+
"name": "mime-type-sensor",
236+
"api": "rdk:component:sensor",
237+
"model": "jessamy:my-module:my-sensor",
238+
"attributes": {
239+
"camera_name": "camera-1"
240+
},
241+
"depends_on": ["camera-1"]
242+
}
243+
```
244+
245+
This is deprecated and not recommended when writing new modules.
246+
247+
Instead, we recommend using implicit dependencies (as shown in the examples above), which do not require users to list the names of dependencies in the `depends_on` field.
248+
236249
## Configure your module's dependencies more easily with a discovery service
237250

238251
If your module requires dependencies, you can make it easier for users to configure them by writing a [discovery service](/operate/reference/services/discovery/) as one model within your module.

0 commit comments

Comments
 (0)