def config_model() -> List[Kind]: return [ ComplexKind( "sub_section", [], [ Property("num", "int32", description="Some arbitrary number."), Property("str", "string", description="Some arbitrary string."), ], ), ComplexKind( "section", [], [ Property("some_number", "int32", required=True, description="Some number.\nAnd some description."), Property("some_string", "string", required=True, description="Some string.\nAnd some description."), Property("some_sub", "sub_section", required=True, description="Some sub.\nAnd some description."), ], ), ]
def test_update(person_model: Model) -> None: with pytest.raises( AttributeError) as not_allowed: # update city with different type person_model.update_kinds([ ComplexKind( "Address", ["Base"], [ Property("city", "int32", required=True), ], ) ]) assert ( str(not_allowed.value) == "Update not possible: following properties would be non unique having the same path but different type: " "Address.city (string -> int32)") updated = person_model.update_kinds([StringKind("Foo")]) assert updated["Foo"].fqn == "Foo" with pytest.raises(AttributeError) as simple: updated.update_kinds([ComplexKind("Foo", [], [])]) assert str( simple.value) == "Update Foo changes an existing property type Foo" with pytest.raises(AttributeError) as duplicate: updated.update_kinds( [ComplexKind("Bla", [], [Property("id", "int32")])]) assert ( str(duplicate.value) == "Update not possible: following properties would be non unique having the same path but different type: " "Bla.id (string -> int32)")
def test_model() -> List[Kind]: string_kind = StringKind("some.string", 0, 3, "\\w+") int_kind = NumberKind("some.int", "int32", 0, 100) bool_kind = BooleanKind("some.bool") base = ComplexKind( "base", [], [ Property("identifier", "string", required=True), Property("kind", "string", required=True), ], ) foo = ComplexKind( "foo", ["base"], [ Property("name", "string"), Property("some_int", "some.int"), Property("some_string", "some.string"), Property("now_is", "datetime"), ], ) bla = ComplexKind( "bla", ["base"], [ Property("name", "string"), Property("now", "date"), Property("f", "int32"), Property("g", "int32[]"), ], ) return [string_kind, int_kind, bool_kind, base, foo, bla]
def test_json_marshalling() -> None: roundtrip(StringKind("string"), Kind) roundtrip(StringKind("string", 5, 13, "foo.*bla"), Kind) roundtrip(StringKind("string", enum={"foo", "bla"}), Kind) roundtrip(NumberKind("num", "int32", minimum=2, maximum=34), Kind) roundtrip(NumberKind("num", "int64", enum={1, 2}), Kind) roundtrip(BooleanKind("b"), Kind) roundtrip(DateKind("d"), Kind) roundtrip(DateTimeKind("d"), Kind) roundtrip(DurationKind("duration"), Kind) roundtrip( TransformKind("synth", "duration", "datetime", "duration_to_datetime", True), Kind) roundtrip(ArrayKind(StringKind("string")), Kind) roundtrip(Property("foo", "foo"), Property) roundtrip( Property("age", "trafo.duration_to_datetime", False, SyntheticProperty(["ctime"])), Property) props = [ Property("array", "string[]"), Property("s", "float"), Property("i", "int32"), Property("other", "SomeComposite"), ] successor_kinds = { EdgeType.default: ["Base", "Test"], EdgeType.delete: ["Base"], } roundtrip(ComplexKind("Test", ["Base"], props), Kind) roundtrip(ComplexKind("Test", [], props, True), Kind) roundtrip(ComplexKind("Test", [], props, True, successor_kinds), Kind)
async def test_model_api(core_client: ApiClient) -> None: # GET /model assert len((await core_client.model()).kinds) >= len(predefined_kinds) # PATCH /model update = await core_client.update_model([ StringKind("only_three", min_length=3, max_length=3), ComplexKind("test_cpl", [], [Property("ot", "only_three")]), ]) assert isinstance(update.get("only_three"), StringKind)
def test_array() -> None: foo = ComplexKind("Foo", [], [ Property("tags", "dictionary[string, string]"), Property("kind", "string") ]) complex_kind = ComplexKind( "TestArray", [], [ Property("kind", "string"), Property("los", "string[]"), Property("lod", "dictionary[string, string][]"), Property("foos", "Foo[]"), Property("los_los", "string[][]"), Property("los_los_los", "string[][][]"), ], ) model = Model.from_kinds([foo, complex_kind]) assert (model.check_valid({ "kind": "TestArray", "los": ["a", "b", "c"], "lod": [{ "a": "b" }, { "b": "c" }], "foos": [{ "kind": "Foo", "tags": { "a": "b" } }, { "kind": "Foo", "tags": { "b": "c" } }], "los_los": [["a", "b"], ["c"], ["d", "e"]], "los_los_los": [[["a", "b"], ["c"]], [["d", "e"], ["f"]]], }) is None)
def test_dictionary() -> None: model = {k.fqn: k for k in predefined_kinds} result = Property.parse_kind("dictionary[string, string]", model) assert isinstance(result, DictionaryKind) assert result.key_kind is model["string"] assert result.value_kind is model["string"] result = Property.parse_kind( "dictionary[string, dictionary[string, float]]", model) assert isinstance(result, DictionaryKind) assert result.key_kind is model["string"] assert result.value_kind == DictionaryKind(model["string"], model["float"]) address = ComplexKind("Foo", [], [ Property("tags", "dictionary[string, string]"), Property("anything", "dictionary[string, any]") ]) address_model = Model.from_kinds([address]) assert address_model.check_valid({ "kind": "Foo", "tags": { "a": "b", "b": "c" } }) is None expected = 'Kind:Foo Property:tags is not valid: value of dictionary[string, string] is not valid: Expected type string but got int: {"kind": "Foo", "tags": {"a": 1, "b": "c"}}' assert expect_error(address_model, { "kind": "Foo", "tags": { "a": 1, "b": "c" } }) == expected assert address_model.check_valid({ "kind": "Foo", "anything": { "a": 1, "b": "c", "c": True } }) is None expected = 'Kind:Foo Property:anything is not valid: dictionary requires a json object, but got this: 1: {"kind": "Foo", "anything": 1}' assert expect_error(address_model, { "kind": "Foo", "anything": 1 }) == expected
def foo_kinds() -> List[Kind]: base = ComplexKind( "base", [], [ Property("identifier", "string", required=True), Property("kind", "string", required=True), Property("ctime", "datetime"), ], ) foo = ComplexKind( "foo", ["base"], [ Property("name", "string"), Property("some_int", "int32"), Property("some_string", "string"), Property("now_is", "datetime"), Property("ctime", "datetime"), Property("age", "trafo.duration_to_datetime", False, SyntheticProperty(["ctime"])), ], successor_kinds={EdgeType.default: ["bla"]}, ) bla = ComplexKind( "bla", ["base"], [ Property("name", "string"), Property("now", "date"), Property("f", "int32"), Property("g", "int32[]"), ], successor_kinds={EdgeType.default: ["bla"]}, ) cloud = ComplexKind("cloud", ["foo"], []) account = ComplexKind("account", ["foo"], []) region = ComplexKind("region", ["foo"], []) parent = ComplexKind("parent", ["foo"], []) child = ComplexKind("child", ["foo"], []) return [base, foo, bla, cloud, account, region, parent, child]
def test_yaml_generation(js: Json) -> None: kind = ComplexKind("test", [], []) assert js == yaml.safe_load(kind.create_yaml(js))
def person_model() -> Model: zip = StringKind("zip") base = ComplexKind( "Base", [], [ Property( "id", "string", required=True, description="Some identifier"), Property("kind", "string", required=True, description="Kind if this node."), Property("list", "string[]", description="A list of strings."), Property("tags", "dictionary[string, string]", description="Key/value pairs."), Property("mtime", "datetime", description="Modification time of this node."), ], ) address = ComplexKind( "Address", ["Base"], [ Property("zip", "zip", description="The zip code."), Property("city", "string", required=True, description="The name of the city.\nAnd another line."), ], ) person = ComplexKind( "Person", ["Base"], [ Property("name", "string", description="The name of the person."), Property("address", "Address", description="The address of the person."), Property("other_addresses", "dictionary[string, Address]", description="Other addresses."), Property("addresses", "Address[]", description="The list of addresses."), Property("any", "any", description="Some arbitrary value."), ], ) any_foo = ComplexKind( "any_foo", ["Base"], [ Property("foo", "any", description="Some foo value."), Property("test", "string", description="Some test value."), ], ) cloud = ComplexKind("cloud", ["Base"], []) account = ComplexKind("account", ["Base"], []) region = ComplexKind("region", ["Base"], []) parent = ComplexKind("parent", ["Base"], []) child = ComplexKind("child", ["Base"], []) return Model.from_kinds([ zip, person, address, base, any_foo, cloud, account, region, parent, child ])