def test_interfaces(): Foo = InterfaceType("Foo", [Field("str", String)]) Baz = InterfaceType("Baz", [Field("int", Int)]) Bar = ObjectType( "Bar", [Field("str", String), Field("int", Int)], interfaces=[Foo, Baz]) Query = ObjectType("Query", [Field("bar", Bar)]) assert print_schema(Schema(Query), indent=" ") == dedent(""" type Bar implements Foo & Baz { str: String int: Int } interface Baz { int: Int } interface Foo { str: String } type Query { bar: Bar } """)
def test_collects_multiple_errors(): iface = InterfaceType("IFace", [Field("f", ListType(String))]) bad_name_union = UnionType("#BadNameUnion", lambda: [object_type]) empty_union = UnionType("EmptyUnion", []) object_type = ObjectType( "SomeObject", [ Field("f", String), Field("__f", lambda: empty_union), Field("g", lambda: bad_name_union), ], interfaces=[iface], ) # type: ObjectType schema = _single_type_schema(object_type) with pytest.raises(SchemaValidationError) as exc_info: validate_schema(schema) assert set([str(e) for e in exc_info.value.errors]) == set([ 'Invalid name "__f".', 'Interface field "IFace.f" expects type "[String]" but "SomeObject.f" ' 'is type "String"', 'UnionType "EmptyUnion" must at least define one member', 'Invalid type name "#BadNameUnion"', ])
def test_accept_object_fields_with_interface_subtype_of_interface_field(): iface = InterfaceType("IFace", [Field("f", lambda: iface)]) # type: InterfaceType obj = ObjectType("Obj", [Field("f", lambda: obj)], interfaces=[iface]) # type: ObjectType schema = _single_type_schema(obj) schema.validate()
def test_reject_interface_with_no_field(): iface = InterfaceType("BadInterface", []) schema = _single_type_schema(iface) with pytest.raises(SchemaError) as exc_info: validate_schema(schema) assert 'Type "BadInterface" must define at least one field' in str( exc_info.value)
def test_reject_interface_fields_with_non_output_type(type_): iface = InterfaceType("BadInterface", [Field("f", type_)]) schema = _single_type_schema(iface) with pytest.raises(SchemaError) as exc_info: validate_schema(schema) assert ('Expected output type for field "f" on "BadInterface" ' 'but got "%s"' % type_) in str(exc_info.value)
def test_reject_object_with_null_interface_non_null_field(): iface = InterfaceType("IFace", [Field("f", NonNullType(String))]) schema = _single_type_schema( ObjectType("SomeObject", [Field("f", String)], interfaces=[iface])) with pytest.raises(SchemaError) as exc_info: validate_schema(schema) assert ('Interface field "IFace.f" expects type "String!" but ' '"SomeObject.f" is type "String"' in str(exc_info.value))
async def test_type_resolution_supports_object_attribute(assert_execution): PetType = InterfaceType("Pet", [Field("name", String)]) DogType = ObjectType( "Dog", [Field("name", String), Field("woofs", Boolean)], interfaces=[PetType], ) CatType = ObjectType( "Cat", [Field("name", String), Field("meows", Boolean)], interfaces=[PetType], ) class Dog: __typename__ = "Dog" def __init__(self, name, woofs): self.name = name self.woofs = woofs class Cat: __typename__ = "Cat" def __init__(self, name, meows): self.name = name self.meows = meows schema = Schema( ObjectType( "Query", [ Field( "pets", ListType(PetType), resolver=lambda *_: [ Dog("Odie", True), Cat("Garfield", False), ], ) ], ), types=[DogType, CatType], ) await assert_execution( schema, """{ pets { name __typename ... on Dog { woofs } ... on Cat { meows } } }""", )
def test_reject_object_fields_with_missing_interface_argument(): iface = InterfaceType("IFace", [Field("f", String, [Argument("arg", String)])]) obj = ObjectType("Obj", [Field("f", String)], interfaces=[iface]) schema = _single_type_schema(obj) with pytest.raises(SchemaError) as exc_info: validate_schema(schema) assert ('Interface field argument "IFace.f.arg" is not provided by "Obj.f"' in str(exc_info.value))
def test_Schema_includes_interface_possible_types_in_the_type_map(): SomeInterface = InterfaceType("SomeInterface", [Field("f", Int)]) SomeSubtype = ObjectType("SomeSubtype", [Field("f", Int)], lambda: [SomeInterface]) schema = Schema( ObjectType("Query", [Field("iface", SomeInterface)]), types=[SomeSubtype], ) assert schema.types.get("SomeSubtype") is SomeSubtype
def test_reject_object_fields_with_incorrectly_typed_interface_argument(): iface = InterfaceType("IFace", [Field("f", String, [Argument("arg", String)])]) obj = ObjectType("Obj", [Field("f", String, [Argument("arg", Int)])], interfaces=[iface]) schema = _single_type_schema(obj) with pytest.raises(SchemaError) as exc_info: validate_schema(schema) assert ('Interface field argument "IFace.f.arg" expects ' 'type "String" but "Obj.f.arg" is type "Int"' in str(exc_info.value))
def test_reject_object_which_implements_interface_along_with_required_args(): iface = InterfaceType("IFace", [Field("f", String)]) schema = _single_type_schema( ObjectType( "SomeObject", [Field("f", String, [Argument("arg", NonNullType(String))])], interfaces=[iface], )) with pytest.raises(SchemaError) as exc_info: validate_schema(schema) assert ('Object field argument "SomeObject.f.arg" is of required ' 'type "String!" but is not provided by interface field "IFace.f"' ) in str(exc_info.value)
def test_replace_interface_in_implementers(schema: Schema) -> None: NewObject = InterfaceType( "Object", fields=[ Field("id", NonNullType(ID)), Field("name", NonNullType(String)), ], ) schema._replace_types_and_directives({"Object": NewObject}) assert (cast(ObjectType, schema.get_type("Person")).interfaces[0] is cast( ObjectType, schema.get_type("Animal")).interfaces[0] is schema.types["Object"] is NewObject)
async def test_type_resolution_supports_strings(assert_execution): def _resolve_pet_type(value, *_): return type(value).__name__ PetType = InterfaceType("Pet", [Field("name", String)], resolve_type=_resolve_pet_type) DogType = ObjectType( "Dog", [Field("name", String), Field("woofs", Boolean)], interfaces=[PetType], ) CatType = ObjectType( "Cat", [Field("name", String), Field("meows", Boolean)], interfaces=[PetType], ) schema = Schema( ObjectType( "Query", [ Field( "pets", ListType(PetType), resolver=lambda *_: [ Dog("Odie", True), Cat("Garfield", False), ], ) ], ), types=[DogType, CatType], ) await assert_execution( schema, """{ pets { name __typename ... on Dog { woofs } ... on Cat { meows } } }""", )
def schema() -> Schema: Object = InterfaceType("Object", fields=[Field("id", NonNullType(ID))]) Person = ObjectType( "Person", fields=[ Field("id", NonNullType(ID)), Field("name", NonNullType(String)), Field("pets", NonNullType(ListType(lambda: Animal))), ], interfaces=[Object], ) Animal = ObjectType( "Animal", fields=[ Field("id", NonNullType(ID)), Field("name", NonNullType(String)), Field("owner", Person), ], interfaces=[Object], ) LivingBeing = UnionType("LivingBeing", [Person, Animal]) CreatePersonInput = InputObjectType( "CreatePersonInput", [InputField("id", ID), InputField("name", NonNullType(String))], ) return Schema( query_type=ObjectType( "Query", fields=[ Field("person", Person, args=[Argument("id", ID)]), Field("pet", Animal, args=[Argument("id", ID)]), Field("living_being", LivingBeing, args=[Argument("id", ID)]), ], ), mutation_type=ObjectType( "Mutation", fields=[Field("createPerson", CreatePersonInput)]), )
) await assert_execution( schema, """{ pets { name __typename ... on Dog { woofs } ... on Cat { meows } } }""", ) NamedType = InterfaceType("Named", [Field("name", String)]) DogType = ObjectType( "Dog", [Field("name", String), Field("woofs", Boolean)], interfaces=[NamedType], ) CatType = ObjectType( "Cat", [Field("name", String), Field("meows", Boolean)], interfaces=[NamedType], ) def _resolve_pet_type(value, *_):
def test_accept_object_with_list_interface_list_field(): iface = InterfaceType("IFace", [Field("f", ListType(String))]) schema = _single_type_schema( ObjectType("SomeObject", [Field("f", ListType(String))], interfaces=[iface])) schema.validate()
Character = InterfaceType( "Character", [ Field( "id", NonNullType(String), description="The id of the character." ), Field("name", String, description="The name of the character."), Field( "friends", ListType(lambda: Character), description=( "The friends of the character, or an empty list if they have " "none." ), ), Field( "appearsIn", ListType(Episode), description="Which movies they appear in.", ), Field( "secretBackstory", String, description="All secrets about their past.", ), ], description="A character in the Star Wars Trilogy", resolve_type=resolve_character_type, ) # type: InterfaceType
from py_gql.schema import ( Argument, Boolean, Directive, Field, InputField, InputObjectType, Int, InterfaceType, ListType, ObjectType, Schema, String, ) Interface = InterfaceType("Interface", [Field("fieldName", String)]) Implementing = ObjectType("Object", [Field("fieldName", String)], interfaces=[Interface]) DirInput = InputObjectType("DirInput", [InputField("field", String)]) WrappedDirInput = InputObjectType("WrappedDirInput", [InputField("field", String)]) Dir = Directive( "dir", ["OBJECT"], [ Argument("arg", DirInput), Argument("argList", ListType(WrappedDirInput))
async def test_type_resolution_on_interface_yields_useful_error( assert_execution, ): # WARN: Different from ref implementation -> this should never happen so we crash. def _resolve_pet_type(value, *_): return { Dog: DogType, Cat: CatType, Human: HumanType }.get(type(value), None) PetType = InterfaceType("Pet", [Field("name", String)], resolve_type=_resolve_pet_type) HumanType = ObjectType("Human", [Field("name", String)]) DogType = ObjectType( "Dog", [Field("name", String), Field("woofs", Boolean)], interfaces=[PetType], ) CatType = ObjectType( "Cat", [Field("name", String), Field("meows", Boolean)], interfaces=[PetType], ) schema = Schema( ObjectType( "Query", [ Field( "pets", ListType(PetType), resolver=lambda *_: [ Dog("Odie", True), Cat("Garfield", False), Human("Jon"), ], ) ], ), types=[DogType, CatType], ) await assert_execution( schema, """{ pets { name __typename ... on Dog { woofs } ... on Cat { meows } } }""", expected_exc=( RuntimeError, ('Runtime ObjectType "Human" is not a possible type for field ' '"pets[2]" of type "Pet".'), ), )
def test_accept_object_with_non_null_interface_null_field(): iface = InterfaceType("IFace", [Field("f", String)]) schema = _single_type_schema( ObjectType("SomeObject", [Field("f", NonNullType(String))], interfaces=[iface])) schema.validate()
from py_gql.schema.validation import validate_schema SomeScalar = ScalarType( "SomeScalar", serialize=lambda a: None, parse=lambda a: None, parse_literal=lambda a, **k: None, ) # type: ScalarType SomeObject = ObjectType("SomeObject", [Field("f", String)]) IncompleteObject = ObjectType("IncompleteObject", []) SomeUnion = UnionType("SomeUnion", [SomeObject]) SomeInterface = InterfaceType("SomeInterface", [Field("f", String)]) SomeEnum = EnumType("SomeEnum", [EnumValue("ONLY")]) SomeInputObject = InputObjectType( "SomeInputObject", [InputField("val", String, default_value="hello")]) def _type_modifiers(t): return [t, ListType(t), NonNullType(t), NonNullType(ListType(t))] def _with_modifiers(types): out = [] # type: List[GraphQLType] for t in types: out.extend(_type_modifiers(t))
def schema_2(): SomeBox = InterfaceType( "SomeBox", [Field("deepBox", lambda: SomeBox), Field("unrelatedField", String)], ) # type: InterfaceType StringBox = ObjectType( "StringBox", [ Field("scalar", String), Field("deepBox", lambda: StringBox), Field("unrelatedField", String), Field("listStringBox", lambda: ListType(StringBox)), Field("stringBox", lambda: StringBox), Field("intBox", lambda: IntBox), ], [SomeBox], ) # type: ObjectType IntBox = ObjectType( "IntBox", [ Field("scalar", Int), Field("deepBox", lambda: IntBox), Field("unrelatedField", String), Field("listStringBox", lambda: ListType(StringBox)), Field("stringBox", lambda: StringBox), Field("intBox", lambda: IntBox), ], [SomeBox], ) # type: ObjectType NonNullStringBox1 = InterfaceType("NonNullStringBox1", [Field("scalar", NonNullType(String))]) NonNullStringBox1Impl = ObjectType( "NonNullStringBox1Impl", [ Field("scalar", NonNullType(String)), Field("unrelatedField", String), Field("deepBox", SomeBox), ], [SomeBox, NonNullStringBox1], ) NonNullStringBox2 = InterfaceType("NonNullStringBox2", [Field("scalar", NonNullType(String))]) NonNullStringBox2Impl = ObjectType( "NonNullStringBox2Impl", [ Field("scalar", NonNullType(String)), Field("unrelatedField", String), Field("deepBox", SomeBox), ], [SomeBox, NonNullStringBox2], ) Connection = ObjectType( "Connection", [ Field( "edges", ListType( ObjectType( "Edge", [ Field( "node", ObjectType( "Node", [Field("id", ID), Field("name", String)], ), ) ], )), ) ], ) yield Schema( ObjectType( "QueryRoot", [Field("someBox", SomeBox), Field("connection", Connection)], ), types=[ IntBox, StringBox, NonNullStringBox1Impl, NonNullStringBox2Impl ], )
def test_accept_interface_fields_with_output_type(type_): iface = InterfaceType("GoodInterface", [Field("f", type_)]) schema = _single_type_schema(iface) schema.validate()
def schema(): Being = InterfaceType( "Being", [Field("name", String, [Argument("surname", Boolean)])]) Pet = InterfaceType( "Pet", [Field("name", String, [Argument("surname", Boolean)])]) Canine = InterfaceType( "Canine", [Field("name", String, [Argument("surname", Boolean)])]) DogCommand = EnumType( "DogCommand", [EnumValue("SIT", 0), EnumValue("HEEL", 1), EnumValue("DOWN", 2)], ) FurColor = EnumType( "FurColor", [ EnumValue("BROWN", 0), EnumValue("BLACK", 1), EnumValue("TAN", 2), EnumValue("SPOTTED", 3), EnumValue("NO_FUR", None), EnumValue("UNKNOWN", -1), ], ) Dog = ObjectType( "Dog", [ Field("name", String, args=[Argument("surname", Boolean)]), Field("nickname", String), Field("barkVolume", Int), Field("barks", Boolean), Field("doesKnowCommand", Boolean, [Argument("dogCommand", DogCommand)]), Field( "isHousetrained", Boolean, [Argument("atOtherHomes", Boolean, True)], ), Field( "isAtLocation", Boolean, [Argument("x", Int), Argument("y", Int)], ), ], [Being, Pet, Canine], ) Cat = ObjectType( "Cat", [ Field("name", String, args=[Argument("surname", Boolean)]), Field("nickname", String), Field("meowVolume", Int), Field("meows", Boolean), Field("furColor", FurColor), ], [Being, Pet], ) CatOrDog = UnionType("CatOrDog", [Dog, Cat]) Intelligent = InterfaceType("Intelligent", [Field("iq", Int)]) Human = ObjectType( "Human", lambda: [ Field("name", String, args=[Argument("surname", Boolean)]), Field("iq", Int), Field("pets", ListType(Pet)), Field("relatives", ListType(Human)), ], [Being, Intelligent], ) Alien = ObjectType( "Alien", [ Field("name", String, args=[Argument("surname", Boolean)]), Field("iq", Int), Field("numEyes", Int), ], [Being, Intelligent], ) DogOrHuman = UnionType("DogOrHuman", [Dog, Human]) HumanOrAlien = UnionType("HumanOrAlien", [Human, Alien]) ComplexInput = InputObjectType( "ComplexInput", [ InputField("requiredField", NonNullType(Boolean)), InputField( "nonNullField", NonNullType(Boolean), default_value=False), InputField("intField", Int), InputField("stringField", String), InputField("booleanField", Boolean), InputField("stringListField", ListType(String)), ], ) ComplicatedArgs = ObjectType( "ComplicatedArgs", [ Field("intArgField", String, [Argument("intArg", Int)]), Field( "nonNullIntArgField", String, [Argument("nonNullIntArg", NonNullType(Int))], ), Field("stringArgField", String, [Argument("stringArg", String)]), Field("booleanArgField", String, [Argument("booleanArg", Boolean)]), Field("enumArgField", String, [Argument("enumArg", FurColor)]), Field("floatArgField", String, [Argument("floatArg", Float)]), Field("idArgField", String, [Argument("idArg", ID)]), Field( "stringListArgField", String, [Argument("stringListArg", ListType(String))], ), Field( "stringListNonNullArgField", String, [ Argument("stringListNonNullArg", ListType(NonNullType(String))) ], ), Field( "complexArgField", String, [Argument("complexArg", ComplexInput)], ), Field( "multipleReqs", String, [ Argument("req1", NonNullType(Int)), Argument("req2", NonNullType(Int)), ], ), Field( "nonNullFieldWithDefault", String, [Argument("arg", NonNullType(Int), default_value=0)], ), Field( "multipleOpts", String, [Argument("opt1", Int, 0), Argument("opt2", Int, 0)], ), Field( "multipleOptAndReq", String, [ Argument("req1", NonNullType(Int)), Argument("req2", NonNullType(Int)), Argument("opt1", Int, 0), Argument("opt2", Int, 0), ], ), ], ) def _invalid(*args, **kwargs): raise ValueError("Invalid scalar is always invalid") def _stringify(value): return str(value) InvalidScalar = ScalarType("Invalid", _stringify, _invalid, _invalid) AnyScalar = ScalarType("Any", _stringify, lambda x: x) # type: ScalarType return Schema( ObjectType( "QueryRoot", [ Field("human", Human, [Argument("id", ID)]), Field("alien", Alien), Field("dog", Dog), Field("cat", Cat), Field("pet", Pet), Field("catOrDog", CatOrDog), Field("dogOrHuman", DogOrHuman), Field("humanOrAlien", HumanOrAlien), Field("humanOrAlien", HumanOrAlien), Field("complicatedArgs", ComplicatedArgs), Field("invalidArg", String, [Argument("arg", InvalidScalar)]), Field("anydArg", String, [Argument("arg", AnyScalar)]), ], ), types=[Cat, Dog, Human, Alien], directives=[ Directive("onQuery", ["QUERY"]), Directive("onMutation", ["MUTATION"]), Directive("onSubscription", ["SUBSCRIPTION"]), Directive("onField", ["FIELD"]), Directive("onFragmentDefinition", ["FRAGMENT_DEFINITION"]), Directive("onFragmentSpread", ["FRAGMENT_SPREAD"]), Directive("onInlineFragment", ["INLINE_FRAGMENT"]), Directive("onSchema", ["SCHEMA"]), Directive("onScalar", ["SCALAR"]), Directive("onObject", ["OBJECT"]), Directive("onFieldDefinition", ["FIELD_DEFINITION"]), Directive("onArgumentDefinition", ["ARGUMENT_DEFINITION"]), Directive("onInterface", ["INTERFACE"]), Directive("onUnion", ["UNION"]), Directive("onEnum", ["ENUM"]), Directive("onEnumValue", ["ENUM_VALUE"]), Directive("onInputObject", ["INPUT_OBJECT"]), Directive("onInputFieldDefinition", ["INPUT_FIELD_DEFINITION"]), ], )
def test_accept_object_fields_with_union_subtype_of_interface_field(): union = UnionType("union", [SomeObject]) iface = InterfaceType("IFace", [Field("f", union)]) obj = ObjectType("Obj", [Field("f", SomeObject)], interfaces=[iface]) schema = _single_type_schema(obj) schema.validate()