1010takes a [Receiver][frequenz.channels.Receiver] and a `key` function as arguments and 
1111stores the latest value received by that receiver for each key separately. 
1212
13- As soon as a value is received for a `key`, the 
14- [`has_value`][frequenz.channels.experimental.GroupingLatestValueCache.has_value] method 
15- returns `True` for that `key`, and the [`get` ][frequenz.channels.LatestValueCache.get] 
16- method for that `key` returns the latest value  received.  The `get` method will raise an 
17- exception if called before any messages have been received from the receiver for a given 
18- ` key` .
13+ The `GroupingLatestValueCache` implements the [`Mapping`][collections.abc.Mapping] 
14+ interface, so it can be used like a dictionary.  In addition, it provides a 
15+ [has_value ][frequenz.channels.experimental.GroupingLatestValueCache.has_value] method to 
16+ check if a value has been  received for a specific key, and a 
17+ [clear][frequenz.channels.experimental.GroupingLatestValueCache.clear] method to clear 
18+ the cached value for a specific  key.
1919
2020Example: 
2121```python 
3939
4040import  asyncio 
4141import  typing 
42- from  collections .abc  import  Set 
42+ from  collections .abc  import  ItemsView , Iterator , KeysView , Mapping , ValuesView 
43+ 
44+ from  typing_extensions  import  override 
4345
4446from  .._receiver  import  Receiver 
4547
4648T_co  =  typing .TypeVar ("T_co" , covariant = True )
49+ T  =  typing .TypeVar ("T" )
4750HashableT  =  typing .TypeVar ("HashableT" , bound = typing .Hashable )
4851
4952
50- class  GroupingLatestValueCache (typing .Generic [T_co , HashableT ]):
51-     """A cache that stores the latest value in a receiver. 
52- 
53-     It provides a way to look up the latest value in a stream without any delay, 
54-     as long as there has been one value received. 
55-     """ 
53+ class  GroupingLatestValueCache (
54+     typing .Generic [T_co , HashableT ], Mapping [HashableT , T_co ]
55+ ):
56+     """A cache that stores the latest value in a receiver, grouped by key.""" 
5657
5758    def  __init__ (
5859        self ,
5960        receiver : Receiver [T_co ],
60-         key : typing .Callable [[T_co ], typing . Any ],
61+         key : typing .Callable [[T_co ], HashableT ],
6162        * ,
6263        unique_id : str  |  None  =  None ,
6364    ) ->  None :
@@ -84,47 +85,119 @@ def unique_id(self) -> str:
8485        """The unique identifier of this instance.""" 
8586        return  self ._unique_id 
8687
87-     def  keys (self ) ->  Set [HashableT ]:
88+     @override  
89+     def  keys (self ) ->  KeysView [HashableT ]:
8890        """Return the set of keys for which values have been received. 
8991
9092        If no key function is provided, this will return an empty set. 
9193        """ 
9294        return  self ._latest_value_by_key .keys ()
9395
94-     def  get (self , key : HashableT ) ->  T_co :
96+     @override  
97+     def  items (self ) ->  ItemsView [HashableT , T_co ]:
98+         """Return an iterator over the key-value pairs of the latest values received.""" 
99+         return  self ._latest_value_by_key .items ()
100+ 
101+     @override  
102+     def  values (self ) ->  ValuesView [T_co ]:
103+         """Return an iterator over the latest values received.""" 
104+         return  self ._latest_value_by_key .values ()
105+ 
106+     @typing .overload  
107+     def  get (self , key : HashableT , default : None  =  None ) ->  T_co  |  None :
108+         """Return the latest value that has been received for a specific key.""" 
109+ 
110+     # MyPy passes this overload as a valid signature, but pylint does not like it. 
111+     @typing .overload  
112+     def  get (  # pylint: disable=signature-differs 
113+         self , key : HashableT , default : T 
114+     ) ->  T_co  |  T :
115+         """Return the latest value that has been received for a specific key.""" 
116+ 
117+     @override  
118+     def  get (self , key : HashableT , default : T  |  None  =  None ) ->  T_co  |  T  |  None :
95119        """Return the latest value that has been received. 
96120
97-         This raises a `ValueError` if no value has been received yet. Use `has_value` to 
98-         check whether a value has been received yet, before trying to access the value, 
99-         to avoid the exception. 
100- 
101121        Args: 
102122            key: An optional key to retrieve the latest value for that key. If not 
103123                provided, it retrieves the latest value received overall. 
124+             default: The default value to return if no value has been received yet for 
125+                 the specified key. If not provided, it defaults to `None`. 
104126
105127        Returns: 
106128            The latest value that has been received. 
129+         """ 
130+         return  self ._latest_value_by_key .get (key , default )
131+ 
132+     @override  
133+     def  __iter__ (self ) ->  Iterator [HashableT ]:
134+         """Return an iterator over the keys for which values have been received.""" 
135+         return  iter (self ._latest_value_by_key )
136+ 
137+     @override  
138+     def  __len__ (self ) ->  int :
139+         """Return the number of keys for which values have been received.""" 
140+         return  len (self ._latest_value_by_key )
141+ 
142+     @override  
143+     def  __getitem__ (self , key : HashableT ) ->  T_co :
144+         """Return the latest value that has been received for a specific key. 
145+ 
146+         Args: 
147+             key: The key to retrieve the latest value for. 
148+ 
149+         Returns: 
150+             The latest value that has been received for that key. 
107151
108152        Raises: 
109-             ValueError : If no value has been received yet. 
153+             KeyError : If no value has been received yet for that key . 
110154        """ 
111155        if  key  not  in   self ._latest_value_by_key :
112-             raise  ValueError (f"No value received for key: { key !r}  " )
156+             raise  KeyError (f"No value received for key: { key !r}  " )
113157        return  self ._latest_value_by_key [key ]
114158
115-     def  has_value (self , key : HashableT ) ->  bool :
116-         """Check whether a value has been received yet. 
117- 
118-         If `key` is provided, it checks whether a value has been received for that key. 
159+     @override  
160+     def  __contains__ (self , key : object , / ) ->  bool :
161+         """Check if a value has been received for a specific key. 
119162
120163        Args: 
121-             key: An optional  key to check if a value has been received  for that key . 
164+             key: The  key to check for. 
122165
123166        Returns: 
124-             `True` if a value has been received, `False` otherwise. 
167+             `True` if a value has been received for that key , `False` otherwise. 
125168        """ 
126169        return  key  in  self ._latest_value_by_key 
127170
171+     @override  
172+     def  __eq__ (self , other : object , / ) ->  bool :
173+         """Check if this cache is equal to another object. 
174+ 
175+         Two caches are considered equal if they have the same keys and values. 
176+ 
177+         Args: 
178+             other: The object to compare with. 
179+ 
180+         Returns: 
181+             `True` if the caches are equal, `False` otherwise. 
182+         """ 
183+         if  not  isinstance (other , GroupingLatestValueCache ):
184+             return  NotImplemented 
185+         return  self ._latest_value_by_key  ==  other ._latest_value_by_key 
186+ 
187+     @override  
188+     def  __ne__ (self , value : object , / ) ->  bool :
189+         """Check if this cache is not equal to another object. 
190+ 
191+         Args: 
192+             value: The object to compare with. 
193+ 
194+         Returns: 
195+             `True` if the caches are not equal, `False` otherwise. 
196+         """ 
197+         if  not  isinstance (value , GroupingLatestValueCache ):
198+             return  NotImplemented 
199+         return  self ._latest_value_by_key  !=  value ._latest_value_by_key 
200+ 
128201    def  clear (self , key : HashableT ) ->  None :
129202        """Clear the latest value for a specific key. 
130203
0 commit comments