Skip to content

Commit 06a1b65

Browse files
committed
Use a sentinel in LatestValueCache to denote if the cache is empty
This is necessary because `None` is a valid value that could have been sent through a channel, so the having a `None` value might not mean that the cache is empty. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent 1595a5f commit 06a1b65

File tree

1 file changed

+28
-3
lines changed

1 file changed

+28
-3
lines changed

src/frequenz/sdk/_internal/_channels.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ def new_receiver(self, *, maxsize: int = 50) -> Receiver[T]:
2727
"""
2828

2929

30+
class _Sentinel:
31+
"""A sentinel to denote that no value has been received yet."""
32+
33+
3034
class LatestValueCache(typing.Generic[T]):
3135
"""A cache that stores the latest value in a receiver."""
3236

@@ -37,14 +41,35 @@ def __init__(self, receiver: Receiver[T]) -> None:
3741
receiver: The receiver to cache.
3842
"""
3943
self._receiver = receiver
40-
self._latest_value: T | None = None
44+
self._latest_value: T | _Sentinel = _Sentinel()
4145
self._task = asyncio.create_task(self._run())
4246

4347
@property
44-
def latest_value(self) -> T | None:
45-
"""Get the latest value in the cache."""
48+
def latest_value(self) -> T:
49+
"""The latest value that has been received.
50+
51+
This raises a `ValueError` if no value has been received yet. Use `has_value` to
52+
check whether a value has been received yet, before trying to access the value,
53+
to avoid the exception.
54+
55+
Returns:
56+
The latest value that has been received.
57+
58+
Raises:
59+
ValueError: If no value has been received yet.
60+
"""
61+
if isinstance(self._latest_value, _Sentinel):
62+
raise ValueError("No value has been received yet.")
4663
return self._latest_value
4764

65+
def has_value(self) -> bool:
66+
"""Check whether a value has been received yet.
67+
68+
Returns:
69+
`True` if a value has been received, `False` otherwise.
70+
"""
71+
return not isinstance(self._latest_value, _Sentinel)
72+
4873
async def _run(self) -> None:
4974
async for value in self._receiver:
5075
self._latest_value = value

0 commit comments

Comments
 (0)