Esempio n. 1
0
    def test_map_disposeinsidemapper(self):
        scheduler = TestScheduler()
        xs = scheduler.create_hot_observable(
            on_next(100, 1), on_next(200, 2), on_next(500, 3), on_next(600, 4)
        )
        results = scheduler.create_observer()
        d = SerialDisposable()
        invoked = [0]

        def projection(x, *args, **kw):
            invoked[0] += 1

            if scheduler.clock > 400:
                d.dispose()
            return x

        d.disposable = xs.pipe(map(projection)).subscribe(results, scheduler)

        def action(scheduler, state):
            return d.dispose()

        scheduler.schedule_absolute(ReactiveTest.disposed, action)
        scheduler.start()

        assert results.messages == [on_next(100, 1), on_next(200, 2)]
        assert xs.subscriptions == [ReactiveTest.subscribe(0, 500)]

        assert invoked[0] == 3
Esempio n. 2
0
    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)
Esempio n. 3
0
    def test_map_with_index_dispose_inside_mapper(self):
        scheduler = TestScheduler()
        xs = scheduler.create_hot_observable(
            on_next(100, 4), on_next(200, 3), on_next(500, 2), on_next(600, 1)
        )
        invoked = [0]
        results = scheduler.create_observer()
        d = SerialDisposable()

        def projection(x, index):
            invoked[0] += 1
            if scheduler.clock > 400:
                d.dispose()

            return x + index * 10

        d.disposable = xs.pipe(map_indexed(projection)).subscribe(results)

        def action(scheduler, state):
            return d.dispose()

        scheduler.schedule_absolute(disposed, action)
        scheduler.start()
        assert results.messages == [on_next(100, 4), on_next(200, 13)]
        assert xs.subscriptions == [subscribe(0, 500)]
        assert invoked[0] == 3
Esempio n. 4
0
    def test_starmap_dispose_inside_mapper(self):
        scheduler = TestScheduler()
        xs = scheduler.create_hot_observable(
            # 100 create
            on_next(110, (1, 10)),
            # 200 subscribe
            on_next(210, (2, 20)),
            on_next(310, (3, 30)),
            on_next(410, (4, 40)),
        )

        results = scheduler.create_observer()
        d = SerialDisposable()
        invoked = [0]

        def mapper(x, y):
            invoked[0] += 1
            if scheduler._clock > 250:
                d.dispose()
            return x + y

        d.disposable = xs.pipe(ops.starmap(mapper)).subscribe(results, scheduler)

        def action(scheduler, state):
            return d.dispose()

        scheduler.schedule_absolute(ReactiveTest.disposed, action)
        scheduler.start()

        assert results.messages == [on_next(110, 11), on_next(210, 22)]

        assert xs.subscriptions == [ReactiveTest.subscribe(0, 310)]
        assert invoked[0] == 3
Esempio n. 5
0
    def subscribe(
            observer: abc.ObserverBase[_T],
            scheduler: Optional[abc.SchedulerBase] = None
    ) -> abc.DisposableBase:
        d1 = SingleAssignmentDisposable()
        subscription = SerialDisposable()

        subscription.disposable = d1

        def on_error(exception: Exception) -> None:
            try:
                result = handler(exception, source)
            except Exception as ex:  # By design. pylint: disable=W0703
                observer.on_error(ex)
                return

            result = (reactivex.from_future(result) if isinstance(
                result, Future) else result)
            d = SingleAssignmentDisposable()
            subscription.disposable = d
            d.disposable = result.subscribe(observer, scheduler=scheduler)

        d1.disposable = source.subscribe(observer.on_next,
                                         on_error,
                                         observer.on_completed,
                                         scheduler=scheduler)
        return subscription
Esempio n. 6
0
        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)
Esempio n. 7
0
        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)
Esempio n. 8
0
    def __init__(self, scheduler: abc.SchedulerBase,
                 observer: abc.ObserverBase[_T_in]) -> None:
        super().__init__()

        self.scheduler = scheduler
        self.observer = observer

        self.lock = threading.RLock()
        self.is_acquired = False
        self.has_faulted = False
        self.queue: List[typing.Action] = []
        self.disposable = SerialDisposable()
Esempio n. 9
0
        def subscribe(
            observer: abc.ObserverBase[_T], _: Optional[abc.SchedulerBase] = None
        ):
            m = SingleAssignmentDisposable()
            d = SerialDisposable()
            d.disposable = m

            def action(scheduler: abc.SchedulerBase, state: Optional[Any] = None):
                d.disposable = ScheduledDisposable(
                    scheduler, source.subscribe(observer)
                )

            m.disposable = scheduler.schedule(action)
            return d
