Ejemplo n.º 1
0
    def subscribe(observer, scheduler=None):
        scheduler = scheduler or current_thread_scheduler

        subscription = SerialDisposable()
        cancelable = SerialDisposable()
        last_exception = [None]
        is_disposed = []

        def action(action1, state=None):
            def on_error(exn):
                last_exception[0] = exn
                cancelable.disposable = scheduler.schedule(action)

            if is_disposed:
                return

            try:
                current = next(sources)
            except StopIteration:
                if last_exception[0]:
                    observer.on_error(last_exception[0])
                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)

        cancelable.disposable = scheduler.schedule(action)

        def dispose():
            is_disposed.append(True)
        return CompositeDisposable(subscription, cancelable, Disposable(dispose))
Ejemplo n.º 2
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
Ejemplo n.º 3
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
Ejemplo n.º 4
0
    def subscribe(observer, scheduler=None):

        scheduler = scheduler or current_thread_scheduler

        subscription = SerialDisposable()
        cancelable = SerialDisposable()

        def action(scheduler, state=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 = rx.from_future(source) if is_future(source) else source

            d = SingleAssignmentDisposable()
            subscription.disposable = d

            def on_resume(state=None):
                scheduler.schedule(action, state)

            d.disposable = current.subscribe_(observer.on_next, on_resume,
                                              on_resume, scheduler)

        cancelable.disposable = scheduler.schedule(action)
        return CompositeDisposable(subscription, cancelable)
Ejemplo n.º 5
0
    def subscribe(observer, scheduler=None):
        scheduler = scheduler or current_thread_scheduler

        subscription = SerialDisposable()
        cancelable = SerialDisposable()
        last_exception = [None]
        is_disposed = []

        def action(action1, state=None):
            def on_error(exn):
                last_exception[0] = exn
                cancelable.disposable = scheduler.schedule(action)

            if is_disposed:
                return

            try:
                current = next(sources_)
            except StopIteration:
                if last_exception[0]:
                    observer.on_error(last_exception[0])
                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)

        cancelable.disposable = scheduler.schedule(action)

        def dispose():
            is_disposed.append(True)
        return CompositeDisposable(subscription, cancelable, Disposable(dispose))
Ejemplo n.º 6
0
    def subscribe(observer, scheduler=None):
        d1 = SingleAssignmentDisposable()
        subscription = SerialDisposable()

        subscription.disposable = d1

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

            result = rx.from_future(result) if is_future(result) 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
        )
        return subscription
Ejemplo n.º 7
0
    def subscribe(observer, scheduler=None):
        scheduler = scheduler or current_thread_scheduler

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

        def action(action1, state=None):
            nonlocal is_disposed
            if is_disposed:
                return

            def on_completed():
                cancelable.disposable = scheduler.schedule(action)

            try:
                current = next(sources_)
            except StopIteration:
                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, observer.on_error, on_completed, scheduler)

        cancelable.disposable = scheduler.schedule(action)

        def dispose():
            nonlocal is_disposed
            is_disposed = True

        return CompositeDisposable(subscription, cancelable, Disposable(dispose))
