Skip to content

Commit a3265aa

Browse files
committed
Move BidirectionalHandle to Bidirectional.Handle
This is a complementary class used by Bidirectional, so it makes sense to have it scoped in its class. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent d8a4d0f commit a3265aa

File tree

5 files changed

+57
-61
lines changed

5 files changed

+57
-61
lines changed

RELEASE_NOTES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ time.
2626
* `frequenz.channels.Broadcast`
2727
* `frequenz.channels.Anycast`
2828
* `frequenz.channels.Bidirectional`
29-
* `frequenz.channels.BidirectionalHandle`
3029
* `frequenz.channels.Broadcast`
3130
* `frequenz.channels.Peekable`
3231
* `frequenz.channels.Receiver`
@@ -42,6 +41,8 @@ time.
4241
messages to receiver but just receive from them. If you used it you can
4342
implement it yourself.
4443

44+
* The class `BidirectionalHandle` was moved to `Bidirectional.Handle`.
45+
4546
## New Features
4647

4748
<!-- Here goes the main new features and examples or instructions on how to use them -->

src/frequenz/channels/__init__.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,13 @@
4747

4848
from . import util
4949
from ._anycast import Anycast
50-
from ._base_classes import (
51-
ChannelClosedError,
52-
ChannelError,
53-
Peekable,
54-
Receiver,
55-
Sender,
56-
)
57-
from ._bidirectional import Bidirectional, BidirectionalHandle
50+
from ._base_classes import ChannelClosedError, ChannelError, Peekable, Receiver, Sender
51+
from ._bidirectional import Bidirectional
5852
from ._broadcast import Broadcast
5953

