Exemplo n.º 1
0
    def test_return_most_recent(self):
        healths = [
            BasicHealthModel(
                name="test",
                health_status=HealthStatus.DEAD,
                health_message="first",
            ),
            BasicHealthModel(
                name="test",
                health_status=HealthStatus.DEAD,
                health_message="second",
            ),
        ]
        obs_a = rx.of(healths[0]).pipe(ops.timestamp(scheduler=HistoricalScheduler(1)))
        obs_b = rx.of(healths[1]).pipe(ops.timestamp(scheduler=HistoricalScheduler(2)))

        result: BasicHealthModel = None

        def assign(v):
            nonlocal result
            result = v

        obs_a.pipe(ops.combine_latest(obs_b), most_critical()).subscribe(assign)
        self.assertEqual(result.health_status, HealthStatus.DEAD)
        self.assertEqual(result.health_message, "second")
Exemplo n.º 2
0
    def start(self):
        if not self.stopped:
            return
        super().start()
        mouse_source, keyboard_source, engagement_source = self.sources

        initial_keyboard_event = keyboard.KeyboardEvent(keyboard.KEY_UP, 0)
        initial_mouse_event = mouse.ButtonEvent(event_type=mouse.UP,
                                                button=0,
                                                time=time.time())
        self.subscriptions = [
            mouse_source.output.pipe(
                operators.start_with(initial_mouse_event)).pipe(
                    operators.combine_latest(
                        keyboard_source.output.pipe(
                            operators.start_with(initial_keyboard_event)),
                        engagement_source.output)).pipe(
                            operators.throttle_first(0.1))  # in seconds
            .subscribe(self.update)
        ]

        if self.window is None:
            self.window = Window(points=self.points_in_buffer,
                                 toggle_callback=self.toggle_recording)

        self.window.show()
        self.window.activateWindow()
        self.window.raise_()
    def start(self):
        if not self.stopped:
            return
        super().start()
        head_rotation_vector, voice_present = self.sources

        # Observable with all data channels merged into one stream
        obs = head_rotation_vector.output.pipe(
            operators.combine_latest(voice_present.output))
        self.subscriptions = [
            obs.subscribe(self.process_state),
        ]
Exemplo n.º 4
0
def submit(gate: str, keys: List[str], ui: Dict[str,
                                                QWidget]) -> rx.Observable:
    if isinstance(gate, str):
        gate = ui[gate]

    gate = _unwrap_subject(gate)
    items = [_unwrap_subject(ui[k]) for k in keys]

    combined = items[0].pipe(ops.combine_latest(*items[1:]),
                             ops.map(lambda vs: dict(zip(keys, vs))))

    return gate.pipe(ops.filter(lambda x: x), ops.with_latest_from(combined),
                     ops.map(lambda x: x[1]))
Exemplo n.º 5
0
    def _combine_most_critical(*obs: Sequence[rx.Observable]):
        """
        Combines an observable sequence of an observable sequence of BasicHealthModel to an
        observable sequence of BasicHealthModel with the most critical health status. If there
        are multiple BasicHealthModel with the same criticality, the most recent item is
        chosen.

        :param obs: Sequence[rx.Observable[BasicHealthModel]]
        """
        return rx.pipe(
            ops.timestamp(),
            ops.combine_latest(*[x.pipe(ops.timestamp()) for x in obs]),
            most_critical(),
        )
