def __init__(self, connection=None): """ Create instance of ConnectionObserver class :param connection: connection used to receive data awaited for """ self.connection = connection self._is_running = False self._is_done = False self._is_cancelled = False self._result = None self._exception = None self.runner = ThreadPoolExecutorRunner() self._future = None
def test_ThreadPoolExecutorRunner_logs_about_reused_executor(): import logging from concurrent.futures import ThreadPoolExecutor from moler.runner import ThreadPoolExecutorRunner logger = logging.getLogger('moler.runner.thread-pool') external_executor = ThreadPoolExecutor() with mock.patch.object(logger, "debug") as log_debug: ThreadPoolExecutorRunner(executor=external_executor) assert mock.call("reusing provided executor {!r}".format(external_executor)) in log_debug.mock_calls external_executor.shutdown()
def __init__(self, connection=None, runner=None): """ Create instance of ConnectionObserver class :param connection: connection used to receive data awaited for """ self.connection = connection self._is_running = False self._is_done = False self._is_cancelled = False self._result = None self._exception = None self.runner = runner if runner else ThreadPoolExecutorRunner() self._future = None self.timeout = 7 self.device_logger = logging.getLogger('moler.{}'.format(self.get_logger_name())) self.logger = logging.getLogger('moler.connection.{}'.format(self.get_logger_name()))
def observer_runner(): from moler.runner import ThreadPoolExecutorRunner runner = ThreadPoolExecutorRunner() yield runner runner.shutdown()
class ConnectionObserver(object): def __init__(self, connection=None): """ Create instance of ConnectionObserver class :param connection: connection used to receive data awaited for """ self.connection = connection self._is_running = False self._is_done = False self._is_cancelled = False self._result = None self._exception = None self.runner = ThreadPoolExecutorRunner() self._future = None def __str__(self): return '{}(id:{})'.format(self.__class__.__name__, instance_id(self)) def __repr__(self): cmd_str = self.__str__() connection_str = '<NO CONNECTION>' if self.connection: connection_str = repr(self.connection) return '{}, using {})'.format(cmd_str[:-1], connection_str) def __call__(self, *args, **kwargs): """ Run connection-observer in foreground till it is done or timeouted """ started_observer = self.start(*args, **kwargs) if started_observer: return started_observer.await_done(*args, **kwargs) # TODO: raise ConnectionObserverFailedToStart def start(self, *args, **kwargs): """Start background execution of connection-observer.""" self._validate_start(*args, **kwargs) self._is_running = True self._future = self.runner.submit(self) return self def _validate_start(self, *args, **kwargs): # check base class invariants first if not self.connection: # only if we have connection we can expect some data on it # at the latest "just before start" we need connection raise NoConnectionProvided(self) # ---------------------------------------------------------------------- # We intentionally do not check if connection is open here. # In such case net result anyway will be failed/timeouted observer - # - so, user will need to investigate "why". # Checking connection state would benefit in early detection of: # "error condition - no chance to succeed since connection is closed". # However, drawback is a requirement on connection to have is_open() API # We choose minimalistic dependency over better troubleshooting support. # ---------------------------------------------------------------------- def await_done(self, timeout=10.0): """Await completion of connection-observer.""" if self.done(): return self.result() if self._future is None: raise ConnectionObserverNotStarted(self) result = self.runner.wait_for(connection_observer=self, connection_observer_future=self._future, timeout=timeout) return result def cancel(self): """Cancel execution of connection-observer.""" if self.cancelled() or self.done(): return False self._is_done = True self._is_cancelled = True return True def cancelled(self): """Return True if the connection-observer has been cancelled.""" return self._is_cancelled def running(self): """Return True if the connection-observer is currently executing.""" if self.done() and self._is_running: self._is_running = False return self._is_running def done(self): """Return True if the connection-observer is already done.""" return self._is_done def set_result(self, result): """Should be used to set final result""" if self.done(): raise ResultAlreadySet(self) self._is_done = True self._result = result @abstractmethod def data_received(self, data): """ Entry point where feeders pass data read from connection Here we perform data parsing to conclude in result setting """ pass def set_exception(self, exception): """Should be used to indicate some failure during observation""" self._is_done = True self._exception = exception def result(self): """Retrieve final result of connection-observer""" if self.cancelled(): raise NoResultSinceCancelCalled(self) if self._exception: raise self._exception if not self.done(): raise ResultNotAvailableYet(self) return self._result
def observer_runner(): from moler.runner import ThreadPoolExecutorRunner runner = ThreadPoolExecutorRunner() return runner