def subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None, ): is_open = [False] def on_next(left: _T) -> None: if is_open[0]: observer.on_next(left) def on_completed() -> None: if is_open[0]: observer.on_completed() subs = source.subscribe( on_next, observer.on_error, on_completed, scheduler=scheduler ) subscriptions = CompositeDisposable(subs) right_subscription = SingleAssignmentDisposable() subscriptions.add(right_subscription) def on_next2(x: Any) -> None: is_open[0] = True right_subscription.dispose() def on_completed2(): right_subscription.dispose() right_subscription.disposable = obs.subscribe( on_next2, observer.on_error, on_completed2, scheduler=scheduler ) return subscriptions
def _subscribe_core( self, observer: Optional[abc.ObserverBase[_T]] = None, scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: self.subscriptions.append(Subscription(self.scheduler.clock)) index = len(self.subscriptions) - 1 disp = CompositeDisposable() def get_action( notification: Notification[_T]) -> abc.ScheduledAction[_T]: def action(scheduler: abc.SchedulerBase, state: Any = None) -> abc.DisposableBase: if observer: notification.accept(observer) return Disposable() return action for message in self.messages: notification = message.value if not isinstance(notification, Notification): raise ValueError("Must be notification") # 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, int(end)) disp.dispose() return Disposable(dispose)
def subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: delays = CompositeDisposable() at_end = [False] def done(): if at_end[0] and delays.length == 0: observer.on_completed() subscription = SerialDisposable() def start(): def on_next(x: _T) -> None: try: assert mapper delay = mapper(x) except Exception as error: # pylint: disable=broad-except observer.on_error(error) return d = SingleAssignmentDisposable() delays.add(d) def on_next(_: Any) -> None: observer.on_next(x) delays.remove(d) done() def on_completed() -> None: observer.on_next(x) delays.remove(d) done() d.disposable = delay.subscribe(on_next, observer.on_error, on_completed, scheduler=scheduler) def on_completed() -> None: at_end[0] = True subscription.dispose() done() subscription.disposable = source.subscribe(on_next, observer.on_error, on_completed, scheduler=scheduler) if not sub_delay: start() else: subscription.disposable = sub_delay.subscribe( lambda _: start(), observer.on_error, start) return CompositeDisposable(subscription, delays)
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( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None, ): active_count = [0] group = CompositeDisposable() is_stopped = [False] queue: List[Observable[_T]] = [] def subscribe(xs: Observable[_T]): subscription = SingleAssignmentDisposable() group.add(subscription) @synchronized(source.lock) def on_completed(): group.remove(subscription) if queue: s = queue.pop(0) subscribe(s) else: active_count[0] -= 1 if is_stopped[0] and active_count[0] == 0: observer.on_completed() on_next = synchronized(source.lock)(observer.on_next) on_error = synchronized(source.lock)(observer.on_error) subscription.disposable = xs.subscribe(on_next, on_error, on_completed, scheduler=scheduler) def on_next(inner_source: Observable[_T]) -> None: assert max_concurrent if active_count[0] < max_concurrent: active_count[0] += 1 subscribe(inner_source) else: queue.append(inner_source) def on_completed(): is_stopped[0] = True if active_count[0] == 0: observer.on_completed() group.add( source.subscribe(on_next, observer.on_error, on_completed, scheduler=scheduler)) return group
def subscribe( observer: abc.ObserverBase[Observable[_T]], scheduler: Optional[abc.SchedulerBase] = None, ): m = SerialDisposable() d = CompositeDisposable(m) r = RefCountDisposable(d) window: Subject[_T] = Subject() observer.on_next(add_ref(window, r)) def on_next(value: _T) -> None: window.on_next(value) def on_error(error: Exception) -> None: window.on_error(error) observer.on_error(error) def on_completed() -> None: window.on_completed() observer.on_completed() d.add( source.subscribe(on_next, on_error, on_completed, scheduler=scheduler)) def create_window_on_completed(): try: window_close = closing_mapper() except Exception as exception: observer.on_error(exception) return def on_completed(): nonlocal window window.on_completed() window = Subject() observer.on_next(add_ref(window, r)) create_window_on_completed() m1 = SingleAssignmentDisposable() m.disposable = m1 m1.disposable = window_close.pipe(ops.take(1)).subscribe( noop, on_error, on_completed, scheduler=scheduler) create_window_on_completed() return r
def schedule_relative( self, duetime: typing.RelativeTime, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None, ) -> abc.DisposableBase: """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 = max(0.0, self.to_seconds(duetime)) sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = action(self, state) log.debug("timeout: %s", seconds) timer = self._reactor.callLater(seconds, interval) def dispose() -> None: if not timer.called: timer.cancel() return CompositeDisposable(sad, Disposable(dispose))
def subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: scheduler = scheduler or CurrentThreadScheduler.singleton() subscription = SerialDisposable() cancelable = SerialDisposable() def action(scheduler: abc.SchedulerBase, state: Optional[Exception] = None) -> None: try: source = next(sources_) except StopIteration: observer.on_completed() return # Allow source to be a factory method taking an error source = source(state) if callable(source) else source current = (reactivex.from_future(source) if isinstance( source, Future) else source) d = SingleAssignmentDisposable() subscription.disposable = d def on_resume(state: Optional[Exception] = None) -> None: scheduler.schedule(action, state) d.disposable = current.subscribe(observer.on_next, on_resume, on_resume, scheduler=scheduler) cancelable.disposable = scheduler.schedule(action) return CompositeDisposable(subscription, cancelable)
def schedule(self, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None) -> abc.DisposableBase: """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: if self._on_self_loop_or_not_running(): handle.cancel() return future: "Future[int]" = 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(self, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None) -> abc.DisposableBase: """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 = self._eventlet.spawn(interval) def dispose() -> None: timer.kill() return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative( self, duetime: typing.RelativeTime, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None, ) -> abc.DisposableBase: """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: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or CurrentThreadScheduler.singleton( ) iterator = iter(iterable) disposed = False def action(_: abc.SchedulerBase, __: 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)
def schedule(self, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None) -> abc.DisposableBase: """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() is_disposed = False def invoke_action() -> None: if not is_disposed: sad.disposable = action(self, state) self._wx.CallAfter(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[_TState], state: Optional[_TState] = None, ) -> abc.DisposableBase: """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 schedule_relative( self, duetime: typing.RelativeTime, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None, ) -> abc.DisposableBase: """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 seconds <= 0.0: 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 = self._loop.call_later(seconds, interval) def dispose() -> None: self._loop.remove_timeout(timer) self._loop.remove_timeout(timer) return CompositeDisposable(sad, Disposable(dispose))
def subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: has_current = [False] is_stopped = [False] m = SingleAssignmentDisposable() g = CompositeDisposable() g.add(m) def on_next(inner_source: Union[Observable[_T], "Future[_T]"]) -> None: if not has_current[0]: has_current[0] = True inner_source = ( reactivex.from_future(inner_source) if isinstance(inner_source, Future) else inner_source ) inner_subscription = SingleAssignmentDisposable() g.add(inner_subscription) def on_completed_inner(): g.remove(inner_subscription) has_current[0] = False if is_stopped[0] and len(g) == 1: observer.on_completed() inner_subscription.disposable = inner_source.subscribe( observer.on_next, observer.on_error, on_completed_inner, scheduler=scheduler, ) def on_completed() -> None: is_stopped[0] = True if not has_current[0] and len(g) == 1: observer.on_completed() m.disposable = source.subscribe( on_next, observer.on_error, on_completed, scheduler=scheduler ) return g
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) switched = [False] _id = [0] original = SingleAssignmentDisposable() subscription = SerialDisposable() timer = SerialDisposable() subscription.disposable = original def create_timer() -> None: my_id = _id[0] def action(scheduler: abc.SchedulerBase, state: Any = None): switched[0] = _id[0] == my_id timer_wins = switched[0] if timer_wins: subscription.disposable = obs.subscribe( observer, scheduler=scheduler) if isinstance(duetime, datetime): timer.disposable = _scheduler.schedule_absolute( duetime, action) else: timer.disposable = _scheduler.schedule_relative( duetime, action) create_timer() def on_next(value: _T) -> None: send_wins = not switched[0] if send_wins: _id[0] += 1 observer.on_next(value) create_timer() def on_error(error: Exception) -> None: on_error_wins = not switched[0] if on_error_wins: _id[0] += 1 observer.on_error(error) def on_completed() -> None: on_completed_wins = not switched[0] if on_completed_wins: _id[0] += 1 observer.on_completed() original.disposable = source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_) return CompositeDisposable(subscription, timer)
def schedule_relative( self, duetime: typing.RelativeTime, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None, ) -> abc.DisposableBase: """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 seconds <= 0: return self.schedule(action, state=state) sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = self.invoke_action(action, state=state) # the operations on the list used here are atomic, so there is no # need to protect its access with a lock handle: List[asyncio.Handle] = [] def stage2() -> None: handle.append(self._loop.call_later(seconds, interval)) handle.append(self._loop.call_soon_threadsafe(stage2)) def dispose() -> None: def do_cancel_handles() -> None: try: handle.pop().cancel() handle.pop().cancel() except Exception: pass if self._on_self_loop_or_not_running(): do_cancel_handles() return future: "Future[int]" = Future() def cancel_handle() -> None: do_cancel_handles() future.set_result(0) self._loop.call_soon_threadsafe(cancel_handle) future.result() return CompositeDisposable(sad, Disposable(dispose))
def subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: return CompositeDisposable( merged_disposable.disposable if merged_disposable else Disposable(), underlying_observable.subscribe(observer, scheduler=scheduler), )
def subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: disp: abc.DisposableBase = Disposable() try: resource = resource_factory() if resource is not None: disp = resource source = observable_factory(resource) except Exception as exception: # pylint: disable=broad-except d = reactivex.throw(exception).subscribe(observer, scheduler=scheduler) return CompositeDisposable(d, disp) return CompositeDisposable( source.subscribe(observer, scheduler=scheduler), disp)
def subscribe( observer: abc.ObserverBase[Any], scheduler: Optional[abc.SchedulerBase] = None ) -> CompositeDisposable: n = len(sources) queues: List[List[Any]] = [[] for _ in range(n)] lock = RLock() is_completed = [False] * n @synchronized(lock) def next_(i: int) -> None: if all(len(q) for q in queues): try: queued_values = [x.pop(0) for x in queues] res = tuple(queued_values) except Exception as ex: # pylint: disable=broad-except observer.on_error(ex) return observer.on_next(res) # after sending the zipped values, complete the observer if at least one # upstream observable is completed and its queue has length zero if any((done for queue, done in zip(queues, is_completed) if len(queue) == 0)): observer.on_completed() def completed(i: int) -> None: is_completed[i] = True if len(queues[i]) == 0: observer.on_completed() subscriptions: List[Optional[abc.DisposableBase]] = [None] * n def func(i: int) -> None: source: Observable[Any] = sources[i] if isinstance(source, Future): source = from_future(source) sad = SingleAssignmentDisposable() def on_next(x: Any) -> None: queues[i].append(x) next_(i) sad.disposable = source.subscribe(on_next, observer.on_error, lambda: completed(i), scheduler=scheduler) subscriptions[i] = sad for idx in range(n): func(idx) return CompositeDisposable(subscriptions)
def subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None, ): group = CompositeDisposable() is_stopped = [False] m = SingleAssignmentDisposable() group.add(m) def on_next(inner_source: Union[Observable[_T], "Future[_T]"]): inner_subscription = SingleAssignmentDisposable() group.add(inner_subscription) inner_source = (from_future(inner_source) if isinstance( inner_source, Future) else inner_source) @synchronized(source.lock) def on_completed(): group.remove(inner_subscription) if is_stopped[0] and len(group) == 1: observer.on_completed() on_next: typing.OnNext[_T] = synchronized(source.lock)( observer.on_next) on_error = synchronized(source.lock)(observer.on_error) subscription = inner_source.subscribe(on_next, on_error, on_completed, scheduler=scheduler) inner_subscription.disposable = subscription def on_completed(): is_stopped[0] = True if len(group) == 1: observer.on_completed() m.disposable = source.subscribe(on_next, observer.on_error, on_completed, scheduler=scheduler) return group
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 subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: was_invoked = [False] def on_completed(): observer.on_completed() try: if not was_invoked[0]: finally_action() was_invoked[0] = True except Exception as err: # pylint: disable=broad-except observer.on_error(err) def on_error(exception: Exception): observer.on_error(exception) try: if not was_invoked[0]: finally_action() was_invoked[0] = True except Exception as err: # pylint: disable=broad-except observer.on_error(err) composite_disposable = CompositeDisposable() composite_disposable.add(OnDispose(was_invoked)) subscription = source.subscribe(observer.on_next, on_error, on_completed, scheduler=scheduler) composite_disposable.add(subscription) return composite_disposable
def subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: inner_subscription = SerialDisposable() has_latest = [False] is_stopped = [False] latest = [0] def on_next(inner_source: Union[Observable[_T], "Future[_T]"]) -> None: nonlocal source d = SingleAssignmentDisposable() with source.lock: latest[0] += 1 _id = latest[0] has_latest[0] = True inner_subscription.disposable = d # Check if Future or Observable if isinstance(inner_source, Future): obs = from_future(inner_source) else: obs = inner_source def on_next(x: Any) -> None: if latest[0] == _id: observer.on_next(x) def on_error(e: Exception) -> None: if latest[0] == _id: observer.on_error(e) def on_completed() -> None: if latest[0] == _id: has_latest[0] = False if is_stopped[0]: observer.on_completed() d.disposable = obs.subscribe( on_next, on_error, on_completed, scheduler=scheduler ) def on_completed() -> None: is_stopped[0] = True if not has_latest[0]: observer.on_completed() subscription = source.subscribe( on_next, observer.on_error, on_completed, scheduler=scheduler ) return CompositeDisposable(subscription, inner_subscription)
def subscribe( observer: abc.ObserverBase[Any], scheduler: Optional[abc.SchedulerBase] = None ) -> CompositeDisposable: n = len(sources) has_value = [False] * n has_value_all = [False] is_done = [False] * n values = [None] * n def _next(i: Any) -> None: has_value[i] = True if has_value_all[0] or all(has_value): res = tuple(values) observer.on_next(res) elif all([x for j, x in enumerate(is_done) if j != i]): observer.on_completed() has_value_all[0] = all(has_value) def done(i: Any) -> None: is_done[i] = True if all(is_done): observer.on_completed() subscriptions: List[Optional[SingleAssignmentDisposable]] = [None] * n def func(i: int) -> None: subscriptions[i] = SingleAssignmentDisposable() def on_next(x: Any) -> None: with parent.lock: values[i] = x _next(i) def on_completed() -> None: with parent.lock: done(i) subscription = subscriptions[i] assert subscription subscription.disposable = sources[i].subscribe(on_next, observer.on_error, on_completed, scheduler=scheduler) for idx in range(n): func(idx) return CompositeDisposable(subscriptions)
def subscribe( observer: abc.ObserverBase[_TResult], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: assert subject_factory connectable = source.pipe( ops.multicast(subject=subject_factory(scheduler))) assert mapper subscription = mapper(connectable).subscribe( observer, scheduler=scheduler) return CompositeDisposable(subscription, connectable.connect(scheduler))
def subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: def on_completed(_: _T) -> None: observer.on_completed() return CompositeDisposable( source.subscribe(observer, scheduler=scheduler), obs.subscribe( on_completed, observer.on_error, noop, scheduler=scheduler ), )
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton() def action(scheduler: abc.SchedulerBase, state: Any = None): observer.on_completed() disp = _scheduler.schedule_relative(duration, action) return CompositeDisposable( disp, source.subscribe(observer, scheduler=scheduler_) )
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) cancelable = SerialDisposable() has_value = [False] value: List[_T] = [cast(_T, None)] _id: List[int] = [0] def on_next(x: _T) -> None: has_value[0] = True value[0] = x _id[0] += 1 current_id = _id[0] d = SingleAssignmentDisposable() cancelable.disposable = d def action(scheduler: abc.SchedulerBase, state: Any = None) -> None: if has_value[0] and _id[0] == current_id: observer.on_next(value[0]) has_value[0] = False d.disposable = _scheduler.schedule_relative(duetime, action) def on_error(exception: Exception) -> None: cancelable.dispose() observer.on_error(exception) has_value[0] = False _id[0] += 1 def on_completed() -> None: cancelable.dispose() if has_value[0]: observer.on_next(value[0]) observer.on_completed() has_value[0] = False _id[0] += 1 subscription = source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_) return CompositeDisposable(subscription, cancelable)