Exemplo n.º 1
0
def generate(src, adjustments, output_folder):
    if "fields" in src:
        src["groups"] = src["fields"]
    src = Src.FieldSpec().normalise(Meta({}, []).at("src"), src)

    adjustments = Adjustments.FieldSpec().normalise(
        Meta({}, []).at("adjustment"), adjustments)

    Resolver(src, adjustments).resolve()

    if os.environ.get("NO_OUTPUT") == "1":
        return

    by_type = defaultdict(list)
    for options in adjustments.output:
        by_type[options.create].append(options)

    for t in ("enums", "fields"):
        if len(by_type[t]) != 1:
            raise errors.InvalidOutput(f"Must specify {t} output only once",
                                       found=len(by_type[t]))
        by_type[t] = by_type[t][0]

    log.info("Writing enums")
    write_enums(by_type["enums"], src, adjustments, output_folder)

    log.info("Writing fields")
    write_fields(by_type["fields"], src, adjustments, output_folder)

    log.info("Writing packets")
    write_packets(by_type["packets"], src, adjustments, output_folder)
Exemplo n.º 2
0
    def meta(self, config="", extra_prepare=None):
        with hp.a_temp_file() as fle:
            fle.write(dedent(config).encode())
            fle.close()

            original = Collector.extra_prepare_after_activation

            class Prepare:
                def __enter__(s):
                    if extra_prepare:

                        def extra(*args, **kwargs):
                            extra_prepare(*args, **kwargs)
                            return original(*args, **kwargs)

                        s.patch = mock.patch.object(
                            Collector, "extra_prepare_after_activation", extra
                        )
                        s.patch.start()

                def __exit__(s, exc_type, exc, tb):
                    if hasattr(s, "patch"):
                        s.patch.stop()

            with Prepare(), open(fle.name) as realfile:
                args_dict = {"photons_app": {"config": realfile}}

                app = App()
                logging_handler = mock.Mock(name="logging_handler")
                collector = app.setup_collector(args_dict, logging_handler, None)
                return Meta({"collector": collector}, [])
Exemplo n.º 3
0
    def __init__(self, store, **options):
        self.store = store

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

        self.meta = Meta(everything, [])
Exemplo n.º 4
0
        def meta(self, collector):
            def resolve(s):
                return DeviceFinder.from_url_str(s)

            collector.configuration["reference_resolver_register"].add("match", resolve)

            return Meta({"collector": collector}, []).at("test")
Exemplo n.º 5
0
    def resolve_packet_fields(self):
        for parent, _ in self.all_parents:
            fields = []
            for field in parent.item_fields:
                bits = self.adjustments.field_attr(parent.full_name,
                                                   field.full_name, "bits")
                if bits:
                    for name in bits:
                        meta = Meta({}, []).at(parent.full_name).at(
                            field.full_name).at(name)
                        f = struct_field_spec().normalise(
                            meta, {
                                "name": name,
                                "type": "bit",
                                "size_bits": 0
                            })
                        f.type = ft.SimpleType("bit", 1)
                        fields.append(f)
                    continue

                if isinstance(field.type, ft.UnionType):
                    fields.append(field)
                elif getattr(field.type, "expanded", False):
                    expand_structs = isinstance(field.type, ft.PacketType)
                    fields.extend(
                        field.expand_fields(expand_structs=expand_structs))
                else:
                    fields.append(field)
            parent.item_fields = fields
Exemplo n.º 6
0
    def setup_addon_register(self, photons_app, __main__):
        """Setup our addon register"""
        # Create the addon getter and register the crosshair namespace
        self.addon_getter = AddonGetter()
        self.addon_getter.add_namespace("lifx.photons", Result.FieldSpec(), Addon.FieldSpec())

        # Initiate the addons from our configuration
        register = Register(self.addon_getter, self)

        if "addons" in photons_app:
            addons = photons_app["addons"]
            if type(addons) in (MergedOptions, dict) or getattr(addons, "is_dict", False):
                spec = sb.dictof(sb.string_spec(), sb.listof(sb.string_spec()))
                meta = Meta(photons_app, []).at("addons")
                for namespace, adns in spec.normalise(meta, addons).items():
                    register.add_pairs(*[(namespace, adn) for adn in adns])
        elif photons_app.get("default_activate"):
            for comp in photons_app["default_activate"]:
                register.add_pairs(("lifx.photons", comp))

        if __main__ is not None:
            register.add_pairs(("lifx.photons", "__main__"))

        # Import our addons
        register.recursive_import_known()

        # Resolve our addons
        register.recursive_resolve_imported()

        return register