Esempio n. 10
0
def test_mutabledisposable_dispose():
    disp = [False]
    m = SerialDisposable()

    def action():
        disp[0] = True

    d = Disposable(action)
    m.disposable = d

    assert d == m.disposable
    assert not disp[0]
    m.dispose()
    assert disp[0]
    assert m.disposable == None
Esempio n. 11
0
    def test_return_disposed_after_next(self):
        scheduler = TestScheduler()
        d = SerialDisposable()
        xs = reactivex.return_value(42)
        results = scheduler.create_observer()

        def action(scheduler, state):
            def on_next(x):
                d.dispose()
                results.on_next(x)

            def on_error(e):
                results.on_error(e)

            def on_completed():
                results.on_completed()

            d.disposable = xs.subscribe(on_next,
                                        on_error,
                                        on_completed,
                                        scheduler=scheduler)
            return d.disposable

        scheduler.schedule_absolute(100, action)
        scheduler.start()
        assert results.messages == [on_next(100, 42)]
Esempio n. 12
0
    def subscribe(
        observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None
    ) -> abc.DisposableBase:
        _scheduler = scheduler_ or CurrentThreadScheduler.singleton()

        subscription = SerialDisposable()
        cancelable = SerialDisposable()
        last_exception = None
        is_disposed = False

        def action(scheduler: abc.SchedulerBase, state: Any = None) -> None:
            def on_error(exn: Exception) -> None:
                nonlocal last_exception
                last_exception = exn
                cancelable.disposable = _scheduler.schedule(action)

            if is_disposed:
                return

            try:
                current = next(sources_)
            except StopIteration:
                if last_exception:
                    observer.on_error(last_exception)
                else:
                    observer.on_completed()
            except Exception as ex:  # pylint: disable=broad-except
                observer.on_error(ex)
            else:
                d = SingleAssignmentDisposable()
                subscription.disposable = d
                d.disposable = current.subscribe(
                    observer.on_next,
                    on_error,
                    observer.on_completed,
                    scheduler=scheduler_,
                )

        cancelable.disposable = _scheduler.schedule(action)

        def dispose() -> None:
            nonlocal is_disposed
            is_disposed = True

        return CompositeDisposable(subscription, cancelable, Disposable(dispose))
Esempio n. 13
0
        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)
Esempio n. 14
0
    def test_filter_dispose_in_predicate(self):
        scheduler = TestScheduler()
        invoked = [0]
        ys = [None]
        xs = scheduler.create_hot_observable(
            on_next(110, 1),
            on_next(180, 2),
            on_next(230, 3),
            on_next(270, 4),
            on_next(340, 5),
            on_next(380, 6),
            on_next(390, 7),
            on_next(450, 8),
            on_next(470, 9),
            on_next(560, 10),
            on_next(580, 11),
            on_completed(600),
            on_next(610, 12),
            on_error(620, "ex"),
            on_completed(630),
        )
        results = scheduler.create_observer()
        d = SerialDisposable()

        def action(scheduler, state):
            def predicate(x):
                invoked[0] += 1
                if x == 8:
                    d.dispose()

                return is_prime(x)

            ys[0] = xs.pipe(filter(predicate))
            return ys[0]

        scheduler.schedule_absolute(created, action)

        def action1(scheduler, state):
            d.disposable = ys[0].subscribe(results)

        scheduler.schedule_absolute(subscribed, action1)

        def action2(scheduler, state):
            d.dispose()

        scheduler.schedule_absolute(disposed, action2)

        scheduler.start()
        assert results.messages == [on_next(230, 3), on_next(340, 5), on_next(390, 7)]
        assert xs.subscriptions == [subscribe(200, 450)]
        assert invoked[0] == 6
Esempio n. 15
0
def test_mutabledisposable_replacebeforedispose():
    disp1 = [False]
    disp2 = [False]
    m = SerialDisposable()

    def action1():
        disp1[0] = True

    d1 = Disposable(action1)
    m.disposable = d1

    assert d1 == m.disposable
    assert not disp1[0]

    def action2():
        disp2[0] = True

    d2 = Disposable(action2)
    m.disposable = d2

    assert d2 == m.disposable
    assert disp1[0]
    assert not disp2[0]
Esempio n. 16
0
        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
Esempio n. 17
0
        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)
Esempio n. 18
0
def test_mutabledisposable_replaceafterdispose():
    disp1 = [False]
    disp2 = [False]
    m = SerialDisposable()
    m.dispose()

    def action1():
        disp1[0] = True

    d1 = Disposable(action1)
    m.disposable = d1

    assert m.disposable == None
    assert disp1[0]

    def action2():
        disp2[0] = True

    d2 = Disposable(action2)
    m.disposable = d2

    assert m.disposable == None
    assert disp2[0]