6054
__all__ = [
6155
"Anycast",
6256
"Bidirectional",
63-
"BidirectionalHandle",
6457
"Broadcast",
6558
"ChannelClosedError",
6659
"ChannelError",

src/frequenz/channels/_bidirectional.py

Lines changed: 49 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,57 @@
55

66
from __future__ import annotations
77

8-
from typing import Generic
8+
from typing import Generic, TypeVar
99

1010
from ._base_classes import Receiver, Sender, T, U
1111
from ._broadcast import Broadcast
1212

13+
V = TypeVar("V")
14+
W = TypeVar("W")
15+
1316

1417
class Bidirectional(Generic[T, U]):
1518
"""A wrapper class for simulating bidirectional channels."""
1619

20+
class Handle(Sender[V], Receiver[W]):
21+
"""A handle to a [Bidirectional][frequenz.channels.Bidirectional] instance.
22+
23+
It can be used to send/receive values between the client and service.
24+
"""
25+
26+
def __init__(self, sender: Sender[V], receiver: Receiver[W]) -> None:
27+
"""Create a `Bidirectional.Handle` instance.
28+
29+
Args:
30+
sender: A sender to send values with.
31+
receiver: A receiver to receive values from.
32+
"""
33+
self._sender = sender
34+
self._receiver = receiver
35+
36+
async def send(self, msg: V) -> bool:
37+
"""Send a value to the other side.
38+
39+
Args:
40+
msg: The value to send.
41+
42+
Returns:
43+
Whether the send was successful or not.
44+
"""
45+
return await self._sender.send(msg)
46+
47+
async def ready(self) -> None:
48+
"""Wait until the receiver is ready with a value."""
49+
await self._receiver.ready() # pylint: disable=protected-access
50+
51+
def consume(self) -> W:
52+
"""Return the latest value once `_ready` is complete.
53+
54+
Returns:
55+
The next value that was received.
56+
"""
57+
return self._receiver.consume() # pylint: disable=protected-access
58+
1759
def __init__(self, client_id: str, service_id: str) -> None:
1860
"""Create a `Bidirectional` instance.
1961
@@ -27,69 +69,29 @@ def __init__(self, client_id: str, service_id: str) -> None:
2769
f"resp_{service_id}_{client_id}"
2870
)
2971

30-
self._client_handle = BidirectionalHandle(
72+
self._client_handle = Bidirectional.Handle(
3173
self._request_channel.new_sender(),
3274
self._response_channel.new_receiver(),
3375
)
34-
self._service_handle = BidirectionalHandle(
76+
self._service_handle = Bidirectional.Handle(
3577
self._response_channel.new_sender(),
3678
self._request_channel.new_receiver(),
3779
)
3880

3981
@property
40-
def client_handle(self) -> BidirectionalHandle[T, U]:
41-
"""Get a BidirectionalHandle for the client to use.
82+
def client_handle(self) -> Bidirectional.Handle[T, U]:
83+
"""Get a `Handle` for the client side to use.
4284
4385
Returns:
4486
Object to send/receive messages with.
4587
"""
4688
return self._client_handle
4789

4890
@property
49-
def service_handle(self) -> BidirectionalHandle[U, T]:
50-
"""Get a `BidirectionalHandle` for the service to use.
91+
def service_handle(self) -> Bidirectional.Handle[U, T]:
92+
"""Get a `Handle` for the service side to use.
5193
5294
Returns:
5395
Object to send/receive messages with.
5496
"""
5597
return self._service_handle
56-
57-
58-
class BidirectionalHandle(Sender[T], Receiver[U]):
59-
"""A handle to a [Bidirectional][frequenz.channels.Bidirectional] instance.
60-
61-
It can be used to send/receive values between the client and service.
62-
"""
63-
64-
def __init__(self, sender: Sender[T], receiver: Receiver[U]) -> None:
65-
"""Create a `BidirectionalHandle` instance.
66-
67-
Args:
68-
sender: A sender to send values with.
69-
receiver: A receiver to receive values from.
70-
"""
71-
self._sender = sender
72-
self._receiver = receiver
73-
74-
async def send(self, msg: T) -> bool:
75-
"""Send a value to the other side.
76-
77-
Args:
78-
msg: The value to send.
79-
80-
Returns:
81-
Whether the send was successful or not.
82-
"""
83-
return await self._sender.send(msg)
84-
85-
async def ready(self) -> None:
86-
"""Wait until the receiver is ready with a value."""
87-
await self._receiver.ready() # pylint: disable=protected-access
88-
89-
def consume(self) -> U:
90-
"""Return the latest value once `_ready` is complete.
91-
92-
Returns:
93-
The next value that was received.
94-
"""
95-
return self._receiver.consume() # pylint: disable=protected-access

tests/test_bidirectional.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55

66
import asyncio
77

8-
from frequenz.channels import Bidirectional, BidirectionalHandle
8+
from frequenz.channels import Bidirectional
99

1010

1111
async def test_request_response() -> None:
1212
"""Ensure bi-directional communication is possible."""
1313

1414
req_resp: Bidirectional[int, str] = Bidirectional("test_client", "test_service")
1515

16-
async def service(handle: BidirectionalHandle[str, int]) -> None:
16+
async def service(handle: Bidirectional.Handle[str, int]) -> None:
1717
while True:
1818
num = await handle.receive()
1919
if num is None:
@@ -27,7 +27,7 @@ async def service(handle: BidirectionalHandle[str, int]) -> None:
2727
service(req_resp.service_handle),
2828
)
2929

30-
client_handle: BidirectionalHandle[int, str] = req_resp.client_handle
30+
client_handle: Bidirectional.Handle[int, str] = req_resp.client_handle
3131

3232
for ctr in range(-5, 5):
3333
await client_handle.send(ctr)

tests/test_broadcast.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import pytest
1010

11-
from frequenz.channels import Broadcast, Receiver, Sender, ChannelClosedError
11+
from frequenz.channels import Broadcast, ChannelClosedError, Receiver, Sender
1212

1313

1414
async def test_broadcast() -> None:

0 commit comments

Comments
 (0)