Exemplo n.º 7
0
async def apply_theme(collector, target, reference, artifact, **kwargs):
    """
    Apply a theme to specified device

    ``lan:apply_theme d073d5000001 -- `{"colors": [<color>, <color>, ...], "theme": "SPLOTCH", "overrides": {<hsbk dictionary>}}'``

    If you don't specify serials, then the theme will apply to all devices found
    on the network.

    Colors may be words like "red", "blue", etc. Or may be [h, s, b, k] arrays
    where each part is optional.

    theme must be a valid theme type and defaults to SPLOTCH

    You may also specify ``duration`` which is how long to take to apply in
    seconds.

    And you may also supply ``overrides`` with ``hue``, ``saturation``,
    ``brightness`` and ``kelvin`` to override the specified colors.
    """
    extra = collector.photons_app.extra_as_json
    everything = {}
    if "overrides" in extra:
        everything["overrides"] = extra["overrides"]

    if "colors" not in extra:
        extra["colors"] = default_colors

    options = Options.FieldSpec().normalise(Meta(everything, []), extra)

    def errors(e):
        log.error(e)

    await target.send(ApplyTheme.script(options), reference, error_catcher=errors)
Exemplo n.º 8
0
    def make_command(self, meta, val, existing):
        v = sb.set_options(path=sb.required(sb.string_spec()),
                           allow_ws_only=sb.defaulted(sb.boolean(),
                                                      False)).normalise(
                                                          meta, val)

        path = v["path"]
        allow_ws_only = v["allow_ws_only"]

        if path not in self.paths:
            raise NoSuchPath(path, sorted(self.paths))

        val = sb.set_options(body=sb.required(
            sb.set_options(args=sb.dictionary_spec(),
                           command=sb.required(sb.string_spec())))).normalise(
                               meta, val)

        args = val["body"]["args"]
        name = val["body"]["command"]

        if existing:
            name = val["body"]["command"] = f"{existing['path']}:{name}"

        extra_context = {}
        if existing:
            extra_context["_parent_command"] = existing["command"]

        everything = meta.everything
        if isinstance(meta.everything, MergedOptions):
            everything = meta.everything.wrapped()
        everything.update(extra_context)
        meta = Meta(everything, []).at("body")

        available_commands = self.paths[path]

        if name not in available_commands:
            raise BadSpecValue(
                "Unknown command",
                wanted=name,
                available=self.available(available_commands,
                                         allow_ws_only=allow_ws_only),
                meta=meta.at("command"),
            )

        command = available_commands[name]["spec"].normalise(
            meta.at("args"), args)

        if not allow_ws_only and command.__whirlwind_ws_only__:
            raise BadSpecValue(
                "Command is for websockets only",
                wanted=name,
                available=self.available(available_commands,
                                         allow_ws_only=allow_ws_only),
                meta=meta.at("command"),
            )

        return command, name
Exemplo n.º 9
0
 def normalise(self, meta, val):
     if "SERIAL_FILTER" in os.environ and self.see_env:
         val = os.environ["SERIAL_FILTER"].split(",")
         if val == ["null"]:
             return None
         meta = Meta(meta.everything, []).at("${SERIAL_FILTER}")
     if val in (None, sb.NotSpecified):
         return val
     return sb.listof(serial_spec()).normalise(meta, val)
Exemplo n.º 10
0
def make_photons_app(cleanup, **options):
    photons_app = PhotonsApp.FieldSpec(formatter=MergedOptionStringFormatter).normalise(
        Meta({}, []).at("photons_app"), options
    )

    photons_app.loop = asyncio.new_event_loop()

    with mock.patch.object(photons_app, "cleanup", cleanup):
        yield photons_app
