Source code for src.data_acquisition.sequencers.screen_sequencer
from abc import ABC, abstractmethod
from logging import Logger
from typing import Generic, Optional, TypeVar, cast
from unittest.mock import MagicMock
from ..eventful_screen import EventfulScreen
from ..sequencers.errors import (
IncorrectMethodCallOrderError,
ScreenSequencerStopIteration,
)
T = TypeVar("T")
[docs]
class ScreenSequencer(Generic[T], ABC):
def __init__(self, *, logger: Optional[Logger] = None) -> None:
self._logger = logger if logger is not None else MagicMock()
self.__previous_result: Optional[T] = None
self._was_first_element_gotten = False
self._was_previous_result_provided = False
@property
def _previous_result(self) -> T:
self._check_previous_result_provided()
return cast(T, self.__previous_result)
def _check_previous_result_provided(self) -> None:
if self._was_first_element_gotten and not self._was_previous_result_provided:
raise IncorrectMethodCallOrderError(
"Previous result must be passed before getting the next element."
)
[docs]
def get_next(self) -> EventfulScreen[T]:
"""
:return: The next screen in the sequence.
:raises IncorrectMethodCallOrderError: If the result of the previous screen was not provided (unless it's the first screen).
:raises StopIteration: If there is no next screen in the sequence.
"""
self._check_previous_result_provided()
try:
result = self._get_next()
except ScreenSequencerStopIteration:
self._log("No more screens in the sequence, raising StopIteration")
raise StopIteration
self._was_first_element_gotten = True
self._was_previous_result_provided = False
self._log(f"Got next screen: {result}")
return result
def _log(self, message: str) -> None:
self._logger.debug(f"{self.__class__.__name__}: {message}")
[docs]
def pass_previous_result(self, result: T) -> None:
"""
:param result: The result of the previous screen.
:raises IncorrectMethodCallOrderError: If the result of the previous screen was already provided or before getting the first screen.
"""
if not self._was_first_element_gotten:
raise IncorrectMethodCallOrderError("First element not yet gotten.")
if self._was_previous_result_provided:
raise IncorrectMethodCallOrderError("Previous result already provided.")
self._log(f"Got previous result: {result}")
self.__previous_result = result
self._was_previous_result_provided = True
@abstractmethod
def _get_next(self) -> EventfulScreen[T]:
pass