Ejemplo n.º 1
0
    def normalise(self, meta, val):
        val = self.spec.normalise(meta, val)

        if "discovery_options" not in meta.everything:
            return val

        base = meta.everything["discovery_options"].clone()

        if val.hardcoded_discovery is not sb.NotSpecified:
            if not base.hardcoded_discovery or val.hardcoded_discovery is None:
                base.hardcoded_discovery = val.hardcoded_discovery
            else:
                hardcoded_discovery = val.hardcoded_discovery
                if isinstance(base.hardcoded_discovery, dict):
                    opts = MergedOptions.using(base.hardcoded_discovery,
                                               val.hardcoded_discovery)
                    hardcoded_discovery = opts.as_dict()
                base.hardcoded_discovery = hardcoded_discovery
        elif isinstance(base.hardcoded_discovery, dict):
            base.hardcoded_discovery = MergedOptions.using(
                base.hardcoded_discovery).as_dict()

        if val.serial_filter is not sb.NotSpecified:
            base.serial_filter = val.serial_filter
        elif isinstance(base.serial_filter, list):
            base.serial_filter = list(base.serial_filter)

        return base
Ejemplo n.º 2
0
    async def execute(self):
        plans = self.sender.make_plans("hev_status", "hev_config")

        serials = await self.serials
        result = ihp.ResultBuilder()

        got = await self.sender.gatherer.gather_all(
            plans,
            serials,
            error_catcher=result.error,
            message_timeout=self.timeout)

        for serial, (complete, info) in got.items():
            if not complete:
                continue

            if info["hev_status"] is Skip:
                continue

            if "hev_status" in info and "hev_config" in info:
                # Create a copy so we don't corrupt the gatherer cache
                final = result.result["results"][serial] = {}
                final["status"] = MergedOptions.using(
                    info["hev_status"]).as_dict()
                final["status"]["last"]["result"] = final["status"]["last"][
                    "result"].name
                final["config"] = info["hev_config"]

        return result
Ejemplo n.º 3
0
 def find_photons_app_options(self, configuration, args_dict):
     """Return us all the photons_app options"""
     d = lambda r: {} if r in (None, "", sb.NotSpecified) else r
     return MergedOptions.using(
         dict(d(configuration.get("photons_app")).items()),
         dict(d(args_dict.get("photons_app")).items()),
     ).as_dict()
Ejemplo n.º 4
0
    def __init__(self, store, **options):
        self.store = store

        everything = MergedOptions.using(options, {"commander": self},
                                         dont_prefix=[dictobj])

        self.meta = Meta(everything, [])
Ejemplo n.º 5
0
    async def execute_task(self, **kwargs):
        self("Usage: (<target>:)<task> <options> -- <extra>")

        target_register = self.target_register
        initial_restrictions = {}
        if self.specific_target is not sb.NotSpecified:
            initial_restrictions.update(
                dict(target_names=[self.specific_target]))
            target_register = target_register.restricted(
                **initial_restrictions)

        targets_by_name = defaultdict(list)
        for name, target in self.target_register.registered.items():
            typ = self.target_register.type_for(name)
            desc = self.target_register.desc_for(name)
            targets_by_name[name] = (typ, desc)

        tasks = []
        for task in task_register.registered:
            if (self.specific_task_groups is not None
                    and task.task_group not in self.specific_task_groups):
                continue

            if self.specific_task is sb.NotSpecified or task.name == self.specific_task:
                _, restrictions = task_register.determine_target_restrictions(
                    task.task)
                if not restrictions:
                    tasks.append((task, restrictions))
                    continue

                restrict = MergedOptions.using(initial_restrictions,
                                               restrictions).as_dict()
                reg = target_register.restricted(**restrict)
                if reg.registered:
                    tasks.append((task, restrictions))

        if len(tasks) == 1:
            self()
            self.print_one_task(targets_by_name, *tasks[0])
        elif tasks:
            self()
            self.print_tasks(targets_by_name, tasks)
        else:
            self("Found no tasks to print help for...")
Ejemplo n.º 6
0
            def messages(self):
                if self.deps["c"]["cap"].has_chain:
                    length = len(self.deps["chain"]["chain"])
                    width = self.deps["chain"]["width"]
                    options = MergedOptions.using(
                        {
                            "target": serial,
                            "tile_index": 0,
                            "length": length,
                            "x": 0,
                            "y": 0,
                            "width": width,
                        },
                        collector.photons_app.extra_as_json,
                    )

                    return [
                        TileMessages.Get64.empty_normalise(**options.as_dict())
                    ]
                return Skip