Exemplo n.º 11
0
 def make():
     if cache["info"] is None:
         make.resolved = True
         meta = Meta(self.collector.configuration,
                     []).at("targets").at(name).at("options")
         cache["info"] = (
             target.type,
             self.types[target.type].normalise(meta, target.options),
         )
     return cache["info"]
Exemplo n.º 12
0
 def make_meta(message_id, **kwargs):
     return Meta(
         {
             "message_id": message_id,
             "final_future": final_future,
             "progress_cb": progress_cb,
             **kwargs,
         },
         [],
     )
Exemplo n.º 13
0
    def get_extra_files(self, result, source, configuration, path):
        extra = hp.nested_dict_retrieve(result, path, [])

        config_root = {"config_root": result.get("config_root", configuration.get("config_root"))}

        config = configuration.wrapped()
        config.update(result, source=source)
        config.update(config_root)

        meta = Meta(config, []).at("photons_app").at("extra_files")

        return extra_files_spec(source).normalise(meta, extra)
Exemplo n.º 14
0
    def theme_msg(self, gatherer):
        everything = {}
        theme_options = dict(self.theme_options)

        if "overrides" in theme_options:
            everything["overrides"] = theme_options["overrides"]

        if "colors" not in theme_options:
            theme_options["colors"] = default_colors

        options = ThemeOptions.FieldSpec().normalise(Meta(everything, []),
                                                     theme_options)
        return ApplyTheme.script(options, gatherer=gatherer)
Exemplo n.º 15
0
def make_run_options(val, animation_options):
    if isinstance(val, RunOptions):
        return val

    if isinstance(val, list):
        val = {"animations": val}

    elif not val or val is sb.NotSpecified:
        val = {
            "animations": [
                [
                    "swipe", {
                        "line_hues": ["0-10", "100-150"],
                        "fade_amount": 0.2
                    }
                ],
                #
                ["falling", {
                    "num_seconds": 10
                }],
                #
                ["balls", {
                    "num_seconds": 10
                }],
                #
                ["twinkles", {
                    "num_seconds": 5,
                    "skip_next_transition": True
                }],
                #
                ["dots", {
                    "skip_next_transition": True
                }],
                #
                ["dice", {
                    "num_iterations": 1
                }],
                #
                [
                    "color_cycle", {
                        "changer": "vertical_morph",
                        "num_seconds": 10
                    }
                ],
            ]
        }

    meta = Meta({"animation_options": animation_options}, [])
    return RunOptions.FieldSpec(
        formatter=MergedOptionStringFormatter).normalise(meta, val)
Exemplo n.º 16
0
    def normalise(self, meta, val):
        if "HARDCODED_DISCOVERY" in os.environ and self.see_env:
            meta = Meta(meta.everything, []).at("${HARDCODED_DISCOVERY}")
            try:
                val = json.loads(os.environ["HARDCODED_DISCOVERY"])
            except (TypeError, ValueError) as error:
                raise BadSpecValue(
                    "Found HARDCODED_DISCOVERY in environment, but it was not valid json",
                    reason=error,
                    meta=meta,
                )

        if val in (sb.NotSpecified, None):
            return val

        return self.spec.normalise(meta, val)
Exemplo n.º 17
0
    def msg(kls, options):
        if not isinstance(options, Options):
            options = Options.FieldSpec().normalise(Meta(options, []), options)

        async def gen(reference, sender, **kwargs):
            serials = []
            canvases = []
            combined_canvas = Canvas()

            plans = sender.make_plans("parts")
            async for serial, _, info in sender.gatherer.gather(plans, reference, **kwargs):
                serials.append(serial)
                for part in info:
                    if part.device.cap.has_chain:
                        combined_canvas.add_parts(part)
                    else:
                        nxt = Canvas()
                        nxt.add_parts(part)
                        canvases.append(nxt)

            if combined_canvas:
                canvases.append(combined_canvas)

            msgs = []

            if options.power_on:
                for serial in serials:
                    msgs.append(
                        LightMessages.SetLightPower(
                            level=65535,
                            duration=options.duration,
                            target=serial,
                            res_required=False,
                        )
                    )

            for canvas in canvases:
                Applier(canvas, options.colors).apply()

                for msg in canvas.msgs(
                    options.override_layer, duration=options.duration, acks=True
                ):
                    msgs.append(msg)

            yield msgs

        return FromGenerator(gen)