Ejemplo n.º 8
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
Ejemplo n.º 9
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
Ejemplo n.º 10
0
    def subscribe(observer, scheduler=None):

        scheduler = scheduler or current_thread_scheduler

        subscription = SerialDisposable()
        cancelable = SerialDisposable()

        def action(scheduler, state=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 = rx.from_future(source) if is_future(source) else source

            d = SingleAssignmentDisposable()
            subscription.disposable = d

            def on_resume(state=None):
                scheduler.schedule(action, state)

            d.disposable = current.subscribe_(observer.on_next, on_resume, on_resume, scheduler)

        cancelable.disposable = scheduler.schedule(action)
        return CompositeDisposable(subscription, cancelable)
Ejemplo n.º 11
0
        def subscribe(observer, _=None):
            m = SingleAssignmentDisposable()
            d = SerialDisposable()
            d.disposable = m

            def action(scheduler, state):
                d.disposable = ScheduledDisposable(scheduler, source.subscribe(observer))

            m.disposable = scheduler.schedule(action)
            return d
Ejemplo n.º 12
0
    def run(self):
      self.gate = RLock()
      self.value = None
      self.hasValue = False
      self.throttleDisposable = SerialDisposable()
      self.resourceId = 0

      subscription = self.parent.source.subscribeSafe(self)

      return CompositeDisposable(subscription, self.throttleDisposable)
Ejemplo n.º 13
0
    def __init__(self, scheduler: typing.Scheduler, single: Single) -> None:
        super().__init__()

        self.scheduler = scheduler
        self.single = single

        self.lock = threading.RLock()
        self.is_acquired = False
        self.has_faulted = False
        self.queue: List[typing.Action] = []
        self.disposable = SerialDisposable()
Ejemplo n.º 14
0
  def subscribe(observer):
    m = SingleAssignmentDisposable()
    d = SerialDisposable()
    d.disposable = m

    def action():
      d.disposable = SchedulerDisposable(scheduler, self.subscribeSafe(observer))

    m.disposable = scheduler.schedule(action)

    return d
Ejemplo n.º 15
0
        def subscribe(observer, _=None):
            m = SingleAssignmentDisposable()
            d = SerialDisposable()
            d.disposable = m

            def action(scheduler, state):
                d.disposable = ScheduledDisposable(scheduler,
                                                   source.subscribe(observer))

            m.disposable = scheduler.schedule(action)
            return d
Ejemplo n.º 16
0
        def subscribe(observer, scheduler_=None):
            _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton(
            )

            if isinstance(duetime, datetime):
                scheduler_method = _scheduler.schedule_absolute
            else:
                scheduler_method = _scheduler.schedule_relative

            switched = [False]
            _id = [0]

            original = SingleAssignmentDisposable()
            subscription = SerialDisposable()
            timer = SerialDisposable()
            subscription.disposable = original

            def create_timer():
                my_id = _id[0]

                def action(scheduler, state=None):
                    switched[0] = (_id[0] == my_id)
                    timer_wins = switched[0]
                    if timer_wins:
                        subscription.disposable = obs.subscribe(
                            observer, scheduler=scheduler)

                timer.disposable = scheduler_method(duetime, action)

            create_timer()

            def on_next(value):
                send_wins = not switched[0]
                if send_wins:
                    _id[0] += 1
                    observer.on_next(value)
                    create_timer()

            def on_error(error):
                on_error_wins = not switched[0]
                if on_error_wins:
                    _id[0] += 1
                    observer.on_error(error)

            def on_completed():
                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_)
            return CompositeDisposable(subscription, timer)
Ejemplo n.º 17
0
    def __init__(self, scheduler: abc.Scheduler,
                 observer: abc.Observer) -> None:
        super().__init__()

        self.scheduler = scheduler
        self.observer = observer

        self.lock = threading.RLock()
        self.is_acquired = False
        self.has_faulted = False
        self.queue: List[Action] = []
        self.disposable = SerialDisposable()
Ejemplo n.º 18
0
        def run(self):
            self.delays = CompositeDisposable()
            self.gate = RLock()
            self.atEnd = False
            self.subscription = SerialDisposable()

            if self.parent.subscriptionDelay == None:
                self.start()
            else:
                self.subscription.disposable = self.parent.subscriptionDelay.subscribeSafe(
                    self.Sigma(self))

            return CompositeDisposable(self.subscription, self.delays)
