def find_value(source, predicate, yield_index): def subscribe(observer): 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) 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 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 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(scheduler, i): if i < count: observer.on_next(start + i) scheduler(i + 1) else: observer.on_completed() return scheduler.schedule_recursive(action, 0) return AnonymousObservable(subscribe)
def sample_observable(self, sampler): source = self def subscribe(observer): at_end = None has_value = None value = None def sample_subscribe(x): nonlocal has_value if has_value: has_value = False observer.on_next(value) if at_end: observer.on_completed() def on_next(new_value): nonlocal value, has_value has_value = True value = new_value def on_completed(): nonlocal at_end at_end = 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 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 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. 1 - res = Rx.Observable.using(function () { return new AsyncSubject(); }, function (s) { return 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): 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 zip_array(self, second, result_selector): first = self def subscribe(observer): length = len(second) index = 0 def on_next(left): nonlocal index if index < length: right = second[index] index += 1 try: result = result_selector(left, right) except Exception as e: observer.on_error(e) return observer.on_next(result) else: observer.on_completed() return first.subscribe(on_next, observer.on_error, observer.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 concat(sources): def subscribe(observer): e = iter(sources) is_disposed = False subscription = SerialDisposable() def action(action1, state=None): current = None if is_disposed: return try: current = next(e) except StopIteration: observer.on_completed() except Exception as ex: observer.on_error(ex) else: d = SingleAssignmentDisposable() subscription.disposable = d d.disposable = current.subscribe(observer.on_next, observer.on_error, lambda: action1()) cancelable = immediate_scheduler.schedule_recursive(action) def dispose(): nonlocal is_disposed is_disposed = True return CompositeDisposable(subscription, cancelable, Disposable(dispose)) return AnonymousObservable(subscribe)
def throw_exception(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(new Error('Error')); 2 - res = rx.Observable.throw_exception(new Error('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( exception) if type(exception) is Exception else exception def subscribe(observer): def action(scheduler, state): observer.on_error(exception) return scheduler.schedule(action) return AnonymousObservable(subscribe)
def materialize(self): """Materializes the implicit notifications of an observable sequence as explicit notification values. Returns an observable sequence containing the materialized notification values from the source sequence. """ source = self def subscribe(observer): 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) return AnonymousObservable(subscribe)
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 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 defer(cls, observable_factory): """Returns an observable sequence that invokes the specified factory function whenever a new observer subscribes. Example: 1 - res = rx.Observable.defer(lambda: rx.Observable.from_([1,2,3])) Keyword arguments: :param types.FunctionType 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. :rtype: Observable """ def subscribe(observer): try: result = observable_factory() except Exception as ex: return Observable.throw_exception(ex).subscribe(observer) result = Observable.from_future(result) return result.subscribe(observer) 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 from_array(cls, array, scheduler): """Converts an array to an observable sequence, using an optional scheduler to enumerate the array. 1 - res = rx.Observable.from_array([1,2,3]) 2 - res = rx.Observable.from_array([1,2,3], rx.Scheduler.timeout) Keyword arguments: scheduler -- [Optional] Scheduler to run the enumeration of the input sequence on. Returns the observable sequence whose elements are pulled from the given enumerable sequence. """ scheduler = scheduler or current_thread_scheduler def subscribe(observer): count = 0 def action(action1, state=None): nonlocal count if count < len(array): observer.on_next(array[count]) count += 1 action1(action) else: observer.on_completed() return scheduler.schedule_recursive(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 catch_handler(source, handler): def subscribe(observer): d1 = SingleAssignmentDisposable() subscription = SerialDisposable() subscription.disposable = d1 def on_error(exception): try: result = handler(exception) except Exception as ex: observer.on_error(ex) return result = Observable.from_future(result) d = SingleAssignmentDisposable() subscription.disposable = d d.disposable = result.subscribe(observer) d1.disposable = source.subscribe( observer.on_next, on_error, observer.on_completed ) return subscription return AnonymousObservable(subscribe)
def from_iterable(cls, iterable, scheduler=None): """Converts an array to an observable sequence, using an optional scheduler to enumerate the array. 1 - res = rx.Observable.from_iterable([1,2,3]) 2 - res = rx.Observable.from_iterable([1,2,3], rx.Scheduler.timeout) Keyword arguments: :param Observable cls: Observable class :param Scheduler scheduler: [Optional] Scheduler to run the enumeration of the input sequence on. :returns: The observable sequence whose elements are pulled from the given enumerable sequence. :rtype: Observable """ scheduler = scheduler or current_thread_scheduler def subscribe(observer): iterator = iter(iterable) def action(action1, state=None): try: item = next(iterator) except StopIteration: observer.on_completed() else: observer.on_next(item) action1(action) return scheduler.schedule_recursive(action) return AnonymousObservable(subscribe)
def catch_exception(cls, *args): """Continues an observable sequence that is terminated by an exception with the next observable sequence. 1 - res = Observable.catch_exception(xs, ys, zs) 2 - res = Observable.catch_exception([xs, ys, zs]) Returns an observable sequence containing elements from consecutive source sequences until a source sequence terminates successfully. """ if isinstance(args[0], list) or isinstance(args[0], Enumerable): sources = args[0] else: sources = list(args) #return Enumerable.catch_exception(Enumerable.for_each(sources)) def subscribe(observer): e = iter(sources) is_disposed = [False] last_exception = [None] subscription = SerialDisposable() def action(action1, state=None): current = None def on_error(exn): last_exception[0] = exn action1() if is_disposed[0]: return try: current = six.next(e) except StopIteration: if last_exception[0]: observer.on_error(last_exception[0]) else: observer.on_completed() except Exception as ex: observer.on_error(ex) else: d = SingleAssignmentDisposable() subscription.disposable = d d.disposable = current.subscribe(observer.on_next, on_error, observer.on_completed) cancelable = immediate_scheduler.schedule_recursive(action) def dispose(): is_disposed[0] = True return CompositeDisposable(subscription, cancelable, Disposable(dispose)) return AnonymousObservable(subscribe)
def zip_array(cls, *args): """Merges the specified observable sequences into one observable sequence by emitting a list with the elements of the observable sequences at corresponding indexes. Keyword arguments: args -- Observable sources. Returns an observable {Observable} sequence containing lists of elements at corresponding indexes. """ sources = list(args) def subscribe(observer): n = len(sources) queues = [[] for _ in range(n)] is_done = [False] * n def next(i): if all([len(q) for q in queues]): res = [x.pop(0) for x in queues] observer.on_next(res) elif all([x for j, x in enumerate(is_done) if j != i]): observer.on_completed() return def done(i): is_done[i] = True if all(is_done): observer.on_completed() return subscriptions = [None] * n def func(i): subscriptions[i] = SingleAssignmentDisposable() def on_next(x): queues[i].append(x) next(i) subscriptions[i].disposable = sources[i].subscribe( on_next, observer.on_error, lambda: done(i)) for idx in range(n): func(idx) composite_disposable = CompositeDisposable(subscriptions) def action(): for _ in queues: queues[n] = [] composite_disposable.add(Disposable.create(action)) return composite_disposable return AnonymousObservable(subscribe)
def generate(cls, initial_state, condition, iterate, result_selector, scheduler=None): """Generates an observable sequence by running a state-driven loop producing the sequence's elements, using the specified scheduler to send out observer messages. 1 - res = rx.Observable.generate(0, function (x) { return x < 10; }, function (x) { return x + 1; }, function (x) { return x; }); 2 - res = rx.Observable.generate(0, function (x) { return x < 10; }, function (x) { return x + 1; }, function (x) { return x; }, Rx.Scheduler.timeout); Keyword arguments: initial_state -- Initial state. condition -- Condition to terminate generation (upon returning false). iterate -- Iteration step function. result_selector -- Selector function for results produced in the sequence. scheduler -- [Optional] Scheduler on which to run the generator loop. If not provided, defaults to CurrentThreadScheduler. Returns the generated sequence. """ scheduler = scheduler or current_thread_scheduler def subscribe(observer): first = True state = initial_state def action(action1, state1=None): nonlocal first, state has_result = False result = None try: if first: first = False else: state = iterate(state) has_result = condition(state) if has_result: result = result_selector(state) except Exception as exception: observer.on_error(exception) return if has_result: observer.on_next(result) action1() else: observer.on_completed() return scheduler.schedule_recursive(action) return AnonymousObservable(subscribe)
def switch_latest(self): """Transforms an observable sequence of observable sequences into an observable sequence producing values only from the most recent observable sequence. Returns the observable sequence that at any point in time produces the elements of the most recent inner observable sequence that has been received. """ sources = self def subscribe(observer): has_latest = False inner_subscription = SerialDisposable() is_stopped = False latest = 0 def on_next(inner_source): nonlocal latest, has_latest d = SingleAssignmentDisposable() latest += 1 _id = latest has_latest = True inner_subscription.disposable = d def on_next(x): if latest == _id: observer.on_next(x) def on_error(e): if latest == _id: observer.on_error(e) def on_completed(): nonlocal has_latest if latest == _id: has_latest = False if is_stopped: observer.on_completed() d.disposable = inner_source.subscribe(on_next, on_error, on_completed) def on_completed(): nonlocal is_stopped is_stopped = True if not has_latest: observer.on_completed() subscription = sources.subscribe(on_next, observer.on_error, on_completed) return CompositeDisposable(subscription, inner_subscription) return AnonymousObservable(subscribe)
def observable_timer_date(duetime, scheduler): def subscribe(observer): def action(scheduler, state): observer.on_next(0) observer.on_completed() return scheduler.schedule_absolute(duetime, action) return AnonymousObservable(subscribe)
def switch_latest(self): """Transforms an observable sequence of observable sequences into an observable sequence producing values only from the most recent observable sequence. :returns: The observable sequence that at any point in time produces the elements of the most recent inner observable sequence that has been received. :rtype: Observable """ sources = self def subscribe(observer): has_latest = [False] inner_subscription = SerialDisposable() is_stopped = [False] latest = [0] def on_next(inner_source): d = SingleAssignmentDisposable() with self.lock: latest[0] += 1 _id = latest[0] has_latest[0] = True inner_subscription.disposable = d # Check if Future or Observable inner_source = Observable.from_future(inner_source) def on_next(x): if latest[0] == _id: observer.on_next(x) def on_error(e): if latest[0] == _id: observer.on_error(e) def on_completed(): if latest[0] == _id: has_latest[0] = False if is_stopped[0]: observer.on_completed() d.disposable = inner_source.subscribe(on_next, on_error, on_completed) def on_completed(): is_stopped[0] = True if not has_latest[0]: observer.on_completed() subscription = sources.subscribe(on_next, observer.on_error, on_completed) return CompositeDisposable(subscription, inner_subscription) return AnonymousObservable(subscribe)
def return_value(cls, value, scheduler=None): scheduler = scheduler or immediate_scheduler def subscribe(observer): def action(scheduler, state=None): observer.on_next(value) observer.on_completed() return scheduler.schedule(action) return AnonymousObservable(subscribe)
def never(cls): """Returns a non-terminating observable sequence, which can be used to denote an infinite duration (e.g. when using reactive joins). Returns an observable sequence whose observers will never get called. """ def subscribe(observer): return Disposable.empty() return AnonymousObservable(subscribe)
def observable_timer_timespan(duetime, scheduler): d = Scheduler.normalize(duetime) def subscribe(observer): def action(scheduler, state): observer.on_next(0) observer.on_completed() return scheduler.schedule_relative(d, action) return AnonymousObservable(subscribe)
def throttle(self, duetime, scheduler): scheduler = scheduler or timeout_scheduler source = self def subscribe(observer): cancelable = SerialDisposable() has_value = False value = None _id = 0 def on_next(x): nonlocal _id, value, has_value, cancelable has_value = True value = x _id += 1 current_id = _id d = SingleAssignmentDisposable() cancelable.disposable = d def action(scheduler, state=None): nonlocal has_value if has_value and _id == current_id: observer.on_next(value) has_value = False d.disposable = scheduler.schedule_relative(duetime, action) def on_error(exception): nonlocal _id, has_value, cancelable cancelable.dispose() observer.on_error(exception) has_value = False _id += 1 def on_completed(): nonlocal cancelable, has_value, _id cancelable.dispose() if has_value: observer.on_next(value) observer.on_completed() has_value = False _id += 1 subscription = source.subscribe(on_next, on_error, on_completed) return CompositeDisposable(subscription, cancelable) return AnonymousObservable(subscribe)