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_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: 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, ): 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 test_groupdisposable_add(): d1 = Disposable() d2 = Disposable() g = CompositeDisposable(d1) assert g.length == 1 assert g.contains(d1) g.add(d2) assert g.length == 2 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[Any], scheduler: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: composite_disposable = CompositeDisposable() composite_disposable.add(OnDispose()) subscription = source.subscribe( observer.on_next, observer.on_error, observer.on_completed, scheduler=scheduler, ) composite_disposable.add(subscription) return composite_disposable
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 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, ): 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_addafterdispose(): disp1 = [False] disp2 = [False] def action1(): disp1[0] = True d1 = Disposable(action1) def action2(): disp2[0] = True d2 = Disposable(action2) g = CompositeDisposable(d1) assert g.length == 1 g.dispose() assert disp1[0] assert g.length == 0 g.add(d2) assert disp2[0] assert g.length == 0
def subscribe( observer: abc.ObserverBase[Observable[_T]], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: window_subject: Subject[_T] = Subject() d = CompositeDisposable() r = RefCountDisposable(d) observer.on_next(add_ref(window_subject, r)) def on_next_window(x: _T) -> None: window_subject.on_next(x) def on_error(err: Exception) -> None: window_subject.on_error(err) observer.on_error(err) def on_completed() -> None: window_subject.on_completed() observer.on_completed() d.add( source.subscribe(on_next_window, on_error, on_completed, scheduler=scheduler)) def on_next_observer(w: Observable[_T]): nonlocal window_subject window_subject.on_completed() window_subject = Subject() observer.on_next(add_ref(window_subject, r)) d.add( boundaries.subscribe(on_next_observer, on_error, on_completed, scheduler=scheduler)) return r
def subscribe( observer: abc.ObserverBase[GroupedObservable[_TKey, _TValue]], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: writers: OrderedDict[_TKey, Subject[_TValue]] = OrderedDict() group_disposable = CompositeDisposable() ref_count_disposable = RefCountDisposable(group_disposable) def on_next(x: _T) -> None: writer = None key = None try: key = key_mapper(x) except Exception as e: for wrt in writers.values(): wrt.on_error(e) observer.on_error(e) return fire_new_map_entry = False writer = writers.get(key) if not writer: try: writer = subject_mapper_() except Exception as e: for wrt in writers.values(): wrt.on_error(e) observer.on_error(e) return writers[key] = writer fire_new_map_entry = True if fire_new_map_entry: group: GroupedObservable[_TKey, _TValue] = GroupedObservable( key, writer, ref_count_disposable) duration_group: GroupedObservable[_TKey, Any] = GroupedObservable( key, writer) try: duration = duration_mapper(duration_group) except Exception as e: for wrt in writers.values(): wrt.on_error(e) observer.on_error(e) return observer.on_next(group) sad = SingleAssignmentDisposable() group_disposable.add(sad) def expire(): if writers[key]: del writers[key] writer.on_completed() group_disposable.remove(sad) def on_next(value: Any) -> None: pass def on_error(exn: Exception) -> None: for wrt in writers.values(): wrt.on_error(exn) observer.on_error(exn) def on_completed(): expire() sad.disposable = duration.pipe(ops.take(1)).subscribe( on_next, on_error, on_completed, scheduler=scheduler) try: element = element_mapper_(x) except Exception as error: for wrt in writers.values(): wrt.on_error(error) observer.on_error(error) return writer.on_next(element) def on_error(ex: Exception) -> None: for wrt in writers.values(): wrt.on_error(ex) observer.on_error(ex) def on_completed() -> None: for wrt in writers.values(): wrt.on_completed() observer.on_completed() group_disposable.add( source.subscribe(on_next, on_error, on_completed, scheduler=scheduler)) return ref_count_disposable
def subscribe( observer: abc.ObserverBase[Observable[_T]], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) n: int = 0 s: Subject[_T] = Subject() timer_d = SerialDisposable() window_id = 0 group_disposable = CompositeDisposable(timer_d) ref_count_disposable = RefCountDisposable(group_disposable) def create_timer(_id: int): nonlocal n, s, window_id m = SingleAssignmentDisposable() timer_d.disposable = m def action(scheduler: abc.SchedulerBase, state: Any = None): nonlocal n, s, window_id if _id != window_id: return n = 0 window_id += 1 new_id = window_id s.on_completed() s = Subject() observer.on_next(add_ref(s, ref_count_disposable)) create_timer(new_id) m.disposable = _scheduler.schedule_relative(timespan, action) observer.on_next(add_ref(s, ref_count_disposable)) create_timer(0) def on_next(x: _T) -> None: nonlocal n, s, window_id new_window = False new_id = 0 s.on_next(x) n += 1 if n == count: new_window = True n = 0 window_id += 1 new_id = window_id s.on_completed() s = Subject() observer.on_next(add_ref(s, ref_count_disposable)) if new_window: create_timer(new_id) def on_error(e: Exception) -> None: s.on_error(e) observer.on_error(e) def on_completed() -> None: s.on_completed() observer.on_completed() group_disposable.add( source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_)) return ref_count_disposable
def subscribe( observer: abc.ObserverBase[Tuple[_TLeft, Observable[_TRight]]], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: group = CompositeDisposable() rcd = RefCountDisposable(group) left_map: OrderedDict[int, Subject[_TRight]] = OrderedDict() right_map: OrderedDict[int, _TRight] = OrderedDict() left_id = [0] right_id = [0] def on_next_left(value: _TLeft) -> None: subject: Subject[_TRight] = Subject() with left.lock: _id = left_id[0] left_id[0] += 1 left_map[_id] = subject try: result = (value, add_ref(subject, rcd)) except Exception as e: log.error("*** Exception: %s" % e) for left_value in left_map.values(): left_value.on_error(e) observer.on_error(e) return observer.on_next(result) for right_value in right_map.values(): subject.on_next(right_value) md = SingleAssignmentDisposable() group.add(md) def expire(): if _id in left_map: del left_map[_id] subject.on_completed() group.remove(md) try: duration = left_duration_mapper(value) except Exception as e: for left_value in left_map.values(): left_value.on_error(e) observer.on_error(e) return def on_error(error: Exception) -> Any: for left_value in left_map.values(): left_value.on_error(error) observer.on_error(error) md.disposable = duration.pipe(ops.take(1)).subscribe( nothing, on_error, expire, scheduler=scheduler) def on_error_left(error: Exception) -> None: for left_value in left_map.values(): left_value.on_error(error) observer.on_error(error) group.add( left.subscribe( on_next_left, on_error_left, observer.on_completed, scheduler=scheduler, )) def send_right(value: _TRight) -> None: with left.lock: _id = right_id[0] right_id[0] += 1 right_map[_id] = value md = SingleAssignmentDisposable() group.add(md) def expire(): del right_map[_id] group.remove(md) try: duration = right_duration_mapper(value) except Exception as e: for left_value in left_map.values(): left_value.on_error(e) observer.on_error(e) return def on_error(error: Exception): with left.lock: for left_value in left_map.values(): left_value.on_error(error) observer.on_error(error) md.disposable = duration.pipe(ops.take(1)).subscribe( nothing, on_error, expire, scheduler=scheduler) with left.lock: for left_value in left_map.values(): left_value.on_next(value) def on_error_right(error: Exception) -> None: for left_value in left_map.values(): left_value.on_error(error) observer.on_error(error) group.add( right.subscribe(send_right, on_error_right, scheduler=scheduler)) return rcd
def subscribe( observer: abc.ObserverBase[Tuple[_T1, _T2]], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: group = CompositeDisposable() left_done = False left_map: OrderedDict[int, _T1] = OrderedDict() left_id = 0 right_done = False right_map: OrderedDict[int, _T2] = OrderedDict() right_id = 0 def on_next_left(value: _T1): nonlocal left_id duration = None current_id = left_id left_id += 1 md = SingleAssignmentDisposable() left_map[current_id] = value group.add(md) def expire(): if current_id in left_map: del left_map[current_id] if not len(left_map) and left_done: observer.on_completed() group.remove(md) try: duration = left_duration_mapper(value) except Exception as exception: observer.on_error(exception) return md.disposable = duration.pipe(take(1)).subscribe( noop, observer.on_error, lambda: expire(), scheduler=scheduler) for val in right_map.values(): result = (value, val) observer.on_next(result) def on_completed_left() -> None: nonlocal left_done left_done = True if right_done or not len(left_map): observer.on_completed() group.add( left.subscribe( on_next_left, observer.on_error, on_completed_left, scheduler=scheduler, )) def on_next_right(value: _T2): nonlocal right_id duration = None current_id = right_id right_id += 1 md = SingleAssignmentDisposable() right_map[current_id] = value group.add(md) def expire(): if current_id in right_map: del right_map[current_id] if not len(right_map) and right_done: observer.on_completed() group.remove(md) try: duration = right_duration_mapper(value) except Exception as exception: observer.on_error(exception) return md.disposable = duration.pipe(take(1)).subscribe( noop, observer.on_error, lambda: expire(), scheduler=scheduler) for val in left_map.values(): result = (val, value) observer.on_next(result) def on_completed_right(): nonlocal right_done right_done = True if left_done or not len(right_map): observer.on_completed() group.add( right.subscribe( on_next_right, observer.on_error, on_completed_right, scheduler=scheduler, )) return group
def subscribe( observer: abc.ObserverBase[Observable[_T]], scheduler_: Optional[abc.SchedulerBase] = None, ): _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) timer_d = SerialDisposable() next_shift = [timeshift] next_span = [timespan] total_time = [DELTA_ZERO] queue: List[Subject[_T]] = [] group_disposable = CompositeDisposable(timer_d) ref_count_disposable = RefCountDisposable(group_disposable) def create_timer(): m = SingleAssignmentDisposable() timer_d.disposable = m is_span = False is_shift = False if next_span[0] == next_shift[0]: is_span = True is_shift = True elif next_span[0] < next_shift[0]: is_span = True else: is_shift = True new_total_time = next_span[0] if is_span else next_shift[0] ts = new_total_time - total_time[0] total_time[0] = new_total_time if is_span: next_span[0] += timeshift if is_shift: next_shift[0] += timeshift @synchronized(source.lock) def action(scheduler: abc.SchedulerBase, state: Any = None): s: Optional[Subject[_T]] = None if is_shift: s = Subject() queue.append(s) observer.on_next(add_ref(s, ref_count_disposable)) if is_span: s = queue.pop(0) s.on_completed() create_timer() m.disposable = _scheduler.schedule_relative(ts, action) queue.append(Subject()) observer.on_next(add_ref(queue[0], ref_count_disposable)) create_timer() def on_next(x: _T) -> None: with source.lock: for s in queue: s.on_next(x) @synchronized(source.lock) def on_error(e: Exception) -> None: for s in queue: s.on_error(e) observer.on_error(e) @synchronized(source.lock) def on_completed() -> None: for s in queue: s.on_completed() observer.on_completed() group_disposable.add( source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_)) return ref_count_disposable