def _if_then(condition: Callable[[], bool], then_source: Observable, else_source: Observable = None) -> Observable: """Determines whether an observable collection contains values. Example: 1 - res = rx.if_then(condition, obs1) 2 - res = rx.if_then(condition, obs1, obs2) Args: condition: The condition which determines if the then_source or else_source will be run. then_source: The observable sequence or Promise that will be run if the condition function returns true. else_source: [Optional] The observable sequence or Promise that will be run if the condition function returns False. If this is not provided, it defaults to rx.empty Returns: An observable sequence which is either the then_source or else_source. """ else_source = else_source or rx.empty() then_source = rx.from_future(then_source) if is_future(then_source) else then_source else_source = rx.from_future(else_source) if is_future(else_source) else else_source def factory(_: abc.Scheduler): return then_source if condition() else else_source return rx.defer(factory)
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_next(inner_source): nonlocal sources d = SingleAssignmentDisposable() with sources.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) if is_future( inner_source) else 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_next(inner_source: Observable): 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 inner_source = from_future(inner_source) if is_future(inner_source) else 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 = inner_source.subscribe_(on_next, on_error, on_completed, scheduler=scheduler)
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 from_future(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 _take_until(other: Observable) -> Callable[[Observable], Observable]: other = from_future(other) if is_future(other) else other def take_until(source: Observable) -> Observable: """Returns the values from the source observable sequence until the other observable sequence produces a value. Args: source: The source observable sequence. Returns: An observable sequence containing the elements of the source sequence up to the point the other sequence interrupted further propagation. """ 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 Observable(subscribe) return take_until
def projection(x, i): mapper_result = mapper(x) if mapper else mapper_indexed(x, i) if isinstance(mapper_result, collections.Iterable): result = Observable.from_(mapper_result) else: result = Observable.from_future(mapper_result) if is_future(mapper_result) else mapper_result return result
def _take_until(other: Observable) -> Callable[[Observable], Observable]: other = from_future(other) if is_future(other) else other def take_until(source: Observable) -> Observable: """Returns the values from the source observable sequence until the other observable sequence produces a value. Args: source: The source observable sequence. Returns: An observable sequence containing the elements of the source sequence up to the point the other sequence interrupted further propagation. """ 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 Observable(subscribe) return take_until
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 subscribe(observer, scheduler=None): try: result = observable_factory(scheduler) except Exception as ex: return Observable.throw(ex).subscribe(observer) result = Observable.from_future(result) if is_future(result) else result return result.subscribe(observer, scheduler)
def projection(x, i): mapper_result = mapper(x) if mapper else mapper_indexed(x, i) if isinstance(mapper_result, collections.abc.Iterable): result = from_(mapper_result) else: result = from_future(mapper_result) if is_future( mapper_result) else mapper_result return result
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)
def accumulate(): has_accumulator_value = accumulator_value[0] is not NotSet if has_accumulator_value: acc_source = accumulator(accumulator_value[0], value) return from_future(acc_source) if is_future( acc_source) else acc_source else: return of(value)
def subscribe(observer, scheduler=None): try: result = observable_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)
def factory(_) -> Observable: try: result = sources[mapper()] except KeyError: result = default_source result = from_future(result) if is_future(result) else result return result
def factory(_) -> Observable: try: result = sources[mapper()] except KeyError: result = default_source result = from_future(result) if is_future(result) else result return result
def projection(x: Any, idx: int) -> Any: mapper_result = mapper(x) if isinstance(mapper_result, collections.abc.Iterable): result = Observable.from_(mapper_result) else: result = Observable.from_future( mapper_result) if is_future( mapper_result) else mapper_result return result.map(lambda y: result_mapper(x, y))
def on_error(exception): try: result = handler(exception) except Exception as ex: observer.on_error(ex) return result = Observable.from_future(result) if is_future(result) else result d = SingleAssignmentDisposable() subscription.disposable = d d.disposable = result.subscribe(observer, scheduler)
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, lambda: completed(i), scheduler) subscriptions[i] = sad
def projection(x: Any, idx: int) -> Any: mapper_result = mapper(x) if mapper else mapper_indexed(x, idx) if isinstance(mapper_result, collections.Iterable): result = Observable.from_(mapper_result) else: result = Observable.from_future(mapper_result) if is_future(mapper_result) else mapper_result if result_mapper: return result.map(lambda y: result_mapper(x, y)) else: return result.map(mapper_indexed=lambda y, i: result_mapper_indexed(x, y, i))
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)
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)
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, lambda: done(i), scheduler) subscriptions[i] = sad
def on_next(inner_source): inner_subscription = SingleAssignmentDisposable() group.add(inner_subscription) inner_source = Observable.from_future(inner_source) if is_future(inner_source) else inner_source def on_completed(): group.remove(inner_subscription) if is_stopped[0] and len(group) == 1: observer.on_completed() disposable = inner_source.subscribe_(observer.on_next, observer.on_error, on_completed, scheduler) inner_subscription.disposable = disposable
def while_do(source: Observable) -> Observable: """Repeats source as long as condition holds emulating a while loop. Args: source: The observable sequence that will be run if the condition function returns true. Returns: An observable sequence which is repeated as long as the condition holds. """ source = rx.from_future(source) if is_future(source) else source return rx.concat_with_iterable(itertools.takewhile(condition, (source for x in infinite())))
def _skip_until(other: Observable) -> Callable[[Observable], Observable]: """Returns the values from the source observable sequence only after the other observable sequence produces a value. Args: other: The observable sequence that triggers propagation of elements of the source sequence. Returns: An observable sequence containing the elements of the source sequence starting from the point the other sequence triggered propagation. """ other = rx.from_future(other) if is_future(other) else other 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) return skip_until
def while_do(source: Observable) -> Observable: """Repeats source as long as condition holds emulating a while loop. Args: source: The observable sequence that will be run if the condition function returns true. Returns: An observable sequence which is repeated as long as the condition holds. """ source = rx.from_future(source) if is_future(source) else source return rx.concat( itertools.takewhile(condition, (source for x in infinite())))
def on_next(inner_source): inner_subscription = SingleAssignmentDisposable() group.add(inner_subscription) inner_source = from_future(inner_source) if is_future(inner_source) else inner_source @synchronized(source.lock) def on_completed(): group.remove(inner_subscription) if is_stopped[0] and len(group) == 1: observer.on_completed() on_next = synchronized(source.lock)(observer.on_next) on_error = synchronized(source.lock)(observer.on_error) subscription = inner_source.subscribe_(on_next, on_error, on_completed, scheduler) inner_subscription.disposable = subscription
def while_do(condition, source: ObservableBase) -> ObservableBase: """Repeats source as long as condition holds emulating a while loop. Keyword arguments: condition -- The condition which determines if the source will be repeated. source -- The observable sequence that will be run if the condition function returns true. Returns an observable sequence which is repeated as long as the condition holds. """ source = Observable.from_future(source) if is_future(source) else source from .concat import concat return concat(Iterable.while_do(condition, source))
def _skip_until(other: Observable) -> Callable[[Observable], Observable]: """Returns the values from the source observable sequence only after the other observable sequence produces a value. Args: other: The observable sequence that triggers propagation of elements of the source sequence. Returns: An observable sequence containing the elements of the source sequence starting from the point the other sequence triggered propagation. """ other = rx.from_future(other) if is_future(other) else other 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) return skip_until
def while_do(source: Union[Observable, Future]) -> Observable: """Repeats source as long as condition holds emulating a while loop. Args: source: The observable sequence that will be run if the condition function returns true. Returns: An observable sequence which is repeated as long as the condition holds. """ if is_future(source): obs = rx.from_future(cast(Future, source)) else: obs = cast(Observable, source) it = itertools.takewhile(condition, (obs for _ in infinite())) return rx.concat_with_iterable(it)
def on_next(inner_source): inner_subscription = SingleAssignmentDisposable() group.add(inner_subscription) inner_source = from_future(inner_source) if is_future( inner_source) else inner_source @synchronized(source.lock) def on_completed(): group.remove(inner_subscription) if is_stopped[0] and len(group) == 1: observer.on_completed() on_next = synchronized(source.lock)(observer.on_next) on_error = synchronized(source.lock)(observer.on_error) subscription = inner_source.subscribe_(on_next, on_error, on_completed, scheduler) inner_subscription.disposable = subscription
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)
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)
def on_next(inner_source): if not has_current[0]: has_current[0] = True inner_source = rx.from_future(inner_source) if is_future( inner_source) else inner_source inner_subscription = SingleAssignmentDisposable() g.add(inner_subscription) def on_completed_inner(): g.remove(inner_subscription) has_current[0] = False if is_stopped[0] and len(g) == 1: observer.on_completed() inner_subscription.disposable = inner_source.subscribe_( observer.on_next, observer.on_error, on_completed_inner, scheduler)
def on_next(inner_source): if not has_current[0]: has_current[0] = True inner_source = rx.from_future(inner_source) if is_future(inner_source) else inner_source inner_subscription = SingleAssignmentDisposable() g.add(inner_subscription) def on_completed_inner(): g.remove(inner_subscription) has_current[0] = False if is_stopped[0] and len(g) == 1: observer.on_completed() inner_subscription.disposable = inner_source.subscribe_( observer.on_next, observer.on_error, on_completed_inner, scheduler )
def _amb(left_source, right_source): """Propagates the observable sequence that reacts first. right_source Second observable sequence. returns an observable sequence that surfaces either of the given sequences, whichever reacted first. """ right_source = Observable.from_future(right_source) if is_future(right_source) else right_source def subscribe(observer, scheduler=None): choice = [None] left_choice = 'L' right_choice = 'R', left_subscription = SingleAssignmentDisposable() right_subscription = SingleAssignmentDisposable() def choice_left(): if not choice[0]: choice[0] = left_choice right_subscription.dispose() def choice_right(): if not choice[0]: choice[0] = right_choice left_subscription.dispose() def on_next_left(value): with left_source.lock: choice_left() if choice[0] == left_choice: observer.on_next(value) def on_error_left(err): with left_source.lock: choice_left() if choice[0] == left_choice: observer.on_error(err) def on_completed_left(): with left_source.lock: choice_left() if choice[0] == left_choice: observer.on_completed() lelf_d = left_source.subscribe_(on_next_left, on_error_left, on_completed_left, scheduler) left_subscription.disposable = lelf_d def send_right(value): with left_source.lock: choice_right() if choice[0] == right_choice: observer.on_next(value) def on_error_right(err): with left_source.lock: choice_right() if choice[0] == right_choice: observer.on_error(err) def on_completed_right(): with left_source.lock: choice_right() if choice[0] == right_choice: observer.on_completed() right_d = right_source.subscribe_(send_right, on_error_right, on_completed_right, scheduler) right_subscription.disposable = right_d return CompositeDisposable(left_subscription, right_subscription) return AnonymousObservable(subscribe)
def _timeout(duetime: typing.AbsoluteTime, other: Optional[Observable] = None, scheduler: Optional[typing.Scheduler] = None ) -> Callable[[Observable], Observable]: other = other or throw(Exception("Timeout")) other = from_future(other) if is_future(other) else other def timeout(source: Observable) -> Observable: """Returns the source observable sequence or the other observable sequence if duetime elapses. Examples: >>> res = timeout(source) Args: source: Source observable to timeout Returns: An obserable sequence switching to the other sequence in case of a timeout. """ 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) return Observable(subscribe) return timeout
def _amb(left_source, right_source): right_source = Observable.from_future(right_source) if is_future( right_source) else right_source def subscribe(observer, scheduler=None): choice = [None] left_choice = 'L' right_choice = 'R' left_subscription = SingleAssignmentDisposable() right_subscription = SingleAssignmentDisposable() def choice_left(): if not choice[0]: choice[0] = left_choice right_subscription.dispose() def choice_right(): if not choice[0]: choice[0] = right_choice left_subscription.dispose() def on_next_left(value): with left_source.lock: choice_left() if choice[0] == left_choice: observer.on_next(value) def on_error_left(err): with left_source.lock: choice_left() if choice[0] == left_choice: observer.on_error(err) def on_completed_left(): with left_source.lock: choice_left() if choice[0] == left_choice: observer.on_completed() lelf_d = left_source.subscribe_(on_next_left, on_error_left, on_completed_left, scheduler) left_subscription.disposable = lelf_d def send_right(value): with left_source.lock: choice_right() if choice[0] == right_choice: observer.on_next(value) def on_error_right(err): with left_source.lock: choice_right() if choice[0] == right_choice: observer.on_error(err) def on_completed_right(): with left_source.lock: choice_right() if choice[0] == right_choice: observer.on_completed() right_d = right_source.subscribe_(send_right, on_error_right, on_completed_right, scheduler) right_subscription.disposable = right_d return CompositeDisposable(left_subscription, right_subscription) return AnonymousObservable(subscribe)
def _amb(right_source: Observable): if is_future(right_source): obs = from_future(cast(Future, right_source)) else: obs = cast(Observable, right_source) def amb(left_source: Observable): def subscribe(observer: typing.Observer, scheduler: typing.Scheduler = None) -> typing.Disposable: choice = [None] left_choice = 'L' right_choice = 'R' left_subscription = SingleAssignmentDisposable() right_subscription = SingleAssignmentDisposable() def choice_left(): if not choice[0]: choice[0] = left_choice right_subscription.dispose() def choice_right(): if not choice[0]: choice[0] = right_choice left_subscription.dispose() def on_next_left(value): with left_source.lock: choice_left() if choice[0] == left_choice: observer.on_next(value) def on_error_left(err): with left_source.lock: choice_left() if choice[0] == left_choice: observer.on_error(err) def on_completed_left(): with left_source.lock: choice_left() if choice[0] == left_choice: observer.on_completed() left_d = left_source.subscribe_(on_next_left, on_error_left, on_completed_left, scheduler) left_subscription.disposable = left_d def send_right(value: Any) -> None: with left_source.lock: choice_right() if choice[0] == right_choice: observer.on_next(value) def on_error_right(err: Exception) -> None: with left_source.lock: choice_right() if choice[0] == right_choice: observer.on_error(err) def on_completed_right() -> None: with left_source.lock: choice_right() if choice[0] == right_choice: observer.on_completed() right_d = obs.subscribe_(send_right, on_error_right, on_completed_right, scheduler) right_subscription.disposable = right_d return CompositeDisposable(left_subscription, right_subscription) return Observable(subscribe) return amb
def timeout(source: ObservableBase, duetime: Union[int, datetime], other: ObservableBase = None) -> ObservableBase: """Returns the source observable sequence or the other observable sequence if duetime elapses. 1 - res = source.timeout(5000); # 5 seconds # As a date and timeout observable 2 - res = source.timeout(datetime(), Observable.return_value(42)) # 5 seconds and timeout observable 3 - res = source.timeout(5000, Observable.return_value(42)) # As a date and timeout observable Keyword arguments: duetime -- Absolute (specified as a datetime object) or relative time (specified as an integer denoting milliseconds) when a timeout occurs. other -- Sequence to return in case of a timeout. If not specified, a timeout error throwing sequence will be used. Returns the source sequence switching to the other sequence in case of a timeout. """ other = other or Observable.throw(Exception("Timeout")) other = Observable.from_future(other) if is_future(other) else other def subscribe(observer, scheduler=None): scheduler = 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) 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) return AnonymousObservable(subscribe)
def _timeout(duetime: typing.AbsoluteTime, other: Optional[Observable] = None, scheduler: Optional[typing.Scheduler] = None ) -> Callable[[Observable], Observable]: other = other or throw(Exception("Timeout")) other = from_future(other) if is_future(other) else other def timeout(source: Observable) -> Observable: """Returns the source observable sequence or the other observable sequence if duetime elapses. Examples: >>> res = timeout(source) Args: source: Source observable to timeout Returns: An obserable sequence switching to the other sequence in case of a timeout. """ 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) return Observable(subscribe) return timeout