Skip to content

Commit 39569c4

Browse files
llucaxMarenz
authored andcommitted
Update the client-base dependency to v0.8.0
We now use the new suggested way to get the `stub`, so it has proper async type hints. We also enable the old behavior to retry on stream exhaustion because we don't expect data streaming to end normally, so we want to keep retrying if that happens. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent f10084e commit 39569c4

File tree

4 files changed

+26
-10
lines changed

4 files changed

+26
-10
lines changed

RELEASE_NOTES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
* The constructor parameter `channel_options` was renamed to `channels_defaults` to match the name used in `BaseApiClient`.
1414
* The constructor now accepts a `connect` parameter, which is `True` by default. If set to `False`, the client will not connect to the server upon instantiation. You can connect later by calling the `connect()` method.
1515

16+
* The `frequenz-client-base` dependency was bumped to v0.8.0.
17+
1618
## New Features
1719

1820
- The client now inherits from `frequenz.client.base.BaseApiClient`, so it provides a few new features, like `disconnect()`ing or using it as a context manager. Please refer to the [`BaseApiClient` documentation](https://frequenz-floss.github.io/frequenz-client-base-python/latest/reference/frequenz/client/base/client/#frequenz.client.base.client.BaseApiClient) for more information on these features.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ requires-python = ">= 3.11, < 4"
3838
dependencies = [
3939
"frequenz-api-microgrid >= 0.15.3, < 0.16.0",
4040
"frequenz-channels >= 1.0.0-rc1, < 2.0.0",
41-
"frequenz-client-base >= 0.6.0, < 0.7",
41+
"frequenz-client-base >= 0.8.0, < 0.9",
4242
"grpcio >= 1.54.2, < 2",
4343
"protobuf >= 4.21.6, < 6",
4444
"timezonefinder >= 6.2.0, < 7",

src/frequenz/client/microgrid/_client.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
"""Client for requests to the Microgrid API."""
55

6+
from __future__ import annotations
7+
68
import asyncio
79
import logging
810
from collections.abc import Callable, Iterable, Set
@@ -31,7 +33,7 @@
3133
)
3234
from ._connection import Connection
3335
from ._constants import RECEIVER_MAX_SIZE
34-
from ._exception import ApiClientError
36+
from ._exception import ApiClientError, ClientNotConnected
3537
from ._metadata import Location, Metadata
3638

3739
DEFAULT_GRPC_CALL_TIMEOUT = 60.0
@@ -89,10 +91,20 @@ def __init__(
8991
connect=connect,
9092
channel_defaults=channel_defaults,
9193
)
92-
self._async_stub: microgrid_pb2_grpc.MicrogridAsyncStub = self.stub # type: ignore
9394
self._broadcasters: dict[int, streaming.GrpcStreamBroadcaster[Any, Any]] = {}
9495
self._retry_strategy = retry_strategy
9596

97+
@property
98+
def stub(self) -> microgrid_pb2_grpc.MicrogridAsyncStub:
99+
"""The gRPC stub for the API."""
100+
if self.channel is None or self._stub is None:
101+
raise ClientNotConnected(server_url=self.server_url, operation="stub")
102+
# This type: ignore is needed because we need to cast the sync stub to
103+
# the async stub, but we can't use cast because the async stub doesn't
104+
# actually exists to the eyes of the interpreter, it only exists for the
105+
# type-checker, so it can only be used for type hints.
106+
return self._stub # type: ignore
107+
96108
async def components( # noqa: DOC502 (raises ApiClientError indirectly)
97109
self,
98110
) -> Iterable[Component]:
@@ -108,7 +120,7 @@ async def components( # noqa: DOC502 (raises ApiClientError indirectly)
108120
"""
109121
component_list = await client.call_stub_method(
110122
self,
111-
lambda: self._async_stub.ListComponents(
123+
lambda: self.stub.ListComponents(
112124
microgrid_pb2.ComponentFilter(),
113125
timeout=int(DEFAULT_GRPC_CALL_TIMEOUT),
114126
),
@@ -145,7 +157,7 @@ async def metadata(self) -> Metadata:
145157
try:
146158
microgrid_metadata = await client.call_stub_method(
147159
self,
148-
lambda: self._async_stub.GetMicrogridMetadata(
160+
lambda: self.stub.GetMicrogridMetadata(
149161
Empty(),
150162
timeout=int(DEFAULT_GRPC_CALL_TIMEOUT),
151163
),
@@ -192,7 +204,7 @@ async def connections( # noqa: DOC502 (raises ApiClientError indirectly)
192204
self.components(),
193205
client.call_stub_method(
194206
self,
195-
lambda: self._async_stub.ListConnections(
207+
lambda: self.stub.ListConnections(
196208
connection_filter,
197209
timeout=int(DEFAULT_GRPC_CALL_TIMEOUT),
198210
),
@@ -249,12 +261,15 @@ async def _new_component_data_receiver(
249261
broadcaster = streaming.GrpcStreamBroadcaster(
250262
f"raw-component-data-{component_id}",
251263
lambda: aiter(
252-
self._async_stub.StreamComponentData(
264+
self.stub.StreamComponentData(
253265
microgrid_pb2.ComponentIdParam(id=component_id)
254266
)
255267
),
256268
transform,
257269
retry_strategy=self._retry_strategy,
270+
# We don't expect any data stream to end, so if it is exhausted for any
271+
# reason we want to keep retrying
272+
retry_on_exhausted_stream=True,
258273
)
259274
self._broadcasters[component_id] = broadcaster
260275
return broadcaster.new_receiver(maxsize=maxsize)
@@ -408,7 +423,7 @@ async def set_power( # noqa: DOC502 (raises ApiClientError indirectly)
408423
"""
409424
await client.call_stub_method(
410425
self,
411-
lambda: self._async_stub.SetPowerActive(
426+
lambda: self.stub.SetPowerActive(
412427
microgrid_pb2.SetPowerActiveParam(
413428
component_id=component_id, power=power_w
414429
),
@@ -447,7 +462,7 @@ async def set_bounds( # noqa: DOC503 (raises ApiClientError indirectly)
447462
)
448463
await client.call_stub_method(
449464
self,
450-
lambda: self._async_stub.AddInclusionBounds(
465+
lambda: self.stub.AddInclusionBounds(
451466
microgrid_pb2.SetBoundsParam(
452467
component_id=component_id,
453468
target_metric=target_metric,

tests/test_client.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ def __init__(self, *, retry_strategy: retry.Strategy | None = None) -> None:
4747
super().__init__("grpc://mock_host:1234", retry_strategy=retry_strategy)
4848
self.mock_stub = mock_stub
4949
self._stub = mock_stub # pylint: disable=protected-access
50-
self._async_stub = mock_stub # pylint: disable=protected-access
5150

5251

5352
async def test_components() -> None:

0 commit comments

Comments
 (0)