Exemplo n.º 6
0
def main():
    loop = asyncio.get_event_loop()
    io_scheduler = AsyncIOThreadSafeScheduler(loop=loop)
    scheduler = ThreadPoolScheduler(multiprocessing.cpu_count())

    semaphore = Subject()

    semaphore_stream = semaphore.pipe(
        ops.flat_map(lambda _: rx.of(True).pipe(
            ops.delay(ARGS.block_time, scheduler=scheduler),
            ops.start_with(False))), ops.start_with(True))

    video_stream_observable = rx.using(
        lambda: VideoStreamDisposable(),
        lambda d: rx.from_iterable(video_stream_iterable(d.cap)))

    gated_video_stream = video_stream_observable.pipe(
        ops.subscribe_on(scheduler),
        ops.sample(1 / ARGS.fps),  # sample frames based on fps
        ops.combine_latest(semaphore_stream),
        ops.filter(lambda tup: tup[1]),  # proceed only if semaphore allows
        ops.map(lambda tup: tup[0])  # take only frame
    )

    disposable = gated_video_stream.pipe(
        ops.filter(has_face),  # filter frames without faces
        ops.map(lambda frame: Image.fromarray(
            cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))),  # map frame to PIL image
        ops.map(lambda img: img.resize(
            (640, 360))),  # resize image (inference will be faster)
        ops.observe_on(io_scheduler),
        ops.map(lambda img: ImageFacesPair(img, analyse_frame(img))
                ),  # analyse frame for faces
        ops.filter(lambda img_faces_pair: any([
            face.top_prediction.confidence > ARGS.threshold
            for face in img_faces_pair.faces
        ])),  # proceed only if there is a known face in the frame
        ops.throttle_first(1),
        ops.flat_map(unlock_request),  # unlock the door
        ops.do_action(
            on_next=lambda _: semaphore.on_next(True)
        )  # trigger semaphore which will block stream for "block-seconds" seconds (doors are unlocked for that long after unlock request)
    ).subscribe(on_error=lambda e: logger.exception(e))

    try:
        loop.run_forever()
    except Exception as e:
        logger.exception(e)
        logger.info("Smart lock face recognition engine shutdown")
        disposable.dispose()
Exemplo n.º 7
0
def submit(gate: Hashable, keys: List[Hashable], ui: Dict[Hashable, QWidget]) -> rx.Observable:
    try:
        gate = ui[gate]
    except (ValueError, TypeError):
        pass

    gate = _unwrap_subject(gate)
    items = [_unwrap_subject(ui[k]) for k in keys]

    combined = items[0].pipe(
        ops.combine_latest(*items[1:]), ops.map(lambda vs: dict(zip(keys, vs)))
    )

    return gate.pipe(
        ops.filter(lambda x: x),
        ops.with_latest_from(combined),
        ops.map(lambda x: x[1]),
    )
Exemplo n.º 8
0
def serve(config, model, data):
    '''Serves a model

    This operator serves a model. It loads models received on the model
    observable, and executes it on each item received on the data observable. 

    The configuration observable must contain a serve section with the following
    fields:

    * input_field: The input field name used to run inference.
    * output_field: The output field name where inference result is set.

    additionally, a "prepare" field can be set if some data transformation is
    needed before feeding the model. When not present, the input data is
    converted to a numpy array

    Args:
        config: configuration observable.

    Returns:
        An observable of predictions. Each item is a copy of the original datay
        item, with an additional field. The name of the additional field if the
        one set in output_field.
    '''
    predict = model.pipe(
        trace_observable(prefix="model", trace_next_payload=False),
        ops.map(load_mlflow_model),
        ops.combine_latest(config),
        ops.starmap(create_model_predict),
    )

    transforms = config.pipe(
        trace_observable(prefix="prepare", trace_next_payload=False),
        ops.map(create_transform_functions))

    prediction = data.pipe(
        rs.ops.with_latest_from(transforms, predict),
        ops.starmap(infer),
        ops.filter(lambda i: i is not None),
    )

    return prediction,