Ejemplo n.º 19
0
        def subscribe(observer, scheduler_=None):
            _scheduler = scheduler or scheduler_ or timeout_scheduler

            if isinstance(duetime, datetime):
                scheduler_method = _scheduler.schedule_absolute
            else:
                scheduler_method = _scheduler.schedule_relative

            switched = [False]
            _id = [0]

            original = SingleAssignmentDisposable()
            subscription = SerialDisposable()
            timer = SerialDisposable()
            subscription.disposable = original

            def create_timer():
                my_id = _id[0]

                def action(scheduler, state=None):
                    switched[0] = (_id[0] == my_id)
                    timer_wins = switched[0]
                    if timer_wins:
                        subscription.disposable = other.subscribe(observer, scheduler=scheduler)

                timer.disposable = scheduler_method(duetime, action)

            create_timer()

            def on_next(value):
                send_wins = not switched[0]
                if send_wins:
                    _id[0] += 1
                    observer.on_next(value)
                    create_timer()

            def on_error(error):
                on_error_wins = not switched[0]
                if on_error_wins:
                    _id[0] += 1
                    observer.on_error(error)

            def on_completed():
                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_)
            return CompositeDisposable(subscription, timer)
Ejemplo n.º 20
0
  def __init__(self, scheduler, observer):
    super(ScheduledObserver, self).__init__()
    self.scheduler = scheduler
    self.observer = observer
    self.state = Atomic(ScheduledObserver.STOPPED, self.lock)
    self.disposable = SerialDisposable()

    self.failed = False
    self.exception = None
    self.completed = False

    self.queue = Queue()
    self.dispatcherJob = None
    self.dispatcherEvent = Semaphore(0)
Ejemplo n.º 21
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
Ejemplo n.º 22
0
        def subscribe(observer, scheduler=None):
            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):
                    try:
                        delay = mapper(x)
                    except Exception as error:
                        observer.on_error(error)
                        return

                    d = SingleAssignmentDisposable()
                    delays.add(d)

                    def on_next(_):
                        observer.on_next(x)
                        delays.remove(d)
                        done()

                    def on_completed():
                        observer.on_next(x)
                        delays.remove(d)
                        done()

                    d.disposable = delay.subscribe_(on_next, observer.on_error, on_completed, scheduler)

                def on_completed():
                    at_end[0] = True
                    subscription.dispose()
                    done()

                subscription.disposable = source.subscribe_(on_next, observer.on_error, on_completed, scheduler)

            if not sub_delay:
                start()
            else:
                subscription.disposable(sub_delay.subscribe_(
                    lambda _: start(),
                    observer.on_error,
                    start))

            return CompositeDisposable(subscription, delays)
Ejemplo n.º 23
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
Ejemplo n.º 24
0
        def run(self):
            self.scheduler = self.parent.scheduler

            self.cancelTimer = SerialDisposable()

            self.gate = RLock()
            self.active = False  # as soon as a value arrived
            self.running = False  # on relative: True, on absolute: True after absolute time
            self.queue = deque()
            self.hasCompleted = False
            self.completeAt = 0
            self.hasFailed = False
            self.exception = None

            self.delay = 0
            self.startTime = self.scheduler.now()

            if self.parent.isAbsolute:
                self.ready = False
                self.cancelTimer.disposable = self.scheduler.scheduleWithAbsolute(
                    self.parent.dueTime, self.start)
            else:
                self.ready = True
                self.delay = Scheduler.normalize(self.parent.dueTime)

            self.sourceSubscription = SingleAssignmentDisposable()
            self.sourceSubscription.disposable = self.parent.source.subscribeSafe(
                self)

            return CompositeDisposable(self.sourceSubscription,
                                       self.cancelTimer)
Ejemplo n.º 25
0
    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)))
Ejemplo n.º 26
0
        def run(self):
            self.scheduler = self.parent.scheduler

            self.cancelTimer = SerialDisposable()

            self.gate = RLock()
            self.evt = Semaphore(0)
            self.stopped = False
            self.stop = Event()
            self.queue = deque()
            self.hasCompleted = False
            self.completeAt = 0
            self.hasFailed = False
            self.exception = None

            self.delay = 0
            self.startTime = self.scheduler.now()

            if self.parent.isAbsolute:
                self.cancelTimer.disposable = self.scheduler.scheduleAbsolute(
                    self.parent.dueTime, self.start)
            else:
                self.delay = Scheduler.normalize(self.parent.dueTime)
                self.scheduleDrain()

            self.sourceSubscription = SingleAssignmentDisposable()
            self.sourceSubscription.disposable = self.parent.source.subscribeSafe(
                self)

            return CompositeDisposable(self.sourceSubscription,
                                       self.cancelTimer)
