class ObserveOnMultiCastObserver(MultiCastObserver): next_observer: MultiCastObserver scheduler: Scheduler source_scheduler: Scheduler def __post_init__(self): self.trampoline = TrampolineScheduler() if self.scheduler.is_order_guaranteed: def schedule_func(action): self.scheduler.schedule(action) # if the order of schedule actions cannot be guaranteed # by the scheduler, then use a TrampolineScheduler on top # of the scheduler to guarantee the order else: def schedule_func(action): def action_on_scheduler(_, __): self.trampoline.schedule(action) self.scheduler.schedule(action_on_scheduler) self.schedule_func = schedule_func def on_next(self, elem: ElementType): ack_subject = AckSubject() if isinstance(elem, list): elem = elem else: try: elem = list(elem) except Exception as exc: self.next_observer.on_error(exc) return def action(_, __): def subscribe_action(_, __): self.next_observer.on_next(elem) self.source_scheduler.schedule(subscribe_action) self.schedule_func(action) return ack_subject def on_error(self, exc): self.next_observer.on_error(exc) def on_completed(self): def action(_, __): def subscribe_action(_, __): self.next_observer.on_completed() self.source_scheduler.schedule(subscribe_action) self.schedule_func(action)
def __post_init__(self): self.trampoline = TrampolineScheduler() if self.scheduler.is_order_guaranteed: def schedule_func(action): self.scheduler.schedule(action) # if the order of schedule actions cannot be guaranteed # by the scheduler, then use a TrampolineScheduler on top # of the scheduler to guarantee the order else: def schedule_func(action): def action_on_scheduler(_, __): self.trampoline.schedule(action) self.scheduler.schedule(action_on_scheduler) self.schedule_func = schedule_func
def to_iterator(source: FlowableSubscribeMixin, scheduler: Scheduler = None): @dataclass class ToIteratorObserver(Observer): received: List[ElementType] is_completed: bool exception: Optional[Exception] def on_next(self, elem: ElementType) -> Ack: if not isinstance(elem, list): elem = list(elem) self.received.append(elem) return continue_ack def on_error(self, exc: Exception): self.exception = exc def on_completed(self): self.is_completed = True observer = ToIteratorObserver( received=[], is_completed=False, exception=None, ) subscribe_scheduler = TrampolineScheduler() scheduler = scheduler or subscribe_scheduler source.subscribe( observer=observer, scheduler=scheduler, subscribe_scheduler=subscribe_scheduler, ) def gen(): while True: while True: if len(observer.received): break if observer.is_completed: return # StopIteration if observer.exception is not None: raise observer.exception scheduler.sleep(0.1) yield from observer.received.pop(0) return gen()
def subscribe( self, on_next: Callable[[Any], None] = None, on_error: Callable[[Any], None] = None, on_completed: Callable[[], None] = None, scheduler: Scheduler = None, subscribe_scheduler: Scheduler = None, observer: Observer = None, ) -> rx.typing.Disposable: """ Calling `subscribe` method starts some kind of process that start a chain reaction where downsream `Flowables` call the `subscribe` method of their linked upstream `Flowable` until the sources start emitting data. Once a `Flowable` is subscribed, we allow it to have mutable states where it make sense. """ assert isinstance(self, SharedFlowableMixin) is False, \ 'a shared Flowable cannot be subscribed, use Flowable inside MultiCast instead' subscribe_scheduler_ = subscribe_scheduler or TrampolineScheduler() scheduler_ = scheduler or subscribe_scheduler_ subscriber = init_subscriber( scheduler=scheduler_, subscribe_scheduler=subscribe_scheduler_, ) subscription = self.unsafe_subscribe(subscriber=subscriber) assert isinstance(subscription, Subscription), \ f'"{subscription}" must be of type Subscription' disposable = self._observe( observable=subscription.observable, on_next=on_next, on_completed=on_completed, on_error=on_error, observer=observer, subscribe_scheduler=subscribe_scheduler_, ) assert isinstance(disposable, rx.typing.Disposable), \ f'"{disposable}" must be of type Disposable' return disposable
def unsafe_subscribe(self, subscriber: Subscriber): scheduler = self._scheduler or TrampolineScheduler() updated_subscriber = init_subscriber( scheduler=subscriber.scheduler, subscribe_scheduler=scheduler, ) subscription = self._source.unsafe_subscribe(updated_subscriber) class SubscribeOnObservable(Observable): def observe(_, observer_info: ObserverInfo): def action(_, __): return subscription.observable.observe(observer_info) disposable = scheduler.schedule(action) return disposable observable = SubscribeOnObservable() return init_subscription(observable=observable)
def gen_subscribe_schedulers(): yield subscriber.subscribe_scheduler for _ in range(self.source.lift_index): yield TrampolineScheduler()
def gen_subscribe_schedulers(): for _ in range(diff_schedulers): yield TrampolineScheduler()
class ObserveOnObserver(Observer): observer: Observer scheduler: Scheduler def __post_init__(self): self.trampoline = TrampolineScheduler() if self.scheduler.is_order_guaranteed: def schedule_func(action): self.scheduler.schedule(action) # if the order of schedule actions cannot be guaranteed # by the scheduler, then use a TrampolineScheduler on top # of the scheduler to guarantee the order else: def schedule_func(action): def action_on_scheduler(_, __): self.trampoline.schedule(action) self.scheduler.schedule(action_on_scheduler) self.schedule_func = schedule_func def on_next(self, elem: ElementType): ack_subject = AckSubject() if isinstance(elem, list): elem = elem else: try: elem = list(elem) except Exception as exc: self.observer.on_error(exc) return stop_ack def action(_, __): inner_ack = self.observer.on_next(elem) if isinstance(inner_ack, ContinueAck): ack_subject.on_next(inner_ack) elif isinstance(inner_ack, StopAck): ack_subject.on_next(inner_ack) elif inner_ack is None: raise Exception( f'observer {self.observer} returned None instead of an Ack' ) else: inner_ack.subscribe(ack_subject) self.schedule_func(action) return ack_subject def on_error(self, exc): self.observer.on_error(exc) def on_completed(self): def action(_, __): self.observer.on_completed() self.schedule_func(action)
def __post_init__(self): self.is_first = True self.is_stopped = False self.subscribe_scheduler = TrampolineScheduler() self._observable_subject = None
def _subscribe_core(self, observer: typing.Observer, scheduler: typing.Scheduler = None): class RxBPScheduler(SchedulerBase): def __init__(self, underlying): super().__init__() self.underlying = underlying def sleep(self, seconds: float) -> None: pass @property def now(self) -> datetime: return self.underlying.now @property def is_order_guaranteed(self) -> bool: # unknown property, therefore select pessimistically return False def schedule(self, action: ScheduledAction, state: TState = None) -> Disposable: return self.underlying.schedule(action=action, state=state) def schedule_relative(self, duetime: RelativeTime, action: ScheduledAction, state: TState = None) -> Disposable: return self.underlying.schedule_relative(duetime=duetime, action=action, state=state) def schedule_absolute(self, duetime: AbsoluteTime, action: ScheduledAction, state: TState = None) -> Disposable: return self.underlying.schedule_absolute(duetime=duetime, action=action, state=state) def schedule_periodic( self, period: RelativeTime, action: ScheduledPeriodicAction, state: Optional[TState] = None) -> Disposable: raise NotImplementedError class ToRxObserver(Observer): @property def is_volatile(self): return False def on_next(self, elem: ElementType): for e in elem: observer.on_next(e) return continue_ack def on_error(self, err): observer.on_error(err) def on_completed(self): observer.on_completed() to_rx_observer = ToRxObserver() if batched is True: def on_next(v): batch = list(v()) observer.on_next(batch) return continue_ack to_rx_observer.on_next = on_next trampoline_scheduler = subscribe_schduler or TrampolineScheduler() scheduler_ = RxBPScheduler( underlying=scheduler ) if scheduler is not None else trampoline_scheduler subscriber = init_subscriber( scheduler=scheduler_, subscribe_scheduler=trampoline_scheduler) # observer_info = init_observer_info(observer=to_rx_observer) return source.subscribe( observer=to_rx_observer, subscribe_scheduler=subscriber.subscribe_scheduler, scheduler=subscriber.subscribe_scheduler, )