Skip to content

Commit cd7008a

Browse files
committed
Fix docstring code example problems
Signed-off-by: Mathias L. Baumann <mathias.baumann@frequenz.com>
1 parent b7bf6ac commit cd7008a

8 files changed

Lines changed: 189 additions & 128 deletions

File tree

src/frequenz/sdk/actor/_decorator.py

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ def actor(cls: Type[Any]) -> Type[Any]:
7676
TypeError: when the class doesn't have a `run` method as per spec.
7777
7878
Example (one actor receiving from two receivers):
79-
``` python
79+
```python
80+
from frequenz.channels import Receiver, Sender, Broadcast
81+
from frequenz.channels.util import Select
8082
@actor
8183
class EchoActor:
8284
def __init__(
@@ -101,25 +103,30 @@ async def run(self) -> None:
101103
await self._output.send(msg.inner)
102104
103105
104-
input_chan_1: Broadcast[bool] = Broadcast("input_chan_1")
105-
input_chan_2: Broadcast[bool] = Broadcast("input_chan_2")
106+
async def main() -> None:
107+
input_chan_1: Broadcast[bool] = Broadcast("input_chan_1")
108+
input_chan_2: Broadcast[bool] = Broadcast("input_chan_2")
106109
107-
echo_chan: Broadcast[bool] = Broadcast("EchoChannel")
110+
echo_chan: Broadcast[bool] = Broadcast("EchoChannel")
108111
109-
echo_actor = EchoActor(
110-
"EchoActor",
111-
recv1=input_chan_1.new_receiver(),
112-
recv2=input_chan_2.new_receiver(),
113-
output=echo_chan.new_sender(),
114-
)
115-
echo_rx = echo_chan.new_receiver()
112+
echo_actor = EchoActor(
113+
"EchoActor",
114+
recv1=input_chan_1.new_receiver(),
115+
recv2=input_chan_2.new_receiver(),
116+
output=echo_chan.new_sender(),
117+
)
118+
echo_rx = echo_chan.new_receiver()
119+
120+
await input_chan_2.new_sender().send(True)
121+
msg = await echo_rx.receive()
116122
117-
await input_chan_2.new_sender().send(True)
118-
msg = await echo_rx.receive()
123+
asyncio.run(main())
119124
```
120125
121126
Example (two Actors composed):
122-
``` python
127+
```python
128+
from frequenz.channels import Receiver, Sender, Broadcast
129+
from frequenz.channels.util import Select
123130
@actor
124131
class Actor1:
125132
def __init__(
@@ -154,24 +161,27 @@ async def run(self) -> None:
154161
await self._output.send(msg)
155162
156163
157-
input_chan: Broadcast[bool] = Broadcast("Input to A1")
158-
a1_chan: Broadcast[bool] = Broadcast["A1 stream"]
159-
a2_chan: Broadcast[bool] = Broadcast["A2 stream"]
160-
a1 = Actor1(
161-
name="ActorOne",
162-
recv=input_chan.new_receiver(),
163-
output=a1_chan.new_sender(),
164-
)
165-
a2 = Actor2(
166-
name="ActorTwo",
167-
recv=a1_chan.new_receiver(),
168-
output=a2_chan.new_sender(),
169-
)
170-
171-
a2_rx = a2_chan.new_receiver()
172-
173-
await input_chan.new_sender().send(True)
174-
msg = await a2_rx.receive()
164+
async def main() -> None:
165+
input_chan: Broadcast[bool] = Broadcast("Input to A1")
166+
a1_chan: Broadcast[bool] = Broadcast("A1 stream")
167+
a2_chan: Broadcast[bool] = Broadcast("A2 stream")
168+
a_1 = Actor1(
169+
name="ActorOne",
170+
recv=input_chan.new_receiver(),
171+
output=a1_chan.new_sender(),
172+
)
173+
a_2 = Actor2(
174+
name="ActorTwo",
175+
recv=a1_chan.new_receiver(),
176+
output=a2_chan.new_sender(),
177+
)
178+
179+
a2_rx = a2_chan.new_receiver()
180+
181+
await input_chan.new_sender().send(True)
182+
msg = await a2_rx.receive()
183+
184+
asyncio.run(main())
175185
```
176186
177187
"""

src/frequenz/sdk/actor/power_distributing/power_distributing.py

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,13 @@ class PowerDistributingActor:
8989
printed.
9090
9191
Example:
92-
``` python
92+
```python
9393
import grpc.aio as grpcaio
9494
95-
from frequenz.sdk.microgrid.graph import _MicrogridComponentGraph
95+
from frequenz.sdk.microgrid._graph import _MicrogridComponentGraph
96+
from frequenz.sdk import microgrid
9697
from frequenz.sdk.microgrid.component import ComponentCategory
98+
from frequenz.sdk.actor import ResamplerConfig
9799
from frequenz.sdk.actor.power_distributing import (
98100
PowerDistributingActor,
99101
Request,
@@ -103,42 +105,60 @@ class PowerDistributingActor:
103105
PartialFailure,
104106
Ignored,
105107
)
108+
from frequenz.channels import Bidirectional, Broadcast, Receiver, Sender
109+
from datetime import timedelta
110+
from frequenz.sdk import actor
111+
112+
HOST = "localhost"
113+
PORT = 50051
114+
115+
async def main() -> None:
116+
await microgrid.initialize(
117+
HOST,
118+
PORT,
119+
ResamplerConfig(resampling_period=timedelta(seconds=1))
120+
)
121+
122+
graph = microgrid.connection_manager.get().component_graph
106123
124+
batteries = graph.components(component_category={ComponentCategory.BATTERY})
125+
batteries_ids = {c.component_id for c in batteries}
107126
108-
target = f"{host}:{port}"
109-
grpc_channel = grpcaio.insecure_channel(target)
110-
api = MicrogridGrpcClient(grpc_channel, target)
127+
battery_status_channel = Broadcast[BatteryStatus]("battery-status")
111128
112-
graph = _MicrogridComponentGraph()
113-
await graph.refresh_from_api(api)
129+
channel = Bidirectional[Request, Result]("user1", "power_distributor")
130+
power_distributor = PowerDistributingActor(
131+
users_channels={"user1": channel.service_handle},
132+
battery_status_sender=battery_status_channel.new_sender(),
133+
)
114134
115-
batteries = graph.components(component_category={ComponentCategory.BATTERY})
116-
batteries_ids = {c.component_id for c in batteries}
135+
# Start the actor
136+
await actor.run(power_distributor)
117137
118-
channel = Bidirectional[Request, Result]("user1", "power_distributor")
119-
power_distributor = PowerDistributingActor(
120-
mock_api, component_graph, {"user1": channel.service_handle}
121-
)
138+
client_handle = channel.client_handle
122139
123-
client_handle = channel.client_handle
124-
125-
# Set power 1200W to given batteries.
126-
request = Request(power=1200.0, batteries=batteries_ids, request_timeout_sec=10.0)
127-
await client_handle.send(request)
128-
129-
# It is recommended to use timeout when waiting for the response!
130-
result: Result = await asyncio.wait_for(client_handle.receive(), timeout=10)
131-
132-
if isinstance(result, Success):
133-
print("Command succeed")
134-
elif isinstance(result, PartialFailure):
135-
print(
136-
f"Batteries {result.failed_batteries} failed, total failed power" \
137-
f"{result.failed_power}")
138-
elif isinstance(result, Ignored):
139-
print(f"Request was ignored, because of newer request")
140-
elif isinstance(result, Error):
141-
print(f"Request failed with error: {result.msg}")
140+
# Set power 1200W to given batteries.
141+
request = Request(power=1200.0, batteries=batteries_ids, request_timeout_sec=10.0)
142+
await client_handle.send(request)
143+
144+
# Set power 1200W to given batteries.
145+
request = Request(power=1200, batteries=batteries_ids, request_timeout_sec=10.0)
146+
await client_handle.send(request)
147+
148+
# It is recommended to use timeout when waiting for the response!
149+
result: Result = await asyncio.wait_for(client_handle.receive(), timeout=10)
150+
151+
if isinstance(result, Success):
152+
print("Command succeed")
153+
elif isinstance(result, PartialFailure):
154+
print(
155+
f"Batteries {result.failed_batteries} failed, total failed power" \
156+
f"{result.failed_power}"
157+
)
158+
elif isinstance(result, Ignored):
159+
print("Request was ignored, because of newer request")
160+
elif isinstance(result, Error):
161+
print(f"Request failed with error: {result.msg}")
142162
```
143163
"""
144164

src/frequenz/sdk/power/_distribution_algorithm.py

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -71,26 +71,26 @@ class DistributionAlgorithm:
7171
7272
We would like our distribution to meet the equation:
7373
74-
``` python
74+
```
7575
distribution[i] = power_w * capacity_ratio[i] * x[i]
7676
```
7777
7878
where:
7979
80-
``` python
80+
```
8181
sum(capacity_ratio[i] * x[i] for i in range(N)) == 1
8282
```
8383
8484
Let `y` be our unknown, the proportion to discharge each battery would be
8585
(1):
8686
87-
``` python
87+
```
8888
x[i] = available_soc[i]*y
8989
```
9090
9191
We can compute `y` from equation above (2):
9292
93-
``` python
93+
```
9494
sum(capacity_ratio[i] * x[i] for i in range(N)) == 1
9595
# =>
9696
sum(capacity_ratio[i] * available_soc[i] * y for i in range(N)) == 1
@@ -100,7 +100,7 @@ class DistributionAlgorithm:
100100
101101
Now we know everything and we can compute distribution:
102102
103-
``` python
103+
```
104104
distribution[i] = power_w * capacity_ratio[i] * x[i] # from (1)
105105
distribution[i] = \
106106
power_w * capacity_ratio[i] * available_soc[i] * y # from (2)
@@ -110,13 +110,13 @@ class DistributionAlgorithm:
110110
111111
Let:
112112
113-
``` python
113+
```
114114
battery_availability_ratio[i] = capacity_ratio[i] * available_soc[i]
115115
total_battery_availability_ratio = sum(battery_availability_ratio)
116116
```
117117
118118
Then:
119-
``` python
119+
```
120120
distribution[i] = power_w * battery_availability_ratio[i] \
121121
/ total_battery_availability_ratio
122122
```
@@ -151,29 +151,33 @@ def __init__(self, distributor_exponent: float = 1) -> None:
151151
If `distribution_exponent` is:
152152
153153
* `0`: distribution for each battery will be the equal.
154-
``` python
155-
Bat1.distribution = 4000; Bat2.distribution = 4000
154+
```python
155+
BAT1_DISTRIBUTION = 4000
156+
BAT2_DISTRIBUTION = 4000
156157
```
157158
158159
* `1`: then `Bat2` will have 3x more power assigned then `Bat1`.
159-
``` python
160-
10 * x + 30 * x = 8000
161-
x = 200
162-
Bat1.distribution = 2000; Bat2.distribution = 6000
160+
```python
161+
# 10 * x + 30 * x = 8000
162+
X = 200
163+
BAT1_DISTRIBUTION = 2000
164+
BAT2_DISTRIBUTION = 6000
163165
```
164166
165167
* `2`: then `Bat2` will have 9x more power assigned then `Bat1`.
166-
``` python
167-
10^2 * x + 30^2 * x = 8000
168-
x = 80
169-
Bat1.distribution = 800; Bat2.distribution = 7200
168+
```python
169+
# 10^2 * x + 30^2 * x = 8000
170+
X = 80
171+
BAT1_DISTRIBUTION = 800
172+
BAT2_DISTRIBUTION = 7200
170173
```
171174
172175
* `3`: then `Bat2` will have 27x more power assigned then `Bat1`.
173-
``` python
174-
10^3 * x + 30^3 * x = 8000
175-
x = 0,285714286
176-
Bat1.distribution = 285; Bat2.distribution = 7715
176+
```python
177+
# 10^3 * x + 30^3 * x = 8000
178+
X = 0.285714286
179+
BAT1_DISTRIBUTION = 285
180+
BAT2_DISTRIBUTION = 7715
177181
```
178182
179183
# Example 2
@@ -189,29 +193,33 @@ def __init__(self, distributor_exponent: float = 1) -> None:
189193
If `distribution_exponent` is:
190194
191195
* `0`: distribution for each battery will be the same.
192-
``` python
193-
Bat1.distribution = 4500; Bat2.distribution = 450
196+
```python
197+
BAT1_DISTRIBUTION = 4500
198+
BAT2_DISTRIBUTION = 450
194199
```
195200
196201
* `1`: then `Bat2` will have 2x more power assigned then `Bat1`.
197-
``` python
198-
30 * x + 60 * x = 900
199-
x = 100
200-
Bat1.distribution = 300; Bat2.distribution = 600
202+
```python
203+
# 30 * x + 60 * x = 900
204+
X = 100
205+
BAT1_DISTRIBUTION = 300
206+
BAT2_DISTRIBUTION = 600
201207
```
202208
203209
* `2`: then `Bat2` will have 4x more power assigned then `Bat1`.
204-
``` python
205-
30^2 * x + 60^2 * x = 900
206-
x = 0.2
207-
Bat1.distribution = 180; Bat2.distribution = 720
210+
```python
211+
# 30^2 * x + 60^2 * x = 900
212+
X = 0.2
213+
BAT1_DISTRIBUTION = 180
214+
BAT2_DISTRIBUTION = 720
208215
```
209216
210217
* `3`: then `Bat2` will have 8x more power assigned then `Bat1`.
211-
``` python
212-
30^3 * x + 60^3 * x = 900
213-
x = 0,003703704
214-
Bat1.distribution = 100; Bat2.distribution = 800
218+
```python
219+
# 30^3 * x + 60^3 * x = 900
220+
X = 0.003703704
221+
BAT1_DISTRIBUTION = 100
222+
BAT2_DISTRIBUTION = 800
215223
```
216224
217225
# Example 3
@@ -226,15 +234,17 @@ def __init__(self, distributor_exponent: float = 1) -> None:
226234
If `distribution_exponent` is:
227235
228236
* `0`: distribution for each battery will be the equal.
229-
``` python
230-
Bat1.distribution = 450; Bat2.distribution = 450
237+
```python
238+
BAT1_DISTRIBUTION = 450
239+
BAT2_DISTRIBUTION = 450
231240
```
232241
233242
* `0.5`: then `Bat2` will have 6/4x more power assigned then `Bat1`.
234-
``` python
235-
sqrt(36) * x + sqrt(16) * x = 900
236-
x = 100
237-
Bat1.distribution = 600; Bat2.distribution = 400
243+
```python
244+
# sqrt(36) * x + sqrt(16) * x = 900
245+
X = 100
246+
BAT1_DISTRIBUTION = 600
247+
BAT2_DISTRIBUTION = 400
238248
```
239249
240250
Raises:

0 commit comments

Comments
 (0)