Exemplo n.º 9
0
    def configure_subscriptions(self, connected):
        if connected:
            self.subjects.image_producer.pipe(
                operators.observe_on(self.feed_scheduler),
                operators.buffer_with_count(self.batch_size),
                bp_operator(BackPressure.DROP, 5),
                operators.take_until(self._stop),
            ).subscribe(ErrorToConsoleObserver(self.feed_image))

            self.inference_comm.back_pressure_chan.pipe(
                operators.subscribe_on(self.process_scheduler),
                operators.take_until(self._stop)).subscribe(
                    ErrorToConsoleObserver(self.update_back_pressure_status))

            # report error when image source is still producing when back pressuring
            self.subjects.analyzer_back_pressure_detected.pipe(
                operators.combine_latest(self.subjects.image_producer),
                operators.filter(lambda x: x[0]),
                operators.throttle_first(1.0),
                operators.take_until(self._stop),
            ).subscribe(
                ErrorToConsoleObserver(lambda x: self.logger.warning(
                    "Image is feeding while back-pressure is detected. Please slow down the FPS"
                )))

            self.inference_comm.result_chan.pipe(
                operators.subscribe_on(self.process_scheduler),
                operators.take_until(self._stop)).subscribe(
                    ErrorToConsoleObserver(self.result_processing))

            self.inference_comm.error_chan.pipe(
                operators.take_until(self._stop)).subscribe(
                    ErrorToConsoleObserver(lambda err: self.logger.error(err)))
            self.inference_comm.connection_chan.pipe(
                operators.take_until(self._stop)).subscribe(
                    ErrorToConsoleObserver(lambda connected: self.logger.info(
                        "GRPC Remote analyzer connected" if connected else
                        "GRPC Remote analyzer disconnected")))
            self.inference_comm.stats_chan.take_until(self._stop).subscribe(
                ErrorToConsoleObserver(lambda x: self.logger.info(
                    f"Processed {x.frame} frames. Average {x.processTime / x.frame} secs"
                )))
Exemplo n.º 10
0
    def test_returns_dead_over_unhealthy(self):
        healths = [
            BasicHealthModel(
                name="test",
                health_status=HealthStatus.DEAD,
            ),
            BasicHealthModel(
                name="test",
                health_status=HealthStatus.UNHEALTHY,
            ),
        ]
        obs_a = rx.of(healths[0]).pipe(ops.timestamp(scheduler=HistoricalScheduler(1)))
        obs_b = rx.of(healths[1]).pipe(ops.timestamp(scheduler=HistoricalScheduler(2)))

        result: BasicHealthModel = None

        def assign(v):
            nonlocal result
            result = v

        obs_a.pipe(ops.combine_latest(obs_b), most_critical()).subscribe(assign)
        self.assertEqual(result.health_status, HealthStatus.DEAD)
Exemplo n.º 11
0
    def start(self):
        # report more image when back pressure
        self.subjects.image_producer.pipe(
            operators.observe_on(self.scheduler),
            operators.combine_latest(
                self.subjects.analyzer_back_pressure_detected),
            operators.filter(
                lambda x: x[1]),  # only operate when back pressure
            operators.buffer_with_time(1.0),  # in 1 sec
            operators.filter(lambda x: len(x) > 3),  # more than 3 emission
            operators.throttle_first(3.0),  # report every 3 seconds
            operators.take_until(self._stop),
        ).subscribe(self.report_back_pressure_emission)

        self.subjects.image_producer.pipe(
            operators.observe_on(
                self.scheduler),  # prevent blocking the upstream subject
            operators.filter(self.back_pressure_barrier),
            operators.buffer_with_count(5),
            bp_drop_report_full(self.subjects.analyzer_back_pressure_detected,
                                3, 1),
            operators.take_until(self._stop),
        ).subscribe(ErrorToConsoleObserver(self.produce_fake_analyze_data))
        super(TestAnalyzer, self).start()
Exemplo n.º 12
0
 def create():
     return e1.pipe(
         ops.combine_latest(e2),
         ops.map(sum),
         )
Exemplo n.º 13
0
 def create():
     return e1.pipe(
         ops.combine_latest(e2),
         ops.map(lambda xy: _raise(ex)),
         )
 def create():
     return e1.pipe(
         ops.combine_latest(e2),
         ops.map(sum),
     )
 def create():
     return e1.pipe(
         ops.combine_latest(e2),
         ops.map(lambda xy: _raise(ex)),
     )
