def test_groupdisposable_clear(): disp1 = [False] disp2 = [False] def action1(): disp1[0] = True d1 = Disposable(action1) def action2(): disp2[0] = True d2 = Disposable(action2) g = CompositeDisposable(d1, d2) assert g.length == 2 g.clear() assert disp1[0] assert disp2[0] assert not g.length disp3 = [False] def action3(): disp3[0] = True d3 = Disposable(action3) g.add(d3) assert not disp3[0] assert g.length == 1
def test_groupdisposable_contains(): d1 = Disposable() d2 = Disposable() g = CompositeDisposable(d1, d2) assert g.length == 2 assert g.contains(d1) assert g.contains(d2)
def _subscribe_core(self, observer: Observer, scheduler: Scheduler = None) -> typing.Disposable: with self.lock: self.check_disposed() if not self.is_stopped: self.observers.append(observer) return InnerSubscription(self, observer) if self.exception: observer.on_error(self.exception) return Disposable() observer.on_completed() return Disposable()
def schedule_relative(self, duetime, action, state=None): """Schedules an action to be executed after duetime. Keyword arguments: duetime -- {timedelta} Relative time after which to execute the action. action -- {Function} Action to be executed. Returns {Disposable} The disposable object used to cancel the scheduled action (best effort).""" scheduler = self seconds = self.to_seconds(duetime) if not seconds: return scheduler.schedule(action, state) sad = SingleAssignmentDisposable() def interval(): sad.disposable = action(scheduler, state) log.debug("timeout: %s", seconds) timer = [gevent.spawn_later(seconds, interval)] def dispose(): # nonlocal timer timer[0].kill() return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative(self, duetime, action, state=None): """Schedules an action to be executed after duetime. Keyword arguments: duetime -- {timedelta} Relative time after which to execute the action. action -- {Function} Action to be executed. Returns {Disposable} The disposable object used to cancel the scheduled action (best effort).""" scheduler = self seconds = scheduler.to_seconds(duetime) if not seconds: return scheduler.schedule(action, state) sad = SingleAssignmentDisposable() def interval(): sad.disposable = self.invoke_action(action, state) log.debug("timeout: %s", seconds) handle = self.loop.call_later(seconds, interval) def dispose(): self.loop.remove_timeout(handle) return CompositeDisposable(sad, Disposable(dispose))
def schedule_absolute( self, duetime: typing.AbsoluteTime, action: typing.ScheduledAction, state: Optional[typing.TState] = None) -> typing.Disposable: """Schedules an action to be executed at duetime. Args: duetime: Absolute time at which to execute the action. action: Action to be executed. state: [Optional] state to be given to the action function. Returns: The disposable object used to cancel the scheduled action (best effort). """ if self._is_disposed: raise DisposedException() dt = self.to_datetime(duetime) si: ScheduledItem[typing.TState] = ScheduledItem( self, state, action, dt) with self._condition: if dt <= self.now: self._ready_list.append(si) else: self._queue.enqueue(si) self._condition.notify() # signal that a new item is available self._ensure_thread() return Disposable(si.cancel)
def schedule_relative(self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: typing.TState = None) -> typing.Disposable: """Schedules an action to be executed after duetime. Args: duetime: Relative time after which to execute the action. action: Action to be executed. Returns: The disposable object used to cancel the scheduled action (best effort). """ seconds = self.to_seconds(duetime) if not seconds: return self.schedule(action, state) sad = SingleAssignmentDisposable() def interval(): sad.disposable = self.invoke_action(action, state) timer = [eventlet.spawn_after(seconds, interval)] def dispose(): # nonlocal timer timer[0].kill() return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative( self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: Optional[typing.TState] = None) -> typing.Disposable: """Schedules an action to be executed after duetime. Args: duetime: Relative time after which to execute the action. action: Action to be executed. state: [Optional] state to be given to the action function. Returns: The disposable object used to cancel the scheduled action (best effort). """ seconds = self.to_seconds(duetime) if not seconds: return self.schedule(action, state=state) sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = self.invoke_action(action, state=state) log.debug("timeout: %s", seconds) timer = gevent.spawn_later(seconds, interval) def dispose() -> None: timer.kill() return CompositeDisposable(sad, Disposable(dispose))
def _wxtimer_schedule(self, time, action, state, periodic=False): scheduler = self sad = SingleAssignmentDisposable() periodic_state = [state] def interval(): if periodic: periodic_state[0] = action(periodic_state[0]) else: sad.disposable = action(scheduler, state) log.debug("timeout: %s", msecs) msecs = int(self.to_seconds(time) * 1000.0) if msecs == 0: msecs = 1 # wx.Timer doesn't support zero. timer = self._timer_class(interval) timer.Start( msecs, self.wx.TIMER_CONTINUOUS if periodic else self.wx.TIMER_ONE_SHOT) self._timers.add(timer) def dispose(): timer.Stop() self._timers.remove(timer) return CompositeDisposable(sad, Disposable(dispose))
def schedule_periodic(self, period: typing.RelativeTime, action: typing.ScheduledPeriodicAction, state: typing.TState = None) -> typing.Disposable: """Schedule a periodic piece of work.""" secs: float = self.to_seconds(period) disposed: threading.Event = threading.Event() s = state def run() -> None: while True: disposed.wait(secs) if disposed.is_set(): return nonlocal s new_state = action(s) if new_state is not None: s = new_state thread = self.thread_factory(run) thread.start() def dispose() -> None: disposed.set() return Disposable(dispose)
def schedule_periodic(self, period: typing.RelativeTime, action: typing.ScheduledPeriodicAction, state: typing.TState = None) -> typing.Disposable: """Schedule a periodic piece of work.""" secs = self.to_seconds(period) disposed: List[bool] = [] s = [state] def run() -> None: while True: time.sleep(secs) if disposed: return new_state = action(s[0]) if new_state is not None: s[0] = new_state thread = self.thread_factory(run) thread.start() def dispose(): disposed.append(True) return Disposable(dispose)
def schedule_relative(self, duetime: RelativeTime, action: ScheduledAction, state: TState = None): """Schedules an action to be executed after duetime. """ duetime = int(self.to_seconds(duetime) * 1000.0) if duetime <= 0: return self.schedule(action, state) scheduler = self is_disposed = False sad = SingleAssignmentDisposable() def invoke_action(): if not is_disposed: sad.disposable = action(scheduler, state) def dispose(): nonlocal is_disposed is_disposed = True self._post(SCHEDULE_RELATIVE, invoke_action, duetime) return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative( self, duetime: RelativeTime, action, state=None, ): if isinstance(duetime, datetime.datetime): timedelta = duetime - datetime.datetime.fromtimestamp(0) timespan = float(timedelta.total_seconds()) elif isinstance(duetime, datetime.timedelta): timespan = float(duetime.total_seconds()) else: timespan = duetime def func(): action(self, None) disposable = [MultipleAssignmentDisposable()] def _(): def __(): future = self.executor.submit(func) disposable[0] = Disposable(lambda: future.cancel()) self.loop.call_later(timespan, __) future = self.loop.call_soon_threadsafe(_) return CompositeDisposable(disposable, Disposable(lambda: future.cancel()))
def schedule(self, action: typing.ScheduledAction, state: Optional[typing.TState] = None ) -> typing.Disposable: """Schedules an action to be executed. Args: action: Action to be executed. state: [Optional] state to be given to the action function. Returns: The disposable object used to cancel the scheduled action (best effort). """ sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = self.invoke_action(action, state=state) handle = self._loop.call_soon_threadsafe(interval) def dispose() -> None: future = Future() def cancel_handle() -> None: handle.cancel() future.set_result(0) self._loop.call_soon_threadsafe(cancel_handle) future.result() return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative(self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: Optional[typing.TState] = None ) -> typing.Disposable: """Schedules an action to be executed after duetime. Args: duetime: Relative time after which to execute the action. action: Action to be executed. state: [Optional] state to be given to the action function. Returns: The disposable object used to cancel the scheduled action (best effort). """ from twisted.internet.task import deferLater seconds = self.to_seconds(duetime) sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = action(self, state) log.debug("timeout: %s", seconds) handle = deferLater(self.reactor, seconds, interval).addErrback(lambda _: None) def dispose() -> None: if not handle.called: handle.cancel() return CompositeDisposable(sad, Disposable(dispose))
def _qtimer_schedule(self, time, action, state, periodic=False): scheduler = self msecs = int(self.to_seconds(time)*1000.0) sad = SingleAssignmentDisposable() periodic_state = [state] def interval(): if periodic: periodic_state[0] = action(periodic_state[0]) else: sad.disposable = action(scheduler, state) log.debug("timeout: %s", msecs) timer = self.qtcore.QTimer() timer.setSingleShot(not periodic) timer.timeout.connect(interval) timer.setInterval(msecs) timer.start() self._timers.add(timer) def dispose(): timer.stop() self._timers.remove(timer) return CompositeDisposable(sad, Disposable(dispose))
def observe(self, observer_info: ObserverInfo): self.observer = observer_info.observer def dispose_func(): self.is_disposed = True return Disposable(dispose_func)
def _gtk_schedule(self, time, action, state, periodic=False): # Do not import GLib into global scope because Qt and GLib # don't like each other there from gi.repository import GLib scheduler = self msecs = int(self.to_seconds(time)*1000) sad = SingleAssignmentDisposable() periodic_state = [state] stopped = [False] def timer_handler(_): if stopped[0]: return False if periodic: periodic_state[0] = action(periodic_state[0]) else: sad.disposable = action(scheduler, state) return periodic GLib.timeout_add(msecs, timer_handler, None) def dispose(): stopped[0] = True return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative(self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: Optional[typing.TState] = None ) -> typing.Disposable: """Schedules an action to be executed after duetime. Args: duetime: Relative time after which to execute the action. action: Action to be executed. state: [Optional] state to be given to the action function. Returns: The disposable object used to cancel the scheduled action (best effort). """ sad = SingleAssignmentDisposable() def invoke_action() -> None: sad.disposable = self.invoke_action(action, state=state) msecs = max(0, int(self.to_seconds(duetime) * 1000.0)) timer = self._root.after(msecs, invoke_action) def dispose() -> None: self._root.after_cancel(timer) return CompositeDisposable(sad, Disposable(dispose))
def _wxtimer_schedule(self, time: typing.AbsoluteOrRelativeTime, action: typing.ScheduledSingleOrPeriodicAction, state: Optional[typing.TState] = None, periodic: bool = False) -> typing.Disposable: scheduler = self sad = SingleAssignmentDisposable() def interval() -> None: nonlocal state if periodic: state = action(state) else: sad.disposable = action(scheduler, state) msecs = int(self.to_seconds(time) * 1000.0) log.debug("timeout wx: %s", msecs) timer = self._timer_class(interval) timer.Start( msecs, self.wx.TIMER_CONTINUOUS if periodic else self.wx.TIMER_ONE_SHOT) self._timers.add(timer) def dispose() -> None: timer.Stop() self._timers.remove(timer) return CompositeDisposable(sad, Disposable(dispose))
def schedule(self, action: typing.ScheduledAction, state: Optional[typing.TState] = None) -> typing.Disposable: """Schedules an action to be executed. Args: action: Action to be executed. state: [Optional] state to be given to the action function. Returns: The disposable object used to cancel the scheduled action (best effort). """ sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = self.invoke_action(action, state=state) timer = gevent.spawn(interval) def dispose() -> None: timer.kill() return CompositeDisposable(sad, Disposable(dispose))
def _gtk_schedule(self, time: typing.AbsoluteOrRelativeTime, action: typing.ScheduledSingleOrPeriodicAction, state: Optional[typing.TState] = None, periodic: bool = False) -> typing.Disposable: # Do not import GLib into global scope because Qt and GLib # don't like each other there from gi.repository import GLib msecs = int(self.to_seconds(time) * 1000.0) sad = SingleAssignmentDisposable() periodic_state = state stopped = False def timer_handler(_) -> bool: if stopped: return False if periodic: nonlocal periodic_state periodic_state = action(periodic_state) else: sad.disposable = self.invoke_action(action, state=state) return periodic GLib.timeout_add(msecs, timer_handler, None) def dispose() -> None: nonlocal stopped stopped = True return CompositeDisposable(sad, Disposable(dispose))
def subscribe( observer: typing.Observer, scheduler: Optional[typing.Scheduler] = None ) -> typing.Disposable: def handler(*args): results = list(args) if mapper: try: results = mapper(args) except Exception as err: # pylint: disable=broad-except observer.on_error(err) return observer.on_next(results) else: if isinstance(results, list) and len(results) <= 1: observer.on_next(*results) else: observer.on_next(results) # observer.on_completed() arguments.append(handler) func(*arguments) return Disposable()
def schedule_relative(self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: typing.TState = None) -> typing.Disposable: """Schedules an action to be executed after duetime. Args: duetime: Relative time after which to execute the action. action: Action to be executed. Returns: The disposable object used to cancel the scheduled action (best effort). """ sad = SingleAssignmentDisposable() def invoke_action(): sad.disposable = self.invoke_action(action, state) msecs = int(self.to_seconds(duetime)*1000.0) alarm = self.master.after(msecs, invoke_action) def dispose(): self.master.after_cancel(alarm) return CompositeDisposable(sad, Disposable(dispose))
def fix_subscriber(subscriber): """Fixes subscriber to make sure it returns a Disposable instead of None or a dispose function""" if not hasattr(subscriber, "dispose"): subscriber = Disposable(subscriber) return subscriber
def schedule_relative(self, duetime: RelativeTime, action: ScheduledAction, state=None): if isinstance(duetime, datetime.datetime): timedelta = duetime - datetime.datetime.fromtimestamp(0) timespan = float(timedelta.total_seconds()) elif isinstance(duetime, datetime.timedelta): timespan = float(duetime.total_seconds()) else: timespan = duetime def _(): def func(): action(self, state) self.loop.call_later(timespan, func) handle = self.loop.call_soon_threadsafe(_) def dispose(): handle.cancel() return Disposable(dispose)
def _subscribe_core(self, observer=None, scheduler=None) -> typing.Disposable: clock = self.scheduler.to_seconds(self.scheduler.now) self.subscriptions.append(Subscription(clock)) index = len(self.subscriptions) - 1 disp = CompositeDisposable() def get_action(notification): def action(scheduler, state): notification.accept(observer) return Disposable() return action for message in self.messages: notification = message.value # Don't make closures within a loop action = get_action(notification) disp.add(self.scheduler.schedule_relative(message.time, action)) def dispose() -> None: start = self.subscriptions[index].subscribe end = self.scheduler.to_seconds(self.scheduler.now) self.subscriptions[index] = Subscription(start, end) disp.dispose() return Disposable(dispose)
def schedule(self, action: typing.ScheduledAction, state: Optional[typing.TState] = None) -> typing.Disposable: """Schedules an action to be executed. Args: action: Action to be executed. state: [Optional] state to be given to the action function. Returns: The disposable object used to cancel the scheduled action (best effort). """ sad = SingleAssignmentDisposable() disposed = False def interval() -> None: if not disposed: sad.disposable = self.invoke_action(action, state=state) self._loop.add_callback(interval) def dispose() -> None: nonlocal disposed disposed = True return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative( self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: Optional[typing.TState] = None) -> typing.Disposable: """Schedules an action to be executed after duetime. Args: duetime: Relative time after which to execute the action. action: Action to be executed. state: [Optional] state to be given to the action function. Returns: The disposable object used to cancel the scheduled action (best effort). """ msecs = max(0, int(self.to_seconds(duetime) * 1000.0)) sad = SingleAssignmentDisposable() is_disposed = False def invoke_action() -> None: if not is_disposed: sad.disposable = action(self, state) log.debug("relative timeout: %sms", msecs) # Use static method, let Qt C++ handle QTimer lifetime self._qtcore.QTimer.singleShot(msecs, invoke_action) def dispose() -> None: nonlocal is_disposed is_disposed = True return CompositeDisposable(sad, Disposable(dispose))
def subscribe( observer: typing.Observer, scheduler_: Optional[typing.Scheduler] = None ) -> typing.Disposable: _scheduler = scheduler or scheduler_ or CurrentThreadScheduler.singleton( ) iterator = iter(iterable) disposed = False def action(_: typing.Scheduler, __: Any = None) -> None: nonlocal disposed try: while not disposed: value = next(iterator) observer.on_next(value) except StopIteration: observer.on_completed() except Exception as error: # pylint: disable=broad-except observer.on_error(error) def dispose() -> None: nonlocal disposed disposed = True disp = Disposable(dispose) return CompositeDisposable(_scheduler.schedule(action), disp)