Esempio n. 1
0
    def test_validate(self):

        fields = opengui.Fields(values={"e": 1},
                                fields=[{
                                    "name": "f"
                                }, {
                                    "name": "g"
                                }])
        self.assertFalse(fields.validate())
        self.assertFalse(fields.valid)
        self.assertEqual(fields.errors, ["unknown field 'e'"])
        self.assertEqual(fields["f"].errors, ["missing value"])
        self.assertEqual(fields["g"].errors, ["missing value"])

        fields = opengui.Fields(values={"e": 1})
        self.assertFalse(fields.validate())
        self.assertEqual(fields.errors, ["unknown field 'e'"])

        fields = opengui.Fields(fields=[{"name": "f"}, {"name": "g"}])
        self.assertFalse(fields.validate())
        self.assertEqual(fields["f"].errors, ["missing value"])
        self.assertEqual(fields["g"].errors, ["missing value"])

        fields = opengui.Fields(values={
            "f": 1,
            "g": 2
        },
                                fields=[{
                                    "name": "f"
                                }, {
                                    "name": "g"
                                }])
        self.assertTrue(fields.validate())
        self.assertTrue(fields.valid)
Esempio n. 2
0
    def formats(self, model):
        """
        Generate all the formats including parent lookups
        """

        formats = {}

        fields = opengui.Fields(fields=self._fields)

        for field in model._fields._order:
            relation = model._ancestor(field.name)
            if relation is not None:
                titles = relation.Parent.many(
                    **{
                        f"{relation.parent_field}__in": model[field.name]
                    }).titles()
                formats[field.name] = {
                    "titles": titles.titles,
                    "format": titles.format
                }
            elif field.format is not None or "titles" in fields[
                    field.name].content:
                formats[field.name] = {}
                if field.format is not None:
                    formats[field.name]["format"] = field.format
                if "titles" in fields[field.name].content:
                    formats[field.name]["titles"] = fields[
                        field.name].content["titles"]

        return formats
Esempio n. 3
0
    def fields(cls, values):

        fields = opengui.Fields(values, cls.load(), [{
            "name":
            "account",
            "fields": [{
                "name": "password"
            }, {
                "name": "ssh",
                "options": ["disabled", "enabled"],
                "default": "disabled"
            }]
        }, {
            "name":
            "network",
            "fields": [{
                "name": "interface",
                "options": ["eth0", "wlan0"],
                "labels": {
                    "eth0": "wired",
                    "wlan0": "wireless"
                },
                "trigger": True
            }]
        }, {
            "name":
            "kubernetes",
            "fields": [{
                "name": "role",
                "options": ["master", "worker", "reset"],
                "trigger": True
            }]
        }])

        if fields["kubernetes"]["role"].original is not None and fields[
                "kubernetes"]["role"].original != "reset":
            fields["kubernetes"]["role"].options = [
                fields["kubernetes"]["role"].original, "reset"
            ]

        if fields["network"]["interface"].value == "wlan0":
            fields["network"].extend([{
                "name": "country",
                "default": "US"
            }, {
                "name": "ssid"
            }, {
                "name": "psk",
                "label": "password",
                "optional": True
            }])

        if fields["kubernetes"]["role"].value and fields["kubernetes"][
                "role"].value != "reset":
            fields["kubernetes"].append({"name": "cluster"})

        if fields["kubernetes"]["role"].value == "worker":
            fields["kubernetes"].append({"name": "name"})

        return fields
Esempio n. 4
0
    def test_ready(self):

        cnc = service.CnC()

        fields = opengui.Fields()

        # missing

        field = {
            "name": "moar",
            "requires": "some"
        }

        self.assertFalse(cnc.ready(fields, field))

        # invalid

        fields.append({
            "name": "some",
            "required": True
        })

        self.assertFalse(cnc.ready(fields, field))

        # requirement met

        fields["some"].value = "fun"

        self.assertTrue(cnc.ready(fields, field))
Esempio n. 5
0
    def fields(cls, values=None, originals=None):

        return opengui.Fields(
            values,
            originals=originals,
            fields=copy.deepcopy(cls.ID + cls.FIELDS + cls.integrations() +
                                 cls.YAML))
Esempio n. 6
0
    def options(self, id=None):
        """
        Generates form for inserts or updates of a single record
        """

        values = (flask.request.json or {}).get(self.SINGULAR)

        if id is None:

            return opengui.Fields(values=values,
                                  fields=self.fields).to_dict(), 200

        originals = dict(self.MODEL.one(**{self.model._id: id}))

        return opengui.Fields(values=values or originals,
                              originals=originals,
                              fields=self.fields).to_dict(), 200