Ejemplo n.º 27
0
        def subscribe(observer, scheduler=None) -> Disposable:
            cancelable = SerialDisposable()
            has_value = [False]
            value = [None]
            _id = [0]

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

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

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

                    has_value[0] = False
                    d.dispose()

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

                    has_value[0] = False
                    d.dispose()

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

            def on_error(e) -> None:
                cancelable.dispose()
                observer.on_error(e)
                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)
    def test_return_disposed_after_next(self):
        scheduler = TestScheduler()
        d = SerialDisposable()
        xs = rx.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)]
Ejemplo n.º 29
0
        def run(self):
            self.subscription = SerialDisposable()
            self.timer = SerialDisposable()
            original = SingleAssignmentDisposable()

            self.subscription.disposable = original

            self.gate = RLock()
            self.currentId = 0
            self.switched = False

            self.createTimer()

            original.disposable = self.parent.source.subscribeSafe(self)

            return CompositeDisposable(self.subscription, self.timer)
        def subscribe(observer, scheduler_=None):
            _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()

            n = [0]
            s = [None]
            timer_d = SerialDisposable()
            window_id = [0]
            group_disposable = CompositeDisposable(timer_d)
            ref_count_disposable = RefCountDisposable(group_disposable)

            def create_timer(_id):
                m = SingleAssignmentDisposable()
                timer_d.disposable = m

                def action(scheduler, state):
                    if _id != window_id[0]:
                        return

                    n[0] = 0
                    window_id[0] += 1
                    new_id = window_id[0]
                    s[0].on_completed()
                    s[0] = Subject()
                    observer.on_next(add_ref(s[0], ref_count_disposable))
                    create_timer(new_id)

                m.disposable = _scheduler.schedule_relative(timespan, action)

            s[0] = Subject()
            observer.on_next(add_ref(s[0], ref_count_disposable))
            create_timer(0)

            def on_next(x):
                new_window = False
                new_id = 0

                s[0].on_next(x)
                n[0] += 1
                if n[0] == count:
                    new_window = True
                    n[0] = 0
                    window_id[0] += 1
                    new_id = window_id[0]
                    s[0].on_completed()
                    s[0] = Subject()
                    observer.on_next(add_ref(s[0], ref_count_disposable))

                if new_window:
                    create_timer(new_id)

            def on_error(e):
                s[0].on_error(e)
                observer.on_error(e)

            def on_completed():
                s[0].on_completed()
                observer.on_completed()

            group_disposable.add(source.subscribe_(on_next, on_error, on_completed, scheduler_))
            return ref_count_disposable
Ejemplo n.º 31
0
        def run(self):
            self.subscription = SerialDisposable()

            d = SingleAssignmentDisposable()
            self.subscription.disposable = d
            d.disposable = self.parent.source.subscribeSafe(self)

            return self.subscription
Ejemplo n.º 32
0
        def subscribe(observer, scheduler=None):
            scheduler = scheduler or immediate_scheduler

            queue = []
            m = SerialDisposable()
            d = CompositeDisposable(m)
            active_count = [0]
            is_acquired = [False]

            def ensure_active():
                is_owner = False
                if queue:
                    is_owner = not is_acquired[0]
                    is_acquired[0] = True

                def action(scheduler, state):
                    if queue:
                        work = queue.pop(0)
                    else:
                        is_acquired[0] = False
                        return

                    sad = SingleAssignmentDisposable()
                    d.add(sad)

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

                        queue.append(result)
                        active_count[0] += 1
                        ensure_active()

                    def on_complete():
                        d.remove(sad)
                        active_count[0] -= 1
                        if active_count[0] == 0:
                            observer.on_completed()

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

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

            queue.append(source)
            active_count[0] += 1
            ensure_active()
            return d