Ejemplo n.º 7
0
    def msg(kls, components, overrides=None):
        """
        Create a :ref:`SetWaveformOptional <LightMessages.SetWaveformOptional>`
        message that may be used to change the state of a device to what has
        been specified.

        .. code-block:: python

            from photons_control.colour import ColourParser


            async def my_action(target, reference):
                msg = ColourParser.msg("green")
                await target.send(msg, reference)
        """
        h, s, b, k = kls.hsbk(components, overrides)

        colour = dict(
            hue=0 if h is None else h,
            set_hue=h is not None,
            saturation=0 if s is None else s,
            set_saturation=s is not None,
            brightness=0 if b is None else b,
            set_brightness=b is not None,
            kelvin=0 if k is None else int(k),
            set_kelvin=k is not None,
        )

        other = dict(
            transient=0,
            cycles=1,
            skew_ratio=0,
            waveform=Waveform.SAW,
            period=0 if not overrides else overrides.get("duration", 0),
        )

        other_override = Effects.make(**(overrides or {}))
        options = MergedOptions.using(other, other_override, overrides or {},
                                      colour)
        return LightMessages.SetWaveformOptional.normalise(
            Meta.empty(), options)
Ejemplo n.º 8
0
    async def start(
        self,
        identity,
        reference,
        *,
        run_options=sb.NotSpecified,
        animations=sb.NotSpecified,
    ):
        pauser = asyncio.Semaphore()
        final_future = hp.ChildOfFuture(
            self.final_future,
            name=f"Animations::start({identity})[final_future]")

        if run_options is sb.NotSpecified:
            run_options = {}

        if animations is not sb.NotSpecified:
            run_options = MergedOptions.using(run_options, {
                "animations": animations
            }).as_dict()

        runner = AnimationRunner(
            self.sender,
            reference,
            run_options,
            final_future=final_future,
            error_catcher=errors,
            animation_options=self.animation_options,
        )

        runner.run_options.pauser = pauser

        def remove(res):
            if identity in self.animations:
                del self.animations[identity]

        self.animations[identity] = Animation(final_future, identity, runner,
                                              pauser).start(
                                                  self.tasks, remove)

        return self.info(started=identity)