Esempio n. 7
0
    def test____len__(self):

        fields = opengui.Fields(fields=[
            {"name": "a"},
            {"name": "b"}
        ])

        self.assertEqual(len(fields), 2)
Esempio n. 8
0
    def test___iter__(self):

        fields = opengui.Fields(fields=[
            {"name": "a"},
            {"name": "b"}
        ])

        self.assertEqual([field.name for field in fields], ["a", "b"])
Esempio n. 9
0
    def test_extend(self):

        fields = opengui.Fields()

        fields.extend([{"name": "a"}, {"name": "b"}])

        self.assertEqual(len(fields.order), 2)
        self.assertEqual(fields.order[0].name, "a")
        self.assertEqual(fields.order[1].name, "b")
Esempio n. 10
0
    def test_validate(self):

        fields = opengui.Fields(values={"e": 1}, fields=[
            {"name": "f"},
            {"name": "g"}
        ])
        self.assertFalse(fields.validate())
        self.assertFalse(fields.valid)
        self.assertEqual(fields.errors, ["unknown field 'e'"])
        self.assertEqual(fields["f"].errors, ["missing value"])
        self.assertEqual(fields["g"].errors, ["missing value"])

        fields = opengui.Fields(values={"e": 1})
        self.assertFalse(fields.validate())
        self.assertEqual(fields.errors, ["unknown field 'e'"])

        fields = opengui.Fields(fields=[
            {"name": "f"},
            {"name": "g"}
        ])
        self.assertFalse(fields.validate())
        self.assertEqual(fields["f"].errors, ["missing value"])
        self.assertEqual(fields["g"].errors, ["missing value"])

        fields = opengui.Fields(values={"f": 1, "g": 2}, fields=[
            {"name": "f"},
            {"name": "g"}
        ])
        self.assertTrue(fields.validate())
        self.assertTrue(fields.valid)

        def unequal(fields):

            if fields["h"].value == fields["i"].value:
                fields.valid = False
                fields.errors.append("h and i must be unequal")

        fields = opengui.Fields(values={"h": 1, "i": 1}, fields=[
            {"name": "h"},
            {"name": "i"}
        ], validation=unequal)
        self.assertFalse(fields.validate())
        self.assertFalse(fields.valid)
        self.assertEqual(fields.errors, ["h and i must be unequal"])
Esempio n. 11
0
    def thy(cls, self=None):  # pylint: disable=too-many-branches
        """
        Base identity to be known without instantiating the class
        """

        # If self wasn't sent, we're just providing a shell of an instance

        if self is None:
            self = ResourceIdentity()
            self.__dict__.update(cls.__dict__)

        self.model = self.MODEL.thy()

        if self.SINGULAR is None:
            if hasattr(self.model,
                       "SINGULAR") and self.model.SINGULAR is not None:
                self.SINGULAR = self.model.SINGULAR
            else:
                self.SINGULAR = self.model.NAME

        if self.PLURAL is None:
            if hasattr(self.model, "PLURAL") and self.model.PLURAL is not None:
                self.PLURAL = self.model.PLURAL
            else:
                self.PLURAL = f"{self.SINGULAR}s"

        if self.FIELDS is None:
            self.FIELDS = []

        self.fields = []
        fields = opengui.Fields(fields=self.FIELDS)

        for model_field in self.model._fields._order:

            form_field = {
                "name": model_field.name,
                "kind": model_field.kind.__name__
            }

            for attribute in ["readonly", "options", "validation"]:
                if getattr(model_field, attribute):
                    form_field[attribute] = getattr(model_field, attribute)

            if model_field.default is not None:
                form_field["default"] = model_field.default() if callable(
                    model_field.default) else model_field.default
            elif not model_field.none:
                form_field["required"] = True

            if model_field.name in fields.names:
                form_field.update(fields[model_field.name].to_dict())

            self.fields.append(form_field)

        return self
Esempio n. 12
0
    def test_to_list(self):

        fields = opengui.Fields(fields=[
            {"name": "a", "label": "A"},
            {"name": "b"}
        ])

        self.assertEqual(fields.to_list(), [
            {"name": "a", "label": "A"},
            {"name": "b"}
        ])
