def return_value(cls, value, scheduler=None): """Returns an observable sequence that contains a single element, using the specified scheduler to send out observer messages. There is an alias called 'just'. example res = rx.Observable.return(42) res = rx.Observable.return(42, rx.Scheduler.timeout) Keyword arguments: value -- Single element in the resulting observable sequence. scheduler -- [Optional] Scheduler to send the single element on. If not specified, defaults to Scheduler.immediate. Returns an observable sequence containing the single specified element. """ scheduler = scheduler or current_thread_scheduler def subscribe(observer): def action(scheduler, state=None): observer.on_next(value) observer.on_completed() return scheduler.schedule(action) return AnonymousObservable(subscribe)
def using(resource_factory, observable_factory) -> ObservableBase: """Constructs an observable sequence that depends on a resource object, whose lifetime is tied to the resulting observable sequence's lifetime. 1 - res = rx.Observable.using(lambda: AsyncSubject(), lambda: s: s) Keyword arguments: 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): disposable = Disposable.empty() try: resource = resource_factory() if resource: disposable = resource source = observable_factory(resource) except Exception as exception: d = Observable.throw(exception).subscribe(observer, scheduler) return CompositeDisposable(d, disposable) return CompositeDisposable(source.subscribe(observer, scheduler), disposable) return AnonymousObservable(subscribe)
def sample_observable(source, sampler): def subscribe(observer): at_end = [None] has_value = [None] value = [None] def sample_subscribe(x=None): if has_value[0]: has_value[0] = False observer.on_next(value[0]) if at_end[0]: observer.on_completed() def on_next(new_value): has_value[0] = True value[0] = new_value def on_completed(): at_end[0] = True return CompositeDisposable( source.subscribe(on_next, observer.on_error, on_completed), sampler.subscribe(sample_subscribe, observer.on_error, sample_subscribe)) return AnonymousObservable(subscribe)
def throw(cls, exception, scheduler=None): """Returns an observable sequence that terminates with an exception, using the specified scheduler to send out the single OnError message. 1 - res = rx.Observable.throw_exception(Exception('Error')) 2 - res = rx.Observable.throw_exception(Exception('Error'), rx.Scheduler.timeout) Keyword arguments: exception -- An object used for the sequence's termination. scheduler -- Scheduler to send the exceptional termination call on. If not specified, defaults to ImmediateScheduler. Returns the observable sequence that terminates exceptionally with the specified exception object. """ scheduler = scheduler or immediate_scheduler exception = exception if isinstance(exception, Exception) else Exception(exception) def subscribe(observer): def action(scheduler, state): observer.on_error(exception) return scheduler.schedule(action) return AnonymousObservable(subscribe)
def take_until_with_time(self, end_time, scheduler=None): """Takes elements for the specified duration until the specified end time, using the specified scheduler to run timers. Examples: 1 - res = source.take_until_with_time(dt, [optional scheduler]) 2 - res = source.take_until_with_time(5000, [optional scheduler]) Keyword Arguments: end_time -- {Number | Date} Time to stop taking elements from the source sequence. If this value is less than or equal to Date(), the result stream will complete immediately. scheduler -- {Scheduler} Scheduler to run the timer on. Returns an observable {Observable} sequence with the elements taken until the specified end time. """ scheduler = scheduler or timeout_scheduler source = self if isinstance(end_time, datetime): scheduler_method = scheduler.schedule_absolute else: scheduler_method = scheduler.schedule_relative def subscribe(observer): def action(scheduler, state): observer.on_completed() task = scheduler_method(end_time, action) return CompositeDisposable(task, source.subscribe(observer)) return AnonymousObservable(subscribe)
def some(source, predicate=None) -> ObservableBase: """Determines whether some element of an observable sequence satisfies a condition if present, else if some items are in the sequence. Example: result = source.some() result = source.some(lambda x: x > 3) Keyword arguments: 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) return source.filter(predicate).some() if predicate else AnonymousObservable(subscribe)
def subscribe_on(self, scheduler) -> ObservableBase: """Subscribe on the specified scheduler. Wrap the source sequence in order to run its subscription and unsubscription logic on the specified scheduler. This operation is not commonly used; see the remarks section for more information on the distinction between subscribe_on and observe_on. Keyword arguments: scheduler -- Scheduler to perform subscription and unsubscription actions on. Returns the source sequence whose subscriptions and unsubscriptions happen on the specified scheduler. This only performs the side-effects of subscription and unsubscription on the specified scheduler. In order to invoke observer callbacks on a scheduler, use observe_on. """ source = self 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 return AnonymousObservable(subscribe)
def take_until(self, other): """Returns the values from the source observable sequence until the other observable sequence produces a value. Keyword arguments: other -- Observable sequence that terminates propagation of elements of the source sequence. Returns an observable sequence containing the elements of the source sequence up to the point the other sequence interrupted further propagation. """ source = self other = Observable.from_future(other) def subscribe(observer): def on_completed(x): observer.on_completed() return CompositeDisposable( source.subscribe(observer), other.subscribe(on_completed, observer.on_error, noop)) return AnonymousObservable(subscribe)
def range(cls, start, count, scheduler=None): """Generates an observable sequence of integral numbers within a specified range, using the specified scheduler to send out observer messages. 1 - res = Rx.Observable.range(0, 10) 2 - res = Rx.Observable.range(0, 10, rx.Scheduler.timeout) Keyword arguments: start -- The value of the first integer in the sequence. count -- The number of sequential integers to generate. scheduler -- [Optional] Scheduler to run the generator loop on. If not specified, defaults to Scheduler.current_thread. Returns an observable sequence that contains a range of sequential integral numbers. """ scheduler = scheduler or current_thread_scheduler def subscribe(observer): def action(recurse, i): if i < count: observer.on_next(start + i) recurse(i + 1) else: observer.on_completed() return scheduler.schedule_recursive(action, 0) return AnonymousObservable(subscribe)
def take_until(source: ObservableBase, other: ObservableBase) -> ObservableBase: """Returns the values from the source observable sequence until the other observable sequence produces a value. Keyword arguments: other -- Observable sequence that terminates propagation of elements of the source sequence. Returns an observable sequence containing the elements of the source sequence up to the point the other sequence interrupted further propagation. """ other = Observable.from_future(other) if is_future(other) else other def subscribe(observer, scheduler=None): def on_completed(_): observer.on_completed() return CompositeDisposable( source.subscribe(observer), other.subscribe_(on_completed, observer.on_error, noop, scheduler)) return AnonymousObservable(subscribe)
def using(cls, resource_factory, observable_factory): """Constructs an observable sequence that depends on a resource object, whose lifetime is tied to the resulting observable sequence's lifetime. Example:: res = rx.Observable.using(lambda: AsyncSubject(), lambda: s: s) Arguments: resource_factory (types.FunctionType): Factory function to obtain a resource object. observable_factory (types.FunctionType): 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): disposable = Disposable.empty() try: resource = resource_factory() if resource: disposable = resource source = observable_factory(resource) except Exception as exception: d = Observable.throw_exception(exception).subscribe(observer) return CompositeDisposable(d, disposable) return CompositeDisposable(source.subscribe(observer), disposable) return AnonymousObservable(subscribe)
def single_or_default_async(source: ObservableBase, has_default: bool = False, default_value: Any = None): def subscribe(observer, scheduler=None): value = [default_value] seen_value = [False] def on_next(x): if seen_value[0]: observer.on_error( Exception('Sequence contains more than one element')) else: value[0] = x seen_value[0] = True def on_completed(): if not seen_value[0] and not has_default: observer.on_error(SequenceContainsNoElementsError()) else: observer.on_next(value[0]) observer.on_completed() return source.subscribe_(on_next, observer.on_error, on_completed, scheduler) return AnonymousObservable(subscribe)
def take_with_time(source: ObservableBase, duration: Union[timedelta, int]) -> ObservableBase: """Takes elements for the specified duration from the start of the observable source sequence. Example: res = source.take_with_time(5000) Description: 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. Keyword arguments: duration -- {Duration for taking elements from the start of the sequence. 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 timeout_scheduler def action(scheduler, state): observer.on_completed() disposable = scheduler.schedule_relative(duration, action) return CompositeDisposable(disposable, source.subscribe(observer, scheduler)) return AnonymousObservable(subscribe)
def function(*args): arguments = list(args) def subscribe(observer): def handler(*args): results = list(args) if selector: try: results = selector(args) except Exception as err: 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 AnonymousObservable(subscribe)
def pairwise(self) -> ObservableBase: """Returns a new observable that triggers on the second and subsequent triggerings of the input observable. The Nth triggering of the input observable passes the arguments from the N-1th and Nth triggering as a pair. The argument passed to the N-1th triggering is held in hidden internal state until the Nth triggering occurs. Returns an observable {Observable} that triggers on successive pairs of observations from the input observable as an array. """ source = self def subscribe(observer, scheduler=None): has_previous = [False] previous = [None] def on_next(x): pair = None with self.lock: if has_previous[0]: pair = (previous[0], x) else: has_previous[0] = True previous[0] = x if pair: observer.on_next(pair) return source.subscribe_(on_next, observer.on_error, observer.on_completed) return AnonymousObservable(subscribe)
def do_on_terminate(source, on_terminate): """Invokes an action on 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 when on_complete or throw is called """ def subscribe(observer, scheduler=None): def on_completed(): try: on_terminate() except Exception as err: observer.on_error(err) else: observer.on_completed() def on_error(exception): try: on_terminate() except Exception as err: observer.on_error(err) else: observer.on_error(exception) return source.subscribe_(observer.on_next, on_error, on_completed, scheduler) return AnonymousObservable(subscribe)
def transduce(self, transducer): """Execute a transducer to transform the observable sequence. Keyword arguments: :param Transducer transducer: A transducer to execute. :returns: An Observable sequence containing the results from the transducer. :rtype: Observable """ source = self def subscribe(observer): xform = transducer(Observing(observer)) def on_next(v): try: xform.step(observer, v) except Exception as e: observer.on_error(e) def on_completed(): xform.complete(observer) return source.subscribe(on_next, observer.on_error, on_completed) return AnonymousObservable(subscribe)
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: 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: observer.on_error(err) composite_disposable = CompositeDisposable() composite_disposable.add(OnDispose(was_invoked)) disposable = source.subscribe_(observer.on_next, on_error, on_completed, scheduler) composite_disposable.add(disposable) return composite_disposable return AnonymousObservable(subscribe)
def observable_window_with_boundaries(self, window_boundaries): source = self def subscribe(observer, scheduler=None): window = [Subject()] d = CompositeDisposable() r = RefCountDisposable(d) observer.on_next(add_ref(window[0], r)) def on_next_window(x): window[0].on_next(x) def on_error(err): window[0].on_error(err) observer.on_error(err) def on_completed(): window[0].on_completed() observer.on_completed() d.add(source.subscribe_(on_next_window, on_error, on_completed, scheduler)) def on_next_observer(w): window[0].on_completed() window[0] = Subject() observer.on_next(add_ref(window[0], r)) d.add(window_boundaries.subscribe_(on_next_observer, on_error, on_completed, scheduler)) return r return AnonymousObservable(subscribe)
def distinct_until_changed(self, key_mapper=None, comparer=None): source = self key_mapper = key_mapper or identity comparer = comparer or default_comparer def subscribe(observer, scheduler=None): has_current_key = [False] current_key = [None] def on_next(value): comparer_equals = False try: key = key_mapper(value) except Exception as exception: observer.on_error(exception) return if has_current_key[0]: try: comparer_equals = comparer(current_key[0], key) except Exception as exception: observer.on_error(exception) return if not has_current_key[0] or not comparer_equals: has_current_key[0] = True current_key[0] = key observer.on_next(value) return source.subscribe(on_next, observer.on_error, observer.on_completed) return AnonymousObservable(subscribe)
def skip_last(count: int, source: ObservableBase) -> ObservableBase: """Bypasses a specified number of elements at the end of an observable sequence. Description: 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. Keyword arguments count -- Number of elements to bypass at the end of the source sequence. Returns an observable {Observable} sequence containing the source sequence elements except for the bypassed ones at the end. """ observable = source def subscribe(observer, scheduler=None): q = [] def on_next(value): front = None with observable.lock: q.append(value) if len(q) > count: front = q.pop(0) if front is not None: observer.on_next(front) return observable.subscribe_(on_next, observer.on_error, observer.on_completed, scheduler) return AnonymousObservable(subscribe)
def default_if_empty(source, default_value=None) -> ObservableBase: """Returns the elements of the specified sequence or the specified value in a singleton sequence if the sequence is empty. res = obs = xs.defaultIfEmpty() obs = xs.defaultIfEmpty(False Keyword arguments: default_value -- The value to return if the sequence is empty. If not provided, this defaults to None. Returns an observable {Observable} sequence that contains the specified default value if the source is empty otherwise, the elements of the source itsource. """ def subscribe(observer, scheduler=None): found = [False] def on_next(x): 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 AnonymousObservable(subscribe)
def add_ref(xs, r): from rx.core import AnonymousObservable def subscribe(observer, scheduler=None): return CompositeDisposable(r.disposable, xs.subscribe(observer)) return AnonymousObservable(subscribe)
def debounce(self, duetime, scheduler=None): """Ignores values from an observable sequence which are followed by another value before duetime. Example: 1 - res = source.debounce(5000) # 5 seconds 2 - res = source.debounce(5000, scheduler) Keyword arguments: duetime -- {Number} Duration of the throttle period for each value (specified as an integer denoting milliseconds). scheduler -- {Scheduler} [Optional] Scheduler to run the throttle timers on. If not specified, the timeout scheduler is used. Returns {Observable} The debounced sequence. """ scheduler = scheduler or timeout_scheduler source = self def subscribe(observer): cancelable = SerialDisposable() has_value = [False] value = [None] _id = [0] def on_next(x): has_value[0] = True value[0] = x _id[0] += 1 current_id = _id[0] d = SingleAssignmentDisposable() cancelable.disposable = d def action(scheduler, state=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): cancelable.dispose() observer.on_error(exception) has_value[0] = False _id[0] += 1 def on_completed(): 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) return CompositeDisposable(subscription, cancelable) return AnonymousObservable(subscribe)
def finally_action(source: ObservableBase, action: Callable) -> ObservableBase: """Invokes a specified action after the source observable sequence terminates gracefully or exceptionally. Example: res = observable.finally(lambda: print('sequence ended') Keyword arguments: source -- Observable sequence. action -- Action to invoke after the source observable sequence terminates. Returns observable sequence with the action-invoking termination behavior applied. """ def subscribe(observer, scheduler=None): try: subscription = source.subscribe(observer, scheduler) except Exception: action() raise def dispose(): try: subscription.dispose() finally: action() return Disposable.create(dispose) return AnonymousObservable(subscribe)
def do_after_terminate(self, 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 on_error is called """ def subscribe(observer): def on_completed(): observer.on_completed() try: after_terminate() except Exception as err: observer.on_error(err) def on_error(exception): observer.on_error(exception) try: after_terminate() except Exception as err: observer.on_error(err) return self.subscribe(observer.on_next, on_error, on_completed) return AnonymousObservable(subscribe)
def from_future(cls, future): """Converts a Future to an Observable sequence Keyword Arguments: future -- {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 {Observable} An Observable sequence which wraps the existing future success and failure. """ def subscribe(observer): 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(): if future and future.cancel: future.cancel() return dispose return AnonymousObservable(subscribe) if is_future(future) else future
def find_value(source: Observable, predicate: Predicate, yield_index): def subscribe(observer, scheduler=None): i = [0] def on_next(x): should_run = False try: should_run = predicate(x, i, source) except Exception as ex: observer.on_error(ex) return if should_run: observer.on_next(i[0] if yield_index else x) observer.on_completed() else: i[0] += 1 def on_completed(): observer.on_next(-1 if yield_index else None) observer.on_completed() return source.subscribe_(on_next, observer.on_error, on_completed, scheduler) return AnonymousObservable(subscribe)
def range(cls, start, count, scheduler=None): """Generates an observable sequence of integral numbers within a specified range, using the specified scheduler to send out observer messages. 1 - res = Rx.Observable.range(0, 10) 2 - res = Rx.Observable.range(0, 10, rx.Scheduler.timeout) Keyword arguments: start -- The value of the first integer in the sequence. count -- The number of sequential integers to generate. scheduler -- [Optional] Scheduler to run the generator loop on. If not specified, defaults to Scheduler.current_thread. Returns an observable sequence that contains a range of sequential integral numbers. """ scheduler = scheduler or current_thread_scheduler end = start + count def subscribe(observer): sd = MultipleAssignmentDisposable() def action(scheduler, n): if n < end: observer.on_next(n) sd.disposable = scheduler.schedule(action, n + 1) else: observer.on_completed() sd.disposable = scheduler.schedule(action, start) return sd return AnonymousObservable(subscribe)
def _element_at_or_default(source, index, has_default=False, default_value=None): if index < 0: raise ArgumentOutOfRangeException() 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 AnonymousObservable(subscribe)