Example #1
0
def _using(resource_factory: Callable[[], typing.Disposable],
           observable_factory: Callable[[typing.Disposable], Observable]
           ) -> Observable:
    """Constructs an observable sequence that depends on a resource
    object, whose lifetime is tied to the resulting observable
    sequence's lifetime.

    Example:
        >>> res = rx.using(lambda: AsyncSubject(), lambda: s: s)

    Args:
        resource_factory: Factory function to obtain a resource object.
        observable_factory: Factory function to obtain an observable
            sequence that depends on the obtained resource.

    Returns:
        An observable sequence whose lifetime controls the lifetime
        of the dependent resource object.
    """

    def subscribe(observer, scheduler=None):
        disp = Disposable()

        try:
            resource = resource_factory()
            if resource is not None:
                disp = resource

            source = observable_factory(resource)
        except Exception as exception:  # pylint: disable=broad-except
            d = rx.throw(exception).subscribe(observer, scheduler=scheduler)
            return CompositeDisposable(d, disp)

        return CompositeDisposable(source.subscribe(observer, scheduler=scheduler), disp)
    return Observable(subscribe)
Example #2
0
def add_ref(xs, r):
    from rx.core import Observable

    def subscribe(observer, scheduler=None):
        return CompositeDisposable(r.disposable, xs.subscribe(observer))

    return Observable(subscribe)
Example #3
0
File: map.py Project: wolf937/RxPY
    def map(source: Observable) -> Observable:
        """Partially applied map operator.

        Project each element of an observable sequence into a new form
        by incorporating the element's index.

        Example:
            >>> map(source)

        Args:
            source: The observable source to transform.

        Returns:
            Returns an observable sequence whose elements are the
            result of invoking the transform function on each element
            of the source.
        """

        def subscribe(obv: Observer, scheduler: Scheduler = None) -> Disposable:
            def on_next(value: Any) -> None:
                try:
                    result = _mapper(value)
                except Exception as err:  # pylint: disable=broad-except
                    obv.on_error(err)
                else:
                    obv.on_next(result)

            return source.subscribe_(on_next, obv.on_error, obv.on_completed, scheduler)
        return Observable(subscribe)
Example #4
0
    def time_interval(source: Observable) -> Observable:
        """Records the time interval between consecutive values in an
        observable sequence.

            >>> res = time_interval(source)

        Return:
            An observable sequence with time interval information on
            values.
        """
        def subscribe(observer, scheduler_):
            _scheduler = scheduler or scheduler_ or timeout_scheduler
            last = _scheduler.now

            def mapper(value):
                nonlocal last

                now = _scheduler.now
                span = now - last
                last = now
                return TimeInterval(value=value, interval=span)

            return source.pipe(ops.map(mapper)).subscribe(observer, scheduler_)

        return Observable(subscribe)
    def element_at_or_default(source: Observable) -> Observable:
        def subscribe(observer, scheduler=None):
            i = [index]

            def on_next(x):
                found = False
                with source.lock:
                    if i[0]:
                        i[0] -= 1
                    else:
                        found = True

                if found:
                    observer.on_next(x)
                    observer.on_completed()

            def on_completed():
                if not has_default:
                    observer.on_error(ArgumentOutOfRangeException())
                else:
                    observer.on_next(default_value)
                    observer.on_completed()

            return source.subscribe_(on_next, observer.on_error, on_completed,
                                     scheduler)

        return Observable(subscribe)
Example #6
0
def _from_future(future: Future) -> Observable:
    """Converts a Future to an Observable sequence

    Args:
        future -- A Python 3 compatible future.
            https://docs.python.org/3/library/asyncio-task.html#future
            http://www.tornadoweb.org/en/stable/concurrent.html#tornado.concurrent.Future

    Returns:
        An Observable sequence which wraps the existing future success
        and failure.
    """
    def subscribe(
            observer: typing.Observer,
            scheduler: Optional[typing.Scheduler] = None) -> typing.Disposable:
        def done(future):
            try:
                value = future.result()
            except Exception as ex:
                observer.on_error(ex)
            else:
                observer.on_next(value)
                observer.on_completed()

        future.add_done_callback(done)

        def dispose() -> None:
            if future and future.cancel:
                future.cancel()

        return Disposable(dispose)

    return Observable(subscribe)