Esempio n. 13
0
    def test___init__(self):

        fields = opengui.Fields()

        self.assertEqual(fields.order, [])
        self.assertEqual(fields.names, {})
        self.assertEqual(fields.values, {})
        self.assertEqual(fields.originals, {})

        fields = opengui.Fields(values={
            "a": 1,
            "b": {
                "c": 2
            }
        },
                                originals={
                                    "a": 3,
                                    "b": {
                                        "c": 4
                                    }
                                },
                                fields=[{
                                    "name": "a"
                                }, {
                                    "name": "b",
                                    "fields": [{
                                        "name": "c"
                                    }]
                                }])

        self.assertEqual(fields.values, {"a": 1, "b": {"c": 2}})
        self.assertEqual(fields.originals, {"a": 3, "b": {"c": 4}})
        self.assertEqual(fields.order[0].name, "a")
        self.assertEqual(fields.names["a"].value, 1)
        self.assertEqual(fields.names["a"].original, 3)
        self.assertEqual(fields.order[1].name, "b")
        self.assertEqual(fields.names["b"].value, {"c": 2})
        self.assertEqual(fields.names["b"].original, {"c": 4})
        self.assertEqual(fields.order[1].fields[0].name, "c")
        self.assertEqual(fields.names["b"].fields.names["c"].value, 2)
        self.assertEqual(fields.names["b"].fields.names["c"].original, 4)
Esempio n. 14
0
    def fields(self, values=None):

        fields = opengui.Fields(values,
                                fields=[{
                                    "name": "text"
                                }, {
                                    "name":
                                    "language",
                                    "options": [
                                        "en-AU", "en-CA", "en-GH", "en-GB",
                                        "en-IN", "en-IE", "en-KE", "en-NZ",
                                        "en-NG", "en-PH", "en-SG", "en-ZA",
                                        "en-TZ", "en-US"
                                    ],
                                    "labels": {
                                        "en-AU": "English (Australia)",
                                        "en-CA": "English (Canada)",
                                        "en-GH": "English (Ghana)",
                                        "en-GB": "English (United Kingdom)",
                                        "en-IN": "English (India)",
                                        "en-IE": "English (Ireland)",
                                        "en-KE": "English (Kenya)",
                                        "en-NZ": "English (New Zealand)",
                                        "en-NG": "English (Nigeria)",
                                        "en-PH": "English (Philippines)",
                                        "en-SG": "English (Singapore)",
                                        "en-ZA": "English (South Africa)",
                                        "en-TZ": "English (Tanzania)",
                                        "en-US": "English (United States)"
                                    },
                                    "default":
                                    "en-US",
                                    "style":
                                    "select"
                                }, {
                                    "name": "node",
                                    "options": [""],
                                    "labels": {
                                        "": "all"
                                    },
                                    "default": "",
                                    "optional": True
                                }])

        for node in pykube.Node.objects(flask.current_app.kube).filter(
                selector={"speech.nandy.io/speakers": "enabled"}):
            fields["node"].options.append(node.obj["metadata"]["name"])
            fields["node"].labels[node.obj["metadata"]
                                  ["name"]] = node.obj["metadata"]["name"]

        fields["node"].options.sort()

        return fields
Esempio n. 15
0
    def test_values(self):

        cnc = service.CnC()

        fields = opengui.Fields(fields=[
            {"name": "none"},
            {"name": "some", "default": "fun"}
        ])

        self.assertEqual(cnc.values(fields), {
            "none": None,
            "some": "fun"
        })
Esempio n. 16
0
    def test_append(self):

        fields = opengui.Fields(values={"a": 1}, originals={"a": 2})

        fields.append({"name": "a", "label": "A"})

        self.assertEqual(fields.order[0].name, "a")
        self.assertEqual(fields.order[0].content["label"], "A")
        self.assertEqual(fields.order[0].value, 1)
        self.assertEqual(fields.order[0].original, 2)
        self.assertEqual(fields.names["a"].content["label"], "A")

        self.assertRaisesRegex(opengui.MissingName, "Missing name in {}", fields.append)
        self.assertRaisesRegex(opengui.DuplicateName, "Name a exists", fields.append, name="a")
Esempio n. 17
0
    def test____getitem__(self):

        fields = opengui.Fields(fields=[{
            "name": "a"
        }, {
            "name": "b",
            "fields": [{
                "name": "c"
            }]
        }])

        self.assertEqual(fields[0].name, "a")
        self.assertEqual(fields[1][0].name, "c")
        self.assertEqual(fields["a"].name, "a")
        self.assertEqual(fields["b"]["c"].name, "c")
