Skip to content

Commit 9db1a85

Browse files
committed
Create named sentinels for each use case
This makes the code easier to read and the documentation look better. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent ec430ce commit 9db1a85

File tree

1 file changed

+21
-15
lines changed

1 file changed

+21
-15
lines changed

src/frequenz/channels/_latest_value_cache.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,21 @@
5151
HashableT = typing.TypeVar("HashableT", bound=typing.Hashable)
5252

5353

54-
class _Sentinel:
54+
class Sentinel:
5555
"""A sentinel to denote that no value has been received yet."""
5656

57+
def __init__(self, desc: str) -> None:
58+
"""Initialize the sentinel."""
59+
self._desc = desc
60+
5761
def __str__(self) -> str:
5862
"""Return a string representation of this sentinel."""
59-
return "<no value received yet>"
63+
return f"<Sentinel: {self._desc}>"
6064

6165

62-
_SENTINEL = _Sentinel()
66+
NO_KEY: typing.Final[Sentinel] = Sentinel("no key provided")
67+
NO_KEY_FUNCTION: typing.Final[Sentinel] = Sentinel("no key function provided")
68+
NO_VALUE_RECEIVED: typing.Final[Sentinel] = Sentinel("no value received yet")
6369

6470

6571
class LatestValueCache(typing.Generic[T_co, HashableT]):
@@ -71,11 +77,11 @@ class LatestValueCache(typing.Generic[T_co, HashableT]):
7177

7278
@typing.overload
7379
def __init__(
74-
self: LatestValueCache[T_co, _Sentinel],
80+
self: LatestValueCache[T_co, Sentinel],
7581
receiver: Receiver[T_co],
7682
*,
7783
unique_id: str | None = None,
78-
key: _Sentinel = _SENTINEL,
84+
key: Sentinel = NO_KEY_FUNCTION,
7985
) -> None:
8086
"""Create a new cache that does not use keys.
8187
@@ -111,7 +117,7 @@ def __init__(
111117
receiver: Receiver[T_co],
112118
*,
113119
unique_id: str | None = None,
114-
key: typing.Callable[[T_co], typing.Any] | _Sentinel = _SENTINEL,
120+
key: typing.Callable[[T_co], typing.Any] | Sentinel = NO_KEY_FUNCTION,
115121
) -> None:
116122
"""Create a new cache.
117123
@@ -126,9 +132,9 @@ def __init__(
126132
received overall.
127133
"""
128134
self._receiver = receiver
129-
self._key: typing.Callable[[T_co], HashableT] | _Sentinel = key
135+
self._key: typing.Callable[[T_co], HashableT] | Sentinel = key
130136
self._unique_id: str = hex(id(self)) if unique_id is None else unique_id
131-
self._latest_value: T_co | _Sentinel = _SENTINEL
137+
self._latest_value: T_co | Sentinel = NO_VALUE_RECEIVED
132138
self._latest_value_by_key: dict[HashableT, T_co] = {}
133139
self._task = asyncio.create_task(
134140
self._run(), name=f"LatestValueCache«{self._unique_id}»"
@@ -139,7 +145,7 @@ def unique_id(self) -> str:
139145
"""The unique identifier of this instance."""
140146
return self._unique_id
141147

142-
def get(self, key: HashableT | _Sentinel = _SENTINEL) -> T_co:
148+
def get(self, key: HashableT | Sentinel = NO_KEY) -> T_co:
143149
"""Return the latest value that has been received.
144150
145151
This raises a `ValueError` if no value has been received yet. Use `has_value` to
@@ -156,16 +162,16 @@ def get(self, key: HashableT | _Sentinel = _SENTINEL) -> T_co:
156162
Raises:
157163
ValueError: If no value has been received yet.
158164
"""
159-
if not isinstance(key, _Sentinel):
165+
if not isinstance(key, Sentinel):
160166
if key not in self._latest_value_by_key:
161167
raise ValueError(f"No value received for key: {key!r}")
162168
return self._latest_value_by_key[key]
163169

164-
if isinstance(self._latest_value, _Sentinel):
170+
if isinstance(self._latest_value, Sentinel):
165171
raise ValueError("No value has been received yet.")
166172
return self._latest_value
167173

168-
def has_value(self, key: HashableT | _Sentinel = _SENTINEL) -> bool:
174+
def has_value(self, key: HashableT | Sentinel = NO_KEY) -> bool:
169175
"""Check whether a value has been received yet.
170176
171177
If `key` is provided, it checks whether a value has been received for that key.
@@ -176,14 +182,14 @@ def has_value(self, key: HashableT | _Sentinel = _SENTINEL) -> bool:
176182
Returns:
177183
`True` if a value has been received, `False` otherwise.
178184
"""
179-
if not isinstance(key, _Sentinel):
185+
if not isinstance(key, Sentinel):
180186
return key in self._latest_value_by_key
181-
return not isinstance(self._latest_value, _Sentinel)
187+
return not isinstance(self._latest_value, Sentinel)
182188

183189
async def _run(self) -> None:
184190
async for value in self._receiver:
185191
self._latest_value = value
186-
if not isinstance(self._key, _Sentinel):
192+
if not isinstance(self._key, Sentinel):
187193
key = self._key(value)
188194
self._latest_value_by_key[key] = value
189195

0 commit comments

Comments
 (0)