Example #7
0
def _return_value(value: Any,
                  scheduler: typing.Scheduler = None) -> Observable:
    """Returns an observable sequence that contains a single element,
    using the specified scheduler to send out observer messages.
    There is an alias called 'just'.

    Examples:
        >>> res = return(42)
        >>> res = return(42, rx.Scheduler.timeout)

    Args:
        value: Single element in the resulting observable sequence.

    Returns:
        An observable sequence containing the single specified
        element.
    """
    def subscribe(observer: typing.Observer,
                  scheduler_: typing.Scheduler = None) -> typing.Disposable:
        _scheduler = scheduler or scheduler_ or current_thread_scheduler

        def action(scheduler: typing.Scheduler, state: Any = None):
            observer.on_next(value)
            observer.on_completed()

        return _scheduler.schedule(action)

    return Observable(subscribe)
Example #8
0
    def skip_last(source: Observable) -> Observable:
        """Bypasses a specified number of elements at the end of an
        observable sequence.

        This operator accumulates a queue with a length enough to store
        the first `count` elements. As more elements are received,
        elements are taken from the front of the queue and produced on
        the result sequence. This causes elements to be delayed.

        Args:
            count: Number of elements to bypass at the end of the
            source sequence.

        Returns:
            An observable sequence containing the source sequence
            elements except for the bypassed ones at the end.
        """
        def subscribe(observer, scheduler=None):
            q = []

            def on_next(value):
                front = None
                with source.lock:
                    q.append(value)
                    if len(q) > count:
                        front = q.pop(0)

                if front is not None:
                    observer.on_next(front)

            return source.subscribe_(on_next, observer.on_error,
                                     observer.on_completed, scheduler)

        return Observable(subscribe)
Example #9
0
    def materialize(source: Observable) -> Observable:
        """Partially applied materialize operator.

        Materializes the implicit notifications of an observable
        sequence as explicit notification values.

        Args:
            source: Source observable to materialize.

        Returns:
            An observable sequence containing the materialized
            notification values from the source sequence.
        """
        def subscribe(observer, scheduler=None):
            def on_next(value):
                observer.on_next(OnNext(value))

            def on_error(exception):
                observer.on_next(OnError(exception))
                observer.on_completed()

            def on_completed():
                observer.on_next(OnCompleted())
                observer.on_completed()

            return source.subscribe_(on_next, on_error, on_completed,
                                     scheduler)

        return Observable(subscribe)
Example #10
0
def _generate(initial_state, condition, iterate) -> Observable:
    def subscribe(observer, scheduler=None):
        scheduler = scheduler or current_thread_scheduler
        first = [True]
        state = [initial_state]
        mad = MultipleAssignmentDisposable()

        def action(scheduler, state1=None):
            has_result = False
            result = None

            try:
                if first[0]:
                    first[0] = False
                else:
                    state[0] = iterate(state[0])

                has_result = condition(state[0])
                if has_result:
                    result = state[0]

            except Exception as exception:  # pylint: disable=broad-except
                observer.on_error(exception)
                return

            if has_result:
                observer.on_next(result)
                mad.disposable = scheduler.schedule(action)
            else:
                observer.on_completed()

        mad.disposable = scheduler.schedule(action)
        return mad
    return Observable(subscribe)
Example #11
0
    def function(*args):
        arguments = list(args)

        def subscribe(observer: typing.Observer, scheduler: typing.Scheduler = None) -> typing.Disposable:
            def handler(*args):
                results = list(args)
                if mapper:
                    try:
                        results = mapper(args)
                    except Exception as err: # pylint: disable=broad-except
                        observer.on_error(err)
                        return

                    observer.on_next(results)
                else:
                    if isinstance(results, list) and len(results) <= 1:
                        observer.on_next(*results)
                    else:
                        observer.on_next(results)

                    observer.on_completed()

            arguments.append(handler)
            func(*arguments)
            return Disposable()

        return Observable(subscribe)