Esempio n. 19
0
        def subscribe(
            observer: abc.ObserverBase[_T],
            scheduler: Optional[abc.SchedulerBase] = None,
        ) -> abc.DisposableBase:
            scheduler = scheduler or ImmediateScheduler.singleton()

            queue: List[Observable[_T]] = []
            m = SerialDisposable()
            d = CompositeDisposable(m)
            active_count = 0
            is_acquired = False

            def ensure_active():
                nonlocal is_acquired

                is_owner = False
                if queue:
                    is_owner = not is_acquired
                    is_acquired = True

                def action(scheduler: abc.SchedulerBase, state: Any = None):
                    nonlocal is_acquired, active_count

                    if queue:
                        work = queue.pop(0)
                    else:
                        is_acquired = False
                        return

                    sad = SingleAssignmentDisposable()
                    d.add(sad)

                    def on_next(value: _T) -> None:
                        nonlocal active_count

                        observer.on_next(value)
                        result = None
                        try:
                            result = mapper(value)
                        except Exception as ex:
                            observer.on_error(ex)
                            return

                        queue.append(result)
                        active_count += 1
                        ensure_active()

                    def on_complete() -> None:
                        nonlocal active_count

                        d.remove(sad)
                        active_count -= 1
                        if active_count == 0:
                            observer.on_completed()

                    sad.disposable = work.subscribe(on_next,
                                                    observer.on_error,
                                                    on_complete,
                                                    scheduler=scheduler)
                    m.disposable = scheduler.schedule(action)

                if is_owner:
                    m.disposable = scheduler.schedule(action)

            queue.append(source)
            active_count += 1
            ensure_active()
            return d
Esempio n. 20
0
        def subscribe(
            observer: abc.ObserverBase[_T],
            scheduler: Optional[abc.SchedulerBase] = None,
        ) -> abc.DisposableBase:
            subscription = SerialDisposable()
            timer = SerialDisposable()
            original = SingleAssignmentDisposable()

            subscription.disposable = original

            switched = False
            _id = [0]

            def set_timer(timeout: Observable[Any]) -> None:
                my_id = _id[0]

                def timer_wins():
                    return _id[0] == my_id

                d = SingleAssignmentDisposable()
                timer.disposable = d

                def on_next(x: Any) -> None:
                    if timer_wins():
                        subscription.disposable = other_.subscribe(
                            observer, scheduler=scheduler)

                    d.dispose()

                def on_error(e: Exception) -> None:
                    if timer_wins():
                        observer.on_error(e)

                def on_completed() -> None:
                    if timer_wins():
                        subscription.disposable = other_.subscribe(observer)

                d.disposable = timeout.subscribe(on_next,
                                                 on_error,
                                                 on_completed,
                                                 scheduler=scheduler)

            set_timer(first_timeout_)

            def observer_wins():
                res = not switched
                if res:
                    _id[0] += 1

                return res

            def on_next(x: _T) -> None:
                if observer_wins():
                    observer.on_next(x)
                    timeout = None
                    try:
                        timeout = (timeout_duration_mapper(x)
                                   if timeout_duration_mapper else
                                   reactivex.never())
                    except Exception as e:
                        observer.on_error(e)
                        return

                    set_timer(timeout)

            def on_error(error: Exception) -> None:
                if observer_wins():
                    observer.on_error(error)

            def on_completed() -> None:
                if observer_wins():
                    observer.on_completed()

            original.disposable = source.subscribe(on_next,
                                                   on_error,
                                                   on_completed,
                                                   scheduler=scheduler)
            return CompositeDisposable(subscription, timer)
Esempio n. 21
0
        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
Esempio n. 22
0
    def subscribe(observer: abc.ObserverBase[_T],
                  scheduler_: Optional[abc.SchedulerBase] = None):
        nonlocal duetime

        _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()

        if isinstance(duetime, datetime):
            duetime_ = _scheduler.to_datetime(duetime) - _scheduler.now
        else:
            duetime_ = _scheduler.to_timedelta(duetime)

        cancelable = SerialDisposable()
        exception: Optional[Exception] = None
        active = [False]
        running = [False]
        queue: List[Timestamp[Notification[_T]]] = []

        def on_next(notification: Timestamp[Notification[_T]]) -> None:
            nonlocal exception
            should_run = False

            with source.lock:
                if isinstance(notification.value, OnError):
                    del queue[:]
                    queue.append(notification)
                    exception = notification.value.exception
                    should_run = not running[0]
                else:
                    queue.append(
                        Timestamp(
                            value=notification.value,
                            timestamp=notification.timestamp + duetime_,
                        ))
                    should_run = not active[0]
                    active[0] = True

            if should_run:
                if exception:
                    observer.on_error(exception)
                else:
                    mad = MultipleAssignmentDisposable()
                    cancelable.disposable = mad

                    def action(scheduler: abc.SchedulerBase,
                               state: Any = None):
                        if exception:
                            return

                        with source.lock:
                            running[0] = True
                            while True:
                                result = None
                                if queue and queue[
                                        0].timestamp <= scheduler.now:
                                    result = queue.pop(0).value

                                if result:
                                    result.accept(observer)

                                if not result:
                                    break

                            should_continue = False
                            recurse_duetime: typing.RelativeTime = 0
                            if queue:
                                should_continue = True
                                diff = queue[0].timestamp - scheduler.now
                                recurse_duetime = max(DELTA_ZERO, diff)
                            else:
                                active[0] = False

                            ex = exception
                            running[0] = False

                        if ex:
                            observer.on_error(ex)
                        elif should_continue:
                            mad.disposable = scheduler.schedule_relative(
                                recurse_duetime, action)

                    mad.disposable = _scheduler.schedule_relative(
                        duetime_, action)

        subscription = source.pipe(
            ops.materialize(),
            ops.timestamp(),
        ).subscribe(on_next, scheduler=_scheduler)

        return CompositeDisposable(subscription, cancelable)
