Skip to content

Commit 96c4d11

Browse files
committed
add thorough examples for JSON schema action arguments
1 parent c84481b commit 96c4d11

File tree

3 files changed

+806
-499
lines changed

3 files changed

+806
-499
lines changed

docs/beginners-guide/articles/actions.md

Lines changed: 129 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
Only methods decorated with `action()` are exposed to clients.
66

77
```py title="Actions" linenums="1"
8-
--8<-- "docs/howto/code/thing_example_2.py:168:172"
9-
--8<-- "docs/howto/code/thing_example_2.py:365:374"
10-
--8<-- "docs/howto/code/thing_example_2.py:510:513"
11-
--8<-- "docs/howto/code/thing_example_2.py:446:451"
12-
--8<-- "docs/howto/code/thing_example_2.py:455:456"
13-
--8<-- "docs/howto/code/thing_example_2.py:375:380"
8+
--8<-- "docs/beginners-guide/code/thing_example_2.py:189:192"
9+
--8<-- "docs/beginners-guide/code/thing_example_2.py:431:445"
10+
--8<-- "docs/beginners-guide/code/thing_example_2.py:643:646"
11+
--8<-- "docs/beginners-guide/code/thing_example_2.py:542:546"
1412
```
1513

1614
Arguments are loosely typed and may need to be constrained with a schema based
@@ -21,21 +19,132 @@ on the robustness the developer is expecting in their application:
2119

2220
=== "Single Argument"
2321

22+
Just specify the expected type of the argument (with or without name)
23+
2424
```py title="Input Schema" linenums="1"
25-
--8<-- "docs/howto/code/thing_example_2.py:168:172"
26-
--8<-- "docs/howto/code/thing_example_2.py:189:205"
25+
--8<-- "docs/beginners-guide/code/thing_example_2.py:189:192"
26+
--8<-- "docs/beginners-guide/code/thing_example_2.py:210:222"
2727
```
2828

29+
???+ note "JSON schema seen in Thing Description"
30+
31+
```py
32+
GentecOpticalEnergyMeter.set_sensor_model.to_affordance().json()
33+
```
34+
35+
```json
36+
{
37+
"description": "Set the attached sensor to the meter under control. Sensor should be defined as a class and added to the AllowedSensors dict.",
38+
"input": {
39+
"type": "string",
40+
"enum": ["QE25LP-S-MB", "QE12LP-S-MB-QED-D0"]
41+
},
42+
"synchronous": True
43+
}
44+
```
45+
2946
=== "Multiple Arguments"
3047

48+
You need to specify the action argument names under the `properties` field with `type` as `object`.
49+
Names not found in the `properties` field can be subsumed under python spread operator `**kwargs` if necessary.
50+
3151
```py title="Input Schema with Multiple Arguments" linenums="1"
32-
--8<-- "docs/howto/code/thing_example_3.py:47:75"
33-
--8<-- "docs/howto/code/thing_example_3.py:78:80"
34-
--8<-- "docs/howto/code/thing_example_3.py:83:83"
35-
--8<-- "docs/howto/code/thing_example_3.py:188:195"
36-
--8<-- "docs/howto/code/thing_example_3.py:219:219"
52+
--8<-- "docs/beginners-guide/code/thing_example_3.py:57:85"
53+
--8<-- "docs/beginners-guide/code/thing_example_3.py:87:87"
54+
--8<-- "docs/beginners-guide/code/thing_example_3.py:213:226"
55+
--8<-- "docs/beginners-guide/code/thing_example_3.py:247:247"
3756
```
3857