Example #12
0
    def skip_until(source: Observable) -> Observable:
        def subscribe(observer, scheduler=None):
            is_open = [False]

            def on_next(left):
                if is_open[0]:
                    observer.on_next(left)

            def on_completed():
                if is_open[0]:
                    observer.on_completed()

            subs = source.subscribe_(on_next, observer.on_error, on_completed,
                                     scheduler)
            subscriptions = CompositeDisposable(subs)

            right_subscription = SingleAssignmentDisposable()
            subscriptions.add(right_subscription)

            def on_next2(x):
                is_open[0] = True
                right_subscription.dispose()

            def on_completed2():
                right_subscription.dispose()

            right_subscription.disposable = other.subscribe_(
                on_next2, observer.on_error, on_completed2, scheduler)

            return subscriptions

        return Observable(subscribe)
    def default_if_empty(source: Observable) -> Observable:
        """Returns the elements of the specified sequence or the
        specified value in a singleton sequence if the sequence is
        empty.

        Examples:
            >>> obs = default_if_empty(source)

        Args:
            source: Source observable.

        Returns:
            An observable sequence that contains the specified default
            value if the source is empty otherwise, the elements of the
            source.
        """
        def subscribe(observer, scheduler=None) -> Disposable:
            found = [False]

            def on_next(x: Any):
                found[0] = True
                observer.on_next(x)

            def on_completed():
                if not found[0]:
                    observer.on_next(default_value)
                observer.on_completed()

            return source.subscribe_(on_next, observer.on_error, on_completed,
                                     scheduler)

        return Observable(subscribe)
Example #14
0
    def take(source: Observable) -> Observable:
        """Returns a specified number of contiguous elements from the start of
        an observable sequence.

        >>> take(source)

        Keyword arguments:
        count -- The number of elements to return.

        Returns an observable sequence that contains the specified number of
        elements from the start of the input sequence.
        """

        if not count:
            return empty()

        def subscribe(observer, scheduler=None):
            remaining = count

            def on_next(value):
                nonlocal remaining

                if remaining > 0:
                    remaining -= 1
                    observer.on_next(value)
                    if not remaining:
                        observer.on_completed()

            return source.subscribe_(on_next, observer.on_error,
                                     observer.on_completed, scheduler)

        return Observable(subscribe)
Example #15
0
    def window(source: Observable) -> Observable:
        def subscribe(observer, scheduler=None):
            window_subject = Subject()
            d = CompositeDisposable()
            r = RefCountDisposable(d)

            observer.on_next(add_ref(window_subject, r))

            def on_next_window(x):
                window_subject.on_next(x)

            def on_error(err):
                window_subject.on_error(err)
                observer.on_error(err)

            def on_completed():
                window_subject.on_completed()
                observer.on_completed()

            d.add(
                source.subscribe_(on_next_window, on_error, on_completed,
                                  scheduler))

            def on_next_observer(w):
                nonlocal window_subject
                window_subject.on_completed()
                window_subject = Subject()
                observer.on_next(add_ref(window_subject, r))

            d.add(
                boundaries.subscribe_(on_next_observer, on_error, on_completed,
                                      scheduler))
            return r

        return Observable(subscribe)
    def take_until_with_time(source: Observable) -> Observable:
        """Takes elements for the specified duration until the specified end
        time, using the specified scheduler to run timers.

        Examples:
            >>> res = take_until_with_time(source)

        Args:
            source: Source observale to take elements from.

        Returns:
            An observable sequence with the elements taken
            until the specified end time.
        """

        def subscribe(observer, scheduler_=None):
            _scheduler = scheduler or scheduler_ or timeout_scheduler

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

            def action(scheduler, state):
                observer.on_completed()

            task = scheduler_method(end_time, action)
            return CompositeDisposable(task, source.subscribe(observer, scheduler=scheduler_))
        return Observable(subscribe)
    def take_with_time(source: Observable) -> Observable:
        """Takes elements for the specified duration from the start of
        the observable source sequence.

        Example:
            >>> res = take_with_time(source)

        This operator accumulates a queue with a length enough to store
        elements received during the initial duration window. As more
        elements are received, elements older than the specified
        duration are taken from the queue and produced on the result
        sequence. This causes elements to be delayed with duration.

        Args:
            source: Source observable to take elements from.

        Returns:
            An observable sequence with the elements taken during the
            specified duration from the start of the source sequence.
        """
        def subscribe(observer, scheduler_=None):
            _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton(
            )

            def action(scheduler, state):
                observer.on_completed()

            disp = _scheduler.schedule_relative(duration, action)
            return CompositeDisposable(
                disp, source.subscribe(observer, scheduler=scheduler_))

        return Observable(subscribe)
    def finally_action(source: Observable) -> Observable:
        """Invokes a specified action after the source observable
        sequence terminates gracefully or exceptionally.

        Example:
            res = finally(source)

        Args:
            source: Observable sequence.

        Returns:
            An observable sequence with the action-invoking termination
            behavior applied.
        """
        def subscribe(observer, scheduler=None):
            try:
                subscription = source.subscribe(observer, scheduler=scheduler)
            except Exception:
                action()
                raise

            def dispose():
                try:
                    subscription.dispose()
                finally:
                    action()

            return Disposable(dispose)

        return Observable(subscribe)
