206 lines
6.2 KiB
Python
206 lines
6.2 KiB
Python
from abc import abstractmethod
|
|
from typing import Any, Callable, Generic, Optional, TypeVar, Union
|
|
|
|
from reactivex import abc, typing
|
|
from reactivex.scheduler import ImmediateScheduler
|
|
|
|
from .observable import Observable
|
|
from .observer import Observer
|
|
|
|
_T = TypeVar("_T")
|
|
|
|
|
|
class Notification(Generic[_T]):
|
|
"""Represents a notification to an observer."""
|
|
|
|
def __init__(self) -> None:
|
|
"""Default constructor used by derived types."""
|
|
self.has_value = False
|
|
self.value: Optional[_T] = None
|
|
self.kind: str = ""
|
|
|
|
def accept(
|
|
self,
|
|
on_next: Union[typing.OnNext[_T], abc.ObserverBase[_T]],
|
|
on_error: Optional[typing.OnError] = None,
|
|
on_completed: Optional[typing.OnCompleted] = None,
|
|
) -> None:
|
|
"""Invokes the delegate corresponding to the notification or an
|
|
observer and returns the produced result.
|
|
|
|
Examples:
|
|
>>> notification.accept(observer)
|
|
>>> notification.accept(on_next, on_error, on_completed)
|
|
|
|
Args:
|
|
on_next: Delegate to invoke for an OnNext notification.
|
|
on_error: [Optional] Delegate to invoke for an OnError
|
|
notification.
|
|
on_completed: [Optional] Delegate to invoke for an
|
|
OnCompleted notification.
|
|
|
|
Returns:
|
|
Result produced by the observation."""
|
|
|
|
if isinstance(on_next, abc.ObserverBase):
|
|
return self._accept_observer(on_next)
|
|
|
|
return self._accept(on_next, on_error, on_completed)
|
|
|
|
@abstractmethod
|
|
def _accept(
|
|
self,
|
|
on_next: typing.OnNext[_T],
|
|
on_error: Optional[typing.OnError],
|
|
on_completed: Optional[typing.OnCompleted],
|
|
) -> None:
|
|
raise NotImplementedError
|
|
|
|
@abstractmethod
|
|
def _accept_observer(self, observer: abc.ObserverBase[_T]) -> None:
|
|
raise NotImplementedError
|
|
|
|
def to_observable(
|
|
self, scheduler: Optional[abc.SchedulerBase] = None
|
|
) -> abc.ObservableBase[_T]:
|
|
"""Returns an observable sequence with a single notification,
|
|
using the specified scheduler, else the immediate scheduler.
|
|
|
|
Args:
|
|
scheduler: [Optional] Scheduler to send out the
|
|
notification calls on.
|
|
|
|
Returns:
|
|
An observable sequence that surfaces the behavior of the
|
|
notification upon subscription.
|
|
"""
|
|
|
|
_scheduler = scheduler or ImmediateScheduler.singleton()
|
|
|
|
def subscribe(
|
|
observer: abc.ObserverBase[_T],
|
|
scheduler: Optional[abc.SchedulerBase] = None,
|
|
) -> abc.DisposableBase:
|
|
def action(scheduler: abc.SchedulerBase, state: Any) -> None:
|
|
self._accept_observer(observer)
|
|
if self.kind == "N":
|
|
observer.on_completed()
|
|
|
|
__scheduler = scheduler or _scheduler
|
|
return __scheduler.schedule(action)
|
|
|
|
return Observable(subscribe)
|
|
|
|
def equals(self, other: "Notification[_T]") -> bool:
|
|
"""Indicates whether this instance and a specified object are
|
|
equal."""
|
|
|
|
other_string = "" if not other else str(other)
|
|
return str(self) == other_string
|
|
|
|
def __eq__(self, other: Any) -> bool:
|
|
return self.equals(other)
|
|
|
|
|
|
class OnNext(Notification[_T]):
|
|
"""Represents an OnNext notification to an observer."""
|
|
|
|
def __init__(self, value: _T) -> None:
|
|
"""Constructs a notification of a new value."""
|
|
|
|
super(OnNext, self).__init__()
|
|
self.value: _T = value
|
|
self.has_value: bool = True
|
|
self.kind: str = "N"
|
|
|
|
def _accept(
|
|
self,
|
|
on_next: typing.OnNext[_T],
|
|
on_error: Optional[typing.OnError] = None,
|
|
on_completed: Optional[typing.OnCompleted] = None,
|
|
) -> None:
|
|
return on_next(self.value)
|
|
|
|
def _accept_observer(self, observer: abc.ObserverBase[_T]) -> None:
|
|
return observer.on_next(self.value)
|
|
|
|
def __str__(self) -> str:
|
|
val: Any = self.value
|
|
if isinstance(val, int):
|
|
val = float(val)
|
|
return "OnNext(%s)" % str(val)
|
|
|
|
|
|
class OnError(Notification[_T]):
|
|
"""Represents an OnError notification to an observer."""
|
|
|
|
def __init__(self, error: Union[Exception, str]) -> None:
|
|
"""Constructs a notification of an exception."""
|
|
|
|
super(OnError, self).__init__()
|
|
self.exception: Exception = (
|
|
error if isinstance(error, Exception) else Exception(error)
|
|
)
|
|
self.kind = "E"
|
|
|
|
def _accept(
|
|
self,
|
|
on_next: typing.OnNext[_T],
|
|
on_error: Optional[typing.OnError],
|
|
on_completed: Optional[typing.OnCompleted],
|
|
) -> None:
|
|
return on_error(self.exception) if on_error else None
|
|
|
|
def _accept_observer(self, observer: abc.ObserverBase[_T]) -> None:
|
|
return observer.on_error(self.exception)
|
|
|
|
def __str__(self) -> str:
|
|
return "OnError(%s)" % str(self.exception)
|
|
|
|
|
|
class OnCompleted(Notification[_T]):
|
|
"""Represents an OnCompleted notification to an observer."""
|
|
|
|
def __init__(self) -> None:
|
|
"""Constructs a notification of the end of a sequence."""
|
|
|
|
super(OnCompleted, self).__init__()
|
|
self.kind = "C"
|
|
|
|
def _accept(
|
|
self,
|
|
on_next: typing.OnNext[_T],
|
|
on_error: Optional[typing.OnError],
|
|
on_completed: Optional[typing.OnCompleted],
|
|
) -> None:
|
|
return on_completed() if on_completed else None
|
|
|
|
def _accept_observer(self, observer: abc.ObserverBase[_T]) -> None:
|
|
return observer.on_completed()
|
|
|
|
def __str__(self) -> str:
|
|
return "OnCompleted()"
|
|
|
|
|
|
def from_notifier(handler: Callable[[Notification[_T]], None]) -> Observer[_T]:
|
|
"""Creates an observer from a notification callback.
|
|
|
|
Args:
|
|
handler: Action that handles a notification.
|
|
|
|
Returns:
|
|
The observer object that invokes the specified handler using
|
|
a notification corresponding to each message it receives.
|
|
"""
|
|
|
|
def _on_next(value: _T) -> None:
|
|
return handler(OnNext(value))
|
|
|
|
def _on_error(error: Exception) -> None:
|
|
return handler(OnError(error))
|
|
|
|
def _on_completed() -> None:
|
|
return handler(OnCompleted())
|
|
|
|
return Observer(_on_next, _on_error, _on_completed)
|