58+
???+ note "JSON schema seen in Thing Description"
59+
60+
```py
61+
Picoscope6000.set_channel.to_affordance().json()
62+
```
63+
64+
```json
65+
{
66+
"description": "Set the parameter for a channel. https://www.picotech.com/download/manuals/picoscope-6000-series-a-api-programmers-guide.pdf",
67+
"input": {
68+
"type": "object",
69+
"properties": {
70+
"channel": {"type": "string", "enum": ["A", "B", "C", "D"]},
71+
"enabled": {"type": "boolean"},
72+
"voltage_range": {
73+
"type": "string",
74+
"enum": [
75+
"10mV",
76+
"20mV",
77+
"50mV",
78+
"100mV",
79+
"200mV",
80+
"500mV",
81+
"1V",
82+
"2V",
83+
"5V",
84+
"10V",
85+
"20V",
86+
"50V",
87+
"MAX_RANGES"
88+
]},
89+
"offset": {"type": "number"},
90+
"coupling": {"type": "string", "enum": ["AC", "DC"]},
91+
"bw_limiter": {"type": "string", "enum": ["full", "20MHz"]}
92+
}
93+
},
94+
"synchronous": True
95+
}
96+
```
97+
98+
=== "Return Type"
99+
100+
```py title="With Return Type"
101+
--8<-- "docs/beginners-guide/code/thing_example_3.py:22:55"
102+
--8<-- "docs/beginners-guide/code/thing_example_3.py:87:87"
103+
--8<-- "docs/beginners-guide/code/thing_example_3.py:349:356"
104+
```
105+
106+
???+ note "JSON schema seen in Thing Description"
107+
108+
```py
109+
Picoscope6000.get_analogue_offset.to_affordance().json()
110+
```
111+
112+
```json
113+
{
114+
"description": "analogue offset for a voltage range and coupling",
115+
"synchronous": True,
116+
"input": {
117+
"type": "object",
118+
"properties": {
119+
"voltage_range": {
120+
"type": "string",
121+
"enum": ["10mV",
122+
"20mV",
123+
"50mV",
124+
"100mV",
125+
"200mV",
126+
"500mV",
127+
"1V",
128+
"2V",
129+
"5V",
130+
"10V",
131+
"20V",
132+
"50V",
133+
"MAX_RANGES"
134+
]
135+
},
136+
"coupling": {"type": "string", "enum": ["AC", "DC"]}
137+
}
138+
},
139+
"output": {
140+
"type": "array",
141+
"minItems": 2,
142+
"maxItems": 2,
143+
"items": {"type": "number"}
144+
},
145+
}
146+
```
147+
39148
=== "pydantic"
40149

41150
=== "Single Argument"
@@ -52,38 +161,21 @@ However, a schema is optional and it only matters that
52161
the method signature is matching when requested from a client. To enable this, set global attribute `allow_relaxed_schema_actions=True`. This setting is used especially when a schema is useful for validation of arguments but not available - not for methods with no arguments.
53162

54163
```py title="Relaxed or Unavailable Schema for Actions" linenums="1"
55-
--8<-- "docs/howto/code/thing_example_2.py:168:172"
56-
--8<-- "docs/howto/code/thing_example_2.py:558:559"
164+
--8<-- "docs/beginners-guide/code/thing_example_2.py:168:172"
165+
--8<-- "docs/beginners-guide/code/thing_example_2.py:558:559"
57166
```
58167

59-
The return value must be validated by the clients themselves. While a schema for the return value can be supplied, there is no separate validation performed on the server:
60-
61-
=== "JSON Schema"
62-
63-
```py title="Output Schema" linenums="1"
64-
--8<-- "docs/howto/code/thing_example_3.py:22:36"
65-
--8<-- "docs/howto/code/thing_example_3.py:38:45"
66-
--8<-- "docs/howto/code/thing_example_3.py:78:80"
67-
--8<-- "docs/howto/code/thing_example_3.py:83:83"
68-
--8<-- "docs/howto/code/thing_example_3.py:307:323"
69-
```
70-
71-
=== "pydantic"
72-
73-
```py title="" linenums="1"
74-
```
75-
76168
It is always possible to custom validate the arguments after invoking the action:
77169

78170
```py title="Custom Validation" linenums="1"
79-
--8<-- "docs/howto/code/actions/parameterized_function.py:3:3"
80-
--8<-- "docs/howto/code/actions/parameterized_function.py:9:27"
171+
--8<-- "docs/beginners-guide/code/actions/parameterized_function.py:3:3"
172+
--8<-- "docs/beginners-guide/code/actions/parameterized_function.py:9:27"
81173
```
82174

83175
The last and least preferred possibility is to use `ParameterizedFunction`:
84176

85177
```py title="Parameterized Function" linenums="1"
86-
--8<-- "docs/howto/code/actions/parameterized_function.py:52:"
178+
--8<-- "docs/beginners-guide/code/actions/parameterized_function.py:52:"
87179
```
88180

89181
`ParameterizedFunction`(s) are classes that implement the `__call__` method and whose arguments are type defined using the same objects as properties. However, this type definition using `Property` object do not make these properties of the `Thing`. The implementation follows convention used by `param` where the
@@ -97,11 +189,11 @@ client side, there is no difference between invoking a normal action and an acti
97189
=== "server"
98190

99191
```py title="Custom Validation" linenums="1"
100-
--8<-- "docs/howto/code/actions/parameterized_function.py:38:44"
192+
--8<-- "docs/beginners-guide/code/actions/parameterized_function.py:38:44"
101193
```
102194

103195
=== "client"
104196

105197
```py title="Custom Validation" linenums="1"
106-
--8<-- "docs/howto/code/actions/parameterized_function.py:30:36"
198+
--8<-- "docs/beginners-guide/code/actions/parameterized_function.py:30:36"
107199
```

0 commit comments

Comments
 (0)