def test_timeout_schedule_action(self): scheduler = TimeoutScheduler() ran = False def action(scheduler, state): nonlocal ran ran = True scheduler.schedule(action) sleep(0.1) assert ran is True
def test_timeout_schedule_action_cancel(self): ran = False scheduler = TimeoutScheduler() def action(scheduler, state): nonlocal ran ran = True d = scheduler.schedule_relative(timedelta(milliseconds=300), action) d.dispose() sleep(0.1) assert ran is False
def test_timeout_schedule_action_due(self): scheduler = TimeoutScheduler() starttime = default_now() endtime = None def action(scheduler, state): nonlocal endtime endtime = default_now() scheduler.schedule_relative(timedelta(milliseconds=200), action) sleep(0.4) assert endtime is not None diff = endtime - starttime assert diff > timedelta(milliseconds=180)
def test_timeout_now_units(self): scheduler = TimeoutScheduler() diff = scheduler.now sleep(1.1) diff = scheduler.now - diff assert timedelta(milliseconds=1000) < diff < timedelta( milliseconds=1300)
def subscribe( observer: abc.ObserverBase[int], scheduler_: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton() nonlocal duetime if not isinstance(duetime, datetime): duetime = _scheduler.now + _scheduler.to_timedelta(duetime) p = max(0.0, _scheduler.to_seconds(period)) mad = MultipleAssignmentDisposable() dt = duetime count = 0 def action(scheduler: abc.SchedulerBase, state: Any) -> None: nonlocal dt nonlocal count if p > 0.0: now = scheduler.now dt = dt + scheduler.to_timedelta(p) if dt <= now: dt = now + scheduler.to_timedelta(p) observer.on_next(count) count += 1 mad.disposable = scheduler.schedule_absolute(dt, action) mad.disposable = _scheduler.schedule_absolute(dt, action) return mad
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) duration = _scheduler.to_timedelta(window_duration or 0.0) if duration <= _scheduler.to_timedelta(0): raise ValueError( "window_duration cannot be less or equal zero.") last_on_next: Optional[datetime] = None def on_next(x: _T) -> None: nonlocal last_on_next emit = False now = _scheduler.now with source.lock: if not last_on_next or now - last_on_next >= duration: last_on_next = now emit = True if emit: observer.on_next(x) return source.subscribe(on_next, observer.on_error, observer.on_completed, scheduler=_scheduler)
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: nonlocal duration _scheduler: abc.SchedulerBase = (scheduler or scheduler_ or TimeoutScheduler.singleton()) duration = _scheduler.to_timedelta(duration) q: List[Dict[str, Any]] = [] def on_next(x: _T) -> None: now = _scheduler.now q.append({"interval": now, "value": x}) while q and now - q[0]["interval"] >= duration: observer.on_next(q.pop(0)["value"]) def on_completed() -> None: now = _scheduler.now while q and now - q[0]["interval"] >= duration: observer.on_next(q.pop(0)["value"]) observer.on_completed() return source.subscribe(on_next, observer.on_error, on_completed, scheduler=_scheduler)
def factory(scheduler_: Optional[abc.SchedulerBase] = None): _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) def mapper(value: _T) -> Timestamp[_T]: return Timestamp(value=value, timestamp=_scheduler.now) return source.pipe(operators.map(mapper))
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) switched = [False] _id = [0] original = SingleAssignmentDisposable() subscription = SerialDisposable() timer = SerialDisposable() subscription.disposable = original def create_timer() -> None: my_id = _id[0] def action(scheduler: abc.SchedulerBase, state: Any = None): switched[0] = _id[0] == my_id timer_wins = switched[0] if timer_wins: subscription.disposable = obs.subscribe( observer, scheduler=scheduler) if isinstance(duetime, datetime): timer.disposable = _scheduler.schedule_absolute( duetime, action) else: timer.disposable = _scheduler.schedule_relative( duetime, action) create_timer() def on_next(value: _T) -> None: send_wins = not switched[0] if send_wins: _id[0] += 1 observer.on_next(value) create_timer() def on_error(error: Exception) -> None: on_error_wins = not switched[0] if on_error_wins: _id[0] += 1 observer.on_error(error) def on_completed() -> None: on_completed_wins = not switched[0] if on_completed_wins: _id[0] += 1 observer.on_completed() original.disposable = source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_) return CompositeDisposable(subscription, timer)
def test_timeout_singleton(self): scheduler = [TimeoutScheduler(), TimeoutScheduler.singleton()] assert scheduler[0] is scheduler[1] gate = [threading.Semaphore(0), threading.Semaphore(0)] scheduler = [None, None] def run(idx): scheduler[idx] = TimeoutScheduler() 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 scheduler[1]
def test_timeout_extend(self): class MyScheduler(TimeoutScheduler): pass scheduler = [ MyScheduler(), MyScheduler.singleton(), TimeoutScheduler.singleton(), ] assert scheduler[0] is scheduler[1] assert scheduler[0] is not scheduler[2]
def subscribe( observer: abc.ObserverBase[int], scheduler_: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: _scheduler: abc.SchedulerBase = (scheduler or scheduler_ or TimeoutScheduler.singleton()) def action(scheduler: abc.SchedulerBase, state: Any) -> None: observer.on_next(0) observer.on_completed() return _scheduler.schedule_absolute(duetime, action)
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton() def action(scheduler: abc.SchedulerBase, state: Any = None): observer.on_completed() disp = _scheduler.schedule_relative(duration, action) return CompositeDisposable( disp, source.subscribe(observer, scheduler=scheduler_) )
def subscribe( observer: abc.ObserverBase[int], scheduler_: Optional[abc.SchedulerBase] = None ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton() d = _scheduler.to_seconds(duetime) def action(scheduler: abc.SchedulerBase, state: Any) -> None: observer.on_next(0) observer.on_completed() if d <= 0.0: return _scheduler.schedule(action) return _scheduler.schedule_relative(d, action)
def subscribe( observer: abc.ObserverBase[int], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler: abc.SchedulerBase = (scheduler or scheduler_ or TimeoutScheduler.singleton()) def action(count: Optional[int] = None) -> Optional[int]: if count is not None: observer.on_next(count) return count + 1 return None if not isinstance(_scheduler, PeriodicScheduler): raise ValueError("Sceduler must be PeriodicScheduler") return _scheduler.schedule_periodic(period, action, state=0)
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) cancelable = SerialDisposable() has_value = [False] value: List[_T] = [cast(_T, None)] _id: List[int] = [0] def on_next(x: _T) -> None: has_value[0] = True value[0] = x _id[0] += 1 current_id = _id[0] d = SingleAssignmentDisposable() cancelable.disposable = d def action(scheduler: abc.SchedulerBase, state: Any = None) -> None: if has_value[0] and _id[0] == current_id: observer.on_next(value[0]) has_value[0] = False d.disposable = _scheduler.schedule_relative(duetime, action) def on_error(exception: Exception) -> None: cancelable.dispose() observer.on_error(exception) has_value[0] = False _id[0] += 1 def on_completed() -> None: cancelable.dispose() if has_value[0]: observer.on_next(value[0]) observer.on_completed() has_value[0] = False _id[0] += 1 subscription = source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_) return CompositeDisposable(subscription, cancelable)
def subscribe( observer: abc.ObserverBase[_TState], scheduler: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: scheduler = scheduler or TimeoutScheduler.singleton() mad = MultipleAssignmentDisposable() state = initial_state has_result = False result: _TState = cast(_TState, None) first = True time: Optional[RelativeTime] = None def action(scheduler: abc.SchedulerBase, _: Any) -> None: nonlocal state nonlocal has_result nonlocal result nonlocal first nonlocal time if has_result: observer.on_next(result) try: if first: first = False else: state = iterate(state) has_result = condition(state) if has_result: result = state time = time_mapper(state) except Exception as e: # pylint: disable=broad-except observer.on_error(e) return if has_result: assert time mad.disposable = scheduler.schedule_relative(time, action) else: observer.on_completed() mad.disposable = scheduler.schedule_relative(0, action) return mad
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) def action(scheduler: abc.SchedulerBase, state: Any = None): observer.on_completed() if isinstance(end_time, datetime): task = _scheduler.schedule_absolute(end_time, action) else: task = _scheduler.schedule_relative(end_time, action) return CompositeDisposable( task, source.subscribe(observer, scheduler=scheduler_))
def subscribe( observer: abc.ObserverBase[TimeInterval[_T]], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) last = _scheduler.now def mapper(value: _T) -> TimeInterval[_T]: nonlocal last now = _scheduler.now span = now - last last = now return TimeInterval(value=value, interval=span) return source.pipe(ops.map(mapper)).subscribe(observer, scheduler=_scheduler)
def to_async_( func: Callable[..., _T], scheduler: Optional[abc.SchedulerBase] = None ) -> Callable[..., Observable[_T]]: """Converts the function into an asynchronous function. Each invocation of the resulting asynchronous function causes an invocation of the original synchronous function on the specified scheduler. Examples: res = reactivex.to_async(lambda x, y: x + y)(4, 3) res = reactivex.to_async(lambda x, y: x + y, Scheduler.timeout)(4, 3) res = reactivex.to_async(lambda x: log.debug(x), Scheduler.timeout)('hello') Args: func: Function to convert to an asynchronous function. scheduler: [Optional] Scheduler to run the function on. If not specified, defaults to Scheduler.timeout. Returns: Aynchronous function. """ _scheduler = scheduler or TimeoutScheduler.singleton() def wrapper(*args: Any) -> Observable[_T]: subject: AsyncSubject[_T] = AsyncSubject() def action(scheduler: abc.SchedulerBase, state: Any = None) -> None: try: result = func(*args) except Exception as ex: # pylint: disable=broad-except subject.on_error(ex) return subject.on_next(result) subject.on_completed() _scheduler.schedule(action) return subject.pipe(ops.as_observable()) return wrapper
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ): _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton() open = [False] def action(scheduler: abc.SchedulerBase, state: Any) -> None: open[0] = True t = _scheduler.schedule_relative(duration, action) def on_next(x: _T): if open[0]: observer.on_next(x) d = source.subscribe( on_next, observer.on_error, observer.on_completed, scheduler=scheduler_ ) return CompositeDisposable(t, d)
def subscribe( observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None, ): _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) open = [False] def on_next(x: _T) -> None: if open[0]: observer.on_next(x) subscription = source.subscribe(on_next, observer.on_error, observer.on_completed, scheduler=scheduler_) def action(scheduler: abc.SchedulerBase, state: Any): open[0] = True disp = getattr(_scheduler, scheduler_method)(start_time, action) return CompositeDisposable(disp, subscription)
def subscribe( observer: abc.ObserverBase[Observable[_T]], scheduler_: Optional[abc.SchedulerBase] = None, ) -> abc.DisposableBase: _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) n: int = 0 s: Subject[_T] = Subject() timer_d = SerialDisposable() window_id = 0 group_disposable = CompositeDisposable(timer_d) ref_count_disposable = RefCountDisposable(group_disposable) def create_timer(_id: int): nonlocal n, s, window_id m = SingleAssignmentDisposable() timer_d.disposable = m def action(scheduler: abc.SchedulerBase, state: Any = None): nonlocal n, s, window_id if _id != window_id: return n = 0 window_id += 1 new_id = window_id s.on_completed() s = Subject() observer.on_next(add_ref(s, ref_count_disposable)) create_timer(new_id) m.disposable = _scheduler.schedule_relative(timespan, action) observer.on_next(add_ref(s, ref_count_disposable)) create_timer(0) def on_next(x: _T) -> None: nonlocal n, s, window_id new_window = False new_id = 0 s.on_next(x) n += 1 if n == count: new_window = True n = 0 window_id += 1 new_id = window_id s.on_completed() s = Subject() observer.on_next(add_ref(s, ref_count_disposable)) if new_window: create_timer(new_id) def on_error(e: Exception) -> None: s.on_error(e) observer.on_error(e) def on_completed() -> None: s.on_completed() observer.on_completed() group_disposable.add( source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_)) return ref_count_disposable
def subscribe(observer: abc.ObserverBase[_T], scheduler_: Optional[abc.SchedulerBase] = None): nonlocal duetime _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton() if isinstance(duetime, datetime): duetime_ = _scheduler.to_datetime(duetime) - _scheduler.now else: duetime_ = _scheduler.to_timedelta(duetime) cancelable = SerialDisposable() exception: Optional[Exception] = None active = [False] running = [False] queue: List[Timestamp[Notification[_T]]] = [] def on_next(notification: Timestamp[Notification[_T]]) -> None: nonlocal exception should_run = False with source.lock: if isinstance(notification.value, OnError): del queue[:] queue.append(notification) exception = notification.value.exception should_run = not running[0] else: queue.append( Timestamp( value=notification.value, timestamp=notification.timestamp + duetime_, )) should_run = not active[0] active[0] = True if should_run: if exception: observer.on_error(exception) else: mad = MultipleAssignmentDisposable() cancelable.disposable = mad def action(scheduler: abc.SchedulerBase, state: Any = None): if exception: return with source.lock: running[0] = True while True: result = None if queue and queue[ 0].timestamp <= scheduler.now: result = queue.pop(0).value if result: result.accept(observer) if not result: break should_continue = False recurse_duetime: typing.RelativeTime = 0 if queue: should_continue = True diff = queue[0].timestamp - scheduler.now recurse_duetime = max(DELTA_ZERO, diff) else: active[0] = False ex = exception running[0] = False if ex: observer.on_error(ex) elif should_continue: mad.disposable = scheduler.schedule_relative( recurse_duetime, action) mad.disposable = _scheduler.schedule_relative( duetime_, action) subscription = source.pipe( ops.materialize(), ops.timestamp(), ).subscribe(on_next, scheduler=_scheduler) return CompositeDisposable(subscription, cancelable)
def test_timeout_now(self): scheduler = TimeoutScheduler() diff = scheduler.now - default_now() assert abs(diff) < timedelta(milliseconds=1)
def subscribe( observer: abc.ObserverBase[Observable[_T]], scheduler_: Optional[abc.SchedulerBase] = None, ): _scheduler = scheduler or scheduler_ or TimeoutScheduler.singleton( ) timer_d = SerialDisposable() next_shift = [timeshift] next_span = [timespan] total_time = [DELTA_ZERO] queue: List[Subject[_T]] = [] group_disposable = CompositeDisposable(timer_d) ref_count_disposable = RefCountDisposable(group_disposable) def create_timer(): m = SingleAssignmentDisposable() timer_d.disposable = m is_span = False is_shift = False if next_span[0] == next_shift[0]: is_span = True is_shift = True elif next_span[0] < next_shift[0]: is_span = True else: is_shift = True new_total_time = next_span[0] if is_span else next_shift[0] ts = new_total_time - total_time[0] total_time[0] = new_total_time if is_span: next_span[0] += timeshift if is_shift: next_shift[0] += timeshift @synchronized(source.lock) def action(scheduler: abc.SchedulerBase, state: Any = None): s: Optional[Subject[_T]] = None if is_shift: s = Subject() queue.append(s) observer.on_next(add_ref(s, ref_count_disposable)) if is_span: s = queue.pop(0) s.on_completed() create_timer() m.disposable = _scheduler.schedule_relative(ts, action) queue.append(Subject()) observer.on_next(add_ref(queue[0], ref_count_disposable)) create_timer() def on_next(x: _T) -> None: with source.lock: for s in queue: s.on_next(x) @synchronized(source.lock) def on_error(e: Exception) -> None: for s in queue: s.on_error(e) observer.on_error(e) @synchronized(source.lock) def on_completed() -> None: for s in queue: s.on_completed() observer.on_completed() group_disposable.add( source.subscribe(on_next, on_error, on_completed, scheduler=scheduler_)) return ref_count_disposable
def run(idx): scheduler[idx] = TimeoutScheduler() gate[idx].release()