Skip to content

Commit 774b849

Browse files
committed
Make .create() return the new created dispatch
There is hardly any use-case for wanting to use `create()` and not have the new dispatch available. This is also in anticipation of the upcoming server-side feature that will return the newly created dispatch. Signed-off-by: Mathias L. Baumann <[email protected]>
1 parent 95064f5 commit 774b849

File tree

3 files changed

+63
-4
lines changed

3 files changed

+63
-4
lines changed

RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
- A new module `frequenz.client.dispatch.test` has been added, providing a fake Service and Client as well as a `DispatchGenerator` to generate `Dispatch` instances filled with random data.
1616
- The `DispatchGenerator.generate_dispatch` method now accepts a `microgrid_id` parameter to generate `Dispatch` instances with a specific microgrid ID.
17+
- The `Client.create()` method now returns the newly created `Dispatch` object.
1718

1819
## Bug Fixes
1920

src/frequenz/client/dispatch/_client.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
from frequenz.client.base.conversion import to_timestamp
2424

25-
from ._internal_types import DispatchCreateRequest
25+
from ._internal_types import DispatchCreateRequest, rounded_start_time
2626
from .types import (
2727
ComponentSelector,
2828
Dispatch,
@@ -123,9 +123,12 @@ async def create(
123123
dry_run: bool = False,
124124
payload: dict[str, Any] | None = None,
125125
recurrence: RecurrenceRule | None = None,
126-
) -> None:
126+
) -> Dispatch:
127127
"""Create a dispatch.
128128
129+
Will try to return the created dispatch, identifying it by
130+
the same fields as the request.
131+
129132
Args:
130133
microgrid_id: The microgrid_id to create the dispatch for.
131134
_type: User defined string to identify the dispatch type.
@@ -137,8 +140,12 @@ async def create(
137140
payload: The payload of the dispatch.
138141
recurrence: The recurrence rule of the dispatch.
139142
143+
Returns:
144+
Dispatch: The created dispatch
145+
140146
Raises:
141147
ValueError: If start_time is in the past.
148+
ValueError: If the created dispatch could not be found.
142149
"""
143150
if start_time <= datetime.now(tz=start_time.tzinfo):
144151
raise ValueError("start_time must not be in the past")
@@ -157,9 +164,14 @@ async def create(
157164
dry_run=dry_run,
158165
payload=payload or {},
159166
recurrence=recurrence or RecurrenceRule(),
160-
).to_protobuf()
167+
)
161168

162-
await self._stub.CreateMicrogridDispatch(request) # type: ignore
169+
await self._stub.CreateMicrogridDispatch(request.to_protobuf()) # type: ignore
170+
171+
if dispatch := await self._try_fetch_created_dispatch(request):
172+
return dispatch
173+
174+
raise ValueError("Could not find the created dispatch")
163175

164176
async def update(
165177
self,
@@ -255,3 +267,31 @@ async def delete(self, dispatch_id: int) -> None:
255267
"""
256268
request = DispatchDeleteRequest(id=dispatch_id)
257269
await self._stub.DeleteMicrogridDispatch(request) # type: ignore
270+
271+
async def _try_fetch_created_dispatch(
272+
self,
273+
request: DispatchCreateRequest,
274+
) -> Dispatch | None:
275+
"""Try to fetch the created dispatch.
276+
277+
Will return the created dispatch if it was found, otherwise None.
278+
279+
Args:
280+
request: The dispatch create request.
281+
282+
Returns:
283+
Dispatch: The created dispatch, if it was found.
284+
"""
285+
async for dispatch in self.list(microgrid_id=request.microgrid_id):
286+
found = True
287+
for key, value in request.__dict__.items():
288+
if key == "start_time":
289+
value = rounded_start_time(value)
290+
291+
if not (found := getattr(dispatch, key) == value):
292+
break
293+
294+
if found:
295+
return dispatch
296+
297+
return None

tests/test_dispatch_client.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,24 @@ async def test_create_dispatch() -> None:
5252
assert stored_dispatches[0] == sample
5353

5454

55+
async def test_create_return_dispatch() -> None:
56+
"""Test creating a dispatch and returning the created dispatch."""
57+
# Make sure we don't rely on the order of the dispatches
58+
generator = DispatchGenerator()
59+
client = FakeClient(shuffle_after_create=True)
60+
61+
for _ in range(100):
62+
sample = generator.generate_dispatch()
63+
64+
dispatch = await client.create(**to_create_params(sample))
65+
66+
# Before we can compare, we need to set the create_time and update_time
67+
# as they are generated by the (fake) remote point
68+
sample = _update(sample, dispatch)
69+
70+
assert dispatch == sample
71+
72+
5573
async def test_list_dispatches() -> None:
5674
"""Test listing dispatches."""
5775
sampler = DispatchGenerator()

0 commit comments

Comments
 (0)