Esempio n. 18
0
    def fields(cls, values=None, originals=None):

        (person_ids, person_labels) = Person.choices()
        (template_ids, template_labels) = Template.choices(cls.SINGULAR)

        fields = opengui.Fields(values, originals=originals, fields=[
            {
                "name": "person_id",
                "label": "person",
                "options": person_ids,
                "labels": person_labels,
                "style": "radios"
            },
            {
                "name": "status",
                "options": cls.STATUSES,
                "style": "radios"
            },
            {
                "name": "template_id",
                "label": "template",
                "options": template_ids,
                "labels": template_labels,
                "style": "select",
                "optional": True,
                "trigger": True
            },
            {
                "name": "name"
            },
            {
                "name": "yaml",
                "style": "textarea",
                "optional": True
            }
        ])

        if fields["template_id"].value:

            template = model_out(TemplateRUD.retrieve(fields["template_id"].value))

            fields["name"].value = template["name"]
            fields["yaml"].value = template["yaml"]

        return fields
Esempio n. 19
0
    def fields(cls, obj, values):

        fields = opengui.Fields(values,
                                obj.get("settings", {}),
                                obj["spec"].get("settings", []),
                                ready=True)

        nodes = []

        for field in fields:

            if field.content.get("node"):
                cls.node(obj["metadata"]["name"], field, nodes)

            if field.content.get("google") == "calendar":
                fields.ready = fields.ready and cls.calendar(field)

        return fields
Esempio n. 20
0
    def test_validate(self):

        fields = opengui.Fields(fields=[{
            "name": "name",
            "value": "yup"
        }, {
            "name": "yaml",
            "style": "textarea",
            "value": "a: 1"
        }])
        self.assertTrue(UnitTest.validate(fields))
        self.assertFields(fields, [{
            "name": "name",
            "value": "yup"
        }, {
            "name": "yaml",
            "style": "textarea",
            "value": "a: 1"
        }])
Esempio n. 21
0
    def response(cls, model):

        converted = {"data": {}}

        integrations = opengui.Fields({}, {}, cls.integrations())

        for field in model.__table__.columns._data.keys():
            if field != "data":
                converted[field] = getattr(model, field)

        for field in model.data:
            if field in integrations.names:
                converted[field] = model.data[field]
            else:
                converted["data"][field] = model.data[field]

        converted["yaml"] = yaml.safe_dump(dict(converted["data"]),
                                           default_flow_style=False)

        return converted
Esempio n. 22
0
    def fields(self, forge, values):
        """
        Gets the dynamic fields
        """

        values["forge"] = forge['id']

        fields = opengui.Fields(values=values, fields=FIELDS, ready=True)

        fields["forge"].description = forge["description"]

        fields.extend(forge.get("input", {}).get("fields", []))

        if "generate" in forge.get("input", {}):
            module_name, method_name = forge["input"]["generate"].rsplilt(
                ".", 1)
            module = __import__(f"tempplate.{module_name}")
            method = getattr(module, method_name)
            fields.extend(method(fields, values, forge))

        return fields
Esempio n. 23
0
    def fields(self, forge, values):
        """
        Gets the dynamic fields
        """

        values["forge"] = forge['id']

        fields = opengui.Fields(values=values, fields=FIELDS, ready=True)

        fields["forge"].description = forge["description"]

        if os.path.exists("/opt/service/forge/fields.yaml"):
            with open("/opt/service/forge/fields.yaml", "r") as fields_file:
                fields.extend(yaml.safe_load(fields_file).get("fields", []))

        for field in forge.get("input", {}).get("fields", []):
            if field["name"] in RESERVED:
                raise Exception(f"field name '{field['name']}' is reserved")
            self.field(fields, field)

        return fields
Esempio n. 24
0
    def fields(cls, values=None, originals=None):

        (person_ids, person_labels) = Person.choices()

        fields = opengui.Fields(values, originals=originals, fields=cls.ID + [
            {
                "name": "person_id",
                "label": "person",
                "options": person_ids,
                "labels": person_labels,
                "style": "radios"
            },
            {
                "name": "status",
                "options": cls.STATUSES,
                "style": "radios"
            },
            {
                "name": "name"
            },
            {
                "name": "created",
                "style": "datetime",
                "readonly": True
            },
            {
                "name": "updated",
                "style": "datetime",
                "readonly": True
            },
            {
                "name": "yaml",
                "style": "textarea",
                "optional": True
            }
        ])

        return fields
