def invokeRec(self, scheduler, state): time = 0 if self.hasResult: self.observer.onNext(self.result) try: if self.first: self.first = False else: state = self.parent.iterate(state) self.hasResult = self.parent.condition(state) if self.hasResult: self.result = self.parent.resultSelector(state) time = self.parent.timeSelector(state) except Exception as e: self.observer.onError(e) self.dispose() return Disposable.empty() if not self.hasResult: self.observer.onCompleted() self.dispose() return Disposable.empty() return self.parent.scheduler.scheduleWithRelativeAndState( state, time, self.invokeRec )
def invokeRec(self, scheduler, state): time = 0 if self.hasResult: self.observer.onNext(self.result) try: if self.first: self.first = False else: state = self.parent.iterate(state) self.hasResult = self.parent.condition(state) if self.hasResult: self.result = self.parent.resultSelector(state) time = self.parent.timeSelector(state) except Exception as e: self.observer.onError(e) self.dispose() return Disposable.empty() if not self.hasResult: self.observer.onCompleted() self.dispose() return Disposable.empty() return self.parent.scheduler.scheduleWithRelativeAndState( state, time, self.invokeRec)
def connect(self, observer): # # We connect the given observer to the subject first, before performing any kind # of initialization which will register an event handler. This is done to ensure # we don't have a time gap between adding the handler and connecting the user's # subject, e.g. when the ImmediateScheduler is used. # # [OK] Use of unsafe Subscribe: called on a known subject implementation. # connection = self.subject.subscribe(observer) self.count += 1 if self.count == 1: try: self.initialize() except Exception as e: self.count -= 1 connection.dispose() observer.onError(e) return Disposable.empty() def dispose(): connection.dispose() with self.parent.gate: self.count -=1 if self.count == 0: self.parent.scheduler.schedule(self.removeHandler.dispose) self.parent.session = None return Disposable.create(dispose)
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 subscribeCore(self, observer): old = None new = None while True: old = self.observer.value if old is DisposedObserver.instance: raise Exception("Object has been disposed") if old is DoneObserver.completed: observer.onCompleted() return Disposable.empty() if isinstance(old, DoneObserver): observer.onError(old.exception) return Disposable.empty() if old is NoopObserver.instance: new = observer else: if isinstance(old, ListObserver): new = old.add(observer) else: new = ListObserver((old, observer)) current = self.observer.compareExchange(new, old) if old is current: break return self.Subscription(self, observer)
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 wrapper(observer): a = subscribe(observer) if isinstance(a, Disposable): return a elif callable(a): return Disposable.create(a) else: return Disposable.empty()
def test_Disposable_dispose(): disposed = [False] def action(): disposed[0] = True d = Disposable(action) assert not disposed[0] d.dispose() assert disposed[0]
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 run(self): srcs = list(self.parent.sources) N = len(srcs) self.queues = [None] * N self.isDone = [False] * N self.subscriptions = [None] * N self.gate = RLock() for i in range(0, N): self.queues[i] = deque() # Loop twice because subscribing could already yield # a value before all queues are initialized for i in range(0, N): d = SingleAssignmentDisposable() self.subscriptions[i] = d o = self.O(self, i) d.disposable = srcs[i].subscribeSafe(o) c = CompositeDisposable(self.subscriptions) def dispose(): for q in self.queues: q.clear() c.add(Disposable.create(dispose)) return c
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_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: 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 _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 subscribeCore(self, observer): index = len(self.subscriptions) self.observers.append(observer) self.subscriptions.append(Struct( subscribe=self.scheduler.now(), unsubscribe=0 )) def scheduled(_, message): # time = message[0] notification = message[1] notification.accept(observer) return Disposable.empty() for m in self.messages: self.scheduler.scheduleWithRelativeAndState(m, m[0], scheduled) def dispose(): self.observers.remove(observer) self.subscriptions[index].unsubscribe = self.scheduler.now() return Disposable.create(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 propagate(self, scheduler, currentId): with self.gate: if self.hasValue and self.resourceId == currentId: self.observer.onNext(self.value) self.hasValue = False return Disposable.empty()
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 scheduled(_, message): # time = message[0] notification = message[1] notification.accept(observer) return Disposable.empty()
def subscribeCore(self, observer): ex = None v = None hv = False with self.gate: errorIfDisposed(self) if not self.isStopped: self.observers.append(observer) return Subject.Subscription(self, observer) ex = self.exception hv = self.hasValue v = self.value if ex != None: observer.onError(ex) elif hv: observer.onNext(v) observer.onCompleted() else: observer.onCompleted() return Disposable.empty()
def observe(self, observer_info: ObserverInfo): self.observer = observer_info.observer def dispose_func(): self.is_disposed = True return Disposable(dispose_func)
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, 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_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 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 subscribeCore(self, observer): d = self._subscribe(observer) if d == None: return Disposable.empty() else: return d
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 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: 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 _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 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 _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 _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 run(self, sources): self.isDisposed = False self.subscription = SerialDisposable() self.gate = AsyncLock() self.stack = [] self.length = [] self.stack.append(iter(sources)) try: length = len(sources) except TypeError: self.length.append(-1) else: self.length.append(length) def scheduled(continuation): self.recurse = continuation self.gate.wait(self.moveNext) cancel = Scheduler.tailRecursion.scheduleRecursive(scheduled) return CompositeDisposable( self.subscription, cancel, Disposable.create(lambda: self.gate.wait(self.dispose)) )
def scheduled(): try: subject.onNext(action()) subject.onCompleted() except Exception as e: subject.onError(e) return Disposable.empty()
def scheduledSubscribe(self, scheduler, autoDetachObserver): try: autoDetachObserver.disposable = self.subscribeCore(autoDetachObserver) except Exception as e: if not autoDetachObserver.fail(e): raise e return Disposable.empty()
def start(self): timer = Timer(self.interval, self._execute) self.timerDisposable.disposable = Disposable.create(timer.cancel) timer.start() return self.timerDisposable
def scheduled(_, message): # time = message[0] notification = message[1] for o in list(self.observers): notification.accept(o) return Disposable.empty()
def scheduleDrain(self): def cancel(): self.stopped = True self.stop.set() self.evt.release() self.stop.clear() self.cancelTimer.disposable = Disposable.create(cancel) self.scheduler.scheduleLongRunning(self.drainQueue)
def run(self): try: result = self.parent.eval() except Exception as e: self.observer.onError(e) self.dispose() return Disposable.empty() else: return result.subscribeSafe(self)
def run(self): def dispose(): try: subscription.dispose() finally: self.parent.action() subscription = self.parent.source.subscribeSafe(self) return Disposable.create(dispose)
def schedulerCallback(self, scheduler, state): with self.lock: if self.isAdded: self.group.remove(self.cancel) else: self.isDone = True self.run(state) return Disposable.empty()
def _scheduleCore(self, state, action): d = SingleAssignmentDisposable() def scheduled(): if not d.isDisposed: d.disposable = action(self, state) future = self.pool.submit(scheduled) cancel = Disposable.create(future.cancel) return CompositeDisposable(d, cancel)
def ensureDispatcher(self): if self.dispatcherJob != None: return with self.lock: if self.dispatcherJob == None: self.dispatcherJob = self.scheduler.scheduleLongRunning(self.dispatch) self.disposable.disposable = CompositeDisposable( self.dispatcherJob, Disposable.create(self.dispatcherEvent.release) )
def timeout(self, scheduler, currentId): timerWins = False with self.gate: self.switched = self.currentId == currentId timerWins = self.switched if timerWins: self.subscription.disposable = self.parent.other.subscribeSafe(self.getForewarder()) return Disposable.empty()
def tick(self, scheduler, state): with self.gate: if state.isSpan: s = self.queue.popleft() s.onCompleted() if state.isShift: self.createWindow() self.createTimer() return Disposable.empty()
def subscribeCore(self, observer): index = len(self.subscriptions) self.observers.append(observer) self.subscriptions.append(Struct( subscribe=self.scheduler.now(), unsubscribe=0 )) def dispose(): self.observers.remove(observer) self.subscriptions[index].unsubscribe = self.scheduler.now() return Disposable.create(dispose)
def run(self): source = None disposable = Disposable.empty() try: resource = self.parent.resourceFactory() if resource != None: disposable = resource source = self.parent.observableFactory(resource) except Exception as e: return CompositeDisposable(Observable.throw(e).subscribeSafe(self), disposable) return CompositeDisposable(source.subscribeSafe(self), disposable)
def subscribeSafe(self, observer): if isinstance(self, ObservableBase): return self.subscribeCore(observer) elif isinstance(self, Producer): return self.subscribeRaw(observer, False) d = Disposable.empty() try: d = self.subscribeCore(observer) except Exception as e: observer.onError(e) return d
def _scheduleRelativeCore(self, state, dueTime, action): dt = Scheduler.normalize(dueTime) if dt == 0: return self.scheduleWithState(state, action) d = SingleAssignmentDisposable() def scheduled(): if not d.isDisposed: d.disposable = action(self, state) timer = Timer(dt, scheduled) cancel = Disposable.create(timer.cancel) return CompositeDisposable(d, cancel)
def addHandler(self, scheduler, onNext): try: removeHandler = self.parent.addHandler(onNext) except Exception as e: self.subject.onError(e) else: self.removeHandler.disposable = removeHandler # # We don't propagate the exception to the OnError channel upon Dispose. This is # not possible at this stage, because we've already auto-detached in the base # class Producer implementation. Even if we would switch the OnError and auto- # detach calls, it wouldn't work because the remove handler logic is scheduled # on the given scheduler, causing asynchrony. We can't block waiting for the # remove handler to run on the scheduler. # return Disposable.empty()
def run(self): observable = None connectable = None try: subject = self.parent.subjectSelector() connectable = ConnectableObservable(self.parent.source, subject) observable = self.parent.selector(connectable) except Exception as e: self.observer.onError(e) self.dispose() return Disposable.empty() else: subscription = observable.subscribeSafe(self) connection = connectable.connect() return CompositeDisposable(subscription, connection)