Example #19
0
def _defer(
        factory: Callable[[Scheduler], Union[Observable,
                                             Future]]) -> Observable:
    """Returns an observable sequence that invokes the specified factory
    function whenever a new observer subscribes.

    Example:
        >>> res = defer(lambda: of(1, 2, 3))

    Args:
        observable_factory: Observable factory function to invoke for
        each observer that subscribes to the resulting sequence.

    Returns:
        An observable sequence whose observers trigger an invocation
        of the given observable factory function.
    """
    def subscribe(observer, scheduler=None):
        try:
            result = factory(scheduler)
        except Exception as ex:  # By design. pylint: disable=W0703
            return throw(ex).subscribe(observer)

        result = from_future(result) if is_future(result) else result
        return result.subscribe(observer, scheduler=scheduler)

    return Observable(subscribe)
Example #20
0
File: do.py Project: wensincai/RxPY
def do_after_terminate(source, after_terminate):
    """Invokes an action after an on_complete() or on_error() event.
     This can be helpful for debugging, logging, and other side effects
     when completion or an error terminates an operation


    on_terminate -- Action to invoke after on_complete or throw is called
    """
    def subscribe(observer, scheduler=None):
        def on_completed():
            observer.on_completed()
            try:
                after_terminate()
            except Exception as err:  # pylint: disable=broad-except
                observer.on_error(err)

        def on_error(exception):
            observer.on_error(exception)
            try:
                after_terminate()
            except Exception as err:  # pylint: disable=broad-except
                observer.on_error(err)

        return source.subscribe(observer.on_next, on_error, on_completed,
                                scheduler)

    return Observable(subscribe)
Example #21
0
    def some(source: Observable) -> Observable:
        """Partially applied operator.

        Determines whether some element of an observable sequence satisfies a
        condition if present, else if some items are in the sequence.

        Example:
            >>> obs = some(source)

        Args:
            predicate -- A function to test each element for a condition.

        Returns:
            An observable sequence containing a single element
            determining whether some elements in the source sequence
            pass the test in the specified predicate if given, else if
            some items are in the sequence.
        """
        def subscribe(observer, scheduler=None):
            def on_next(_):
                observer.on_next(True)
                observer.on_completed()

            def on_error():
                observer.on_next(False)
                observer.on_completed()
            return source.subscribe_(on_next, observer.on_error, on_error, scheduler)

        if predicate:
            return source.pipe(
                ops.filter(predicate),
                _some(),
            )

        return Observable(subscribe)