Esempio n. 23
0
        def subscribe(
            observer: abc.ObserverBase[_T],
            scheduler: Optional[abc.SchedulerBase] = None,
        ) -> abc.DisposableBase:
            cancelable = SerialDisposable()
            has_value: bool = False
            value: _T = cast(_T, None)
            _id = [0]

            def on_next(x: _T) -> None:
                nonlocal value, has_value

                throttle = None
                try:
                    throttle = throttle_duration_mapper(x)
                except Exception as e:  # pylint: disable=broad-except
                    observer.on_error(e)
                    return

                has_value = True
                value = x
                _id[0] += 1
                current_id = _id[0]
                d = SingleAssignmentDisposable()
                cancelable.disposable = d

                def on_next(x: Any) -> None:
                    nonlocal has_value
                    if has_value and _id[0] == current_id:
                        observer.on_next(value)

                    has_value = False
                    d.dispose()

                def on_completed() -> None:
                    nonlocal has_value
                    if has_value and _id[0] == current_id:
                        observer.on_next(value)

                    has_value = False
                    d.dispose()

                d.disposable = throttle.subscribe(on_next,
                                                  observer.on_error,
                                                  on_completed,
                                                  scheduler=scheduler)

            def on_error(e: Exception) -> None:
                nonlocal has_value
                cancelable.dispose()
                observer.on_error(e)
                has_value = False
                _id[0] += 1

            def on_completed() -> None:
                nonlocal has_value
                cancelable.dispose()
                if has_value:
                    observer.on_next(value)

                observer.on_completed()
                has_value = False
                _id[0] += 1

            subscription = source.subscribe(on_next,
                                            on_error,
                                            on_completed,
                                            scheduler=scheduler)
            return CompositeDisposable(subscription, cancelable)
Esempio n. 24
0
def test_mutabledisposable_ctor_prop():
    m = SerialDisposable()
    assert not m.disposable
Esempio n. 25
0
        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
Esempio n. 26
0
class ScheduledObserver(Observer[_T_in]):
    def __init__(self, scheduler: abc.SchedulerBase,
                 observer: abc.ObserverBase[_T_in]) -> None:
        super().__init__()

        self.scheduler = scheduler
        self.observer = observer

        self.lock = threading.RLock()
        self.is_acquired = False
        self.has_faulted = False
        self.queue: List[typing.Action] = []
        self.disposable = SerialDisposable()

        # Note to self: list append is thread safe
        # http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm

    def _on_next_core(self, value: Any) -> None:
        def action() -> None:
            self.observer.on_next(value)

        self.queue.append(action)

    def _on_error_core(self, error: Exception) -> None:
        def action() -> None:
            self.observer.on_error(error)

        self.queue.append(action)

    def _on_completed_core(self) -> None:
        def action() -> None:
            self.observer.on_completed()

        self.queue.append(action)

    def ensure_active(self) -> None:
        is_owner = False

        with self.lock:
            if not self.has_faulted and self.queue:
                is_owner = not self.is_acquired
                self.is_acquired = True

        if is_owner:
            self.disposable.disposable = self.scheduler.schedule(self.run)

    def run(self, scheduler: abc.SchedulerBase, state: Any) -> None:
        parent = self

        with self.lock:
            if parent.queue:
                work = parent.queue.pop(0)
            else:
                parent.is_acquired = False
                return

        try:
            work()
        except Exception:
            with self.lock:
                parent.queue = []
                parent.has_faulted = True
            raise

        self.scheduler.schedule(self.run)

    def dispose(self) -> None:
        super().dispose()
        self.disposable.dispose()