Ejemplo n.º 33
0
    def schedule_periodic(self,
                          period: typing.RelativeTime,
                          action: ScheduledPeriodicAction,
                          state: TState = None) -> typing.Disposable:
        """Schedules a periodic piece of work.

        Args:
            period: Period in seconds or timedelta for running the
                work periodically.
            action: Action to be executed.
            state: [Optional] Initial state passed to the action upon
                the first iteration.

        Returns:
            The disposable object used to cancel the scheduled
            recurring action (best effort)."""

        disp = SerialDisposable()

        def invoke_action(scheduler: typing.Scheduler,
                          _: TState) -> Optional[Disposable]:
            nonlocal state

            if disp.is_disposed:
                return None

            disp.disposable = self.schedule_relative(period, invoke_action,
                                                     None)

            try:
                new_state = action(state)
            except Exception:
                disp.dispose()
                raise

            if state is not None:
                state = new_state

            return None

        disp.disposable = self.schedule_relative(period, invoke_action, state)
        return disp
Ejemplo n.º 34
0
    def __init__(self, scheduler: abc.Scheduler, observer: abc.Observer) -> None:
        super().__init__()

        self.scheduler = scheduler
        self.observer = observer

        self.lock = threading.RLock()
        self.is_acquired = False
        self.has_faulted = False
        self.queue: List[Action] = []
        self.disposable = SerialDisposable()
Ejemplo n.º 35
0
    def subscribe(observer, scheduler_=None):
        _scheduler = scheduler_ or CurrentThreadScheduler.singleton()

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

        def action(action1, state=None):
            def on_error(exn):
                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_)

        cancelable.disposable = _scheduler.schedule(action)

        def dispose():
            nonlocal is_disposed
            is_disposed = True

        return CompositeDisposable(subscription, cancelable,
                                   Disposable(dispose))
Ejemplo n.º 36
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]
Ejemplo n.º 37
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]
Ejemplo n.º 38
0
    def run(self):
      self.delays = CompositeDisposable()
      self.gate = RLock()
      self.atEnd = False
      self.subscription = SerialDisposable()

      if self.parent.subscriptionDelay == None:
        self.start()
      else:
        self.subscription.disposable = self.parent.subscriptionDelay.subscribeSafe(self.Sigma(self))

      return CompositeDisposable(self.subscription, self.delays)
Ejemplo n.º 39
0
        def run(self):
            self.gate = RLock()
            self.list = []
            self.n = 0
            self.windowId = 0

            self.timerDisposable = SerialDisposable()
            self.createTimer(0)

            subscription = self.parent.source.subscribeSafe(self)

            return CompositeDisposable(self.timerDisposable, subscription)
Ejemplo n.º 40
0
        def run(self):
            self.gate = RLock()
            self.innerSubscription = SerialDisposable()
            self.isStopped = False
            self.latest = 0
            self.hasLatest = False

            self.subscription = SingleAssignmentDisposable()
            self.subscription.disposable = self.parent.sources.subscribeSafe(
                self)

            return CompositeDisposable(self.subscription,
                                       self.innerSubscription)
Ejemplo n.º 41
0
        def subscribe(observer, scheduler=None):
            inner_subscription = SerialDisposable()
            has_latest = [False]
            is_stopped = [False]
            latest = [0]

            def on_next(inner_source: Union[Observable, Future]):
                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 is_future(inner_source):
                    obs = from_future(cast(Future, inner_source))
                else:
                    obs = cast(Observable, 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)
Ejemplo n.º 42
0
  def __init__(self, scheduler, observer):
    super(ScheduledObserver, self).__init__()
    self.scheduler = scheduler
    self.observer = observer
    self.state = Atomic(ScheduledObserver.STOPPED, self.lock)
    self.disposable = SerialDisposable()

    self.failed = False
    self.exception = None
    self.completed = False

    self.queue = Queue()
    self.dispatcherJob = None
    self.dispatcherEvent = Semaphore(0)