Example #22
0
File: do.py Project: wensincai/RxPY
    def partial(source: Observable) -> Observable:
        def subscribe(observer, scheduler=None):

            was_invoked = [False]

            def on_completed():
                observer.on_completed()
                try:
                    if not was_invoked[0]:
                        finally_action()
                        was_invoked[0] = True
                except Exception as err:  # pylint: disable=broad-except
                    observer.on_error(err)

            def on_error(exception):
                observer.on_error(exception)
                try:
                    if not was_invoked[0]:
                        finally_action()
                        was_invoked[0] = True
                except Exception as err:  # pylint: disable=broad-except
                    observer.on_error(err)

            composite_disposable = CompositeDisposable()
            composite_disposable.add(OnDispose(was_invoked))
            subscription = source.subscribe_(observer.on_next, on_error,
                                             on_completed, scheduler)
            composite_disposable.add(subscription)

            return composite_disposable

        return Observable(subscribe)
Example #23
0
def _with_latest_from(parent: Observable, *sources: Observable) -> Observable:
    NO_VALUE = object()

    def subscribe(observer, scheduler=None):
        def subscribe_all(parent, *children):

            values = [NO_VALUE for _ in children]

            def subscribe_child(i, child):
                subscription = SingleAssignmentDisposable()

                def on_next(value):
                    with parent.lock:
                        values[i] = value
                subscription.disposable = child.subscribe_(on_next, observer.on_error, scheduler=scheduler)
                return subscription

            parent_subscription = SingleAssignmentDisposable()

            def on_next(value):
                with parent.lock:
                    if NO_VALUE not in values:
                        result = (value,) + tuple(values)
                        observer.on_next(result)

            disp = parent.subscribe_(on_next, observer.on_error, observer.on_completed, scheduler)
            parent_subscription.disposable = disp

            children_subscription = [subscribe_child(i, child) for i, child in enumerate(children)]

            return [parent_subscription] + children_subscription
        return CompositeDisposable(subscribe_all(parent, *sources))
    return Observable(subscribe)
Example #24
0
    def skip(source: Observable) -> Observable:
        """The skip operator.

        Bypasses a specified number of elements in an observable sequence
        and then returns the remaining elements.

        Args:
            source: The source observable.

        Returns:
            An observable sequence that contains the elements that occur
            after the specified index in the input sequence.
        """
        def subscribe(observer, scheduler=None):
            remaining = count

            def on_next(value):
                nonlocal remaining

                if remaining <= 0:
                    observer.on_next(value)
                else:
                    remaining -= 1

            return source.subscribe_(on_next, observer.on_error,
                                     observer.on_completed, scheduler)

        return Observable(subscribe)
Example #25
0
    def throttle_first(source: Observable) -> Observable:
        """Returns an observable that emits only the first item emitted
        by the source Observable during sequential time windows of a
        specifiedduration.

        Args:
            source: Source observable to throttle.

        Returns:
            An Observable that performs the throttle operation.
        """
        def subscribe(observer, scheduler_=None):
            _scheduler = scheduler or scheduler_ or timeout_scheduler

            duration = _scheduler.to_timedelta(window_duration or 0.0)
            if duration <= _scheduler.to_timedelta(0):
                raise ValueError('window_duration cannot be less or equal zero.')
            last_on_next = [0]

            def on_next(x):
                emit = False
                now = _scheduler.now

                with source.lock:
                    if not last_on_next[0] or now - last_on_next[0] >= duration:
                        last_on_next[0] = now
                        emit = True
                if emit:
                    observer.on_next(x)

            return source.subscribe_(on_next, observer.on_error, observer.on_completed, scheduler=_scheduler)
        return Observable(subscribe)
    def skip_last_with_time(source: Observable) -> Observable:
        def subscribe(observer, scheduler_=None):
            nonlocal duration

            _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton(
            )
            duration = _scheduler.to_timedelta(duration)
            q = []

            def on_next(x):
                now = _scheduler.now
                q.append({"interval": now, "value": x})
                while q and now - q[0]["interval"] >= duration:
                    observer.on_next(q.pop(0)["value"])

            def on_completed():
                now = _scheduler.now
                while q and now - q[0]["interval"] >= duration:
                    observer.on_next(q.pop(0)["value"])

                observer.on_completed()

            return source.subscribe_(on_next, observer.on_error, on_completed,
                                     scheduler_)

        return Observable(subscribe)
