85 lines
2.5 KiB
Python
85 lines
2.5 KiB
Python
from typing import Any, Iterable, Optional, TypeVar
|
|
|
|
from reactivex import Observable, abc
|
|
from reactivex.disposable import (
|
|
CompositeDisposable,
|
|
Disposable,
|
|
SerialDisposable,
|
|
SingleAssignmentDisposable,
|
|
)
|
|
from reactivex.scheduler import CurrentThreadScheduler
|
|
|
|
_T = TypeVar("_T")
|
|
|
|
|
|
def catch_with_iterable_(sources: Iterable[Observable[_T]]) -> Observable[_T]:
|
|
|
|
"""Continues an observable sequence that is terminated by an
|
|
exception with the next observable sequence.
|
|
|
|
Examples:
|
|
>>> res = catch([xs, ys, zs])
|
|
>>> res = reactivex.catch(src for src in [xs, ys, zs])
|
|
|
|
Args:
|
|
sources: an Iterable of observables. Thus a generator is accepted.
|
|
|
|
Returns:
|
|
An observable sequence containing elements from consecutive
|
|
source sequences until a source sequence terminates
|
|
successfully.
|
|
"""
|
|
|
|
sources_ = iter(sources)
|
|
|
|
def subscribe(
|
|
observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None
|
|
) -> abc.DisposableBase:
|
|
_scheduler = scheduler_ or CurrentThreadScheduler.singleton()
|
|
|
|
subscription = SerialDisposable()
|
|
cancelable = SerialDisposable()
|
|
last_exception = None
|
|
is_disposed = False
|
|
|
|
def action(scheduler: abc.SchedulerBase, state: Any = None) -> None:
|
|
def on_error(exn: Exception) -> None:
|
|
nonlocal last_exception
|
|
last_exception = exn
|
|
cancelable.disposable = _scheduler.schedule(action)
|
|
|
|
if is_disposed:
|
|
return
|
|
|
|
try:
|
|
current = next(sources_)
|
|
except StopIteration:
|
|
if last_exception:
|
|
observer.on_error(last_exception)
|
|
else:
|
|
observer.on_completed()
|
|
except Exception as ex: # pylint: disable=broad-except
|
|
observer.on_error(ex)
|
|
else:
|
|
d = SingleAssignmentDisposable()
|
|
subscription.disposable = d
|
|
d.disposable = current.subscribe(
|
|
observer.on_next,
|
|
on_error,
|
|
observer.on_completed,
|
|
scheduler=scheduler_,
|
|
)
|
|
|
|
cancelable.disposable = _scheduler.schedule(action)
|
|
|
|
def dispose() -> None:
|
|
nonlocal is_disposed
|
|
is_disposed = True
|
|
|
|
return CompositeDisposable(subscription, cancelable, Disposable(dispose))
|
|
|
|
return Observable(subscribe)
|
|
|
|
|
|
__all__ = ["catch_with_iterable_"]
|