Ejemplo n.º 43
0
class PeriodicTimer(object):
  """A timer that runs every interval seconds, can shift in time"""
  def __init__(self, interval, action):
    super(PeriodicTimer, self).__init__()
    self.interval = interval
    self.action = action
    self.timerDisposable = SerialDisposable()

  def start(self):
    timer = Timer(self.interval, self._execute)

    self.timerDisposable.disposable = Disposable.create(timer.cancel)

    timer.start()

    return self.timerDisposable

  def cancel(self):
    self.timerDisposable.dispose()

  def _execute(self):
    self.action()
    self.run()
Ejemplo n.º 44
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
Ejemplo n.º 45
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
Ejemplo n.º 46
0
  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(ThrottleObservable.Sink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.gate = RLock()
      self.value = None
      self.hasValue = False
      self.throttleDisposable = SerialDisposable()
      self.resourceId = 0

      subscription = self.parent.source.subscribeSafe(self)

      return CompositeDisposable(subscription, self.throttleDisposable)

    def onNext(self, value):
      throttle = None

      try:
        throttle = self.parent.throttleSelector(value)
      except Exception as e:
        with self.gate:
          self.observer.onError(e)
          self.dispose()

        return

      currentId = 0

      with self.gate:
        self.hasValue = True
        self.value = value
        self.resourceId += 1
        currentId = self.resourceId

      d = SingleAssignmentDisposable()
      self.throttleDisposable.disposable = d
      d.disposable = throttle.subscribeSafe(self.Delta(self, value, currentId, d))

    def onError(self, exception):
      self.throttleDisposable.dispose()

      with self.gate:
        self.observer.onError(exception)
        self.dispose()

        self.hasValue = False
        self.resourceId += 1

    def onCompleted(self):
      self.throttleDisposable.dispose()

      with self.gate:
        if self.hasValue:
          self.observer.onNext(self.value)

        self.observer.onCompleted()
        self.dispose()

        self.hasValue = False
        self.resourceId += 1

    class Delta(Observer):
      def __init__(self, parent, value, currentId, cancelSelf):
        self.parent = parent
        self.value = value
        self.currentId = currentId
        self.cancelSelf = cancelSelf

      def onNext(self, value):
        with self.parent.gate:
          if self.parent.hasValue and self.parent.resourceId == self.currentId:
            self.parent.observer.onNext(self.value)

          self.parent.hasValue = False
          self.cancelSelf.dispose()

      def onError(self, exception):
        with self.parent.gate:
          self.parent.observer.onError(exception)
          self.parent.dispose()

      def onCompleted(self):
        with self.parent.gate:
          if self.parent.hasValue and self.parent.resourceId == self.currentId:
            self.parent.observer.onNext(self.value)

          self.parent.hasValue = False
          self.cancelSelf.dispose()
Ejemplo n.º 47
0
class ScheduledObserver(ObserverBase):
    def __init__(self, scheduler: abc.Scheduler, observer: abc.Observer) -> None:
        super().__init__()

        self.scheduler = scheduler
        self.observer = observer

        self.lock = threading.RLock()
        self.is_acquired = False
        self.has_faulted = False
        self.queue: List[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():
            self.observer.on_next(value)
        self.queue.append(action)

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

    def _on_completed_core(self) -> None:
        def action():
            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.Scheduler, 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()
Ejemplo n.º 48
0
class ScheduledObserver(ObserverBase):
  STOPPED = 0
  RUNNING = 1
  PENDING = 2
  FAULTED = 9

  def __init__(self, scheduler, observer):
    super(ScheduledObserver, self).__init__()
    self.scheduler = scheduler
    self.observer = observer
    self.state = Atomic(ScheduledObserver.STOPPED, self.lock)
    self.disposable = SerialDisposable()

    self.failed = False
    self.exception = None
    self.completed = False

    self.queue = Queue()
    self.dispatcherJob = None
    self.dispatcherEvent = Semaphore(0)

  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 dispatch(self, cancel):
    while True:
      self.dispatcherEvent.acquire()

      if cancel.isDisposed:
        return

      while True:
        next = self.queue.get()

        try:
          self.observer.onNext(next)
        except Exception as e:
          self.clearQueue()
          raise e

        self.dispatcherEvent.acquire()

        if cancel.isDisposed:
          return

      if self.failed:
        self.observer.onError(self.exception)
        self.dispose()

        return

      if self.completed:
        self.observer.onCompleted()
        self.dispose()

        return

  def ensureActive(self, n = 1):
    if self.scheduler.isLongRunning:
      while n > 0:
        self.dispatcherEvent.release()
        n -= 1

        self.ensureDispatcher()
    else:
      self.ensureActiveSlow()

  def ensureActiveSlow(self):
    isOwner = False

    while True:
      old = self.state.compareExchange(
        ScheduledObserver.RUNNING,
        ScheduledObserver.STOPPED
      )

      if old == ScheduledObserver.STOPPED:
        isOwner = True
        break
      elif old == ScheduledObserver.FAULTED:
        return
      elif (
          (old == ScheduledObserver.PENDING or old == ScheduledObserver.RUNNING) and
          self.state.compareExchange(ScheduledObserver.PENDING, ScheduledObserver.RUNNING) == ScheduledObserver.RUNNING
        ):
        break

    if isOwner:
      self.disposable = self.scheduler.scheduleRecursiveWithState(None, self.run)

  def run(self, state, continuation):
    next = None

    while True:
      try:
        next = self.queue.get_nowait()
      except Empty:
        next = None

      if next != None:
        break

      if self.failed:
        # wait until the queue is drained
        if not self.queue.empty():
          continue

        self.state.value = ScheduledObserver.STOPPED

        self.observer.onError(self.exception)
        self.dispose()

        return

      if self.completed:
        # wait until the queue is drained
        if not self.queue.empty():
          continue

        self.state.value = ScheduledObserver.STOPPED

        self.observer.onCompleted()
        self.dispose()

        return

      old = self.state.compareExchange(
        ScheduledObserver.STOPPED,
        ScheduledObserver.RUNNING
      )

      if old == ScheduledObserver.RUNNING or old == ScheduledObserver.FAULTED:
        return

      # assert(old == ScheduledObserver.PENDING)

      self.state.value = ScheduledObserver.RUNNING
    #end while

    # we found an item, so next != None
    self.state.value = ScheduledObserver.RUNNING

    try:
      self.observer.onNext(next)
    except Exception as e:
      self.state.value = ScheduledObserver.FAULTED
      self.clearQueue()

      raise e

    continuation(state)

  def onNextCore(self, value):
    self.queue.put(value)

  def onErrorCore(self, exception):
    self.exception = exception
    self.failed = True

  def onCompletedCore(self):
    self.completed = True

  def clearQueue(self):
    try:
      while True:
        self.queue.get()
    except Empty:
      pass

  def dispose(self):
    super(ScheduledObserver, self).dispose()
    self.disposable.dispose()
Ejemplo n.º 49
0
  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(DelayObservable.Sink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.delays = CompositeDisposable()
      self.gate = RLock()
      self.atEnd = False
      self.subscription = SerialDisposable()

      if self.parent.subscriptionDelay == None:
        self.start()
      else:
        self.subscription.disposable = self.parent.subscriptionDelay.subscribeSafe(self.Sigma(self))

      return CompositeDisposable(self.subscription, self.delays)

    def start(self):
      self.subscription.disposable = self.parent.source.subscribeSafe(self)

    def onNext(self, value):
      try:
        delay = self.parent.delaySelector(value)
      except Exception as e:
        with self.gate:
          self.observer.onError(e)
          self.dispose()
      else:
        d = SingleAssignmentDisposable()
        self.delays.add(d)
        d.disposable = delay.subscribeSafe(self.Delta(self, value, d))

    def onError(self, exception):
      with self.gate:
        self.observer.onError(exception)
        self.dispose()

    def onCompleted(self):
      with self.gate:
        self.atEnd = True
        self.subscription.dispose()

        self.checkDone()

    def checkDone(self):
      if self.atEnd and self.delays.length == 0:
        self.observer.onCompleted()
        self.dispose()

    class Sigma(Observer):
      def __init__(self, parent):
        self.parent = parent

      def onNext(self, value):
        self.parent.start()

      def onError(self, exception):
        self.parent.observer.onError(exception)
        self.parent.dispose()

      def onCompleted(self):
        self.parent.start()

    class Delta(Observer):
      def __init__(self, parent, value, cancelSelf):
        self.parent = parent
        self.value = value
        self.cancelSelf = cancelSelf

      def onNext(self, delay):
        with self.parent.gate:
          self.parent.observer.onNext(self.value)
          self.parent.delays.remove(self.cancelSelf)
          self.parent.checkDone()

      def onError(self, exception):
        with self.parent.gate:
          self.parent.observer.onError(exception)
          self.parent.dispose()

      def onCompleted(self):
        with self.parent.gate:
          self.parent.observer.onNext(self.value)
          self.parent.delays.remove(self.cancelSelf)
          self.parent.checkDone()
Ejemplo n.º 50
0
        def subscribe(observer, scheduler=None):
            subscription = SerialDisposable()
            timer = SerialDisposable()
            original = SingleAssignmentDisposable()

            subscription.disposable = original

            switched = False
            _id = [0]

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

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

                d = SingleAssignmentDisposable()
                timer.disposable = d

                def on_next(x):
                    if timer_wins():
                        subscription.disposable = other.subscribe(observer, scheduler=scheduler)

                    d.dispose()

                def on_error(e):
                    if timer_wins():
                        observer.on_error(e)

                def on_completed():
                    if timer_wins():
                        subscription.disposable = other.subscribe(observer)

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

            set_timer(first_timeout)

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

                return res

            def on_next(x):
                if observer_wins():
                    observer.on_next(x)
                    timeout = None
                    try:
                        timeout = timeout_duration_mapper(x)
                    except Exception as e:
                        observer.on_error(e)
                        return

                    set_timer(timeout)

            def on_error(error):
                if observer_wins():
                    observer.on_error(error)

            def on_completed():
                if observer_wins():
                    observer.on_completed()

            original.disposable = source.subscribe_(on_next, on_error, on_completed, scheduler)
            return CompositeDisposable(subscription, timer)
Ejemplo n.º 51
0
 def __init__(self, interval, action):
   super(PeriodicTimer, self).__init__()
   self.interval = interval
   self.action = action
   self.timerDisposable = SerialDisposable()
Ejemplo n.º 52
0
  class Sink(rx.linq.sink.Sink):
    def __init__(self, parent, observer, cancel):
      super(ThrottleTime.Sink, self).__init__(observer, cancel)
      self.parent = parent

    def run(self):
      self.gate = RLock()
      self.value = None
      self.hasValue = False
      self.propagatorDisposable = SerialDisposable()
      self.resourceId = 0

      subscription = self.parent.source.subscribeSafe(self)

      return CompositeDisposable(subscription, self.propagatorDisposable)

    def onNext(self, value):
      currentId = 0

      with self.gate:
        self.hasValue = True
        self.value = value
        self.resourceId += 1
        currentId = self.resourceId

      d = SingleAssignmentDisposable()
      self.propagatorDisposable.disposable = d
      d.disposable = self.parent.scheduler.scheduleWithRelativeAndState(
        currentId,
        self.parent.dueTime,
        self.propagate
      )

    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 onError(self, exception):
      self.propagatorDisposable.dispose()

      with self.gate:
        self.observer.onError(exception)
        self.dispose()

        self.hasValue = False
        self.resourceId += 1

    def onCompleted(self):
      self.propagatorDisposable.dispose()

      with self.gate:
        if self.hasValue:
          self.observer.onNext(self.value)

        self.observer.onCompleted()
        self.dispose()

        self.hasValue = False
        self.resourceId += 1