@@ -241,6 +241,48 @@ def capacity(self) -> int:
241241 """
242242 return self ._buffer .maxlen
243243
244+ # pylint before 3.0 only accepts names with 3 or more chars
245+ def at (self , key : int | datetime ) -> float : # pylint: disable=invalid-name
246+ """
247+ Return the sample at the given index or timestamp.
248+
249+ In contrast to the [`window`][frequenz.sdk.timeseries.MovingWindow.window] method,
250+ which expects a slice as argument, this method expects a single index as argument
251+ and returns a single value.
252+
253+ Args:
254+ key: The index or timestamp of the sample to return.
255+
256+ Returns:
257+ The sample at the given index or timestamp.
258+
259+ Raises:
260+ IndexError: If the buffer is empty or the index is out of bounds.
261+ """
262+ if self ._buffer .count_valid () == 0 :
263+ raise IndexError ("The buffer is empty." )
264+
265+ if isinstance (key , datetime ):
266+ assert self ._buffer .oldest_timestamp is not None
267+ assert self ._buffer .newest_timestamp is not None
268+ if (
269+ key < self ._buffer .oldest_timestamp
270+ or key > self ._buffer .newest_timestamp
271+ ):
272+ raise IndexError (
273+ f"Timestamp { key } is out of range [{ self ._buffer .oldest_timestamp } , "
274+ f"{ self ._buffer .newest_timestamp } ]"
275+ )
276+ return self ._buffer [self ._buffer .to_internal_index (key )]
277+
278+ if isinstance (key , int ):
279+ _logger .debug ("Returning value at index %s " , key )
280+ timestamp = self ._buffer .get_timestamp (key )
281+ assert timestamp is not None
282+ return self ._buffer [self ._buffer .to_internal_index (timestamp )]
283+
284+ raise TypeError ("Key has to be either a timestamp or an integer." )
285+
244286 def window (
245287 self ,
246288 start : datetime | int | None ,
@@ -251,6 +293,10 @@ def window(
251293 """
252294 Return an array containing the samples in the given time interval.
253295
296+ In contrast to the [`at`][frequenz.sdk.timeseries.MovingWindow.at] method,
297+ which expects a single index as argument, this method expects a slice as argument
298+ and returns an array.
299+
254300 Args:
255301 start: The start of the time interval. If `None`, the start of the
256302 window is used.
@@ -372,15 +418,11 @@ def __getitem__(self, key: SupportsIndex | datetime | slice) -> float | ArrayLik
372418 raise ValueError ("Slicing with a step other than 1 is not supported." )
373419 return self .window (key .start , key .stop )
374420
375- if self ._buffer .count_valid () == 0 :
376- raise IndexError ("The buffer is empty." )
377-
378421 if isinstance (key , datetime ):
379- _logger . debug ( "Returning value at time %s " , key )
380- return self . _buffer [ self . _buffer . to_internal_index ( key )]
422+ return self . at ( key )
423+
381424 if isinstance (key , SupportsIndex ):
382- _logger .debug ("Returning value at index %s " , key )
383- return self ._buffer [key ]
425+ return self .at (key .__index__ ())
384426
385427 raise TypeError (
386428 "Key has to be either a timestamp or an integer "
0 commit comments