venv added, updated
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
from .asyncsubject import AsyncSubject
|
||||
from .behaviorsubject import BehaviorSubject
|
||||
from .replaysubject import ReplaySubject
|
||||
from .subject import Subject
|
||||
|
||||
__all__ = ["Subject", "AsyncSubject", "BehaviorSubject", "ReplaySubject"]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,85 @@
|
||||
from typing import Optional, TypeVar, cast
|
||||
|
||||
from .. import abc
|
||||
from ..disposable import Disposable
|
||||
from .innersubscription import InnerSubscription
|
||||
from .subject import Subject
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class AsyncSubject(Subject[_T]):
|
||||
"""Represents the result of an asynchronous operation. The last value
|
||||
before the close notification, or the error received through
|
||||
on_error, is sent to all subscribed observers."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Creates a subject that can only receive one value and that value is
|
||||
cached for all future observations."""
|
||||
|
||||
super().__init__()
|
||||
|
||||
self.value: _T = cast(_T, None)
|
||||
self.has_value: bool = False
|
||||
|
||||
def _subscribe_core(
|
||||
self,
|
||||
observer: abc.ObserverBase[_T],
|
||||
scheduler: Optional[abc.SchedulerBase] = None,
|
||||
) -> abc.DisposableBase:
|
||||
with self.lock:
|
||||
self.check_disposed()
|
||||
if not self.is_stopped:
|
||||
self.observers.append(observer)
|
||||
return InnerSubscription(self, observer)
|
||||
|
||||
ex = self.exception
|
||||
has_value = self.has_value
|
||||
value = self.value
|
||||
|
||||
if ex:
|
||||
observer.on_error(ex)
|
||||
elif has_value:
|
||||
observer.on_next(value)
|
||||
observer.on_completed()
|
||||
else:
|
||||
observer.on_completed()
|
||||
|
||||
return Disposable()
|
||||
|
||||
def _on_next_core(self, value: _T) -> None:
|
||||
"""Remember the value. Upon completion, the most recently received value
|
||||
will be passed on to all subscribed observers.
|
||||
|
||||
Args:
|
||||
value: The value to remember until completion
|
||||
"""
|
||||
with self.lock:
|
||||
self.value = value
|
||||
self.has_value = True
|
||||
|
||||
def _on_completed_core(self) -> None:
|
||||
"""Notifies all subscribed observers of the end of the sequence. The
|
||||
most recently received value, if any, will now be passed on to all
|
||||
subscribed observers."""
|
||||
|
||||
with self.lock:
|
||||
observers = self.observers.copy()
|
||||
self.observers.clear()
|
||||
value = self.value
|
||||
has_value = self.has_value
|
||||
|
||||
if has_value:
|
||||
for observer in observers:
|
||||
observer.on_next(value)
|
||||
observer.on_completed()
|
||||
else:
|
||||
for observer in observers:
|
||||
observer.on_completed()
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Unsubscribe all observers and release resources."""
|
||||
|
||||
with self.lock:
|
||||
self.value = cast(_T, None)
|
||||
super().dispose()
|
||||
@@ -0,0 +1,69 @@
|
||||
from typing import Optional, TypeVar, cast
|
||||
|
||||
from .. import abc
|
||||
from ..disposable import Disposable
|
||||
from .innersubscription import InnerSubscription
|
||||
from .subject import Subject
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class BehaviorSubject(Subject[_T]):
|
||||
"""Represents a value that changes over time. Observers can
|
||||
subscribe to the subject to receive the last (or initial) value and
|
||||
all subsequent notifications.
|
||||
"""
|
||||
|
||||
def __init__(self, value: _T) -> None:
|
||||
"""Initializes a new instance of the BehaviorSubject class which
|
||||
creates a subject that caches its last value and starts with the
|
||||
specified value.
|
||||
|
||||
Args:
|
||||
value: Initial value sent to observers when no other value has been
|
||||
received by the subject yet.
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
|
||||
self.value: _T = value
|
||||
|
||||
def _subscribe_core(
|
||||
self,
|
||||
observer: abc.ObserverBase[_T],
|
||||
scheduler: Optional[abc.SchedulerBase] = None,
|
||||
) -> abc.DisposableBase:
|
||||
with self.lock:
|
||||
self.check_disposed()
|
||||
if not self.is_stopped:
|
||||
self.observers.append(observer)
|
||||
observer.on_next(self.value)
|
||||
return InnerSubscription(self, observer)
|
||||
ex = self.exception
|
||||
|
||||
if ex:
|
||||
observer.on_error(ex)
|
||||
else:
|
||||
observer.on_completed()
|
||||
|
||||
return Disposable()
|
||||
|
||||
def _on_next_core(self, value: _T) -> None:
|
||||
"""Notifies all subscribed observers with the value."""
|
||||
with self.lock:
|
||||
observers = self.observers.copy()
|
||||
self.value = value
|
||||
|
||||
for observer in observers:
|
||||
observer.on_next(value)
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Release all resources.
|
||||
|
||||
Releases all resources used by the current instance of the
|
||||
BehaviorSubject class and unsubscribe all observers.
|
||||
"""
|
||||
|
||||
with self.lock:
|
||||
self.value = cast(_T, None)
|
||||
super().dispose()
|
||||
@@ -0,0 +1,26 @@
|
||||
import threading
|
||||
from typing import TYPE_CHECKING, Optional, TypeVar
|
||||
|
||||
from .. import abc
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .subject import Subject
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class InnerSubscription(abc.DisposableBase):
|
||||
def __init__(
|
||||
self, subject: "Subject[_T]", observer: Optional[abc.ObserverBase[_T]] = None
|
||||
):
|
||||
self.subject = subject
|
||||
self.observer = observer
|
||||
|
||||
self.lock = threading.RLock()
|
||||
|
||||
def dispose(self) -> None:
|
||||
with self.lock:
|
||||
if not self.subject.is_disposed and self.observer:
|
||||
if self.observer in self.subject.observers:
|
||||
self.subject.observers.remove(self.observer)
|
||||
self.observer = None
|
||||
@@ -0,0 +1,141 @@
|
||||
import sys
|
||||
from collections import deque
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Deque, NamedTuple, Optional, TypeVar, cast
|
||||
|
||||
from reactivex.observer.scheduledobserver import ScheduledObserver
|
||||
from reactivex.scheduler import CurrentThreadScheduler
|
||||
|
||||
from .. import abc, typing
|
||||
from ..observer import Observer
|
||||
from .subject import Subject
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class RemovableDisposable(abc.DisposableBase):
|
||||
def __init__(self, subject: Subject[_T], observer: Observer[_T]):
|
||||
self.subject = subject
|
||||
self.observer = observer
|
||||
|
||||
def dispose(self) -> None:
|
||||
self.observer.dispose()
|
||||
if not self.subject.is_disposed and self.observer in self.subject.observers:
|
||||
self.subject.observers.remove(self.observer)
|
||||
|
||||
|
||||
class QueueItem(NamedTuple):
|
||||
interval: datetime
|
||||
value: Any
|
||||
|
||||
|
||||
class ReplaySubject(Subject[_T]):
|
||||
"""Represents an object that is both an observable sequence as well
|
||||
as an observer. Each notification is broadcasted to all subscribed
|
||||
and future observers, subject to buffer trimming policies.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
buffer_size: Optional[int] = None,
|
||||
window: Optional[typing.RelativeTime] = None,
|
||||
scheduler: Optional[abc.SchedulerBase] = None,
|
||||
) -> None:
|
||||
"""Initializes a new instance of the ReplaySubject class with
|
||||
the specified buffer size, window and scheduler.
|
||||
|
||||
Args:
|
||||
buffer_size: [Optional] Maximum element count of the replay
|
||||
buffer.
|
||||
window [Optional]: Maximum time length of the replay buffer.
|
||||
scheduler: [Optional] Scheduler the observers are invoked on.
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
self.buffer_size = sys.maxsize if buffer_size is None else buffer_size
|
||||
self.scheduler = scheduler or CurrentThreadScheduler.singleton()
|
||||
self.window = (
|
||||
timedelta.max if window is None else self.scheduler.to_timedelta(window)
|
||||
)
|
||||
self.queue: Deque[QueueItem] = deque()
|
||||
|
||||
def _subscribe_core(
|
||||
self,
|
||||
observer: abc.ObserverBase[_T],
|
||||
scheduler: Optional[abc.SchedulerBase] = None,
|
||||
) -> abc.DisposableBase:
|
||||
so = ScheduledObserver(self.scheduler, observer)
|
||||
subscription = RemovableDisposable(self, so)
|
||||
|
||||
with self.lock:
|
||||
self.check_disposed()
|
||||
self._trim(self.scheduler.now)
|
||||
self.observers.append(so)
|
||||
|
||||
for item in self.queue:
|
||||
so.on_next(item.value)
|
||||
|
||||
if self.exception is not None:
|
||||
so.on_error(self.exception)
|
||||
elif self.is_stopped:
|
||||
so.on_completed()
|
||||
|
||||
so.ensure_active()
|
||||
return subscription
|
||||
|
||||
def _trim(self, now: datetime) -> None:
|
||||
while len(self.queue) > self.buffer_size:
|
||||
self.queue.popleft()
|
||||
|
||||
while self.queue and (now - self.queue[0].interval) > self.window:
|
||||
self.queue.popleft()
|
||||
|
||||
def _on_next_core(self, value: _T) -> None:
|
||||
"""Notifies all subscribed observers with the value."""
|
||||
|
||||
with self.lock:
|
||||
observers = self.observers.copy()
|
||||
now = self.scheduler.now
|
||||
self.queue.append(QueueItem(interval=now, value=value))
|
||||
self._trim(now)
|
||||
|
||||
for observer in observers:
|
||||
observer.on_next(value)
|
||||
|
||||
for observer in observers:
|
||||
cast(ScheduledObserver[_T], observer).ensure_active()
|
||||
|
||||
def _on_error_core(self, error: Exception) -> None:
|
||||
"""Notifies all subscribed observers with the exception."""
|
||||
|
||||
with self.lock:
|
||||
observers = self.observers.copy()
|
||||
self.observers.clear()
|
||||
self.exception = error
|
||||
now = self.scheduler.now
|
||||
self._trim(now)
|
||||
|
||||
for observer in observers:
|
||||
observer.on_error(error)
|
||||
cast(ScheduledObserver[_T], observer).ensure_active()
|
||||
|
||||
def _on_completed_core(self) -> None:
|
||||
"""Notifies all subscribed observers of the end of the sequence."""
|
||||
|
||||
with self.lock:
|
||||
observers = self.observers.copy()
|
||||
self.observers.clear()
|
||||
now = self.scheduler.now
|
||||
self._trim(now)
|
||||
|
||||
for observer in observers:
|
||||
observer.on_completed()
|
||||
cast(ScheduledObserver[_T], observer).ensure_active()
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Releases all resources used by the current instance of the
|
||||
ReplaySubject class and unsubscribe all observers."""
|
||||
|
||||
with self.lock:
|
||||
self.queue.clear()
|
||||
super().dispose()
|
||||
110
myenv/lib/python3.12/site-packages/reactivex/subject/subject.py
Normal file
110
myenv/lib/python3.12/site-packages/reactivex/subject/subject.py
Normal file
@@ -0,0 +1,110 @@
|
||||
import threading
|
||||
from typing import List, Optional, TypeVar
|
||||
|
||||
from .. import abc
|
||||
from ..disposable import Disposable
|
||||
from ..internal import DisposedException
|
||||
from ..observable import Observable
|
||||
from ..observer import Observer
|
||||
from .innersubscription import InnerSubscription
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class Subject(Observable[_T], Observer[_T], abc.SubjectBase[_T]):
|
||||
"""Represents an object that is both an observable sequence as well
|
||||
as an observer. Each notification is broadcasted to all subscribed
|
||||
observers.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.is_disposed = False
|
||||
self.observers: List[abc.ObserverBase[_T]] = []
|
||||
self.exception: Optional[Exception] = None
|
||||
|
||||
self.lock = threading.RLock()
|
||||
|
||||
def check_disposed(self) -> None:
|
||||
if self.is_disposed:
|
||||
raise DisposedException()
|
||||
|
||||
def _subscribe_core(
|
||||
self,
|
||||
observer: abc.ObserverBase[_T],
|
||||
scheduler: Optional[abc.SchedulerBase] = None,
|
||||
) -> abc.DisposableBase:
|
||||
with self.lock:
|
||||
self.check_disposed()
|
||||
if not self.is_stopped:
|
||||
self.observers.append(observer)
|
||||
return InnerSubscription(self, observer)
|
||||
|
||||
if self.exception is not None:
|
||||
observer.on_error(self.exception)
|
||||
else:
|
||||
observer.on_completed()
|
||||
return Disposable()
|
||||
|
||||
def on_next(self, value: _T) -> None:
|
||||
"""Notifies all subscribed observers with the value.
|
||||
|
||||
Args:
|
||||
value: The value to send to all subscribed observers.
|
||||
"""
|
||||
|
||||
with self.lock:
|
||||
self.check_disposed()
|
||||
super().on_next(value)
|
||||
|
||||
def _on_next_core(self, value: _T) -> None:
|
||||
with self.lock:
|
||||
observers = self.observers.copy()
|
||||
|
||||
for observer in observers:
|
||||
observer.on_next(value)
|
||||
|
||||
def on_error(self, error: Exception) -> None:
|
||||
"""Notifies all subscribed observers with the exception.
|
||||
|
||||
Args:
|
||||
error: The exception to send to all subscribed observers.
|
||||
"""
|
||||
|
||||
with self.lock:
|
||||
self.check_disposed()
|
||||
super().on_error(error)
|
||||
|
||||
def _on_error_core(self, error: Exception) -> None:
|
||||
with self.lock:
|
||||
observers = self.observers.copy()
|
||||
self.observers.clear()
|
||||
self.exception = error
|
||||
|
||||
for observer in observers:
|
||||
observer.on_error(error)
|
||||
|
||||
def on_completed(self) -> None:
|
||||
"""Notifies all subscribed observers of the end of the sequence."""
|
||||
|
||||
with self.lock:
|
||||
self.check_disposed()
|
||||
super().on_completed()
|
||||
|
||||
def _on_completed_core(self) -> None:
|
||||
with self.lock:
|
||||
observers = self.observers.copy()
|
||||
self.observers.clear()
|
||||
|
||||
for observer in observers:
|
||||
observer.on_completed()
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Unsubscribe all observers and release resources."""
|
||||
|
||||
with self.lock:
|
||||
self.is_disposed = True
|
||||
self.observers = []
|
||||
self.exception = None
|
||||
super().dispose()
|
||||
Reference in New Issue
Block a user