venv added, updated

This commit is contained in:
Norbert
2024-09-13 09:46:28 +02:00
parent 577596d9f3
commit 82af8c809a
4812 changed files with 640223 additions and 2 deletions

View File

@@ -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"]

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View 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()