def test_currentthread_schedule(self): scheduler = CurrentThreadScheduler() ran = False def action(scheduler, state=None): nonlocal ran ran = True scheduler.schedule(action) assert ran is True
def test_currentthread_schedule_error(self): scheduler = CurrentThreadScheduler() class MyException(Exception): pass def action(scheduler, state=None): raise MyException() with pytest.raises(MyException): scheduler.schedule(action)
def test_currentthread_schedule_block(self): scheduler = CurrentThreadScheduler() ran = False def action(scheduler, state=None): nonlocal ran ran = True t = scheduler.now scheduler.schedule_relative(0.2, action) t = scheduler.now - t assert ran is True assert t >= timedelta(seconds=0.2)
def test_currentthread_schedule_nested(self): scheduler = CurrentThreadScheduler() ran = False def action(scheduler, state=None): def inner_action(scheduler, state=None): nonlocal ran ran = True return scheduler.schedule(inner_action) scheduler.schedule(action) assert ran is True
def outer(scheduler, state=None): def action1(scheduler, state=None): tests.append(1) def action2(scheduler, state=None): tests.append(2) CurrentThreadScheduler().schedule(action2) CurrentThreadScheduler().schedule(action1) def action3(scheduler, state=None): tests.append(3) CurrentThreadScheduler().schedule(action3)
def subscribe( observer: abc.ObserverBase[_T], scheduler: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: scheduler = scheduler or CurrentThreadScheduler.singleton() subscription = SerialDisposable() cancelable = SerialDisposable() def action(scheduler: abc.SchedulerBase, state: Optional[Exception] = None) -> None: try: source = next(sources_) except StopIteration: observer.on_completed() return # Allow source to be a factory method taking an error source = source(state) if callable(source) else source current = (reactivex.from_future(source) if isinstance( source, Future) else source) d = SingleAssignmentDisposable() subscription.disposable = d def on_resume(state: Optional[Exception] = None) -> None: scheduler.schedule(action, state) d.disposable = current.subscribe(observer.on_next, on_resume, on_resume, scheduler=scheduler) cancelable.disposable = scheduler.schedule(action) return CompositeDisposable(subscription, cancelable)
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or CurrentThreadScheduler.singleton( ) iterator = iter(iterable) disposed = False def action(_: abc.SchedulerBase, __: Any = None) -> None: nonlocal disposed try: while not disposed: value = next(iterator) observer.on_next(value) except StopIteration: observer.on_completed() except Exception as error: # pylint: disable=broad-except observer.on_error(error) def dispose() -> None: nonlocal disposed disposed = True disp = Disposable(dispose) return CompositeDisposable(_scheduler.schedule(action), disp)
def test_currentthread_now_units(self): scheduler = CurrentThreadScheduler() diff = scheduler.now sleep(1.1) diff = scheduler.now - diff assert timedelta(milliseconds=1000) < diff < timedelta( milliseconds=1300)
def test_currentthread_ensuretrampoline_nested(self): scheduler = CurrentThreadScheduler() ran1, ran2 = False, False def outer_action(scheduler, state): def inner_action1(scheduler, state): nonlocal ran1 ran1 = True scheduler.schedule(inner_action1) def inner_action2(scheduler, state): nonlocal ran2 ran2 = True return scheduler.schedule(inner_action2) scheduler.ensure_trampoline(outer_action) assert ran1 is True assert ran2 is True
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or CurrentThreadScheduler.singleton( ) def action(scheduler: abc.SchedulerBase, state: Any = None) -> None: observer.on_next(value) observer.on_completed() return _scheduler.schedule(action)
def test_currentthread_ensuretrampoline_and_cancel(self): scheduler = CurrentThreadScheduler() ran1, ran2 = False, False def outer_action(scheduler, state): def inner_action1(scheduler, state): nonlocal ran1 ran1 = True def inner_action2(scheduler, state): nonlocal ran2 ran2 = True d = scheduler.schedule(inner_action2) d.dispose() return scheduler.schedule(inner_action1) scheduler.ensure_trampoline(outer_action) assert ran1 is True assert ran2 is False
def test_currentthread_extend(self): class MyScheduler(CurrentThreadScheduler): pass scheduler = [ MyScheduler(), MyScheduler.singleton(), MyScheduler.singleton(), CurrentThreadScheduler.singleton(), ] assert scheduler[0] is not scheduler[1] assert scheduler[1] is scheduler[2] assert scheduler[1] is not scheduler[3]
def test_currentthread_singleton(self): scheduler = [ CurrentThreadScheduler(), CurrentThreadScheduler.singleton(), CurrentThreadScheduler.singleton(), ] assert scheduler[0] is not scheduler[1] assert scheduler[1] is scheduler[2] gate = [threading.Semaphore(0), threading.Semaphore(0)] scheduler = [None, None] def run(idx): scheduler[idx] = CurrentThreadScheduler.singleton() gate[idx].release() for idx in (0, 1): threading.Thread(target=run, args=(idx, )).start() gate[idx].acquire() assert scheduler[0] is not None assert scheduler[1] is not None assert scheduler[0] is not scheduler[1]
def test_currentthread_schedule_nested_order(self): scheduler = CurrentThreadScheduler() tests = [] def outer(scheduler, state=None): def action1(scheduler, state=None): tests.append(1) def action2(scheduler, state=None): tests.append(2) CurrentThreadScheduler().schedule(action2) CurrentThreadScheduler().schedule(action1) def action3(scheduler, state=None): tests.append(3) CurrentThreadScheduler().schedule(action3) scheduler.ensure_trampoline(outer) assert tests == [1, 2, 3]
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or CurrentThreadScheduler.singleton( ) def action(_: abc.SchedulerBase, __: Any = None) -> None: nonlocal observer try: observer.on_next(supplier()) observer.on_completed() except Exception as e: # pylint: disable=broad-except observer.on_error(e) return _scheduler.schedule(action)
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))
def subscribe( observer: abc.ObserverBase[int], scheduler_: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: nonlocal range_t _scheduler = scheduler or scheduler_ or CurrentThreadScheduler.singleton() sd = MultipleAssignmentDisposable() def action( scheduler: abc.SchedulerBase, iterator: Optional[Iterator[int]] ) -> None: try: assert iterator observer.on_next(next(iterator)) sd.disposable = _scheduler.schedule(action, state=iterator) except StopIteration: observer.on_completed() sd.disposable = _scheduler.schedule(action, iter(range_t)) return sd
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: List[QueueItem] = []
def test_currentthread_now(self): scheduler = CurrentThreadScheduler() diff = scheduler.now - default_now() assert abs(diff) < timedelta(milliseconds=5)
def run(idx): scheduler[idx] = CurrentThreadScheduler.singleton() gate[idx].release()
def subscribe( self, on_next: Optional[Union[abc.ObserverBase[_T], abc.OnNext[_T], None]] = None, on_error: Optional[abc.OnError] = None, on_completed: Optional[abc.OnCompleted] = None, *, scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: """Subscribe an observer to the observable sequence. You may subscribe using an observer or callbacks, not both; if the first argument is an instance of :class:`Observer <..abc.ObserverBase>` or if it has a (callable) attribute named :code:`on_next`, then any callback arguments will be ignored. Examples: >>> source.subscribe() >>> source.subscribe(observer) >>> source.subscribe(observer, scheduler=scheduler) >>> source.subscribe(on_next) >>> source.subscribe(on_next, on_error) >>> source.subscribe(on_next, on_error, on_completed) >>> source.subscribe(on_next, on_error, on_completed, scheduler=scheduler) Args: observer: [Optional] The object that is to receive notifications. on_error: [Optional] Action to invoke upon exceptional termination of the observable sequence. on_completed: [Optional] Action to invoke upon graceful termination of the observable sequence. on_next: [Optional] Action to invoke for each element in the observable sequence. scheduler: [Optional] The default scheduler to use for this subscription. Returns: Disposable object representing an observer's subscription to the observable sequence. """ if (isinstance(on_next, abc.ObserverBase) or hasattr(on_next, "on_next") and callable(getattr(on_next, "on_next"))): obv = cast(abc.ObserverBase[_T], on_next) on_next = obv.on_next on_error = obv.on_error on_completed = obv.on_completed auto_detach_observer: AutoDetachObserver[_T] = AutoDetachObserver( on_next, on_error, on_completed) def fix_subscriber( subscriber: Union[abc.DisposableBase, Callable[[], None]] ) -> abc.DisposableBase: """Fixes subscriber to make sure it returns a Disposable instead of None or a dispose function""" if isinstance(subscriber, abc.DisposableBase) or hasattr( subscriber, "dispose"): # Note: cast can be avoided using Protocols (Python 3.9) return cast(abc.DisposableBase, subscriber) return Disposable(subscriber) def set_disposable(_: Optional[abc.SchedulerBase] = None, __: Any = None) -> None: try: subscriber = self._subscribe_core(auto_detach_observer, scheduler) except Exception as ex: # By design. pylint: disable=W0703 if not auto_detach_observer.fail(ex): raise else: auto_detach_observer.subscription = fix_subscriber(subscriber) # Subscribe needs to set up the trampoline before for subscribing. # Actually, the first call to Subscribe creates the trampoline so # that it may assign its disposable before any observer executes # OnNext over the CurrentThreadScheduler. This enables single- # threaded cancellation # https://social.msdn.microsoft.com/Forums/en-US/eb82f593-9684-4e27- # 97b9-8b8886da5c33/whats-the-rationale-behind-how-currentthreadsche # dulerschedulerequired-behaves?forum=rx current_thread_scheduler = CurrentThreadScheduler.singleton() if current_thread_scheduler.schedule_required(): current_thread_scheduler.schedule(set_disposable) else: set_disposable() # Hide the identity of the auto detach observer return Disposable(auto_detach_observer.dispose)