def subscribe(observer, scheduler=None): window = [Subject()] d = CompositeDisposable() r = RefCountDisposable(d) observer.on_next(add_ref(window[0], r)) def on_next_window(x): window[0].on_next(x) def on_error(err): window[0].on_error(err) observer.on_error(err) def on_completed(): window[0].on_completed() observer.on_completed() d.add(source.subscribe_(on_next_window, on_error, on_completed, scheduler)) def on_next_observer(w): window[0].on_completed() window[0] = Subject() observer.on_next(add_ref(window[0], r)) d.add(window_boundaries.subscribe_(on_next_observer, on_error, on_completed, scheduler)) return r
def _subscribe_core(self, observer=None, scheduler=None) -> typing.Disposable: clock = self.scheduler.to_seconds(self.scheduler.now) self.subscriptions.append(Subscription(clock)) index = len(self.subscriptions) - 1 disp = CompositeDisposable() def get_action(notification): def action(scheduler, state): notification.accept(observer) return Disposable() return action for message in self.messages: notification = message.value # Don't make closures within a loop action = get_action(notification) disp.add(self.scheduler.schedule_relative(message.time, action)) def dispose() -> None: start = self.subscriptions[index].subscribe end = self.scheduler.to_seconds(self.scheduler.now) self.subscriptions[index] = Subscription(start, end) disp.dispose() return Disposable(dispose)
def subscribe(observer, scheduler=None): group = CompositeDisposable() is_stopped = [False] m = SingleAssignmentDisposable() group.add(m) def on_next(inner_source): inner_subscription = SingleAssignmentDisposable() group.add(inner_subscription) inner_source = from_future(inner_source) if is_future(inner_source) else inner_source @synchronized(source.lock) def on_completed(): group.remove(inner_subscription) if is_stopped[0] and len(group) == 1: observer.on_completed() on_next = synchronized(source.lock)(observer.on_next) on_error = synchronized(source.lock)(observer.on_error) subscription = inner_source.subscribe_(on_next, on_error, on_completed, scheduler) inner_subscription.disposable = subscription def on_completed(): is_stopped[0] = True if len(group) == 1: observer.on_completed() m.disposable = source.subscribe_(on_next, observer.on_error, on_completed, scheduler) return group
def subscribe(observer, scheduler=None): was_invoked = [False] def on_completed(): observer.on_completed() try: if not was_invoked[0]: finally_action() was_invoked[0] = True except Exception as err: # pylint: disable=broad-except observer.on_error(err) def on_error(exception): observer.on_error(exception) try: if not was_invoked[0]: finally_action() was_invoked[0] = True except Exception as err: # pylint: disable=broad-except observer.on_error(err) composite_disposable = CompositeDisposable() composite_disposable.add(OnDispose(was_invoked)) subscription = source.subscribe_(observer.on_next, on_error, on_completed, scheduler) composite_disposable.add(subscription) return composite_disposable
def subscribe(observer, scheduler_=None): _scheduler = scheduler or scheduler_ or timeout_scheduler n = [0] s = [None] timer_d = SerialDisposable() window_id = [0] group_disposable = CompositeDisposable(timer_d) ref_count_disposable = RefCountDisposable(group_disposable) def create_timer(_id): m = SingleAssignmentDisposable() timer_d.disposable = m def action(scheduler, state): if _id != window_id[0]: return n[0] = 0 window_id[0] += 1 new_id = window_id[0] s[0].on_completed() s[0] = Subject() observer.on_next(add_ref(s[0], ref_count_disposable)) create_timer(new_id) m.disposable = _scheduler.schedule_relative(timespan, action) s[0] = Subject() observer.on_next(add_ref(s[0], ref_count_disposable)) create_timer(0) def on_next(x): new_window = False new_id = 0 s[0].on_next(x) n[0] += 1 if n[0] == count: new_window = True n[0] = 0 window_id[0] += 1 new_id = window_id[0] s[0].on_completed() s[0] = Subject() observer.on_next(add_ref(s[0], ref_count_disposable)) if new_window: create_timer(new_id) def on_error(e): s[0].on_error(e) observer.on_error(e) def on_completed(): s[0].on_completed() observer.on_completed() group_disposable.add(source.subscribe_(on_next, on_error, on_completed, scheduler_)) return ref_count_disposable
def subscribe(observer, scheduler=None): is_open = [False] def on_next(left): if is_open[0]: observer.on_next(left) def on_completed(): if is_open[0]: observer.on_completed() subs = source.subscribe_(on_next, observer.on_error, on_completed, scheduler) subscriptions = CompositeDisposable(subs) right_subscription = SingleAssignmentDisposable() subscriptions.add(right_subscription) def on_next2(x): is_open[0] = True right_subscription.dispose() def on_completed2(): right_subscription.dispose() right_subscription.disposable = other.subscribe_(on_next2, observer.on_error, on_completed2, scheduler) return subscriptions
def run(self): srcs = list(self.parent.sources) N = len(srcs) self.queues = [None] * N self.isDone = [False] * N self.subscriptions = [None] * N self.gate = RLock() for i in range(0, N): self.queues[i] = deque() # Loop twice because subscribing could already yield # a value before all queues are initialized for i in range(0, N): d = SingleAssignmentDisposable() self.subscriptions[i] = d o = self.O(self, i) d.disposable = srcs[i].subscribeSafe(o) c = CompositeDisposable(self.subscriptions) def dispose(): for q in self.queues: q.clear() c.add(Disposable.create(dispose)) return c
def test_groupdisposable_clear(): disp1 = [False] disp2 = [False] def action1(): disp1[0] = True d1 = Disposable(action1) def action2(): disp2[0] = True d2 = Disposable(action2) g = CompositeDisposable(d1, d2) assert g.length == 2 g.clear() assert disp1[0] assert disp2[0] assert not g.length disp3 = [False] def action3(): disp3[0] = True d3 = Disposable(action3) g.add(d3); assert not disp3[0] assert g.length == 1
def test_groupdisposable_contains(): d1 = Disposable() d2 = Disposable() g = CompositeDisposable(d1, d2) assert g.length == 2 assert g.contains(d1) assert g.contains(d2)
def run(self): self.gate = RLock() groupDisposable = CompositeDisposable() self.refCountDisposable = RefCountDisposable(groupDisposable) self.createWindow() groupDisposable.add(self.parent.scheduler.schedulePeriodic(self.parent.timeSpan, self.tick)) groupDisposable.add(self.parent.source.subscribeSafe(self)) return self.refCountDisposable
def test_groupdisposable_remove(): disp1 = [False] disp2 = [False] def action1(): disp1[0] = True d1 = Disposable(action1) def action2(): disp2[0] = True d2 = Disposable(action2) g = CompositeDisposable(d1, d2) assert g.length == 2 assert g.contains(d1) assert g.contains(d2) assert g.remove(d1) assert g.length == 1 assert not g.contains(d1) assert g.contains(d2) assert disp1[0] assert g.remove(d2) assert not g.contains(d1) assert not g.contains(d2) assert disp2[0] disp3 = [False] def action3(): disp3[0] = True d3 = Disposable(action3) assert not g.remove(d3) assert not disp3[0]
def _qtimer_schedule(self, time, action, state, periodic=False): scheduler = self msecs = int(self.to_seconds(time)*1000.0) sad = SingleAssignmentDisposable() periodic_state = [state] def interval(): if periodic: periodic_state[0] = action(periodic_state[0]) else: sad.disposable = action(scheduler, state) log.debug("timeout: %s", msecs) timer = self.qtcore.QTimer() timer.setSingleShot(not periodic) timer.timeout.connect(interval) timer.setInterval(msecs) timer.start() self._timers.add(timer) def dispose(): timer.stop() self._timers.remove(timer) return CompositeDisposable(sad, Disposable(dispose))
def _wxtimer_schedule(self, time, action, state, periodic=False): scheduler = self sad = SingleAssignmentDisposable() periodic_state = [state] def interval(): if periodic: periodic_state[0] = action(periodic_state[0]) else: sad.disposable = action(scheduler, state) msecs = int(self.to_seconds(time) * 1000.0) if msecs == 0: msecs = 1 # wx.Timer doesn't support zero. log.debug("timeout: %s", msecs) timer = self._timer_class(interval) timer.Start( msecs, self.wx.TIMER_CONTINUOUS if periodic else self.wx.TIMER_ONE_SHOT) self._timers.add(timer) def dispose(): timer.Stop() self._timers.remove(timer) return CompositeDisposable(sad, Disposable(dispose))
def _gtk_schedule(self, time: typing.AbsoluteOrRelativeTime, action: typing.ScheduledSingleOrPeriodicAction, state: Optional[typing.TState] = None, periodic: bool = False) -> typing.Disposable: msecs = max(0, int(self.to_seconds(time) * 1000.0)) sad = SingleAssignmentDisposable() stopped = False def timer_handler(_) -> bool: if stopped: return False nonlocal state if periodic: state = action(state) else: sad.disposable = self.invoke_action(action, state=state) return periodic self._glib.timeout_add(msecs, timer_handler, None) def dispose() -> None: nonlocal stopped stopped = True return CompositeDisposable(sad, Disposable(dispose))
def unsafe_subscribe( self, subscriber: MultiCastSubscriber) -> MultiCastSubscription: def on_completed(): for subject in imperative_call.subjects: subject.on_completed() def on_error(exc: Exception): for subject in imperative_call.subjects: subject.on_error(exc) composite_disposable_ = composite_disposable or CompositeDisposable( ) builder = ImperativeMultiCastBuilder( composite_disposable=composite_disposable_, subscriber=subscriber, # source_scheduler=subscriber.source_scheduler, # multicast_scheduler=subscriber.multicast_scheduler, ) imperative_call = func(builder) flowable = imperative_call.blocking_flowable.pipe( rxbp.op.do_action( on_disposed=lambda: composite_disposable_.dispose(), on_completed=on_completed, on_error=on_error, ), ).materialize().share() return imperative_call.output_selector( flowable, ).unsafe_subscribe(subscriber=subscriber)
class FromFlowableMultiCastObserver(Observer): next_observer: MultiCastObserver subscriber: MultiCastSubscriber composite_disposable: CompositeDisposable() def on_next(self, elem: MultiCastItem) -> Ack: def scheduler_action(): def action(_, __): try: self.next_observer.on_next(elem) self.next_observer.on_completed() except Exception as exc: self.next_observer.on_error(exc) return self.subscriber.subscribe_schedulers[1].schedule(action) disposable = self.subscriber.schedule_action( index=0, action=scheduler_action, ) self.composite_disposable.add(disposable) return continue_ack def on_error(self, exc: Exception) -> None: self.next_observer.on_error(exc) def on_completed(self) -> None: self.next_observer.on_completed()
def on_subscribe(observer, scheduler=None): def subscribe_all(parent, *children): parent_subscription = SingleAssignmentDisposable() values = [NO_VALUE for _ in children] def on_parent_next(value): if NO_VALUE not in values: result = (value, ) + tuple(values) observer.on_next(result) def subscribe_child(i, child): subscription = SingleAssignmentDisposable() def on_next(value): values[i] = value if NO_VALUE not in values and parent_subscription.disposable is None: disp = parent.subscribe(on_parent_next, observer.on_error, observer.on_completed, scheduler=scheduler) parent_subscription.disposable = disp subscription.disposable = child.subscribe( on_next, observer.on_error, scheduler=scheduler) return subscription children_subscription = [ subscribe_child(i, child) for i, child in enumerate(children) ] return [parent_subscription] + children_subscription return CompositeDisposable(subscribe_all(parent, *sources))
def schedule_relative( self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: Optional[typing.TState] = None) -> typing.Disposable: """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). """ seconds = max(0.0, self.to_seconds(duetime)) sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = action(self, state) log.debug("timeout: %s", seconds) timer = self._reactor.callLater(seconds, interval) def dispose() -> None: if not timer.called: timer.cancel() return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative(self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: typing.TState = None) -> typing.Disposable: """Schedules an action to be executed after duetime. Args: duetime: Relative time after which to execute the action. action: Action to be executed. Returns: The disposable object used to cancel the scheduled action (best effort). """ seconds = self.to_seconds(duetime) if not seconds: return self.schedule(action, state) sad = SingleAssignmentDisposable() def interval(): sad.disposable = self.invoke_action(action, state) timer = [eventlet.spawn_after(seconds, interval)] def dispose(): # nonlocal timer timer[0].kill() return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative(self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: Optional[typing.TState] = None ) -> typing.Disposable: """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). """ sad = SingleAssignmentDisposable() def invoke_action() -> None: sad.disposable = self.invoke_action(action, state=state) msecs = int(self.to_seconds(duetime) * 1000.0) alarm = self.master.after(msecs, invoke_action) def dispose() -> None: self.master.after_cancel(alarm) return CompositeDisposable(sad, Disposable(dispose))
def subscribe(observer, scheduler=None): at_end = [None] has_value = [None] value = [None] def sample_subscribe(x=None): if has_value[0]: has_value[0] = False observer.on_next(value[0]) if at_end[0]: observer.on_completed() def on_next(new_value): has_value[0] = True value[0] = new_value def on_completed(): at_end[0] = True return CompositeDisposable( source.subscribe_(on_next, observer.on_error, on_completed, scheduler), sampler.subscribe_(sample_subscribe, observer.on_error, sample_subscribe, scheduler))
def observe(self, observer_info: ObserverInfo): """ sources[0] ------------------------> Subject -- \ sources[1] -> ConnectableObserver -> Subject -----> ConcatObserver ... / sources[n] -> ConnectableObserver -> Subject -- """ conn_observers = [ ConnectableObserver(underlying=None, ) for _ in self.sources ] iter_conn_obs = iter(conn_observers) concat_observer = ConcatObserver( next_observer=observer_info.observer, connectables=iter_conn_obs, ) for conn_observer in conn_observers: conn_observer.underlying = concat_observer def gen_disposable_from_observer(): for source, conn_observer in zip(self.sources[1:], conn_observers): yield source.observe( observer_info.copy(observer=conn_observer, )) others_disposables = gen_disposable_from_observer() first_disposable = self.sources[0].observe( observer_info.copy(observer=concat_observer, )) return CompositeDisposable(first_disposable, *others_disposables)
def from_marbles(string: str, timespan: RelativeTime = 0.1, lookup: Dict = None, error: Exception = None, scheduler: Scheduler = None) -> Observable: disp = CompositeDisposable() messages = parse(string, timespan=timespan, lookup=lookup, error=error, raise_stopped=True) def schedule_msg(message, observer, scheduler): timespan, notification = message def action(scheduler, state=None): notification.accept(observer) disp.add(scheduler.schedule_relative(timespan, action)) def subscribe(observer, scheduler_): _scheduler = scheduler or scheduler_ or new_thread_scheduler for message in messages: # Don't make closures within a loop schedule_msg(message, observer, _scheduler) return disp return Observable(subscribe)
def subscribe(observer, scheduler=None) -> Disposable: cancelable = SerialDisposable() has_value = [False] value = [None] _id = [0] def on_next(x): throttle = None try: throttle = throttle_duration_mapper(x) except Exception as e: # pylint: disable=broad-except observer.on_error(e) return has_value[0] = True value[0] = x _id[0] += 1 current_id = _id[0] d = SingleAssignmentDisposable() cancelable.disposable = d def on_next(x: Any) -> None: if has_value[0] and _id[0] == current_id: observer.on_next(value[0]) has_value[0] = False d.dispose() def on_completed() -> None: if has_value[0] and _id[0] == current_id: observer.on_next(value[0]) has_value[0] = False d.dispose() d.disposable = throttle.subscribe_(on_next, observer.on_error, on_completed, scheduler=scheduler) def on_error(e) -> None: cancelable.dispose() observer.on_error(e) 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 schedule_relative(self, duetime: RelativeTime, action: ScheduledAction, state: TState = None): """Schedules an action to be executed after duetime. """ duetime = int(self.to_seconds(duetime) * 1000.0) if duetime <= 0: return self.schedule(action, state) scheduler = self is_disposed = False sad = SingleAssignmentDisposable() def invoke_action(): if not is_disposed: sad.disposable = action(scheduler, state) def dispose(): nonlocal is_disposed is_disposed = True self._post(SCHEDULE_RELATIVE, invoke_action, duetime) return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative(self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: typing.TState = None) -> typing.Disposable: """Schedules an action to be executed after duetime. Args: duetime: Relative time after which to execute the action. action: Action to be executed. Returns: The disposable object used to cancel the scheduled action (best effort). """ scheduler = self msecs = int(self.to_seconds(duetime) * 1000.0) sad = SingleAssignmentDisposable() is_disposed = False def invoke_action(): if not is_disposed: sad.disposable = action(scheduler, state) log.debug("relative timeout: %sms", msecs) # Use static method, let Qt C++ handle QTimer lifetime self.qtcore.QTimer.singleShot(msecs, invoke_action) def dispose(): nonlocal is_disposed is_disposed = True return CompositeDisposable(sad, Disposable(dispose))
def subscribe(observer, scheduler=None): scheduler = scheduler or current_thread_scheduler subscription = SerialDisposable() cancelable = SerialDisposable() last_exception = [None] is_disposed = [] def action(action1, state=None): def on_error(exn): last_exception[0] = exn cancelable.disposable = scheduler.schedule(action) if is_disposed: return try: current = next(sources) except StopIteration: if last_exception[0]: observer.on_error(last_exception[0]) 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) cancelable.disposable = scheduler.schedule(action) def dispose(): is_disposed.append(True) return CompositeDisposable(subscription, cancelable, Disposable(dispose))
def schedule(self, action: typing.ScheduledAction, state: Optional[typing.TState] = None ) -> typing.Disposable: """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). """ sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = self.invoke_action(action, state=state) handle = self._loop.call_soon_threadsafe(interval) def dispose() -> None: future = Future() def cancel_handle() -> None: handle.cancel() future.set_result(0) self._loop.call_soon_threadsafe(cancel_handle) future.result() return CompositeDisposable(sad, Disposable(dispose))
def subscribe( observer: typing.Observer, scheduler_: Optional[typing.Scheduler] = None ) -> typing.Disposable: _scheduler = scheduler or scheduler_ or CurrentThreadScheduler.singleton( ) iterator = iter(iterable) disposed = False def action(_: typing.Scheduler, __: 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 observe(self, observer_info: ObserverInfo): self.observer = observer_info.observer class ZipLeftObserver(Observer): def on_next(_, elem: ElementType) -> Ack: return self._on_next_left(elem) def on_error(_, exc: Exception): self._on_error(exc) def on_completed(_): self._on_completed_left() class ZipRightObserver(Observer): def on_next(_, elem: ElementType) -> Ack: return self._on_next_right(elem) def on_error(_, exc: Exception): self._on_error(exc) def on_completed(_): self._on_completed_right() left_observer = ZipLeftObserver() left_subscription = observer_info.copy(observer=left_observer, ) d1 = self.left.observe(left_subscription) right_observer = ZipRightObserver() right_subscription = observer_info.copy(observer=right_observer, ) d2 = self.right.observe(right_subscription) return CompositeDisposable(d1, d2)
def schedule_relative(self, duetime, action, state=None): """Schedules an action to be executed after duetime. Keyword arguments: duetime -- {timedelta} Relative time after which to execute the action. action -- {Function} Action to be executed. Returns {Disposable} The disposable object used to cancel the scheduled action (best effort).""" scheduler = self seconds = self.to_seconds(duetime) if not seconds: return scheduler.schedule(action, state) sad = SingleAssignmentDisposable() def interval(): sad.disposable = action(scheduler, state) log.debug("timeout: %s", seconds) timer = [gevent.spawn_later(seconds, interval)] def dispose(): # nonlocal timer timer[0].kill() return CompositeDisposable(sad, Disposable(dispose))
def schedule_relative( self, duetime: RelativeTime, action, state=None, ): if isinstance(duetime, datetime.datetime): timedelta = duetime - datetime.datetime.fromtimestamp(0) timespan = float(timedelta.total_seconds()) elif isinstance(duetime, datetime.timedelta): timespan = float(duetime.total_seconds()) else: timespan = duetime def func(): action(self, None) disposable = [MultipleAssignmentDisposable()] def _(): def __(): future = self.executor.submit(func) disposable[0] = Disposable(lambda: future.cancel()) self.loop.call_later(timespan, __) future = self.loop.call_soon_threadsafe(_) return CompositeDisposable(disposable, Disposable(lambda: future.cancel()))
def schedule_relative(self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: Optional[typing.TState] = None ) -> typing.Disposable: """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). """ from twisted.internet.task import deferLater seconds = self.to_seconds(duetime) sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = action(self, state) log.debug("timeout: %s", seconds) handle = deferLater(self.reactor, seconds, interval).addErrback(lambda _: None) def dispose() -> None: if not handle.called: handle.cancel() return CompositeDisposable(sad, Disposable(dispose))
def observe(self, observer_info: ObserverInfo): observer_info = observer_info.observer d1 = BooleanDisposable() def action(_, __): try: item = next(self.iterator) has_next = True except StopIteration: has_next = False except Exception as e: # stream errors observer_info.on_error(e) return Disposable() if not has_next: observer_info.on_completed() else: # start sending items self.fast_loop(item, observer_info, self.scheduler, d1, self.scheduler.get_execution_model(), sync_index=0) d2 = self.subscribe_scheduler.schedule(action) return CompositeDisposable(d1, d2)
def schedule_relative( self, duetime: typing.RelativeTime, action: typing.ScheduledAction, state: Optional[typing.TState] = None) -> typing.Disposable: """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). """ seconds = self.to_seconds(duetime) if seconds <= 0.0: return self.schedule(action, state) sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = self.invoke_action(action, state) timer = Timer(seconds, interval) timer.daemon = True timer.start() def dispose() -> None: timer.cancel() return CompositeDisposable(sad, Disposable(dispose))
def run(self): self.scheduler = self.parent.scheduler self.cancelTimer = SerialDisposable() self.gate = RLock() self.active = False # as soon as a value arrived self.running = False # on relative: True, on absolute: True after absolute time self.queue = deque() self.hasCompleted = False self.completeAt = 0 self.hasFailed = False self.exception = None self.delay = 0 self.startTime = self.scheduler.now() if self.parent.isAbsolute: self.ready = False self.cancelTimer.disposable = self.scheduler.scheduleWithAbsolute( self.parent.dueTime, self.start) else: self.ready = True self.delay = Scheduler.normalize(self.parent.dueTime) self.sourceSubscription = SingleAssignmentDisposable() self.sourceSubscription.disposable = self.parent.source.subscribeSafe( self) return CompositeDisposable(self.sourceSubscription, self.cancelTimer)
def _gtk_schedule(self, time: typing.AbsoluteOrRelativeTime, action: typing.ScheduledSingleOrPeriodicAction, state: Optional[typing.TState] = None, periodic: bool = False) -> typing.Disposable: # Do not import GLib into global scope because Qt and GLib # don't like each other there from gi.repository import GLib msecs = int(self.to_seconds(time) * 1000.0) sad = SingleAssignmentDisposable() periodic_state = state stopped = False def timer_handler(_) -> bool: if stopped: return False if periodic: nonlocal periodic_state periodic_state = action(periodic_state) else: sad.disposable = self.invoke_action(action, state=state) return periodic GLib.timeout_add(msecs, timer_handler, None) def dispose() -> None: nonlocal stopped stopped = True return CompositeDisposable(sad, Disposable(dispose))
def schedule(self, action: typing.ScheduledAction, state: Optional[typing.TState] = None) -> typing.Disposable: """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). """ sad = SingleAssignmentDisposable() def interval() -> None: sad.disposable = self.invoke_action(action, state) timer = Timer(0, interval) timer.daemon = True timer.start() def dispose() -> None: timer.cancel() return CompositeDisposable(sad, Disposable(dispose))
def subscribe(observer, scheduler=None): scheduler = scheduler or current_thread_scheduler subscription = SerialDisposable() cancelable = SerialDisposable() def action(scheduler, state=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 = rx.from_future(source) if is_future(source) else source d = SingleAssignmentDisposable() subscription.disposable = d def on_resume(state=None): scheduler.schedule(action, state) d.disposable = current.subscribe_(observer.on_next, on_resume, on_resume, scheduler) cancelable.disposable = scheduler.schedule(action) return CompositeDisposable(subscription, cancelable)
def _wxtimer_schedule(self, time: typing.AbsoluteOrRelativeTime, action: typing.ScheduledSingleOrPeriodicAction, state: Optional[typing.TState] = None, periodic: bool = False) -> typing.Disposable: scheduler = self sad = SingleAssignmentDisposable() def interval() -> None: nonlocal state if periodic: state = action(state) else: sad.disposable = action(scheduler, state) msecs = int(self.to_seconds(time) * 1000.0) log.debug("timeout wx: %s", msecs) timer = self._timer_class(interval) timer.Start( msecs, self.wx.TIMER_CONTINUOUS if periodic else self.wx.TIMER_ONE_SHOT) self._timers.add(timer) def dispose() -> None: timer.Stop() self._timers.remove(timer) return CompositeDisposable(sad, Disposable(dispose))
def _gtk_schedule(self, time, action, state, periodic=False): # Do not import GLib into global scope because Qt and GLib # don't like each other there from gi.repository import GLib scheduler = self msecs = int(self.to_seconds(time)*1000) sad = SingleAssignmentDisposable() periodic_state = [state] stopped = [False] def timer_handler(_): if stopped[0]: return False if periodic: periodic_state[0] = action(periodic_state[0]) else: sad.disposable = action(scheduler, state) return periodic GLib.timeout_add(msecs, timer_handler, None) def dispose(): stopped[0] = True return CompositeDisposable(sad, Disposable(dispose))
def run(self): self.gate = RLock() self.s = Subject() self.n = 0 self.windowId = 0 self.timerDisposable = SerialDisposable() groupDisposable = CompositeDisposable(self.timerDisposable) self.refCountDisposable = RefCountDisposable(groupDisposable) # AddRef was originally WindowObservable but this is just an alias for AddRef self.observer.onNext(AddRef(self.s, self.refCountDisposable)) self.createTimer(0) groupDisposable.add(self.parent.source.subscribeSafe(self)) return self.refCountDisposable
class RecursiveScheduledFunction(object): def __init__(self, action, scheduler, method = None): self.action = action self.group = CompositeDisposable() self.lock = RLock() if method == None: self.schedule = scheduler.scheduleWithState else: self.schedule = getattr(scheduler, method) def run(self, state): self.action(state, self.actionCallback) def actionCallback(self, newState, dueTime = None): self.isDone = False self.isAdded = False if dueTime == None: self.cancel = self.schedule( newState, self.schedulerCallback ) else: self.cancel = self.schedule( newState, dueTime, self.schedulerCallback ) with self.lock: if not self.isDone: self.group.add(self.cancel) self.isAdded = True def schedulerCallback(self, scheduler, state): with self.lock: if self.isAdded: self.group.remove(self.cancel) else: self.isDone = True self.run(state) return Disposable.empty()
def run(self, observer, cancel, setSink): self.groupDisposable = CompositeDisposable() self.refCountDisposable = RefCountDisposable(self.groupDisposable) sink = self.Sink(self, observer, cancel) setSink(sink) self.groupDisposable.add(self.source.subscribeSafe(sink)) return self.refCountDisposable
def __init__(self, action, scheduler, method = None): self.action = action self.group = CompositeDisposable() self.lock = RLock() if method == None: self.schedule = scheduler.scheduleWithState else: self.schedule = getattr(scheduler, method)
def run(self): self.totalTime = 0 self.nextShift = self.parent.timeShift self.nextSpan = self.parent.timeSpan self.gate = RLock() self.queue = deque() self.timerDisposable = SerialDisposable() groupDisposable = CompositeDisposable(self.timerDisposable) self.refCountDisposable = RefCountDisposable(groupDisposable) self.createWindow() self.createTimer() groupDisposable.add(self.parent.source.subscribeSafe(self)) return self.refCountDisposable
def run(self): self.gate = RLock() self.isStopped = False self.group = CompositeDisposable() self.sourceSubscription = SingleAssignmentDisposable() self.group.add(self.sourceSubscription) self.sourceSubscription.disposable = self.parent.sources.subscribeSafe(self) return self.group
def run(self): self.delays = CompositeDisposable() self.gate = RLock() self.atEnd = False self.subscription = SerialDisposable() if self.parent.subscriptionDelay == None: self.start() else: self.subscription.disposable = self.parent.subscriptionDelay.subscribeSafe(self.Sigma(self)) return CompositeDisposable(self.subscription, self.delays)
def subscribe(observer, scheduler=None): m = SerialDisposable() d = CompositeDisposable(m) r = RefCountDisposable(d) window = [Subject()] observer.on_next(add_ref(window[0], r)) def on_next(value): window[0].on_next(value) def on_error(error): window[0].on_error(error) observer.on_error(error) def on_completed(): window[0].on_completed() observer.on_completed() d.add(source.subscribe_(on_next, on_error, on_completed, scheduler)) def create_window_on_completed(): try: window_close = window_closing_mapper() except Exception as exception: observer.on_error(exception) return def on_completed(): window[0].on_completed() window[0] = Subject() observer.on_next(add_ref(window[0], r)) create_window_on_completed() m1 = SingleAssignmentDisposable() m.disposable = m1 m1.disposable = window_close.pipe(ops.take(1)).subscribe_(noop, on_error, on_completed, scheduler) create_window_on_completed() return r
def test_groupdisposable_addafterdispose(): disp1 = [False] disp2 = [False] def action1(): disp1[0] = True d1 = Disposable(action1) def action2(): disp2[0] = True d2 = Disposable(action2) g = CompositeDisposable(d1) assert g.length == 1 g.dispose() assert disp1[0] assert g.length == 0 g.add(d2) assert disp2[0] assert g.length == 0
def subscribe(observer, scheduler=None): active_count = [0] group = CompositeDisposable() is_stopped = [False] queue = [] def subscribe(xs): subscription = SingleAssignmentDisposable() group.add(subscription) @synchronized(source.lock) def on_completed(): group.remove(subscription) if queue: s = queue.pop(0) subscribe(s) else: active_count[0] -= 1 if is_stopped[0] and active_count[0] == 0: observer.on_completed() on_next = synchronized(source.lock)(observer.on_next) on_error = synchronized(source.lock)(observer.on_error) subscription.disposable = xs.subscribe_(on_next, on_error, on_completed, scheduler) def on_next(inner_source): if active_count[0] < max_concurrent: active_count[0] += 1 subscribe(inner_source) else: queue.append(inner_source) def on_completed(): is_stopped[0] = True if active_count[0] == 0: observer.on_completed() group.add(source.subscribe_(on_next, observer.on_error, on_completed, scheduler)) return group
def subscribe(observer, scheduler=None): has_current = [False] is_stopped = [False] m = SingleAssignmentDisposable() g = CompositeDisposable() g.add(m) def on_next(inner_source): if not has_current[0]: has_current[0] = True inner_source = rx.from_future(inner_source) if is_future(inner_source) else inner_source inner_subscription = SingleAssignmentDisposable() g.add(inner_subscription) def on_completed_inner(): g.remove(inner_subscription) has_current[0] = False if is_stopped[0] and len(g) == 1: observer.on_completed() inner_subscription.disposable = inner_source.subscribe_( observer.on_next, observer.on_error, on_completed_inner, scheduler ) def on_completed(): is_stopped[0] = True if not has_current[0] and len(g) == 1: observer.on_completed() m.disposable = source.subscribe_(on_next, observer.on_error, on_completed, scheduler) return g
def run(self): self.gate = RLock() self.group = CompositeDisposable() self.refCount = RefCountDisposable(self.group) leftSubscription = SingleAssignmentDisposable() self.group.add(leftSubscription) self.leftID = 0 self.leftMap = {} rightSubscription = SingleAssignmentDisposable() self.group.add(rightSubscription) self.rightID = 0 self.rightMap = {} leftSubscription.disposable = self.parent.left.subscribeSafe(self.Left(self, leftSubscription)) rightSubscription.disposable = self.parent.right.subscribeSafe(self.Right(self, rightSubscription)) return self.refCount
def subscribe(observer, scheduler=None): group = CompositeDisposable() rcd = RefCountDisposable(group) left_map = OrderedDict() right_map = OrderedDict() left_id = [0] right_id = [0] def on_next_left(value): subject = Subject() with left.lock: _id = left_id[0] left_id[0] += 1 left_map[_id] = subject try: result = (value, add_ref(subject, rcd)) except Exception as e: log.error("*** Exception: %s" % e) for left_value in left_map.values(): left_value.on_error(e) observer.on_error(e) return observer.on_next(result) for right_value in right_map.values(): subject.on_next(right_value) md = SingleAssignmentDisposable() group.add(md) def expire(): if _id in left_map: del left_map[_id] subject.on_completed() group.remove(md) try: duration = left_duration_mapper(value) except Exception as e: for left_value in left_map.values(): left_value.on_error(e) observer.on_error(e) return def on_error(error): for left_value in left_map.values(): left_value.on_error(error) observer.on_error(error) md.disposable = duration.pipe(ops.take(1)).subscribe_(nothing, on_error, expire, scheduler) def on_error_left(error): for left_value in left_map.values(): left_value.on_error(error) observer.on_error(error) group.add(left.subscribe_(on_next_left, on_error_left, observer.on_completed, scheduler)) def send_right(value): with left.lock: _id = right_id[0] right_id[0] += 1 right_map[_id] = value md = SingleAssignmentDisposable() group.add(md) def expire(): del right_map[_id] group.remove(md) try: duration = right_duration_mapper(value) except Exception as e: for left_value in left_map.values(): left_value.on_error(e) observer.on_error(e) return def on_error(error): with left.lock: for left_value in left_map.values(): left_value.on_error(error) observer.on_error(error) md.disposable = duration.pipe(ops.take(1)).subscribe_(nothing, on_error, expire, scheduler) with left.lock: for left_value in left_map.values(): left_value.on_next(value) def on_error_right(error): for left_value in left_map.values(): left_value.on_error(error) observer.on_error(error) group.add(right.subscribe_(send_right, on_error_right, scheduler=scheduler)) return rcd
class GroupByUntil(Producer): def __init__(self, source, keySelector, elementSelector, durationSelector): self.source = source self.keySelector = keySelector self.elementSelector = elementSelector self.durationSelector = durationSelector def run(self, observer, cancel, setSink): self.groupDisposable = CompositeDisposable() self.refCountDisposable = RefCountDisposable(self.groupDisposable) sink = self.Sink(self, observer, cancel) setSink(sink) self.groupDisposable.add(self.source.subscribeSafe(sink)) return self.refCountDisposable class Sink(rx.linq.sink.Sink): def __init__(self, parent, observer, cancel): super(GroupByUntil.Sink, self).__init__(observer, cancel) self.parent = parent self.map = {} self.null = None self.nullGate = RLock() self.nullGateForDeltas = RLock() self.observerGate = RLock() self.writerGate = RLock() def onNext(self, value): key = None try: key = self.parent.keySelector(value) except Exception as e: self.onError(e) return fireNewMapEntry = False writer = None try: if key == None: with self.nullGate: if self.null == None: self.null = Subject() fireNewMapEntry = True writer = self.null else: if key in self.map: writer = self.map[key] else: writer = Subject() self.map[key] = writer fireNewMapEntry = True except Exception as e: self.onError(e) return if fireNewMapEntry: group = GroupObservable(key, writer, self.parent.refCountDisposable) duration = None durationGroup = GroupObservable(key, writer) try: duration = self.parent.durationSelector(durationGroup) except Exception as e: self.onError(e) return with self.observerGate: self.observer.onNext(group) md = SingleAssignmentDisposable() self.parent.groupDisposable.add(md) md.disposable = duration.subscribeSafe(self.Delta(self, key, writer, md)) element = None try: element = self.parent.elementSelector(value) except Exception as e: self.onError(e) else: with self.writerGate: writer.onNext(element) def onError(self, exception): # # NOTE: A race with OnCompleted triggered by a duration selector is fine when # using Subject<T>. It will transition into a terminal state, making one # of the two calls a no-op by swapping in a DoneObserver<T>. # null = None with self.nullGate: null = self.null if null != None: null.onError(exception) for x in self.map.values(): x.onError(exception) with self.observerGate: self.observer.onError(exception) self.dispose() def onCompleted(self): # # NOTE: A race with OnCompleted triggered by a duration selector is fine when # using Subject<T>. It will transition into a terminal state, making one # of the two calls a no-op by swapping in a DoneObserver<T>. # null = None with self.nullGate: null = self.null if null != None: null.onCompleted() for x in self.map.values(): x.onCompleted() with self.observerGate: self.observer.onCompleted() self.dispose() class Delta(Observer): def __init__(self, parent, key, writer, cancelSelf): self.parent = parent self.key = key self.writer = writer self.cancelSelf = cancelSelf def onNext(self, value): self.onCompleted() def onError(self, exception): self.parent.onError(exception) self.cancelSelf.dispose() def onCompleted(self): if self.key == None: null = None with self.parent.nullGate: null = self.parent.null self.parent.null = None with self.parent.nullGateForDeltas: null.onCompleted() else: try: del self.parent.map[self.key] except KeyError: pass else: with self.parent.writerGate: self.writer.onCompleted() self.parent.parent.groupDisposable.remove(self.cancelSelf)
class SerialSink(rx.linq.sink.Sink): def __init__(self, parent, observer, cancel): super(Merge.SerialSink, self).__init__(observer, cancel) self.parent = parent def run(self): self.gate = RLock() self.isStopped = False self.group = CompositeDisposable() self.sourceSubscription = SingleAssignmentDisposable() self.group.add(self.sourceSubscription) self.sourceSubscription.disposable = self.parent.sources.subscribeSafe(self) return self.group def onNext(self, value): innerSubscription = SingleAssignmentDisposable() self.group.add(innerSubscription) innerSubscription.disposable = value.subscribeSafe(self.LockObserver(self, innerSubscription)) def onError(self, exception): with self.gate: self.observer.onError(exception) self.dispose() def onCompleted(self): self.isStopped = True if self.group.length == 1: # # Notice there can be a race between OnCompleted of the source and any # of the inner sequences, where both see _group.Count == 1, and one is # waiting for the lock. There won't be a double OnCompleted observation # though, because the call to Dispose silences the observer by swapping # in a NopObserver<T>. # with self.gate: self.observer.onCompleted() self.dispose() else: self.sourceSubscription.dispose() class LockObserver(Observer): def __init__(self, parent, subscription): self.parent = parent self.subscription = subscription def onNext(self, value): with self.parent.gate: self.parent.observer.onNext(value) def onError(self, exception): with self.parent.gate: self.parent.observer.onError(exception) self.parent.dispose() def onCompleted(self): self.parent.group.remove(self.subscription) if self.parent.isStopped and self.parent.group.length == 1: # # Notice there can be a race between OnCompleted of the source and any # of the inner sequences, where both see _group.Count == 1, and one is # waiting for the lock. There won't be a double OnCompleted observation # though, because the call to Dispose silences the observer by swapping # in a NopObserver<T>. # with self.parent.gate: self.parent.observer.onCompleted() self.parent.dispose()
def subscribe(observer, scheduler=None): composite_disposable = CompositeDisposable() composite_disposable.add(OnDispose()) subscription = source.subscribe_(observer.on_next, observer.on_error, observer.on_completed, scheduler) composite_disposable.add(subscription) return composite_disposable
def subscribe(observer, scheduler_=None): _scheduler = scheduler or scheduler_ or timeout_scheduler timer_d = SerialDisposable() next_shift = [timeshift] next_span = [timespan] total_time = [DELTA_ZERO] q = [] 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 def action(scheduler, state=None): s = None if is_shift: s = Subject() q.append(s) observer.on_next(add_ref(s, ref_count_disposable)) if is_span: s = q.pop(0) s.on_completed() create_timer() m.disposable = _scheduler.schedule_relative(ts, action) q.append(Subject()) observer.on_next(add_ref(q[0], ref_count_disposable)) create_timer() def on_next(x): for s in q: s.on_next(x) def on_error(e): for s in q: s.on_error(e) observer.on_error(e) def on_completed(): for s in q: s.on_completed() observer.on_completed() group_disposable.add(source.subscribe_(on_next, on_error, on_completed, scheduler_)) return ref_count_disposable
class Sink(rx.linq.sink.Sink): def __init__(self, parent, observer, cancel): super(GroupJoin.Sink, self).__init__(observer, cancel) self.parent = parent def run(self): self.gate = RLock() self.group = CompositeDisposable() self.refCount = RefCountDisposable(self.group) leftSubscription = SingleAssignmentDisposable() self.group.add(leftSubscription) self.leftID = 0 self.leftMap = {} rightSubscription = SingleAssignmentDisposable() self.group.add(rightSubscription) self.rightID = 0 self.rightMap = {} leftSubscription.disposable = self.parent.left.subscribeSafe(self.Left(self, leftSubscription)) rightSubscription.disposable = self.parent.right.subscribeSafe(self.Right(self, rightSubscription)) return self.refCount class Left(Observer): def __init__(self, parent, subscription): self.parent = parent self.subscription = subscription def expire(self, resourceId, group, resource): with self.parent.gate: if resourceId in self.parent.leftMap: del self.parent.leftMap[resourceId] group.onCompleted() self.parent.group.remove(resource) def onNext(self, value): s = Subject() resourceId = 0 with self.parent.gate: self.parent.leftID += 1 resourceId = self.parent.leftID self.parent.leftMap[resourceId] = s # AddRef was originally WindowObservable but this is just an alias for AddRef window = AddRef(s, self.parent.refCount) md = SingleAssignmentDisposable() self.parent.group.add(md) try: duration = self.parent.parent.leftDurationSelector(value) except Exception as e: self.onError(e) return else: md.disposable = duration.subscribeSafe(self.Delta(self, resourceId, s, md)) try: result = self.parent.parent.resultSelector(value, window) except Exception as e: self.onError(e) return else: with self.parent.gate: self.parent.observer.onNext(result) for rightValue in self.parent.rightMap.values(): s.onNext(rightValue) def onError(self, exception): with self.parent.gate: for o in self.parent.leftMap.values(): o.onError(exception) self.parent.observer.onError(exception) self.parent.dispose() def onCompleted(self): with self.parent.gate: self.parent.observer.onCompleted() self.parent.dispose() self.dispose() class Delta(Observer): """Expires parent on Next or Completed""" def __init__(self, parent, resourceId, group, resource): self.parent = parent self.resourceId = resourceId self.group = group self.resource = resource def onNext(self, value): self.parent.expire(self.resourceId, self.group, self.resource) def onError(self, exception): self.parent.onError(exception) def onCompleted(self): self.parent.expire(self.resourceId, self.group, self.resource) #end Delta #end Left class Right(Observer): def __init__(self, parent, subscription): self.parent = parent self.subscription = subscription def expire(self, resourceId, resource): with self.parent.gate: self.parent.rightMap.pop(resourceId, None) self.parent.group.remove(resource) def onNext(self, value): resourceId = 0 with self.parent.gate: self.parent.rightID += 1 resourceId = self.parent.rightID self.parent.rightMap[resourceId] = value md = SingleAssignmentDisposable() self.parent.group.add(md) try: duration = self.parent.parent.rightDurationSelector(value) except Exception as e: self.onError(e) return else: md.disposable = duration.subscribeSafe(self.Delta(self, resourceId, md)) with self.parent.gate: for o in self.parent.leftMap.values(): o.onNext(value) def onError(self, exception): with self.parent.gate: for o in self.parent.leftMap.values(): o.onError(exception) self.parent.observer.onError(exception) self.parent.dispose() def onCompleted(self): self.dispose() class Delta(Observer): """Expires parent on Next or Completed""" def __init__(self, parent, resourceId, resource): self.parent = parent self.resourceId = resourceId self.resource = resource def onNext(self, value): self.parent.expire(self.resourceId, self.resource) def onError(self, exception): self.parent.onError(exception) def onCompleted(self): self.parent.expire(self.resourceId, self.resource)
class ConcurrentSink(rx.linq.sink.Sink): def __init__(self, parent, observer, cancel): super(Merge.ConcurrentSink, self).__init__(observer, cancel) self.parent = parent def run(self): self.gate = RLock() self.q = Queue() self.isStopped = False self.activeCount = 0 self.group = CompositeDisposable() self.sourceSubscription = SingleAssignmentDisposable() self.group.add(self.sourceSubscription) self.sourceSubscription.disposable = self.parent.sources.subscribeSafe(self) return self.group def onNext(self, value): with self.gate: if self.activeCount < self.parent.maxConcurrency: self.activeCount += 1 self.subscribe(value) else: self.q.put_nowait(value) def onError(self, exception): with self.gate: self.observer.onError(exception) self.dispose() def onCompleted(self): with self.gate: self.isStopped = True if self.activeCount == 0: self.observer.onCompleted() self.dispose() else: self.sourceSubscription.dispose() def subscribe(self, innerSource): subscription = SingleAssignmentDisposable() self.group.add(subscription) subscription.disposable = innerSource.subscribeSafe(self.LockObserver(self, subscription)) class LockObserver(Observer): def __init__(self, parent, subscription): self.parent = parent self.subscription = subscription def onNext(self, value): with self.parent.gate: self.parent.observer.onNext(value) def onError(self, exception): with self.parent.gate: self.parent.observer.onError(exception) self.parent.dispose() def onCompleted(self): self.parent.group.remove(self.subscription) with self.parent.gate: if self.parent.q.qsize() > 0: s = self.q.get() self.parent.subscribe(s) else: self.parent.activeCount -= 1 if self.parent.isStopped and self.parent.activeCount == 0: self.parent.observer.onCompleted() self.parent.dispose()