op.catch()
op.retry()

"""Utility"""
op.delay()
op.materialize()
op.time_interval()
op.timeout()
op.timestamp()

"""Conditional and Boolean"""
op.all()
op.contains()
op.default_if_empty()
op.sequence_equal()
op.skip_until()
op.skip_while()
op.take_until()
op.take_while()

"""Connectable"""
op.publish()
op.ref_count()
op.replay()

"""Combining"""
op.combine_latest()
op.merge()
op.start_with()
op.zip()
Exemplo n.º 17
0
    def run(self,
            print_output=True,
            ct: Optional[CancellationToken] = None,
            poll_interval=10,
            first_check=0.2,
            max_time=None,
            ct_check=0.2) -> rx.Observable:
        """Starts the MCERD process.

        Args:
            print_output: whether MCERD output is also printed to console
            ct: token that is checked periodically to see if
                the simulation should be stopped.
            poll_interval: seconds between each check to see if the simulation
                process is still running.
            first_check: seconds until the first time mcerd is polled.
            max_time: maximum running time in seconds.
            ct_check: how often cancellation is checked in seconds.

        Return:
            observable stream where each item is a dictionary. All dictionaries
            contain the same keys.
        """
        # Create files necessary to run MCERD
        self.create_mcerd_files()
        cmd = self.get_command()
        ct = ct or CancellationToken()

        process = subprocess.Popen(cmd,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   cwd=gf.get_bin_dir(),
                                   universal_newlines=True)

        errs = rx.from_iterable(iter(process.stderr.readline, ""))
        outs = rx.from_iterable(iter(process.stdout.readline, ""))

        is_running = MCERD.running_check(process, first_check, poll_interval)
        ct_check = MCERD.cancellation_check(process, ct_check, ct)

        if max_time is not None:
            timeout = MCERD.timeout_check(process, max_time, ct)
        else:
            timeout = rx.empty()

        thread_count = multiprocessing.cpu_count()
        pool_scheduler = ThreadPoolScheduler(thread_count)

        merged = rx.merge(errs, outs).pipe(
            ops.subscribe_on(pool_scheduler),
            MCERD.get_pipeline(self._seed,
                               self._rec_filename,
                               print_output=print_output),
            ops.combine_latest(rx.merge(is_running, ct_check, timeout)),
            ops.starmap(
                lambda x, y: {
                    **x,
                    **y, MCERD.IS_RUNNING:
                    x[MCERD.IS_RUNNING] and y[MCERD.IS_RUNNING]
                }),
            ops.take_while(lambda x: x[MCERD.IS_RUNNING], inclusive=True),
        )

        # on_completed does not get called if the take_while condition is
        # inclusive so this is a quick fix to get the files deleted.
        # TODO surely there is a way to get the on_completed called?
        def del_if_not_running(x):
            if not x[MCERD.IS_RUNNING]:
                self.delete_unneeded_files()

        return merged.pipe(
            ops.do_action(on_next=del_if_not_running,
                          on_error=lambda _: self.delete_unneeded_files(),
                          on_completed=self.delete_unneeded_files))