Esempio n. 25
0
    def request(cls, converted):

        values = {}

        integrations = opengui.Fields({}, {}, cls.integrations())

        for field in converted.keys():

            if field in integrations.names:
                values.setdefault("data", {})
                values["data"][field] = converted[field]
            elif field != "yaml":
                values[field] = converted[field]

        if "yaml" in converted:
            values.setdefault("data", {})
            values["data"].update(yaml.safe_load(converted["yaml"]))

        if "data" in converted:
            values.setdefault("data", {})
            values["data"].update(converted["data"])

        return values
Esempio n. 26
0
    def test_to_dict(self):

        fields = opengui.Fields(
            fields=[
                {"name": "a", "label": "A"},
                {"name": "b"}
            ],
            errors=['boo'],
            valid=True,
            ready=False
        )

        self.assertEqual(fields.to_dict(), {
            "fields": [
                {"name": "a", "label": "A"},
                {"name": "b"}
            ],
            "errors": [
                "boo"
            ],
            "valid": True,
            "ready": False
        })
Esempio n. 27
0
    def fields(self, likes, values, originals=None):
        """
        Apply options and titles to fields
        """

        fields = opengui.Fields(values=values,
                                originals=originals,
                                fields=self._fields)

        for field in fields:
            relation = self._model._ancestor(field.name)
            if relation is not None:
                like = {
                    "like": likes[name]
                    for name in likes if name == field.name
                }
                parent = relation.Parent.many(**like).limit()
                titles = parent.titles()

                field.content["format"] = titles.format
                field.content["overflow"] = parent.overflow

                value = field.value if field.value is not None else field.original

                if (not like and value is not None and value not in titles):
                    titles = relation.Parent.one(**{
                        relation.parent_field: value
                    }).titles()
                    field.content["overflow"] = True

                field.options = titles.ids
                field.content["titles"] = titles.titles

                field.content.update(like)

        return fields
Esempio n. 28
0
    def calendar(field):

        # https://www.googleapis.com/auth/calendar.readonly

        # Successfully installed cachetools-4.1.0 google-auth-1.14.0 google-auth-httplib2-0.0.3 google-auth-oauthlib-0.4.1 httplib2-0.17.2 oauthlib-3.1.0 pyasn1-modules-0.2.8 requests-oauthlib-1.3.0 rsa-4.0

        # 4/ywEX3hVZgLcTCxzQf9qAMRS_GJTLEhMtDfhTpeNCACYZWAVl31ecVho

        ready = False

        subfields = [{
            "name":
            "credentials",
            "description":
            "\n".join([
                "Go to the Link below.", "Create a new project.",
                "Enable Calendar API.", "Create credentials (OAuth, Other).",
                "Download the JSON and paste it above."
            ]),
            "link": {
                "name": "Google API's",
                "url": "https://console.developers.google.com/apis/"
            }
        }]

        credentials = json.loads(
            field.value['credentials']
        ) if field.value and field.value.get("credentials") else {}

        if credentials and "token" not in credentials:

            if not field.value.get("code"):

                flow = google_auth_oauthlib.flow.Flow.from_client_config(
                    credentials,
                    scopes=[
                        'https://www.googleapis.com/auth/calendar.readonly'
                    ],
                    redirect_uri='urn:ietf:wg:oauth:2.0:oob')

                url, state = flow.authorization_url(
                    prompt='consent',
                    access_type='offline',
                    include_granted_scopes='true')

                credentials["state"] = state

                subfields.append({
                    "name":
                    "code",
                    "description":
                    "\n".join([
                        "Go to the Link below.", "Click Advanced.",
                        "Authorise access to your Calendars.",
                        "Copy the Code and paste it above."
                    ]),
                    "link": {
                        "name": "Authorize Calendar Access",
                        "url": url
                    }
                })

            else:

                flow = google_auth_oauthlib.flow.Flow.from_client_config(
                    credentials,
                    scopes=[
                        'https://www.googleapis.com/auth/calendar.readonly'
                    ],
                    redirect_uri='urn:ietf:wg:oauth:2.0:oob',
                    state=credentials['state'])

                flow.fetch_token(code=field.value["code"])

                credentials = json.loads(flow.credentials.to_json())

        if credentials and "token" in credentials:

            service = googleapiclient.discovery.build(
                'calendar',
                'v3',
                credentials=google.oauth2.credentials.Credentials(
                    **credentials))

            options = []
            labels = {}
            page_token = None

            while True:

                calendar_list = service.calendarList().list(
                    pageToken=page_token).execute()

                for calendar in calendar_list['items']:
                    options.append(calendar['id'])
                    labels[calendar['id']] = calendar["summary"]

                page_token = calendar_list.get('nextPageToken')

                if not page_token:
                    break

            subfields.append({
                "name": "watch",
                "description": "The Calendar you'd like to watch.",
                "options": options,
                "labels": labels
            })

            ready = True

        field.fields = opengui.Fields(field.value, field.original, subfields)

        if credentials:
            field.fields["credentials"].value = json.dumps(credentials)

        return ready