Exemplo n.º 18
0
        def meta(self, superman, batman, vegemite, collector):
            reg = collector.configuration["target_register"]

            HeroTarget = mock.Mock(name="HeroTarget")
            herotarget = Target.FieldSpec().empty_normalise(type="hero")
            reg.register_type("hero", HeroTarget)

            VillianTarget = mock.Mock(name="VillianTarget")
            villiantarget = Target.FieldSpec().empty_normalise(type="villian")
            reg.register_type("villian", VillianTarget)

            supermancreator = mock.Mock(name="supermancreator", return_value=superman)
            reg.add_target("superman", herotarget, supermancreator)

            batmancreator = mock.Mock(name="batmancreator", return_value=batman)
            reg.add_target("batman", herotarget, batmancreator)

            vegemitecreator = mock.Mock(name="vegemitecreator", return_value=vegemite)
            reg.add_target("vegemite", villiantarget, vegemitecreator)

            return Meta({"collector": collector}, []).at("test")
Exemplo n.º 19
0
            t = T.create(config, {"one": 20})

            assert t.protocol_register is protocol_register
            assert t.final_future is final_future
            assert t.one == 20

            assert t.item_kls is Item
            assert t.script_runner_kls is ScriptRunner

    describe "normalise":
        async it "gets protocol_register and final_future from the meta":
            protocol_register = mock.Mock(name="protocol_register")
            final_future = mock.Mock(name="final_future")
            config = {"protocol_register": protocol_register, "final_future": final_future}
            meta = Meta(config, []).at("transport")

            spec = Target.FieldSpec(formatter=MergedOptionStringFormatter)
            t = spec.normalise(meta, {})

            assert t.protocol_register is protocol_register
            assert t.final_future is final_future

    describe "Usage":

        describe "script":

            @pytest.fixture()
            def script(self):
                return mock.Mock(name="script")
Exemplo n.º 20
0
    it "can get target_values", collector:
        target1 = mock.Mock(name="target1")
        maker1 = mock.Mock(name="maker1", return_value=("type1", target1))

        target2 = mock.Mock(name="target2")
        maker2 = mock.Mock(name="maker2", return_value=("type2", target2))

        register = TargetRegister(collector)
        register.targets["target1"] = maker1
        register.targets["target2"] = maker2

        assert register.target_values == [target1, target2]

    it "can get used targets", collector:
        meta = Meta({}, []).at("targets")
        targets = PhotonsAppSpec().targets_spec.normalise(
            meta,
            {
                "target1": {"type": "example", "options": {"one": 1}},
                "target2": {"type": "example", "options": {"one": 2}},
            },
        )

        class T(dictobj.Spec):
            one = dictobj.Field(sb.integer_spec)

        register = TargetRegister(collector)
        register.register_type("example", T.FieldSpec())
        for name, options in targets.items():
            register.add_target(name, options)