Ejemplo n.º 9
0
            with mock.patch.multiple(
                collector,
                find_photons_app_options=find_photons_app_options,
                determine_mainline_module=determine_mainline_module,
                setup_addon_register=setup_addon_register,
            ):
                yield __main__

            find_photons_app_options.assert_called_once_with(configuration, args_dict)
            determine_mainline_module.assert_called_once_with()
            setup_addon_register.assert_called_once_with(photons_app, __main__)

        it "puts things into the configuration and sets up the addon register":
            extra = str(uuid.uuid1())
            photons_app = {"extra": extra}
            configuration = MergedOptions()
            collector = Collector()
            register = mock.Mock(name="register")
            args_dict = mock.Mock(name="args_dict")

            with self.mocks(collector, configuration, args_dict, photons_app, register):
                collector.extra_prepare(configuration, args_dict)

            class AFuture:
                def __eq__(s, other):
                    return isinstance(other, asyncio.Future)

            assert collector.register is register
            assert configuration.as_dict() == {
                "$@": extra,
                "collector": collector,
Ejemplo n.º 10
0
 def alter_clone_args_dict(self, new_collector, new_args_dict, options=None):
     return MergedOptions.using(
         new_args_dict,
         {"photons_app": self.configuration["photons_app"].as_dict()},
         options or {},
     )
Ejemplo n.º 11
0
    async def execute_task(self, **kwargs):
        if self.reference == "help":
            if self.artifact in register.animations:
                print_help(
                    animation_kls=register.animations[self.artifact].Animation,
                    animation_name=self.artifact,
                )
            else:
                print_help()
            return

        if self.reference in register.available_animations():
            ref = self.artifact
            self.artifact = self.reference
            self.reference = ref

        extra = self.collector.photons_app.extra_as_json
        reference = self.collector.reference_object(self.reference)

        options = {}
        specific_animation = self.artifact not in (None, "", sb.NotSpecified)

        if specific_animation:
            options = extra
            run_options = extra.pop("run_options", {})
        else:
            run_options = extra
            if isinstance(run_options, list):
                run_options = {"animations": run_options}

        if specific_animation:
            background = sb.NotSpecified
            layered = {
                "animations": [[self.artifact, background, options]],
                "animation_limit": 1
            }
            run_options = MergedOptions.using(layered, run_options).as_dict()

        def errors(e):
            if isinstance(e, KeyboardInterrupt):
                return

            if not isinstance(e, PhotonsAppError):
                log.exception(e)
            else:
                log.error(e)

        conf = self.collector.configuration
        photons_app = conf["photons_app"]

        with photons_app.using_graceful_future() as final_future:
            async with self.target.session() as sender:
                runner = AnimationRunner(
                    sender,
                    reference,
                    run_options,
                    final_future=final_future,
                    error_catcher=errors,
                    animation_options=conf.get("animation_options", {}),
                )
                async with runner:
                    await runner.run()
Ejemplo n.º 12
0
 def meta(s):
     options = MergedOptions.using(
         {"target_register": s.target_register}, dont_prefix=[mock.Mock]
     )
     return Meta(options, [])
Ejemplo n.º 13
0
    async def execute(self,
                      path,
                      body,
                      extra_options=None,
                      allow_ws_only=False):
        """
        Responsible for creating a command and calling execute on it.

        If command is not already a Command instance then we normalise it
        into one.

        We have available on the meta object:

        __init__ options
            Anything that is provided to the Commander and Executor at __init__

        store
            The store of commands

        path
            The path that was passed in

        executor
            This executor

        request_future
            A future that is cancelled after execute is finished

        extra options
            Anything provided as extra_options to this function
        """
        request_future = asyncio.Future()
        request_future._merged_options_formattable = True

        try:
            everything = MergedOptions.using(
                self.commander.meta.everything,
                {
                    "path": path,
                    "store": self.commander.store,
                    "executor": self,
                    "progress_cb": self.progress_cb,
                    "request_future": request_future,
                    "request_handler": self.request_handler,
                },
                self.extra_options,
                extra_options or {},
                dont_prefix=[dictobj],
            )

            meta = Meta(everything, self.commander.meta.path).at("<input>")
            execute = self.commander.store.command_spec.normalise(
                meta, {
                    "path": path,
                    "body": body,
                    "allow_ws_only": allow_ws_only
                })

            return await execute()
        finally:
            request_future.cancel()
Ejemplo n.º 14
0
 def configuration(self):
     return MergedOptions()
Ejemplo n.º 15
0
        thing, val = await commander.executor(progress_cb, request_handler).execute(
            "/v1", {"command": "thing", "args": {"value": value}}, {"other": other2}
        )

        assert val == value
        assert thing.other is other2
        assert thing.store is store2
        assert store is not store2

    async it "can inject values that are dictobj's":

        class Other(dictobj):
            fields = ["one"]

        other = Other("twenty")
        progress_cb = mock.Mock(name="progress_cb")
        request_handler = mock.Mock(name="request_handler")
        commander = Commander(store, other=other)

        value = str(uuid.uuid1())
        thing, val = await commander.executor(progress_cb, request_handler).execute(
            "/v1", {"command": "thing", "args": {"value": value}}
        )

        assert val == value
        assert thing.other is other

    async it "allows commands to be retrieved from a MergedOptions":
        options = MergedOptions.using({"command": FieldsRequired}, dont_prefix=[dictobj])
        assert options["command"] is FieldsRequired
Ejemplo n.º 16
0
 def start_configuration(self):
     """Create the base of the configuration"""
     return MergedOptions(dont_prefix=[dictobj])
Ejemplo n.º 17
0
            changer = attrs.attrs_path("many", 2).changer_to("nope")
            assert repr(changer) == "<Will change <Path many[2]> to nope>"
            assert changer == ChangeAttr.test("many[2]", "nope", attempted=False)
            await changer()
            assert repr(changer) == "<Changed many[2] to nope>"
            assert changer == ChangeAttr.test("many[2]", "nope")

            changer = attrs.attrs_path("stuff").changer_to("better")
            assert repr(changer) == "<Will change <Path stuff> to better>"
            assert changer == ChangeAttr.test("stuff", "better", attempted=False)
            await changer()
            assert repr(changer) == "<Changed stuff to better>"
            assert changer == ChangeAttr.test("stuff", "better")

            assert MergedOptions.using(attrs._attrs).as_dict() == {
                "one": {
                    "list1": [{"blah": False}, {"blah": False}],
                    "list2": [1, 2, 3],
                    "thing3": 56,
                },
                "stuff": "better",
                "many": ["yes", "yah", "nope"],
            }

        async it "can add attributes that don't already exist to the base of attrs", attrs:
            changer = attrs.attrs_path("new").changer_to("newer")
            assert repr(changer) == "<Will change <Path new> to newer>"
            await changer()
            assert repr(changer) == "<Changed new to newer>"
Ejemplo n.º 18
0
            with mock.patch.multiple(
                collector,
                find_photons_app_options=find_photons_app_options,
                determine_mainline_module=determine_mainline_module,
                setup_addon_register=setup_addon_register,
            ):
                yield __main__

            find_photons_app_options.assert_called_once_with(configuration, args_dict)
            determine_mainline_module.assert_called_once_with()
            setup_addon_register.assert_called_once_with(photons_app, __main__)

        it "puts things into the configuration and sets up the addon register":
            extra = str(uuid.uuid1())
            photons_app = {"extra": extra}
            configuration = MergedOptions()
            collector = Collector()
            register = mock.Mock(name="register")
            args_dict = mock.Mock(name="args_dict")

            with self.mocks(collector, configuration, args_dict, photons_app, register):
                collector.extra_prepare(configuration, args_dict)

            class AFuture:
                def __eq__(s, other):
                    return isinstance(other, asyncio.Future)

            assert collector.register is register
            assert configuration.as_dict() == {
                "$@": extra,
                "collector": collector,