Esempio n. 29
0
    def thy(cls, self=None):  # pylint: disable=too-many-branches
        """
        Base identity to be known without instantiating the class
        """

        # If self wasn't sent, we're just providing a shell of an instance

        if self is None:
            self = ResourceIdentity()
            self.__dict__.update(cls.__dict__)

        self._model = self.MODEL.thy()

        if self.SINGULAR is None:
            if hasattr(self._model,
                       "SINGULAR") and self._model.SINGULAR is not None:
                self.SINGULAR = self._model.SINGULAR
            else:
                self.SINGULAR = self._model.NAME

        if self.PLURAL is None:
            if hasattr(self._model,
                       "PLURAL") and self._model.PLURAL is not None:
                self.PLURAL = self._model.PLURAL
            else:
                self.PLURAL = f"{self.SINGULAR}s"

        if self.FIELDS is None:
            self.FIELDS = []

        self._fields = []
        fields = opengui.Fields(fields=self.FIELDS)

        for model_field in self._model._fields._order:

            form_field = {
                "name": model_field.name,
                "kind": model_field.kind.__name__
            }

            for attribute in ["options", "validation", "init", "inject"]:
                if getattr(model_field, attribute):
                    form_field[attribute] = getattr(model_field, attribute)

            if model_field.auto:
                form_field["readonly"] = True

            if model_field.default is not None:
                form_field["default"] = model_field.default() if callable(
                    model_field.default) else model_field.default
                if isinstance(form_field["default"], set):
                    form_field["default"] = sorted(list(form_field["default"]))
            elif not model_field.auto and (not model_field.none
                                           or model_field.name
                                           in self._model._titles):
                form_field["required"] = True

            if model_field.name in fields.names:
                form_field.update(fields[model_field.name].to_dict())

            self._fields.append(form_field)

        if self.LIST is None:
            self.LIST = list(self._model._list)

        # Make sure all the list checks out

        for field in self.LIST:
            if field.split("__")[0] not in self._model._fields:
                raise ResourceError(self,
                                    f"cannot find field {field} from list")

        return self
Esempio n. 30
0
    def test_validate(self):

        fields = opengui.Fields(fields=[{
            "name": "name"
        }, {
            "name": "yaml",
            "style": "textarea"
        }])
        self.assertFalse(klotio.service.validate(fields))
        self.assertFields(fields, [{
            "name": "name",
            "errors": ["missing value"]
        }, {
            "name": "yaml",
            "style": "textarea",
            "errors": ["missing value"]
        }])

        fields = opengui.Fields(fields=[{
            "name": "name"
        }, {
            "name": "yaml",
            "style": "textarea",
            "value": "a: 1"
        }])
        self.assertFalse(klotio.service.validate(fields))
        self.assertFields(fields, [{
            "name": "name",
            "errors": ["missing value"]
        }, {
            "name": "yaml",
            "style": "textarea",
            "value": "a: 1"
        }])

        fields = opengui.Fields(fields=[{
            "name": "name",
            "value": "yup"
        }, {
            "name": "yaml",
            "style": "textarea",
            "value": "a:1"
        }])
        self.assertFalse(klotio.service.validate(fields))
        self.assertFields(fields, [{
            "name": "name",
            "value": "yup"
        }, {
            "name": "yaml",
            "style": "textarea",
            "value": "a:1",
            "errors": ["must be dict"]
        }])

        fields = opengui.Fields(fields=[{
            "name": "name",
            "value": "yup"
        }, {
            "name": "yaml",
            "style": "textarea",
            "value": "a: 1"
        }])
        self.assertTrue(klotio.service.validate(fields))
        self.assertFields(fields, [{
            "name": "name",
            "value": "yup"
        }, {
            "name": "yaml",
            "style": "textarea",
            "value": "a: 1"
        }])