Exemplo n.º 21
0
            it "complains if nothing was specified and is mandatory", val, special:
                spec = reference_spec(mandatory=True, special=special)

                with assertRaises(BadOption, "This task requires you specify a reference"):
                    spec.normalise(Meta.empty(), val)

            @pytest.mark.parametrize("val", [None, "", sb.NotSpecified])
            it "returns not specified if nothing was specified and isn't mandatory", val:
                spec = reference_spec(mandatory=False, special=False)
                assert spec.normalise(Meta.empty(), val) is sb.NotSpecified

            @pytest.mark.parametrize("val", [None, "", sb.NotSpecified])
            it "returns a reference object if nothing but not mandatory", val, collector:
                spec = reference_spec(mandatory=False, special=True)
                assert isinstance(
                    spec.normalise(Meta({"collector": collector}, []).at("test"), val), FoundSerials
                )

    describe "with a value":

        @pytest.fixture()
        def meta(self, collector):
            def resolve(s):
                return DeviceFinder.from_url_str(s)

            collector.configuration["reference_resolver_register"].add("match", resolve)

            return Meta({"collector": collector}, []).at("test")

        @pytest.mark.parametrize(
            "special,mandatory", [(False, False), (False, True), (True, False), (True, True)]
Exemplo n.º 22
0
                "/v2": {"three": three},
                "/v3": {"hello/five": five},
            }

    describe "command decorator":
        it "uses the formatter given to the store":
            store = Store(formatter=MergedOptionStringFormatter)

            @store.command("thing", path="/v1")
            class Thing(store.Command):
                one = dictobj.Field(sb.integer_spec)
                two = dictobj.Field(sb.string_spec)
                three = dictobj.Field(sb.overridden("{wat}"), formatted=True)

            wat = mock.Mock(name="wat")
            meta = Meta({"wat": wat}, []).at("options")
            thing = store.paths["/v1"]["thing"]["spec"].normalise(meta, {"one": 2, "two": "yeap"})
            assert thing == {"one": 2, "two": "yeap", "three": wat}

        it "complains if you try to reuse a command":
            store = Store()

            @store.command("thing")
            class Thing(store.Command):
                pass

            # Can use a child kls
            @store.command("another_path")
            class Other(Thing):
                pass
Exemplo n.º 23
0
        it "complains if instantiated with bad options", device:

            class Op(Operator):
                class Options(Operator.Options):
                    will_be_wrong = dictobj.Field(sb.integer_spec())
                    will_be_missing = dictobj.Field(sb.boolean, wrapper=sb.required)

            try:
                Op(device, options={"will_be_wrong": "nope"})
            except BadSpecValue as error:
                assert len(error.errors) == 2
                assertSameError(
                    error.errors[0],
                    BadSpecValue,
                    "Expected a value but got none",
                    {"meta": Meta({}, []).at("will_be_missing")},
                    [],
                )
                assertSameError(
                    error.errors[1],
                    BadSpecValue,
                    "Expected an integer",
                    {"meta": Meta({}, []).at("will_be_wrong"), "got": str},
                    [],
                )
            else:
                assert False, "Expected an error"

        it "puts options and device attrs on operator before setup", device:
            got = []
Exemplo n.º 24
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()
Exemplo n.º 25
0
describe "Communication":
    async it "is formattable", V:

        class Other:
            pass

        other = Other()
        options = {"comms": V.communication, "other": other}

        class Thing(dictobj.Spec):
            other = dictobj.Field(sb.overridden("{other}"), formatted=True)
            comms = dictobj.Field(sb.overridden("{comms}"), formatted=True)

        thing = Thing.FieldSpec(formatter=MergedOptionStringFormatter).normalise(
            Meta(options, []).at("thing"), {}
        )

        assert thing.comms is V.communication
        assert thing.other == str(other)

    async it "takes in a transport_target", V:
        assert V.communication.transport_target is V.transport_target
        assert V.communication.found == Found()
        assert isinstance(V.communication.receiver, Receiver)

    async it "has a stop fut", V:
        assert not V.communication.stop_fut.done()
        V.communication.stop_fut.cancel()
        assert not V.final_future.cancelled()
Exemplo n.º 26
0
 def meta(s):
     return Meta({"collector": s.collector, "final_future": s.final_future}, []).at(
         "options"
     )
Exemplo n.º 27
0
 def create(kls, configuration, options=None):
     options = options if options is not None else configuration
     meta = Meta(configuration, []).at("options")
     return kls.FieldSpec(formatter=MergedOptionStringFormatter).normalise(
         meta, options)
Exemplo n.º 28
0
 def meta(s):
     options = MergedOptions.using(
         {"target_register": s.target_register}, dont_prefix=[mock.Mock]
     )
     return Meta(options, [])
Exemplo n.º 29
0
 def creator(name, typ, target):
     meta = Meta(self.configuration, []).at("targets").at(name).at("options")
     t = typ.normalise(meta, target.options)
     t.instantiated_name = name
     return t