Example #27
0
def catch_handler(
        source: Observable, handler: Callable[[Exception, Observable],
                                              Observable]) -> Observable:
    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

    return Observable(subscribe)
Example #28
0
def observable_timer_duetime_and_period(
        duetime,
        period,
        scheduler: Optional[typing.Scheduler] = None) -> Observable:
    def subscribe(observer, scheduler_=None):
        _scheduler = scheduler or scheduler_ or timeout_scheduler
        nonlocal duetime

        if not isinstance(duetime, datetime):
            duetime = _scheduler.now + _scheduler.to_timedelta(duetime)

        p = _scheduler.normalize(period)
        mad = MultipleAssignmentDisposable()
        dt = [duetime]
        count = [0]

        def action(scheduler, state):
            if p > 0:
                now = scheduler.now
                dt[0] = dt[0] + scheduler.to_timedelta(p)
                if dt[0] <= now:
                    dt[0] = now + scheduler.to_timedelta(p)

            observer.on_next(count[0])
            count[0] += 1
            mad.disposable = scheduler.schedule_absolute(dt[0], action)

        mad.disposable = _scheduler.schedule_absolute(dt[0], action)
        return mad

    return Observable(subscribe)
Example #29
0
def observable_timer_duetime_and_period(
        duetime,
        period,
        scheduler: Optional[typing.Scheduler] = None) -> Observable:
    def subscribe(observer, scheduler_=None):
        _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton()
        nonlocal duetime

        if not isinstance(duetime, datetime):
            duetime = _scheduler.now + _scheduler.to_timedelta(duetime)

        p = max(0.0, _scheduler.to_seconds(period))
        mad = MultipleAssignmentDisposable()
        dt = duetime
        count = 0

        def action(scheduler, state):
            nonlocal dt
            nonlocal count

            if p > 0.0:
                now = scheduler.now
                dt = dt + scheduler.to_timedelta(p)
                if dt <= now:
                    dt = now + scheduler.to_timedelta(p)

            observer.on_next(count)
            count += 1
            mad.disposable = scheduler.schedule_absolute(dt, action)

        mad.disposable = _scheduler.schedule_absolute(dt, action)
        return mad

    return Observable(subscribe)
Example #30
0
def _zip(*args: Observable) -> Observable:
    """Merges the specified observable sequences into one observable
    sequence by creating a tuple whenever all of the
    observable sequences have produced an element at a corresponding
    index.

    Example:
        >>> res = zip(obs1, obs2)

    Args:
        args: Observable sources to zip.

    Returns:
        An observable sequence containing the result of combining
        elements of the sources as tuple.
    """

    sources = list(args)

    def subscribe(
            observer: typing.Observer,
            scheduler: Optional[typing.Scheduler] = None
    ) -> CompositeDisposable:
        n = len(sources)
        queues: List[List] = [[] for _ in range(n)]
        lock = RLock()

        @synchronized(lock)
        def next(i):
            if all([len(q) for q in queues]):
                try:
                    queued_values = [x.pop(0) for x in queues]
                    res = tuple(queued_values)
                except Exception as ex:  # pylint: disable=broad-except
                    observer.on_error(ex)
                    return

                observer.on_next(res)

        subscriptions = [None] * n

        def func(i):
            source = sources[i]
            sad = SingleAssignmentDisposable()
            source = from_future(source) if is_future(source) else source

            def on_next(x):
                queues[i].append(x)
                next(i)

            sad.disposable = source.subscribe_(on_next, observer.on_error,
                                               observer.on_completed,
                                               scheduler)
            subscriptions[i] = sad

        for idx in range(n):
            func(idx)
        return CompositeDisposable(subscriptions)

    return Observable(subscribe)