Exemplo n.º 18
0
class Component(Drawable, StyleResolver, MouseEventHandler, EventDispatcher,
                ContextAware, ReactiveObject):
    visible: RP[bool] = rv.new_property()

    parent: RP[Maybe[Container]] = rv.from_value(Nothing)

    offset: RV[Point] = parent.as_view().map(lambda _, parent: parent.map(
        lambda p: rx.combine_latest(p.observe("offset"), p.observe("location"))
        .pipe(ops.map(lambda v: v[0] + v[1]))).or_else_call(lambda: rx.of(
            Point(0, 0)))).pipe(lambda _: (ops.exclusive(), ))

    _minimum_size: RP[Dimension] = rv.from_value(Dimension(0, 0))

    _preferred_size: RP[Dimension] = rv.from_value(Dimension(0, 0))

    minimum_size_override: RP[Maybe[Dimension]] = rv.from_value(Nothing)

    minimum_size: RV[Dimension] = rv.combine_latest(
        _minimum_size,
        minimum_size_override)(ops.pipe(ops.map(lambda v: v[1].value_or(v[0])),
                                        ops.distinct_until_changed()))

    preferred_size_override: RP[Maybe[Dimension]] = rv.from_value(
        Nothing).pipe(lambda o:
                      (ops.combine_latest(o.observe("minimum_size")),
                       ops.map(lambda t: t[0].map(lambda v: t[1].copy(
                           width=max(v.width, t[1].width),
                           height=max(v.height, t[1].height)))),
                       ops.distinct_until_changed()))

    preferred_size: RV[Dimension] = rv.combine_latest(
        _preferred_size, preferred_size_override, minimum_size)(ops.pipe(
            ops.map(lambda v: (v[1].value_or(v[0]), v[2])),
            ops.map(lambda v: v[0].copy(width=max(v[0].width, v[1].width),
                                        height=max(v[0].height, v[1].height))),
            ops.distinct_until_changed()))

    bounds: RP[Bounds] = Bounded.bounds.pipe(lambda o: (
        ops.combine_latest(o.observe("minimum_size")),
        ops.map(lambda v: v[0].copy(width=max(v[0].width, v[1].width),
                                    height=max(v[0].height, v[1].height))),
        ops.start_with(o.preferred_size)))

    def __init__(self, context: Context, visible: bool = True) -> None:
        if context is None:
            raise ValueError("Argument 'context' is required.")

        # noinspection PyTypeChecker
        self.visible = visible

        self._context = context
        self._valid = False
        self._ui = self.create_ui()

        assert self._ui is not None

        super().__init__()

        self.validate()

        self.ui \
            .on_invalidate(self) \
            .pipe(ops.take_until(self.on_dispose)) \
            .subscribe(lambda _: self.invalidate(), on_error=self.error_handler)

    @property
    def context(self) -> Context:
        return self._context

    @property
    def ui(self) -> ComponentUI:
        return self._ui

    @property
    def look_and_feel(self) -> LookAndFeel:
        return self.context.look_and_feel

    def create_ui(self) -> ComponentUI:
        return self.context.look_and_feel.create_ui(self)

    def show(self) -> None:
        # noinspection PyTypeChecker
        self.visible = True

    def hide(self) -> None:
        # noinspection PyTypeChecker
        self.visible = False

    @property
    def valid(self) -> bool:
        return self._valid

    # noinspection PyTypeChecker
    def validate(self, force: bool = False) -> None:
        if self.visible and (not self.valid or force):
            self._minimum_size = self.ui.minimum_size(self)
            self._preferred_size = self.ui.preferred_size(self)

            self._valid = True

            self.parent.map(lambda p: p.request_layout())

    def invalidate(self) -> None:
        self._valid = False

        self.parent.map(lambda p: p.invalidate())

    def draw(self, g: Graphics) -> None:
        if self.visible:
            g.save()

            (dx,
             dy) = self.parent.map(lambda p: p.location).value_or(Point(0, 0))
            (cx, cy, cw, ch) = self.ui.clip_bounds(self).tuple

            g.translate(dx, dy)
            g.rectangle(cx, cy, cw, ch)

            g.clip()

            try:
                self.draw_component(g)
            except BaseException as e:
                self.error_handler(e)

            g.restore()

    def draw_component(self, g: Graphics) -> None:
        self.ui.draw(g, self)

    def position_of(self, event: PositionalEvent) -> Point:
        if event is None:
            raise ValueError("Argument 'event' is required.")

        return event.position - self.offset

    @property
    def inputs(self) -> Mapping[str, Input]:
        return self.context.inputs

    @property
    def parent_dispatcher(self) -> Maybe[EventDispatcher]:
        # noinspection PyTypeChecker
        return self.parent

    def __repr__(self) -> Any:
        return str({"id": id(self), "type": type(self).__name__})