venv added, updated
This commit is contained in:
1339
myenv/lib/python3.12/site-packages/reactivex/__init__.py
Normal file
1339
myenv/lib/python3.12/site-packages/reactivex/__init__.py
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
myenv/lib/python3.12/site-packages/reactivex/_version.py
Normal file
1
myenv/lib/python3.12/site-packages/reactivex/_version.py
Normal file
@@ -0,0 +1 @@
|
||||
__version__ = "4.0.4"
|
||||
22
myenv/lib/python3.12/site-packages/reactivex/abc/__init__.py
Normal file
22
myenv/lib/python3.12/site-packages/reactivex/abc/__init__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from .disposable import DisposableBase
|
||||
from .observable import ObservableBase, Subscription
|
||||
from .observer import ObserverBase, OnCompleted, OnError, OnNext
|
||||
from .periodicscheduler import PeriodicSchedulerBase
|
||||
from .scheduler import ScheduledAction, SchedulerBase
|
||||
from .startable import StartableBase
|
||||
from .subject import SubjectBase
|
||||
|
||||
__all__ = [
|
||||
"DisposableBase",
|
||||
"ObserverBase",
|
||||
"ObservableBase",
|
||||
"OnCompleted",
|
||||
"OnError",
|
||||
"OnNext",
|
||||
"SchedulerBase",
|
||||
"PeriodicSchedulerBase",
|
||||
"SubjectBase",
|
||||
"Subscription",
|
||||
"ScheduledAction",
|
||||
"StartableBase",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
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,34 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from types import TracebackType
|
||||
from typing import Optional, Type
|
||||
|
||||
|
||||
class DisposableBase(ABC):
|
||||
"""Disposable abstract base class."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def dispose(self) -> None:
|
||||
"""Dispose the object: stop whatever we're doing and release all of the
|
||||
resources we might be using.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __enter__(self) -> DisposableBase:
|
||||
"""Context management protocol."""
|
||||
return self
|
||||
|
||||
def __exit__(
|
||||
self,
|
||||
exctype: Optional[Type[BaseException]],
|
||||
excinst: Optional[BaseException],
|
||||
exctb: Optional[TracebackType],
|
||||
) -> None:
|
||||
"""Context management protocol."""
|
||||
self.dispose()
|
||||
|
||||
|
||||
__all__ = ["DisposableBase"]
|
||||
@@ -0,0 +1,45 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Callable, Generic, Optional, TypeVar, Union
|
||||
|
||||
from .disposable import DisposableBase
|
||||
from .observer import ObserverBase, OnCompleted, OnError, OnNext
|
||||
from .scheduler import SchedulerBase
|
||||
|
||||
_T_out = TypeVar("_T_out", covariant=True)
|
||||
|
||||
|
||||
class ObservableBase(Generic[_T_out], ABC):
|
||||
"""Observable abstract base class.
|
||||
|
||||
Represents a push-style collection."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def subscribe(
|
||||
self,
|
||||
on_next: Optional[Union[OnNext[_T_out], ObserverBase[_T_out]]] = None,
|
||||
on_error: Optional[OnError] = None,
|
||||
on_completed: Optional[OnCompleted] = None,
|
||||
*,
|
||||
scheduler: Optional[SchedulerBase] = None,
|
||||
) -> DisposableBase:
|
||||
"""Subscribe an observer to the observable sequence.
|
||||
|
||||
Args:
|
||||
observer: [Optional] The object that is to receive
|
||||
notifications.
|
||||
scheduler: [Optional] The default scheduler to use for this
|
||||
subscription.
|
||||
|
||||
Returns:
|
||||
Disposable object representing an observer's subscription
|
||||
to the observable sequence.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
Subscription = Callable[[ObserverBase[_T_out], Optional[SchedulerBase]], DisposableBase]
|
||||
|
||||
__all__ = ["ObservableBase", "Subscription"]
|
||||
48
myenv/lib/python3.12/site-packages/reactivex/abc/observer.py
Normal file
48
myenv/lib/python3.12/site-packages/reactivex/abc/observer.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Callable, Generic, TypeVar
|
||||
|
||||
_T = TypeVar("_T")
|
||||
_T_in = TypeVar("_T_in", contravariant=True)
|
||||
|
||||
OnNext = Callable[[_T], None]
|
||||
OnError = Callable[[Exception], None]
|
||||
OnCompleted = Callable[[], None]
|
||||
|
||||
|
||||
class ObserverBase(Generic[_T_in], ABC):
|
||||
"""Observer abstract base class
|
||||
|
||||
An Observer is the entity that receives all emissions of a
|
||||
subscribed Observable.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def on_next(self, value: _T_in) -> None:
|
||||
"""Notifies the observer of a new element in the sequence.
|
||||
|
||||
Args:
|
||||
value: The received element.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def on_error(self, error: Exception) -> None:
|
||||
"""Notifies the observer that an exception has occurred.
|
||||
|
||||
Args:
|
||||
error: The error that has occurred.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def on_completed(self) -> None:
|
||||
"""Notifies the observer of the end of the sequence."""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
__all__ = ["ObserverBase", "OnNext", "OnError", "OnCompleted"]
|
||||
@@ -0,0 +1,49 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Callable, Optional, TypeVar, Union
|
||||
|
||||
from .disposable import DisposableBase
|
||||
from .scheduler import RelativeTime, ScheduledAction
|
||||
|
||||
_TState = TypeVar("_TState") # Can be anything
|
||||
|
||||
ScheduledPeriodicAction = Callable[[Optional[_TState]], Optional[_TState]]
|
||||
ScheduledSingleOrPeriodicAction = Union[
|
||||
ScheduledAction[_TState], ScheduledPeriodicAction[_TState]
|
||||
]
|
||||
|
||||
|
||||
class PeriodicSchedulerBase(ABC):
|
||||
"""PeriodicScheduler abstract base class."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def schedule_periodic(
|
||||
self,
|
||||
period: RelativeTime,
|
||||
action: ScheduledPeriodicAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> DisposableBase:
|
||||
"""Schedules a periodic piece of work.
|
||||
|
||||
Args:
|
||||
period: Period in seconds or timedelta for running the
|
||||
work periodically.
|
||||
action: Action to be executed.
|
||||
state: [Optional] Initial state passed to the action upon
|
||||
the first iteration.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled
|
||||
recurring action (best effort).
|
||||
"""
|
||||
|
||||
return NotImplemented
|
||||
|
||||
|
||||
__all__ = [
|
||||
"PeriodicSchedulerBase",
|
||||
"ScheduledPeriodicAction",
|
||||
"ScheduledSingleOrPeriodicAction",
|
||||
"RelativeTime",
|
||||
]
|
||||
152
myenv/lib/python3.12/site-packages/reactivex/abc/scheduler.py
Normal file
152
myenv/lib/python3.12/site-packages/reactivex/abc/scheduler.py
Normal file
@@ -0,0 +1,152 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Callable, Optional, TypeVar, Union
|
||||
|
||||
from .disposable import DisposableBase
|
||||
|
||||
_TState = TypeVar("_TState") # Can be anything
|
||||
|
||||
AbsoluteTime = Union[datetime, float]
|
||||
RelativeTime = Union[timedelta, float]
|
||||
AbsoluteOrRelativeTime = Union[datetime, timedelta, float]
|
||||
ScheduledAction = Callable[
|
||||
["SchedulerBase", Optional[_TState]],
|
||||
Optional[DisposableBase],
|
||||
]
|
||||
|
||||
|
||||
class SchedulerBase(ABC):
|
||||
"""Scheduler abstract base class."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def now(self) -> datetime:
|
||||
"""Represents a notion of time for this scheduler. Tasks being
|
||||
scheduled on a scheduler will adhere to the time denoted by this
|
||||
property.
|
||||
|
||||
Returns:
|
||||
The scheduler's current time, as a datetime instance.
|
||||
"""
|
||||
|
||||
return NotImplemented
|
||||
|
||||
@abstractmethod
|
||||
def schedule(
|
||||
self, action: ScheduledAction[_TState], state: Optional[_TState] = None
|
||||
) -> DisposableBase:
|
||||
"""Schedules an action to be executed.
|
||||
|
||||
Args:
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
return NotImplemented
|
||||
|
||||
@abstractmethod
|
||||
def schedule_relative(
|
||||
self,
|
||||
duetime: RelativeTime,
|
||||
action: ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> DisposableBase:
|
||||
"""Schedules an action to be executed after duetime.
|
||||
|
||||
Args:
|
||||
duetime: Relative time after which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
return NotImplemented
|
||||
|
||||
@abstractmethod
|
||||
def schedule_absolute(
|
||||
self,
|
||||
duetime: AbsoluteTime,
|
||||
action: ScheduledAction[_TState],
|
||||
state: Optional[_TState] = None,
|
||||
) -> DisposableBase:
|
||||
"""Schedules an action to be executed at duetime.
|
||||
|
||||
Args:
|
||||
duetime: Absolute time at which to execute the action.
|
||||
action: Action to be executed.
|
||||
state: [Optional] state to be given to the action function.
|
||||
|
||||
Returns:
|
||||
The disposable object used to cancel the scheduled action
|
||||
(best effort).
|
||||
"""
|
||||
|
||||
return NotImplemented
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def to_seconds(cls, value: AbsoluteOrRelativeTime) -> float:
|
||||
"""Converts time value to seconds. This method handles both absolute
|
||||
(datetime) and relative (timedelta) values. If the argument is already
|
||||
a float, it is simply returned unchanged.
|
||||
|
||||
Args:
|
||||
value: the time value to convert to seconds.
|
||||
|
||||
Returns:
|
||||
The value converted to seconds.
|
||||
"""
|
||||
|
||||
return NotImplemented
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def to_datetime(cls, value: AbsoluteOrRelativeTime) -> datetime:
|
||||
"""Converts time value to datetime. This method handles both absolute
|
||||
(float) and relative (timedelta) values. If the argument is already
|
||||
a datetime, it is simply returned unchanged.
|
||||
|
||||
Args:
|
||||
value: the time value to convert to datetime.
|
||||
|
||||
Returns:
|
||||
The value converted to datetime.
|
||||
"""
|
||||
|
||||
return NotImplemented
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def to_timedelta(cls, value: AbsoluteOrRelativeTime) -> timedelta:
|
||||
"""Converts time value to timedelta. This method handles both absolute
|
||||
(datetime) and relative (float) values. If the argument is already
|
||||
a timedelta, it is simply returned unchanged. If the argument is an
|
||||
absolute time, the result value will be the timedelta since the epoch,
|
||||
January 1st, 1970, 00:00:00.
|
||||
|
||||
Args:
|
||||
value: the time value to convert to timedelta.
|
||||
|
||||
Returns:
|
||||
The value converted to timedelta.
|
||||
"""
|
||||
|
||||
return NotImplemented
|
||||
|
||||
|
||||
__all__ = [
|
||||
"SchedulerBase",
|
||||
"AbsoluteTime",
|
||||
"RelativeTime",
|
||||
"AbsoluteOrRelativeTime",
|
||||
"ScheduledAction",
|
||||
]
|
||||
@@ -0,0 +1,14 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class StartableBase(ABC):
|
||||
"""Abstract base class for Thread- and Process-like objects."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def start(self) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
__all__ = ["StartableBase"]
|
||||
72
myenv/lib/python3.12/site-packages/reactivex/abc/subject.py
Normal file
72
myenv/lib/python3.12/site-packages/reactivex/abc/subject.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from abc import abstractmethod
|
||||
from typing import Optional, TypeVar, Union
|
||||
|
||||
from .disposable import DisposableBase
|
||||
from .observable import ObservableBase
|
||||
from .observer import ObserverBase, OnCompleted, OnError, OnNext
|
||||
from .scheduler import SchedulerBase
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class SubjectBase(ObserverBase[_T], ObservableBase[_T]):
|
||||
"""Subject abstract base class.
|
||||
|
||||
Represents an object that is both an observable sequence as well
|
||||
as an observer.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def subscribe(
|
||||
self,
|
||||
on_next: Optional[Union[OnNext[_T], ObserverBase[_T]]] = None,
|
||||
on_error: Optional[OnError] = None,
|
||||
on_completed: Optional[OnCompleted] = None,
|
||||
*,
|
||||
scheduler: Optional[SchedulerBase] = None,
|
||||
) -> DisposableBase:
|
||||
"""Subscribe an observer to the observable sequence.
|
||||
|
||||
Args:
|
||||
observer: [Optional] The object that is to receive
|
||||
notifications.
|
||||
scheduler: [Optional] The default scheduler to use for this
|
||||
subscription.
|
||||
|
||||
Returns:
|
||||
Disposable object representing an observer's subscription
|
||||
to the observable sequence.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def on_next(self, value: _T) -> None:
|
||||
"""Notifies the observer of a new element in the sequence.
|
||||
|
||||
Args:
|
||||
value: The received element.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def on_error(self, error: Exception) -> None:
|
||||
"""Notifies the observer that an exception has occurred.
|
||||
|
||||
Args:
|
||||
error: The error that has occurred.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def on_completed(self) -> None:
|
||||
"""Notifies the observer of the end of the sequence."""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
__all__ = ["SubjectBase"]
|
||||
@@ -0,0 +1,19 @@
|
||||
from .booleandisposable import BooleanDisposable
|
||||
from .compositedisposable import CompositeDisposable
|
||||
from .disposable import Disposable
|
||||
from .multipleassignmentdisposable import MultipleAssignmentDisposable
|
||||
from .refcountdisposable import RefCountDisposable
|
||||
from .scheduleddisposable import ScheduledDisposable
|
||||
from .serialdisposable import SerialDisposable
|
||||
from .singleassignmentdisposable import SingleAssignmentDisposable
|
||||
|
||||
__all__ = [
|
||||
"BooleanDisposable",
|
||||
"CompositeDisposable",
|
||||
"Disposable",
|
||||
"MultipleAssignmentDisposable",
|
||||
"RefCountDisposable",
|
||||
"ScheduledDisposable",
|
||||
"SerialDisposable",
|
||||
"SingleAssignmentDisposable",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
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,20 @@
|
||||
from threading import RLock
|
||||
|
||||
from reactivex.abc import DisposableBase
|
||||
|
||||
|
||||
class BooleanDisposable(DisposableBase):
|
||||
"""Represents a Disposable that can be checked for status."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initializes a new instance of the BooleanDisposable class."""
|
||||
|
||||
self.is_disposed = False
|
||||
self.lock = RLock()
|
||||
|
||||
super().__init__()
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Sets the status to disposed"""
|
||||
|
||||
self.is_disposed = True
|
||||
@@ -0,0 +1,103 @@
|
||||
from threading import RLock
|
||||
from typing import Any, List
|
||||
|
||||
from reactivex import abc
|
||||
|
||||
|
||||
class CompositeDisposable(abc.DisposableBase):
|
||||
"""Represents a group of disposable resources that are disposed
|
||||
together"""
|
||||
|
||||
def __init__(self, *args: Any):
|
||||
if args and isinstance(args[0], list):
|
||||
self.disposable: List[abc.DisposableBase] = args[0]
|
||||
else:
|
||||
self.disposable = list(args)
|
||||
|
||||
self.is_disposed = False
|
||||
self.lock = RLock()
|
||||
super(CompositeDisposable, self).__init__()
|
||||
|
||||
def add(self, item: abc.DisposableBase) -> None:
|
||||
"""Adds a disposable to the CompositeDisposable or disposes the
|
||||
disposable if the CompositeDisposable is disposed
|
||||
|
||||
Args:
|
||||
item: Disposable to add."""
|
||||
|
||||
should_dispose = False
|
||||
with self.lock:
|
||||
if self.is_disposed:
|
||||
should_dispose = True
|
||||
else:
|
||||
self.disposable.append(item)
|
||||
|
||||
if should_dispose:
|
||||
item.dispose()
|
||||
|
||||
def remove(self, item: abc.DisposableBase) -> bool:
|
||||
"""Removes and disposes the first occurrence of a disposable
|
||||
from the CompositeDisposable."""
|
||||
|
||||
if self.is_disposed:
|
||||
return False
|
||||
|
||||
should_dispose = False
|
||||
with self.lock:
|
||||
if item in self.disposable:
|
||||
self.disposable.remove(item)
|
||||
should_dispose = True
|
||||
|
||||
if should_dispose:
|
||||
item.dispose()
|
||||
|
||||
return should_dispose
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Disposes all disposable in the group and removes them from
|
||||
the group."""
|
||||
|
||||
if self.is_disposed:
|
||||
return
|
||||
|
||||
with self.lock:
|
||||
self.is_disposed = True
|
||||
current_disposable = self.disposable
|
||||
self.disposable = []
|
||||
|
||||
for disp in current_disposable:
|
||||
disp.dispose()
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Removes and disposes all disposable from the
|
||||
CompositeDisposable, but does not dispose the
|
||||
CompositeDisposable."""
|
||||
|
||||
with self.lock:
|
||||
current_disposable = self.disposable
|
||||
self.disposable = []
|
||||
|
||||
for disposable in current_disposable:
|
||||
disposable.dispose()
|
||||
|
||||
def contains(self, item: abc.DisposableBase) -> bool:
|
||||
"""Determines whether the CompositeDisposable contains a specific
|
||||
disposable.
|
||||
|
||||
Args:
|
||||
item: Disposable to search for
|
||||
|
||||
Returns:
|
||||
True if the disposable was found; otherwise, False"""
|
||||
|
||||
return item in self.disposable
|
||||
|
||||
def to_list(self) -> List[abc.DisposableBase]:
|
||||
return self.disposable[:]
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.disposable)
|
||||
|
||||
@property
|
||||
def length(self) -> int:
|
||||
return len(self.disposable)
|
||||
@@ -0,0 +1,43 @@
|
||||
from threading import RLock
|
||||
from typing import Optional
|
||||
|
||||
from reactivex import typing
|
||||
from reactivex.abc import DisposableBase
|
||||
from reactivex.internal import noop
|
||||
from reactivex.typing import Action
|
||||
|
||||
|
||||
class Disposable(DisposableBase):
|
||||
"""Main disposable class"""
|
||||
|
||||
def __init__(self, action: Optional[typing.Action] = None) -> None:
|
||||
"""Creates a disposable object that invokes the specified
|
||||
action when disposed.
|
||||
|
||||
Args:
|
||||
action: Action to run during the first call to dispose.
|
||||
The action is guaranteed to be run at most once.
|
||||
|
||||
Returns:
|
||||
The disposable object that runs the given action upon
|
||||
disposal.
|
||||
"""
|
||||
|
||||
self.is_disposed = False
|
||||
self.action: Action = action or noop
|
||||
|
||||
self.lock = RLock()
|
||||
|
||||
super().__init__()
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Performs the task of cleaning up resources."""
|
||||
|
||||
dispose = False
|
||||
with self.lock:
|
||||
if not self.is_disposed:
|
||||
dispose = True
|
||||
self.is_disposed = True
|
||||
|
||||
if dispose:
|
||||
self.action()
|
||||
@@ -0,0 +1,49 @@
|
||||
from threading import RLock
|
||||
from typing import Optional
|
||||
|
||||
from reactivex.abc import DisposableBase
|
||||
|
||||
|
||||
class MultipleAssignmentDisposable(DisposableBase):
|
||||
"""Represents a disposable resource whose underlying disposable
|
||||
resource can be replaced by another disposable resource."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.current: Optional[DisposableBase] = None
|
||||
self.is_disposed = False
|
||||
self.lock = RLock()
|
||||
|
||||
super().__init__()
|
||||
|
||||
def get_disposable(self) -> Optional[DisposableBase]:
|
||||
return self.current
|
||||
|
||||
def set_disposable(self, value: DisposableBase) -> None:
|
||||
"""If the MultipleAssignmentDisposable has already been
|
||||
disposed, assignment to this property causes immediate disposal
|
||||
of the given disposable object."""
|
||||
|
||||
with self.lock:
|
||||
should_dispose = self.is_disposed
|
||||
if not should_dispose:
|
||||
self.current = value
|
||||
|
||||
if should_dispose and value is not None:
|
||||
value.dispose()
|
||||
|
||||
disposable = property(get_disposable, set_disposable)
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Disposes the underlying disposable as well as all future
|
||||
replacements."""
|
||||
|
||||
old = None
|
||||
|
||||
with self.lock:
|
||||
if not self.is_disposed:
|
||||
self.is_disposed = True
|
||||
old = self.current
|
||||
self.current = None
|
||||
|
||||
if old is not None:
|
||||
old.dispose()
|
||||
@@ -0,0 +1,82 @@
|
||||
from threading import RLock
|
||||
from typing import Optional
|
||||
|
||||
from reactivex.abc import DisposableBase
|
||||
|
||||
from .disposable import Disposable
|
||||
|
||||
|
||||
class RefCountDisposable(DisposableBase):
|
||||
"""Represents a disposable resource that only disposes its underlying
|
||||
disposable resource when all dependent disposable objects have been
|
||||
disposed."""
|
||||
|
||||
class InnerDisposable(DisposableBase):
|
||||
def __init__(self, parent: "RefCountDisposable") -> None:
|
||||
self.parent: Optional[RefCountDisposable] = parent
|
||||
self.is_disposed = False
|
||||
self.lock = RLock()
|
||||
|
||||
def dispose(self) -> None:
|
||||
with self.lock:
|
||||
parent = self.parent
|
||||
self.parent = None
|
||||
|
||||
if parent is not None:
|
||||
parent.release()
|
||||
|
||||
def __init__(self, disposable: DisposableBase) -> None:
|
||||
"""Initializes a new instance of the RefCountDisposable class with the
|
||||
specified disposable."""
|
||||
|
||||
self.underlying_disposable = disposable
|
||||
self.is_primary_disposed = False
|
||||
self.is_disposed = False
|
||||
self.lock = RLock()
|
||||
self.count = 0
|
||||
|
||||
super().__init__()
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Disposes the underlying disposable only when all dependent
|
||||
disposable have been disposed."""
|
||||
|
||||
if self.is_disposed:
|
||||
return
|
||||
|
||||
underlying_disposable = None
|
||||
with self.lock:
|
||||
if not self.is_primary_disposed:
|
||||
self.is_primary_disposed = True
|
||||
if not self.count:
|
||||
self.is_disposed = True
|
||||
underlying_disposable = self.underlying_disposable
|
||||
|
||||
if underlying_disposable is not None:
|
||||
underlying_disposable.dispose()
|
||||
|
||||
def release(self) -> None:
|
||||
if self.is_disposed:
|
||||
return
|
||||
|
||||
should_dispose = False
|
||||
with self.lock:
|
||||
self.count -= 1
|
||||
if not self.count and self.is_primary_disposed:
|
||||
self.is_disposed = True
|
||||
should_dispose = True
|
||||
|
||||
if should_dispose:
|
||||
self.underlying_disposable.dispose()
|
||||
|
||||
@property
|
||||
def disposable(self) -> DisposableBase:
|
||||
"""Returns a dependent disposable that when disposed decreases the
|
||||
refcount on the underlying disposable."""
|
||||
|
||||
with self.lock:
|
||||
if self.is_disposed:
|
||||
return Disposable()
|
||||
|
||||
self.count += 1
|
||||
return self.InnerDisposable(self)
|
||||
@@ -0,0 +1,38 @@
|
||||
from threading import RLock
|
||||
from typing import Any
|
||||
|
||||
from reactivex import abc
|
||||
|
||||
from .singleassignmentdisposable import SingleAssignmentDisposable
|
||||
|
||||
|
||||
class ScheduledDisposable(abc.DisposableBase):
|
||||
"""Represents a disposable resource whose disposal invocation will
|
||||
be scheduled on the specified Scheduler"""
|
||||
|
||||
def __init__(
|
||||
self, scheduler: abc.SchedulerBase, disposable: abc.DisposableBase
|
||||
) -> None:
|
||||
"""Initializes a new instance of the ScheduledDisposable class
|
||||
that uses a Scheduler on which to dispose the disposable."""
|
||||
|
||||
self.scheduler = scheduler
|
||||
self.disposable = SingleAssignmentDisposable()
|
||||
self.disposable.disposable = disposable
|
||||
self.lock = RLock()
|
||||
|
||||
super().__init__()
|
||||
|
||||
@property
|
||||
def is_disposed(self) -> bool:
|
||||
return self.disposable.is_disposed
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Disposes the wrapped disposable on the provided scheduler."""
|
||||
|
||||
def action(scheduler: abc.SchedulerBase, state: Any) -> None:
|
||||
"""Scheduled dispose action"""
|
||||
|
||||
self.disposable.dispose()
|
||||
|
||||
self.scheduler.schedule(action)
|
||||
@@ -0,0 +1,58 @@
|
||||
from threading import RLock
|
||||
from typing import Optional
|
||||
|
||||
from reactivex import abc
|
||||
|
||||
|
||||
class SerialDisposable(abc.DisposableBase):
|
||||
"""Represents a disposable resource whose underlying disposable
|
||||
resource can be replaced by another disposable resource, causing
|
||||
automatic disposal of the previous underlying disposable resource.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.current: Optional[abc.DisposableBase] = None
|
||||
self.is_disposed = False
|
||||
self.lock = RLock()
|
||||
|
||||
super().__init__()
|
||||
|
||||
def get_disposable(self) -> Optional[abc.DisposableBase]:
|
||||
return self.current
|
||||
|
||||
def set_disposable(self, value: abc.DisposableBase) -> None:
|
||||
"""If the SerialDisposable has already been disposed, assignment
|
||||
to this property causes immediate disposal of the given
|
||||
disposable object. Assigning this property disposes the previous
|
||||
disposable object."""
|
||||
|
||||
old: Optional[abc.DisposableBase] = None
|
||||
|
||||
with self.lock:
|
||||
should_dispose = self.is_disposed
|
||||
if not should_dispose:
|
||||
old = self.current
|
||||
self.current = value
|
||||
|
||||
if old is not None:
|
||||
old.dispose()
|
||||
|
||||
if should_dispose and value is not None:
|
||||
value.dispose()
|
||||
|
||||
disposable = property(get_disposable, set_disposable)
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Disposes the underlying disposable as well as all future
|
||||
replacements."""
|
||||
|
||||
old: Optional[abc.DisposableBase] = None
|
||||
|
||||
with self.lock:
|
||||
if not self.is_disposed:
|
||||
self.is_disposed = True
|
||||
old = self.current
|
||||
self.current = None
|
||||
|
||||
if old is not None:
|
||||
old.dispose()
|
||||
@@ -0,0 +1,53 @@
|
||||
from threading import RLock
|
||||
from typing import Optional
|
||||
|
||||
from reactivex.abc import DisposableBase
|
||||
|
||||
|
||||
class SingleAssignmentDisposable(DisposableBase):
|
||||
"""Single assignment disposable.
|
||||
|
||||
Represents a disposable resource which only allows a single
|
||||
assignment of its underlying disposable resource. If an underlying
|
||||
disposable resource has already been set, future attempts to set the
|
||||
underlying disposable resource will throw an Error."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initializes a new instance of the SingleAssignmentDisposable
|
||||
class.
|
||||
"""
|
||||
self.is_disposed: bool = False
|
||||
self.current: Optional[DisposableBase] = None
|
||||
self.lock = RLock()
|
||||
|
||||
super().__init__()
|
||||
|
||||
def get_disposable(self) -> Optional[DisposableBase]:
|
||||
return self.current
|
||||
|
||||
def set_disposable(self, value: DisposableBase) -> None:
|
||||
if self.current:
|
||||
raise Exception("Disposable has already been assigned")
|
||||
|
||||
with self.lock:
|
||||
should_dispose = self.is_disposed
|
||||
if not should_dispose:
|
||||
self.current = value
|
||||
|
||||
if self.is_disposed and value:
|
||||
value.dispose()
|
||||
|
||||
disposable = property(get_disposable, set_disposable)
|
||||
|
||||
def dispose(self) -> None:
|
||||
"""Sets the status to disposed"""
|
||||
old: Optional[DisposableBase] = None
|
||||
|
||||
with self.lock:
|
||||
if not self.is_disposed:
|
||||
self.is_disposed = True
|
||||
old = self.current
|
||||
self.current = None
|
||||
|
||||
if old is not None:
|
||||
old.dispose()
|
||||
@@ -0,0 +1,29 @@
|
||||
from .basic import default_comparer, default_error, noop
|
||||
from .concurrency import default_thread_factory, synchronized
|
||||
from .constants import DELTA_ZERO, UTC_ZERO
|
||||
from .exceptions import (
|
||||
ArgumentOutOfRangeException,
|
||||
DisposedException,
|
||||
SequenceContainsNoElementsError,
|
||||
)
|
||||
from .priorityqueue import PriorityQueue
|
||||
from .utils import NotSet, add_ref, alias, infinite
|
||||
|
||||
__all__ = [
|
||||
"add_ref",
|
||||
"alias",
|
||||
"ArgumentOutOfRangeException",
|
||||
"DisposedException",
|
||||
"default_comparer",
|
||||
"default_error",
|
||||
"infinite",
|
||||
"noop",
|
||||
"NotSet",
|
||||
"SequenceContainsNoElementsError",
|
||||
"concurrency",
|
||||
"DELTA_ZERO",
|
||||
"UTC_ZERO",
|
||||
"synchronized",
|
||||
"default_thread_factory",
|
||||
"PriorityQueue",
|
||||
]
|
||||
Binary file not shown.
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,36 @@
|
||||
from datetime import datetime
|
||||
from typing import Any, NoReturn, TypeVar, Union
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
def noop(*args: Any, **kw: Any) -> None:
|
||||
"""No operation. Returns nothing"""
|
||||
|
||||
|
||||
def identity(x: _T) -> _T:
|
||||
"""Returns argument x"""
|
||||
return x
|
||||
|
||||
|
||||
def default_now() -> datetime:
|
||||
return datetime.utcnow()
|
||||
|
||||
|
||||
def default_comparer(x: _T, y: _T) -> bool:
|
||||
return x == y
|
||||
|
||||
|
||||
def default_sub_comparer(x: Any, y: Any) -> Any:
|
||||
return x - y
|
||||
|
||||
|
||||
def default_key_serializer(x: Any) -> str:
|
||||
return str(x)
|
||||
|
||||
|
||||
def default_error(err: Union[Exception, str]) -> NoReturn:
|
||||
if isinstance(err, BaseException):
|
||||
raise err
|
||||
|
||||
raise Exception(err)
|
||||
@@ -0,0 +1,26 @@
|
||||
from threading import RLock, Thread
|
||||
from typing import Any, Callable, TypeVar
|
||||
|
||||
from typing_extensions import ParamSpec
|
||||
|
||||
from reactivex.typing import StartableTarget
|
||||
|
||||
_T = TypeVar("_T")
|
||||
_P = ParamSpec("_P")
|
||||
|
||||
|
||||
def default_thread_factory(target: StartableTarget) -> Thread:
|
||||
return Thread(target=target, daemon=True)
|
||||
|
||||
|
||||
def synchronized(lock: RLock) -> Callable[[Callable[_P, _T]], Callable[_P, _T]]:
|
||||
"""A decorator for synchronizing access to a given function."""
|
||||
|
||||
def wrapper(fn: Callable[_P, _T]) -> Callable[_P, _T]:
|
||||
def inner(*args: _P.args, **kw: _P.kwargs) -> Any:
|
||||
with lock:
|
||||
return fn(*args, **kw)
|
||||
|
||||
return inner
|
||||
|
||||
return wrapper
|
||||
@@ -0,0 +1,4 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
DELTA_ZERO = timedelta(0)
|
||||
UTC_ZERO = datetime.utcfromtimestamp(0)
|
||||
@@ -0,0 +1,36 @@
|
||||
# Rx Exceptions
|
||||
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class SequenceContainsNoElementsError(Exception):
|
||||
def __init__(self, msg: Optional[str] = None):
|
||||
super().__init__(msg or "Sequence contains no elements")
|
||||
|
||||
|
||||
class ArgumentOutOfRangeException(ValueError):
|
||||
def __init__(self, msg: Optional[str] = None):
|
||||
super(ArgumentOutOfRangeException, self).__init__(
|
||||
msg or "Argument out of range"
|
||||
)
|
||||
|
||||
|
||||
class DisposedException(Exception):
|
||||
def __init__(self, msg: Optional[str] = None):
|
||||
super().__init__(msg or "Object has been disposed")
|
||||
|
||||
|
||||
class ReEntracyException(Exception):
|
||||
def __init__(self, msg: Optional[str] = None):
|
||||
super().__init__(msg or "Re-entrancy detected")
|
||||
|
||||
|
||||
class CompletedException(Exception):
|
||||
def __init__(self, msg: Optional[str] = None):
|
||||
super().__init__(msg or "Observer completed")
|
||||
|
||||
|
||||
class WouldBlockException(Exception):
|
||||
def __init__(self, msg: Optional[str] = None):
|
||||
super().__init__(msg or "Would block")
|
||||
@@ -0,0 +1,54 @@
|
||||
import heapq
|
||||
from sys import maxsize
|
||||
from typing import Generic, List, Tuple, TypeVar
|
||||
|
||||
_T1 = TypeVar("_T1")
|
||||
|
||||
|
||||
class PriorityQueue(Generic[_T1]):
|
||||
"""Priority queue for scheduling. Note that methods aren't thread-safe."""
|
||||
|
||||
MIN_COUNT = ~maxsize
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.items: List[Tuple[_T1, int]] = []
|
||||
self.count = PriorityQueue.MIN_COUNT # Monotonic increasing for sort stability
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""Returns length of queue"""
|
||||
|
||||
return len(self.items)
|
||||
|
||||
def peek(self) -> _T1:
|
||||
"""Returns first item in queue without removing it"""
|
||||
return self.items[0][0]
|
||||
|
||||
def dequeue(self) -> _T1:
|
||||
"""Returns and removes item with lowest priority from queue"""
|
||||
|
||||
item: _T1 = heapq.heappop(self.items)[0]
|
||||
if not self.items:
|
||||
self.count = PriorityQueue.MIN_COUNT
|
||||
return item
|
||||
|
||||
def enqueue(self, item: _T1) -> None:
|
||||
"""Adds item to queue"""
|
||||
|
||||
heapq.heappush(self.items, (item, self.count))
|
||||
self.count += 1
|
||||
|
||||
def remove(self, item: _T1) -> bool:
|
||||
"""Remove given item from queue"""
|
||||
|
||||
for index, _item in enumerate(self.items):
|
||||
if _item[0] == item:
|
||||
self.items.pop(index)
|
||||
heapq.heapify(self.items)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Remove all items from the queue."""
|
||||
self.items = []
|
||||
self.count = PriorityQueue.MIN_COUNT
|
||||
@@ -0,0 +1,61 @@
|
||||
from functools import update_wrapper
|
||||
from types import FunctionType
|
||||
from typing import TYPE_CHECKING, Any, Callable, Iterable, Optional, TypeVar, cast
|
||||
|
||||
from typing_extensions import ParamSpec
|
||||
|
||||
from reactivex import abc
|
||||
from reactivex.disposable import CompositeDisposable
|
||||
from reactivex.disposable.refcountdisposable import RefCountDisposable
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from reactivex import Observable
|
||||
|
||||
_T = TypeVar("_T")
|
||||
_P = ParamSpec("_P")
|
||||
|
||||
|
||||
def add_ref(xs: "Observable[_T]", r: RefCountDisposable) -> "Observable[_T]":
|
||||
from reactivex import Observable
|
||||
|
||||
def subscribe(
|
||||
observer: abc.ObserverBase[Any], scheduler: Optional[abc.SchedulerBase] = None
|
||||
) -> abc.DisposableBase:
|
||||
return CompositeDisposable(r.disposable, xs.subscribe(observer))
|
||||
|
||||
return Observable(subscribe)
|
||||
|
||||
|
||||
def infinite() -> Iterable[int]:
|
||||
n = 0
|
||||
while True:
|
||||
yield n
|
||||
n += 1
|
||||
|
||||
|
||||
def alias(name: str, doc: str, fun: Callable[_P, _T]) -> Callable[_P, _T]:
|
||||
# Adapted from
|
||||
# https://stackoverflow.com/questions/13503079/how-to-create-a-copy-of-a-python-function#
|
||||
# See also help(type(lambda: 0))
|
||||
_fun = cast(FunctionType, fun)
|
||||
args = (_fun.__code__, _fun.__globals__)
|
||||
kwargs = {"name": name, "argdefs": _fun.__defaults__, "closure": _fun.__closure__}
|
||||
alias_ = FunctionType(*args, **kwargs) # type: ignore
|
||||
alias_ = update_wrapper(alias_, _fun)
|
||||
alias_.__kwdefaults__ = _fun.__kwdefaults__
|
||||
alias_.__doc__ = doc
|
||||
alias_.__annotations__ = _fun.__annotations__
|
||||
return cast(Callable[_P, _T], alias_)
|
||||
|
||||
|
||||
class NotSet:
|
||||
"""Sentinel value."""
|
||||
|
||||
def __eq__(self, other: Any) -> bool:
|
||||
return self is other
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "NotSet"
|
||||
|
||||
|
||||
__all__ = ["add_ref", "infinite", "alias", "NotSet"]
|
||||
205
myenv/lib/python3.12/site-packages/reactivex/notification.py
Normal file
205
myenv/lib/python3.12/site-packages/reactivex/notification.py
Normal file
@@ -0,0 +1,205 @@
|
||||
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)
|
||||
@@ -0,0 +1,5 @@
|
||||
from .connectableobservable import ConnectableObservable
|
||||
from .groupedobservable import GroupedObservable
|
||||
from .observable import Observable
|
||||
|
||||
__all__ = ["Observable", "ConnectableObservable", "GroupedObservable"]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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,31 @@
|
||||
from typing import TypeVar
|
||||
|
||||
from reactivex import Observable, never
|
||||
from reactivex import operators as _
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
def amb_(*sources: Observable[_T]) -> Observable[_T]:
|
||||
"""Propagates the observable sequence that reacts first.
|
||||
|
||||
Example:
|
||||
>>> winner = amb(xs, ys, zs)
|
||||
|
||||
Returns:
|
||||
An observable sequence that surfaces any of the given sequences,
|
||||
whichever reacted first.
|
||||
"""
|
||||
|
||||
acc: Observable[_T] = never()
|
||||
|
||||
def func(previous: Observable[_T], current: Observable[_T]) -> Observable[_T]:
|
||||
return _.amb(previous)(current)
|
||||
|
||||
for source in sources:
|
||||
acc = func(acc, source)
|
||||
|
||||
return acc
|
||||
|
||||
|
||||
__all__ = ["amb_"]
|
||||
@@ -0,0 +1,35 @@
|
||||
from asyncio import Future
|
||||
from typing import Callable, Mapping, Optional, TypeVar, Union
|
||||
|
||||
from reactivex import Observable, abc, defer, empty, from_future
|
||||
|
||||
_Key = TypeVar("_Key")
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
def case_(
|
||||
mapper: Callable[[], _Key],
|
||||
sources: Mapping[_Key, Observable[_T]],
|
||||
default_source: Optional[Union[Observable[_T], "Future[_T]"]] = None,
|
||||
) -> Observable[_T]:
|
||||
|
||||
default_source_: Union[Observable[_T], "Future[_T]"] = default_source or empty()
|
||||
|
||||
def factory(_: abc.SchedulerBase) -> Observable[_T]:
|
||||
try:
|
||||
result: Union[Observable[_T], "Future[_T]"] = sources[mapper()]
|
||||
except KeyError:
|
||||
result = default_source_
|
||||
|
||||
if isinstance(result, Future):
|
||||
|
||||
result_: Observable[_T] = from_future(result)
|
||||
else:
|
||||
result_ = result
|
||||
|
||||
return result_
|
||||
|
||||
return defer(factory)
|
||||
|
||||
|
||||
__all__ = ["case_"]
|
||||
@@ -0,0 +1,84 @@
|
||||
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_"]
|
||||
@@ -0,0 +1,76 @@
|
||||
from typing import Any, List, Optional, Tuple
|
||||
|
||||
from reactivex import Observable, abc
|
||||
from reactivex.disposable import CompositeDisposable, SingleAssignmentDisposable
|
||||
|
||||
|
||||
def combine_latest_(*sources: Observable[Any]) -> Observable[Tuple[Any, ...]]:
|
||||
"""Merges the specified observable sequences into one observable
|
||||
sequence by creating a tuple whenever any of the
|
||||
observable sequences produces an element.
|
||||
|
||||
Examples:
|
||||
>>> obs = combine_latest(obs1, obs2, obs3)
|
||||
|
||||
Returns:
|
||||
An observable sequence containing the result of combining
|
||||
elements of the sources into a tuple.
|
||||
"""
|
||||
|
||||
parent = sources[0]
|
||||
|
||||
def subscribe(
|
||||
observer: abc.ObserverBase[Any], scheduler: Optional[abc.SchedulerBase] = None
|
||||
) -> CompositeDisposable:
|
||||
|
||||
n = len(sources)
|
||||
has_value = [False] * n
|
||||
has_value_all = [False]
|
||||
is_done = [False] * n
|
||||
values = [None] * n
|
||||
|
||||
def _next(i: Any) -> None:
|
||||
has_value[i] = True
|
||||
|
||||
if has_value_all[0] or all(has_value):
|
||||
res = tuple(values)
|
||||
observer.on_next(res)
|
||||
|
||||
elif all([x for j, x in enumerate(is_done) if j != i]):
|
||||
observer.on_completed()
|
||||
|
||||
has_value_all[0] = all(has_value)
|
||||
|
||||
def done(i: Any) -> None:
|
||||
is_done[i] = True
|
||||
if all(is_done):
|
||||
observer.on_completed()
|
||||
|
||||
subscriptions: List[Optional[SingleAssignmentDisposable]] = [None] * n
|
||||
|
||||
def func(i: int) -> None:
|
||||
subscriptions[i] = SingleAssignmentDisposable()
|
||||
|
||||
def on_next(x: Any) -> None:
|
||||
with parent.lock:
|
||||
values[i] = x
|
||||
_next(i)
|
||||
|
||||
def on_completed() -> None:
|
||||
with parent.lock:
|
||||
done(i)
|
||||
|
||||
subscription = subscriptions[i]
|
||||
assert subscription
|
||||
subscription.disposable = sources[i].subscribe(
|
||||
on_next, observer.on_error, on_completed, scheduler=scheduler
|
||||
)
|
||||
|
||||
for idx in range(n):
|
||||
func(idx)
|
||||
return CompositeDisposable(subscriptions)
|
||||
|
||||
return Observable(subscribe)
|
||||
|
||||
|
||||
__all__ = ["combine_latest_"]
|
||||
@@ -0,0 +1,62 @@
|
||||
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 concat_with_iterable_(sources: Iterable[Observable[_T]]) -> Observable[_T]:
|
||||
def subscribe(
|
||||
observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None
|
||||
) -> abc.DisposableBase:
|
||||
_scheduler = scheduler_ or CurrentThreadScheduler.singleton()
|
||||
|
||||
sources_ = iter(sources)
|
||||
|
||||
subscription = SerialDisposable()
|
||||
cancelable = SerialDisposable()
|
||||
is_disposed = False
|
||||
|
||||
def action(scheduler: abc.SchedulerBase, state: Any = None) -> None:
|
||||
nonlocal is_disposed
|
||||
if is_disposed:
|
||||
return
|
||||
|
||||
def on_completed() -> None:
|
||||
cancelable.disposable = _scheduler.schedule(action)
|
||||
|
||||
try:
|
||||
current = next(sources_)
|
||||
except StopIteration:
|
||||
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,
|
||||
observer.on_error,
|
||||
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__ = ["concat_with_iterable_"]
|
||||
@@ -0,0 +1,82 @@
|
||||
from typing import List, Optional, TypeVar
|
||||
|
||||
from reactivex import abc
|
||||
from reactivex.disposable import CompositeDisposable, Disposable
|
||||
|
||||
from .observable import Observable
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class ConnectableObservable(Observable[_T]):
|
||||
"""Represents an observable that can be connected and
|
||||
disconnected."""
|
||||
|
||||
def __init__(self, source: abc.ObservableBase[_T], subject: abc.SubjectBase[_T]):
|
||||
self.subject = subject
|
||||
self.has_subscription = False
|
||||
self.subscription: Optional[abc.DisposableBase] = None
|
||||
self.source = source
|
||||
|
||||
super().__init__()
|
||||
|
||||
def _subscribe_core(
|
||||
self,
|
||||
observer: abc.ObserverBase[_T],
|
||||
scheduler: Optional[abc.SchedulerBase] = None,
|
||||
) -> abc.DisposableBase:
|
||||
return self.subject.subscribe(observer, scheduler=scheduler)
|
||||
|
||||
def connect(
|
||||
self, scheduler: Optional[abc.SchedulerBase] = None
|
||||
) -> Optional[abc.DisposableBase]:
|
||||
"""Connects the observable."""
|
||||
|
||||
if not self.has_subscription:
|
||||
self.has_subscription = True
|
||||
|
||||
def dispose() -> None:
|
||||
self.has_subscription = False
|
||||
|
||||
subscription = self.source.subscribe(self.subject, scheduler=scheduler)
|
||||
self.subscription = CompositeDisposable(subscription, Disposable(dispose))
|
||||
|
||||
return self.subscription
|
||||
|
||||
def auto_connect(self, subscriber_count: int = 1) -> Observable[_T]:
|
||||
"""Returns an observable sequence that stays connected to the
|
||||
source indefinitely to the observable sequence.
|
||||
Providing a subscriber_count will cause it to connect() after
|
||||
that many subscriptions occur. A subscriber_count of 0 will
|
||||
result in emissions firing immediately without waiting for
|
||||
subscribers.
|
||||
"""
|
||||
|
||||
connectable_subscription: List[Optional[abc.DisposableBase]] = [None]
|
||||
count = [0]
|
||||
source = self
|
||||
is_connected = [False]
|
||||
|
||||
if subscriber_count == 0:
|
||||
connectable_subscription[0] = source.connect()
|
||||
is_connected[0] = True
|
||||
|
||||
def subscribe(
|
||||
observer: abc.ObserverBase[_T],
|
||||
scheduler: Optional[abc.SchedulerBase] = None,
|
||||
) -> abc.DisposableBase:
|
||||
count[0] += 1
|
||||
should_connect = count[0] == subscriber_count and not is_connected[0]
|
||||
subscription = source.subscribe(observer)
|
||||
if should_connect:
|
||||
connectable_subscription[0] = source.connect(scheduler)
|
||||
is_connected[0] = True
|
||||
|
||||
def dispose() -> None:
|
||||
subscription.dispose()
|
||||
count[0] -= 1
|
||||
is_connected[0] = False
|
||||
|
||||
return Disposable(dispose)
|
||||
|
||||
return Observable(subscribe)
|
||||
@@ -0,0 +1,43 @@
|
||||
from asyncio import Future
|
||||
from typing import Callable, Optional, TypeVar, Union
|
||||
|
||||
from reactivex import Observable, abc, from_future, throw
|
||||
from reactivex.scheduler import ImmediateScheduler
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
def defer_(
|
||||
factory: Callable[[abc.SchedulerBase], Union[Observable[_T], "Future[_T]"]]
|
||||
) -> Observable[_T]:
|
||||
"""Returns an observable sequence that invokes the specified factory
|
||||
function whenever a new observer subscribes.
|
||||
|
||||
Example:
|
||||
>>> res = defer(lambda scheduler: of(1, 2, 3))
|
||||
|
||||
Args:
|
||||
observable_factory: Observable factory function to invoke for
|
||||
each observer that subscribes to the resulting sequence. The
|
||||
factory takes a single argument, the scheduler used.
|
||||
|
||||
Returns:
|
||||
An observable sequence whose observers trigger an invocation
|
||||
of the given observable factory function.
|
||||
"""
|
||||
|
||||
def subscribe(
|
||||
observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None
|
||||
) -> abc.DisposableBase:
|
||||
try:
|
||||
result = factory(scheduler or ImmediateScheduler.singleton())
|
||||
except Exception as ex: # By design. pylint: disable=W0703
|
||||
return throw(ex).subscribe(observer)
|
||||
|
||||
result = from_future(result) if isinstance(result, Future) else result
|
||||
return result.subscribe(observer, scheduler=scheduler)
|
||||
|
||||
return Observable(subscribe)
|
||||
|
||||
|
||||
__all__ = ["defer_"]
|
||||
@@ -0,0 +1,22 @@
|
||||
from typing import Any, Optional
|
||||
|
||||
from reactivex import Observable, abc
|
||||
from reactivex.scheduler import ImmediateScheduler
|
||||
|
||||
|
||||
def empty_(scheduler: Optional[abc.SchedulerBase] = None) -> Observable[Any]:
|
||||
def subscribe(
|
||||
observer: abc.ObserverBase[Any], scheduler_: Optional[abc.SchedulerBase] = None
|
||||
) -> abc.DisposableBase:
|
||||
|
||||
_scheduler = scheduler or scheduler_ or ImmediateScheduler.singleton()
|
||||
|
||||
def action(_: abc.SchedulerBase, __: Any) -> None:
|
||||
observer.on_completed()
|
||||
|
||||
return _scheduler.schedule(action)
|
||||
|
||||
return Observable(subscribe)
|
||||
|
||||
|
||||
__all__ = ["empty_"]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user