Skip to content

Commit 8eed457

Browse files
committed
Make all select-related classes and functions covariant
When selecting, we should allow containers of more specific types to be mixed with less specific types. We also use the new public type variables. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent e2c3873 commit 8eed457

File tree

1 file changed

+12
-13
lines changed

1 file changed

+12
-13
lines changed

src/frequenz/channels/_select.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,12 @@
133133

134134
import asyncio
135135
from collections.abc import AsyncIterator
136-
from typing import Any, Generic, TypeGuard, TypeVar
136+
from typing import Any, Generic, TypeGuard
137137

138138
from ._exceptions import Error
139+
from ._generic import ReceiverMessageT_co
139140
from ._receiver import Receiver, ReceiverStoppedError
140141

141-
_T = TypeVar("_T")
142-
143142

144143
class _EmptyResult:
145144
"""A sentinel value to distinguish between None and empty result.
@@ -152,7 +151,7 @@ def __repr__(self) -> str:
152151
return "<empty>"
153152

154153

155-
class Selected(Generic[_T]):
154+
class Selected(Generic[ReceiverMessageT_co]):
156155
"""A result of a [`select()`][frequenz.channels.select] iteration.
157156
158157
The selected receiver is consumed immediately and the received message is stored in
@@ -166,7 +165,7 @@ class Selected(Generic[_T]):
166165
Please see [`select()`][frequenz.channels.select] for an example.
167166
"""
168167

169-
def __init__(self, receiver: Receiver[_T], /) -> None:
168+
def __init__(self, receiver: Receiver[ReceiverMessageT_co], /) -> None:
170169
"""Initialize this selected result.
171170
172171
The receiver is consumed immediately when creating the instance and the received
@@ -178,10 +177,10 @@ def __init__(self, receiver: Receiver[_T], /) -> None:
178177
Args:
179178
receiver: The receiver that was selected.
180179
"""
181-
self._recv: Receiver[_T] = receiver
180+
self._recv: Receiver[ReceiverMessageT_co] = receiver
182181
"""The receiver that was selected."""
183182

184-
self._message: _T | _EmptyResult = _EmptyResult()
183+
self._message: ReceiverMessageT_co | _EmptyResult = _EmptyResult()
185184
"""The message that was received.
186185
187186
If there was an exception while receiving the message, then this will be `None`.
@@ -198,7 +197,7 @@ def __init__(self, receiver: Receiver[_T], /) -> None:
198197
"""Flag to indicate if this selected has been handled in the if-chain."""
199198

200199
@property
201-
def message(self) -> _T:
200+
def message(self) -> ReceiverMessageT_co:
202201
"""The message that was received, if any.
203202
204203
Returns:
@@ -248,8 +247,8 @@ def __repr__(self) -> str:
248247
# `TypeGuard`s can't be used as methods. For more information see:
249248
# https://github.com/microsoft/pyright/discussions/3125
250249
def selected_from(
251-
selected: Selected[Any], receiver: Receiver[_T]
252-
) -> TypeGuard[Selected[_T]]:
250+
selected: Selected[Any], receiver: Receiver[ReceiverMessageT_co]
251+
) -> TypeGuard[Selected[ReceiverMessageT_co]]:
253252
"""Check whether the given receiver was selected by [`select()`][frequenz.channels.select].
254253
255254
This function is used in conjunction with the
@@ -283,23 +282,23 @@ class SelectError(Error):
283282
"""
284283

285284

286-
class UnhandledSelectedError(SelectError, Generic[_T]):
285+
class UnhandledSelectedError(SelectError, Generic[ReceiverMessageT_co]):
287286
"""A receiver was not handled in a [`select()`][frequenz.channels.select] iteration.
288287
289288
This exception is raised when a [`select()`][frequenz.channels.select] iteration
290289
finishes without a call to [`selected_from()`][frequenz.channels.selected_from] for
291290
the selected receiver.
292291
"""
293292

294-
def __init__(self, selected: Selected[_T]) -> None:
293+
def __init__(self, selected: Selected[ReceiverMessageT_co]) -> None:
295294
"""Initialize this error.
296295
297296
Args:
298297
selected: The selected receiver that was not handled.
299298
"""
300299
recv = selected._recv # pylint: disable=protected-access
301300
super().__init__(f"Selected receiver {recv} was not handled in the if-chain")
302-
self.selected: Selected[_T] = selected
301+
self.selected: Selected[ReceiverMessageT_co] = selected
303302
"""The selected receiver that was not handled."""
304303

305304

0 commit comments

Comments
 (0)