55
66import asyncio
77from collections import deque
8- from typing import Any , Deque , Optional , Set , Tuple
8+ from typing import Any , Deque , Set , Tuple
99
1010from frequenz .channels .base_classes import Receiver , T
1111
@@ -21,7 +21,7 @@ def __init__(self, **kwargs: Receiver[T]) -> None:
2121 """
2222 self ._receivers = kwargs
2323 self ._pending : Set [asyncio .Task [Any ]] = {
24- asyncio .create_task (recv .receive (), name = name )
24+ asyncio .create_task (recv .__anext__ (), name = name )
2525 for name , recv in self ._receivers .items ()
2626 }
2727 self ._results : Deque [Tuple [str , T ]] = deque (maxlen = len (self ._receivers ))
@@ -31,9 +31,12 @@ def __del__(self) -> None:
3131 for task in self ._pending :
3232 task .cancel ()
3333
34- async def receive (self ) -> Optional [ Tuple [str , T ] ]:
34+ async def __anext__ (self ) -> Tuple [str , T ]:
3535 """Wait until there's a message in any of the channels.
3636
37+ Raises:
38+ StopAsyncIteration: When the channel is closed.
39+
3740 Returns:
3841 The next message that was received, or `None`, if all channels have
3942 closed.
@@ -45,17 +48,17 @@ async def receive(self) -> Optional[Tuple[str, T]]:
4548 return self ._results .popleft ()
4649
4750 if len (self ._pending ) == 0 :
48- return None
51+ raise StopAsyncIteration ()
4952 done , self ._pending = await asyncio .wait (
5053 self ._pending , return_when = asyncio .FIRST_COMPLETED
5154 )
5255 for item in done :
5356 name = item .get_name ()
54- result = item .result ()
5557 # if channel is closed, don't add a task for it again.
56- if result is None :
58+ if isinstance ( item . exception (), StopAsyncIteration ) :
5759 continue
60+ result = item .result ()
5861 self ._results .append ((name , result ))
5962 self ._pending .add (
60- asyncio .create_task (self ._receivers [name ].receive (), name = name )
63+ asyncio .create_task (self ._receivers [name ].__anext__ (), name = name )
6164 )
0 commit comments