def schema_with_field_type(type_): return GraphQLSchema( query=GraphQLObjectType(name="Query", fields={"f": GraphQLField(type_)}), types=[type_], )
def test_executes_using_a_schema(): BlogImage = GraphQLObjectType( 'BlogImage', { 'url': GraphQLField(GraphQLString), 'width': GraphQLField(GraphQLInt), 'height': GraphQLField(GraphQLInt), }) BlogAuthor = GraphQLObjectType( 'Author', lambda: { 'id': GraphQLField(GraphQLString), 'name': GraphQLField(GraphQLString), 'pic': GraphQLField(BlogImage, args={ 'width': GraphQLArgument(GraphQLInt), 'height': GraphQLArgument(GraphQLInt), }, resolver=lambda obj, info, **args: obj.pic( args['width'], args['height'])), 'recentArticle': GraphQLField(BlogArticle), }) BlogArticle = GraphQLObjectType( 'Article', { 'id': GraphQLField(GraphQLNonNull(GraphQLString)), 'isPublished': GraphQLField(GraphQLBoolean), 'author': GraphQLField(BlogAuthor), 'title': GraphQLField(GraphQLString), 'body': GraphQLField(GraphQLString), 'keywords': GraphQLField(GraphQLList(GraphQLString)), }) BlogQuery = GraphQLObjectType( 'Query', { 'article': GraphQLField( BlogArticle, args={'id': GraphQLArgument(GraphQLID)}, resolver=lambda obj, info, **args: Article(args['id'])), 'feed': GraphQLField(GraphQLList(BlogArticle), resolver=lambda *_: map(Article, range(1, 10 + 1))), }) BlogSchema = GraphQLSchema(BlogQuery) class Article(object): def __init__(self, id): self.id = id self.isPublished = True self.author = Author() self.title = 'My Article {}'.format(id) self.body = 'This is a post' self.hidden = 'This data is not exposed in the schema' self.keywords = ['foo', 'bar', 1, True, None] class Author(object): id = 123 name = 'John Smith' def pic(self, width, height): return Pic(123, width, height) @property def recentArticle(self): return Article(1) class Pic(object): def __init__(self, uid, width, height): self.url = 'cdn://{}'.format(uid) self.width = str(width) self.height = str(height) request = ''' { feed { id, title }, article(id: "1") { ...articleFields, author { id, name, pic(width: 640, height: 480) { url, width, height }, recentArticle { ...articleFields, keywords } } } } fragment articleFields on Article { id, isPublished, title, body, hidden, notdefined } ''' # Note: this is intentionally not validating to ensure appropriate # behavior occurs when executing an invalid query. result = execute(BlogSchema, parse(request)) assert not result.errors assert result.data == \ { "feed": [ { "id": "1", "title": "My Article 1" }, { "id": "2", "title": "My Article 2" }, { "id": "3", "title": "My Article 3" }, { "id": "4", "title": "My Article 4" }, { "id": "5", "title": "My Article 5" }, { "id": "6", "title": "My Article 6" }, { "id": "7", "title": "My Article 7" }, { "id": "8", "title": "My Article 8" }, { "id": "9", "title": "My Article 9" }, { "id": "10", "title": "My Article 10" } ], "article": { "id": "1", "isPublished": True, "title": "My Article 1", "body": "This is a post", "author": { "id": "123", "name": "John Smith", "pic": { "url": "cdn://123", "width": 640, "height": 480 }, "recentArticle": { "id": "1", "isPublished": True, "title": "My Article 1", "body": "This is a post", "keywords": [ "foo", "bar", "1", "true", None ] } } } }
human_type = GraphQLObjectType( "Human", lambda: { "id": GraphQLField( GraphQLNonNull(GraphQLString), description="The id of the human." ), "name": GraphQLField(GraphQLString, description="The name of the human."), "friends": GraphQLField( GraphQLList(character_interface), description="The friends of the human," " or an empty list if they have none.", resolve=lambda human, _info: get_friends(human), ), "appearsIn": GraphQLField( GraphQLList(episode_enum), description="Which movies they appear in." ), "homePlanet": GraphQLField( GraphQLString, description="The home planet of the human, or null if unknown.", ), "secretBackstory": GraphQLField( GraphQLString, resolve=lambda human, _info: get_secret_backstory(human), description="Where are they from and how they came to be who they are.", ), }, interfaces=[character_interface], description="A humanoid creature in the Star Wars universe.", )
async def executes_arbitrary_code(): # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class Data: def a(self, _info): return "Apple" def b(self, _info): return "Banana" def c(self, _info): return "Cookie" def d(self, _info): return "Donut" def e(self, _info): return "Egg" f = "Fish" # Called only by DataType::pic static resolver def pic(self, _info, size=50): return f"Pic of size: {size}" def deep(self, _info): return DeepData() def promise(self, _info): return promise_data() # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class DeepData: def a(self, _info): return "Already Been Done" def b(self, _info): return "Boring" def c(self, _info): return ["Contrived", None, "Confusing"] def deeper(self, _info): return [Data(), None, Data()] async def promise_data(): await asyncio.sleep(0) return Data() DeepDataType: GraphQLObjectType DataType = GraphQLObjectType( "DataType", lambda: { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLString), "d": GraphQLField(GraphQLString), "e": GraphQLField(GraphQLString), "f": GraphQLField(GraphQLString), "pic": GraphQLField( GraphQLString, args={"size": GraphQLArgument(GraphQLInt)}, resolve=lambda obj, info, size: obj.pic(info, size), ), "deep": GraphQLField(DeepDataType), "promise": GraphQLField(DataType), }, ) DeepDataType = GraphQLObjectType( "DeepDataType", { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLList(GraphQLString)), "deeper": GraphQLField(GraphQLList(DataType)), }, ) document = parse(""" query ($size: Int) { a, b, x: c ...c f ...on DataType { pic(size: $size) promise { a } } deep { a b c deeper { a b } } } fragment c on DataType { d e } """) awaitable_result = execute(GraphQLSchema(DataType), document, Data(), variable_values={"size": 100}) assert isinstance(awaitable_result, Awaitable) result = await awaitable_result assert result == ( { "a": "Apple", "b": "Banana", "x": "Cookie", "d": "Donut", "e": "Egg", "f": "Fish", "pic": "Pic of size: 100", "promise": { "a": "Apple" }, "deep": { "a": "Already Been Done", "b": "Boring", "c": ["Contrived", None, "Confusing"], "deeper": [ { "a": "Apple", "b": "Banana" }, None, { "a": "Apple", "b": "Banana" }, ], }, }, None, )
TestType = GraphQLObjectType( "TestType", { "fieldWithEnumInput": field_with_input_arg(GraphQLArgument(TestEnum)), "fieldWithNonNullableEnumInput": field_with_input_arg(GraphQLArgument(GraphQLNonNull(TestEnum))), "fieldWithObjectInput": field_with_input_arg(GraphQLArgument(TestInputObject)), "fieldWithCustomObjectInput": field_with_input_arg(GraphQLArgument(TestCustomInputObject)), "fieldWithNullableStringInput": field_with_input_arg(GraphQLArgument(GraphQLString)), "fieldWithNonNullableStringInput": field_with_input_arg(GraphQLArgument(GraphQLNonNull(GraphQLString))), "fieldWithDefaultArgumentValue": field_with_input_arg( GraphQLArgument(GraphQLString, default_value="Hello World")), "fieldWithNonNullableStringInputAndDefaultArgValue": field_with_input_arg( GraphQLArgument(GraphQLNonNull(GraphQLString), default_value="Hello World")), "fieldWithNestedInputObject": field_with_input_arg( GraphQLArgument(TestNestedInputObject, default_value="Hello World")), "list": field_with_input_arg(GraphQLArgument(GraphQLList(GraphQLString))), "nnList": field_with_input_arg( GraphQLArgument(GraphQLNonNull(GraphQLList(GraphQLString)))), "listNN": field_with_input_arg( GraphQLArgument(GraphQLList(GraphQLNonNull(GraphQLString)))), "nnListNN": field_with_input_arg( GraphQLArgument( GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString))))), }, )
def get_graphql_schema_from_schema_graph(schema_graph, class_to_field_type_overrides=None, hidden_classes=None): """Return a GraphQL schema object corresponding to the schema of the given schema graph. Args: schema_graph: SchemaGraph class_to_field_type_overrides: optional dict, class name -> {field name -> field type}, (string -> {string -> GraphQLType}). Used to override the type of a field in the class where it's first defined and all the class's subclasses. hidden_classes: optional set of strings, classes to not include in the GraphQL schema. Returns: tuple of (GraphQL schema object, GraphQL type equivalence hints dict). The tuple is of type (GraphQLSchema, {GraphQLObjectType -> GraphQLUnionType}). """ if class_to_field_type_overrides is None: class_to_field_type_overrides = dict() if hidden_classes is None: hidden_classes = set() _validate_overriden_fields_are_not_defined_in_superclasses( class_to_field_type_overrides, schema_graph) # The field types of subclasses must also be overridden. # Remember that the result returned by get_subclass_set(class_name) includes class_name itself. inherited_field_type_overrides = _get_inherited_field_types( class_to_field_type_overrides, schema_graph) graphql_types = OrderedDict() type_equivalence_hints = OrderedDict() # For each vertex class, construct its analogous GraphQL type representation. for vertex_cls_name in sorted(schema_graph.vertex_class_names): vertex_cls = schema_graph.get_element_by_class_name(vertex_cls_name) if vertex_cls_name in hidden_classes: continue inherited_field_type_overrides.setdefault(vertex_cls_name, dict()) field_type_overrides = inherited_field_type_overrides[vertex_cls_name] # We have to use delayed type binding here, because some of the type references # are circular: if an edge connects vertices of types A and B, then # GraphQL type A has a List[B] field, and type B has a List[A] field. # To avoid the circular dependency, GraphQL allows us to initialize the types # initially without their field information, and fill in their field information # later using a lambda function as the second argument to GraphQLObjectType. # This lambda function will be called on each type after all types are created # in their initial blank state. # # However, 'cls_name' is a variable that would not be correctly bound # if we naively tried to construct a lambda in-place, because Python lambdas # are not closures. Instead, call a function with 'cls_name' as an argument, # and have that function construct and return the required lambda. field_specification_lambda = _create_field_specification( schema_graph, graphql_types, field_type_overrides, hidden_classes, vertex_cls_name) # Abstract classes are interfaces, concrete classes are object types. current_graphql_type = None if vertex_cls.abstract: # "fields" is a kwarg in the interface constructor, even though # it's a positional arg in the object type constructor. current_graphql_type = GraphQLInterfaceType( vertex_cls_name, fields=field_specification_lambda) else: # For similar reasons as the field_specification_lambda, # we need to create an interface specification lambda function that # specifies the interfaces implemented by this type. interface_specification_lambda = _create_interface_specification( schema_graph, graphql_types, hidden_classes, vertex_cls_name) # N.B.: Ignore the "is_type_of" argument below, it is simply a circumvention of # a validation check inside the GraphQL library. The library assumes that we'll # use its execution system, so it complains that we don't provide a means to # differentiate between different implementations of the same interface. # We don't care, because we compile the GraphQL query to a database query. current_graphql_type = GraphQLObjectType( vertex_cls_name, field_specification_lambda, interfaces=interface_specification_lambda, is_type_of=lambda: None, ) graphql_types[vertex_cls_name] = current_graphql_type # For each vertex class, construct all union types representations. for vertex_cls_name in sorted(schema_graph.vertex_class_names): vertex_cls = schema_graph.get_element_by_class_name(vertex_cls_name) if vertex_cls_name in hidden_classes: continue vertex_cls_subclasses = schema_graph.get_subclass_set(vertex_cls_name) if not vertex_cls.abstract and len(vertex_cls_subclasses) > 1: # In addition to creating this class' corresponding GraphQL type, we'll need a # union type to represent it when it appears as the endpoint of an edge. union_type_name = _get_union_type_name(vertex_cls_subclasses) # For similar reasons as the field_specification_lambda, # we need to create a union type specification lambda function that specifies # the types that this union type is composed of. type_specification_lambda = _create_union_types_specification( schema_graph, graphql_types, hidden_classes, vertex_cls_name) union_type = GraphQLUnionType(union_type_name, types=type_specification_lambda) graphql_types[union_type_name] = union_type type_equivalence_hints[graphql_types[vertex_cls_name]] = union_type # Include all abstract non-vertex classes whose only non-abstract subclasses are vertices. for non_graph_cls_name in sorted(schema_graph.non_graph_class_names): if non_graph_cls_name in hidden_classes: continue if not schema_graph.get_element_by_class_name( non_graph_cls_name).abstract: continue # No need to add the possible abstract class if it doesn't have subclasses besides itself. if len(schema_graph.get_subclass_set(non_graph_cls_name)) > 1: if _has_only_vertex_non_abstract_subclasses( non_graph_cls_name, schema_graph): # Add abstract class as an interface. inherited_field_type_overrides.setdefault( non_graph_cls_name, dict()) field_type_overrides = inherited_field_type_overrides[ non_graph_cls_name] field_specification_lambda = _create_field_specification( schema_graph, graphql_types, field_type_overrides, hidden_classes, non_graph_cls_name, ) graphql_type = GraphQLInterfaceType( non_graph_cls_name, fields=field_specification_lambda) graphql_types[non_graph_cls_name] = graphql_type if not graphql_types: raise EmptySchemaError( "After evaluating all subclasses of V, we were not able to find " "visible schema data to import into the GraphQL schema object") # Create the root query GraphQL type. Consists of all non-union classes, i.e. # all non-abstract classes (as GraphQL types) and all abstract classes (as GraphQL interfaces). RootSchemaQuery = GraphQLObjectType( "RootSchemaQuery", OrderedDict([(name, GraphQLField(GraphQLList(value))) for name, value in sorted(six.iteritems(graphql_types), key=lambda x: x[0]) if not isinstance(value, GraphQLUnionType)]), ) schema = GraphQLSchema(RootSchemaQuery, directives=DIRECTIVES) # Note that the GraphQLSchema reconstructs the set of types in the schema by recursively # searching through the fields of the RootSchemaQuery. Since union types can only appear in the # fields of other types as edges, union types with no in or out edges will not appear in the # schema. Therefore, we remove these unions and their keys from the type equivalence hints. return schema, _get_referenced_type_equivalences(graphql_types, type_equivalence_hints)
def describe_handles_non_null_argument(): # noinspection PyPep8Naming def _resolve(_obj, _info, cannotBeNull): if isinstance(cannotBeNull, str): return f"Passed: {cannotBeNull}" schema_with_non_null_arg = GraphQLSchema( GraphQLObjectType( "Query", { "withNonNullArg": GraphQLField( GraphQLString, args={ "cannotBeNull": GraphQLArgument(GraphQLNonNull(GraphQLString)) }, resolve=_resolve, ) }, )) def succeeds_when_passed_non_null_literal_value(): result = execute( schema_with_non_null_arg, parse(""" query { withNonNullArg (cannotBeNull: "literal value") } """), ) assert result == ({ "withNonNullArg": "Passed: literal value" }, None) def succeeds_when_passed_non_null_variable_value(): result = execute( schema_with_non_null_arg, parse(""" query ($testVar: String = "default value") { withNonNullArg (cannotBeNull: $testVar) } """), variable_values={}, ) # intentionally missing variable assert result == ({ "withNonNullArg": "Passed: default value" }, None) def field_error_when_missing_non_null_arg(): # Note: validation should identify this issue first # (missing args rule) however execution should still # protect against this. result = execute( schema_with_non_null_arg, parse(""" query { withNonNullArg } """), ) assert result == ( { "withNonNullArg": None }, [{ "message": "Argument 'cannotBeNull' of required type" " 'String!' was not provided.", "locations": [(3, 23)], "path": ["withNonNullArg"], }], ) def field_error_when_non_null_arg_provided_null(): # Note: validation should identify this issue first # (values of correct type rule) however execution # should still protect against this. result = execute( schema_with_non_null_arg, parse(""" query { withNonNullArg(cannotBeNull: null) } """), ) assert result == ( { "withNonNullArg": None }, [{ "message": "Argument 'cannotBeNull' of non-null type" " 'String!' must not be null.", "locations": [(3, 52)], "path": ["withNonNullArg"], }], ) def field_error_when_non_null_arg_not_provided_variable_value(): # Note: validation should identify this issue first # (variables in allowed position rule) however execution # should still protect against this. result = execute( schema_with_non_null_arg, parse(""" query ($testVar: String) { withNonNullArg(cannotBeNull: $testVar) } """), variable_values={}, ) # intentionally missing variable assert result == ( { "withNonNullArg": None }, [{ "message": "Argument 'cannotBeNull' of required type" " 'String!' was provided the variable" " '$testVar' which was not provided" " a runtime value.", "locations": [(3, 52)], "path": ["withNonNullArg"], }], ) def field_error_when_non_null_arg_provided_explicit_null_variable(): result = execute( schema_with_non_null_arg, parse(""" query ($testVar: String = "default value") { withNonNullArg (cannotBeNull: $testVar) } """), variable_values={"testVar": None}, ) assert result == ( { "withNonNullArg": None }, [{ "message": "Argument 'cannotBeNull' of non-null type" " 'String!' must not be null.", "locations": [(3, 53)], "path": ["withNonNullArg"], }], )
def test_builds_a_schema_with_a_recursive_type_reference(): recurType = GraphQLObjectType( name="Recur", fields=lambda: {"recur": GraphQLField(recurType)}) schema = GraphQLSchema(query=recurType) _test_schema(schema)
def test_builds_a_schema_with_an_enum(): FoodEnum = GraphQLEnumType( name="Food", description="Varieties of food stuffs", values=OrderedDict([ ( "VEGETABLES", GraphQLEnumValue(1, description="Foods that are vegetables."), ), ("FRUITS", GraphQLEnumValue(2, description="Foods that are fruits.")), ("OILS", GraphQLEnumValue(3, description="Foods that are oils.")), ("DAIRY", GraphQLEnumValue(4, description="Foods that are dairy.")), ("MEAT", GraphQLEnumValue(5, description="Foods that are meat.")), ]), ) schema = GraphQLSchema(query=GraphQLObjectType( name="EnumFields", fields={ "food": GraphQLField( FoodEnum, description="Repeats the arg you give it", args={ "kind": GraphQLArgument(FoodEnum, description="what kind of food?") }, ) }, )) client_schema = _test_schema(schema) clientFoodEnum = client_schema.get_type("Food") assert isinstance(clientFoodEnum, GraphQLEnumType) assert clientFoodEnum.values == [ GraphQLEnumValue( name="VEGETABLES", value="VEGETABLES", description="Foods that are vegetables.", deprecation_reason=None, ), GraphQLEnumValue( name="FRUITS", value="FRUITS", description="Foods that are fruits.", deprecation_reason=None, ), GraphQLEnumValue( name="OILS", value="OILS", description="Foods that are oils.", deprecation_reason=None, ), GraphQLEnumValue( name="DAIRY", value="DAIRY", description="Foods that are dairy.", deprecation_reason=None, ), GraphQLEnumValue( name="MEAT", value="MEAT", description="Foods that are meat.", deprecation_reason=None, ), ]
MammalType = GraphQLInterfaceType( "Mammal", lambda: { "progeny": GraphQLField(GraphQLList(MammalType)), # type: ignore "mother": GraphQLField(MammalType), # type: ignore "father": GraphQLField(MammalType), # type: ignore }, interfaces=[LifeType], ) DogType = GraphQLObjectType( "Dog", lambda: { "name": GraphQLField(GraphQLString), "barks": GraphQLField(GraphQLBoolean), "progeny": GraphQLField(GraphQLList(DogType)), # type: ignore "mother": GraphQLField(DogType), # type: ignore "father": GraphQLField(DogType), # type: ignore }, interfaces=[MammalType, LifeType, NamedType], is_type_of=lambda value, info: isinstance(value, Dog), ) CatType = GraphQLObjectType( "Cat", lambda: { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), "progeny": GraphQLField(GraphQLList(CatType)), # type: ignore "mother": GraphQLField(CatType), # type: ignore "father": GraphQLField(CatType), # type: ignore },
humanType = GraphQLObjectType( "Human", description="A humanoid creature in the Star Wars universe.", fields=lambda: { "id": GraphQLField( GraphQLNonNull(GraphQLString), description="The id of the human.", ), "name": GraphQLField( GraphQLString, description="The name of the human.", ), "friends": GraphQLField( GraphQLList(characterInterface), description= "The friends of the human, or an empty list if they have none.", resolver=lambda human, info, **args: getFriends(human), ), "appearsIn": GraphQLField( GraphQLList(episodeEnum), description="Which movies they appear in.", ), "homePlanet": GraphQLField( GraphQLString, description="The home planet of the human, or null if unknown.", ), }, interfaces=[characterInterface], )
from collections import OrderedDict from py.test import raises from graphql.type import (GraphQLArgument, GraphQLBoolean, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLUnionType) from graphql.type.definition import is_input_type, is_output_type BlogImage = GraphQLObjectType( 'Image', { 'url': GraphQLField(GraphQLString), 'width': GraphQLField(GraphQLInt), 'height': GraphQLField(GraphQLInt), }) BlogAuthor = GraphQLObjectType( 'Author', lambda: { 'id': GraphQLField(GraphQLString), 'name': GraphQLField(GraphQLString), 'pic': GraphQLField(BlogImage, args={ 'width': GraphQLArgument(GraphQLInt), 'height': GraphQLArgument(GraphQLInt), }),
user_connection: GraphQLObjectType user_type = GraphQLObjectType( "User", fields=lambda: { "name": GraphQLField(GraphQLString), "friends": GraphQLField( friend_connection, args=connection_args, resolve=lambda user, _info, **args: connection_from_array( user.friends, args ), ), "friendsForward": GraphQLField( user_connection, args=forward_connection_args, resolve=lambda user, _info, **args: connection_from_array( user.friends, args ), ), "friendsBackward": GraphQLField( user_connection, args=backward_connection_args, resolve=lambda user, _info, **args: connection_from_array( user.friends, args ), ), }, ) friend_connection = connection_definitions(
TestType = GraphQLObjectType( "TestType", { "fieldWithObjectInput": GraphQLField( GraphQLString, args={"input": GraphQLArgument(TestInputObject)}, resolver=input_to_json, ), "fieldWithCustomObjectInput": GraphQLField( GraphQLBoolean, args={"input": GraphQLArgument(TestCustomInputObject)}, resolver=lambda root, info, **args: isinstance( args.get("input"), my_special_dict ), ), "fieldWithNullableStringInput": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLString)}, resolver=input_to_json, ), "fieldWithNonNullableStringInput": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLNonNull(GraphQLString))}, resolver=input_to_json, ), "fieldWithDefaultArgumentValue": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLString, "Hello World")}, resolver=input_to_json, ), "fieldWithNestedInputObject": GraphQLField( GraphQLString, args={"input": GraphQLArgument(TestNestedInputObject, "Hello World")}, resolver=input_to_json, ), "list": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLList(GraphQLString))}, resolver=input_to_json, ), "nnList": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLNonNull(GraphQLList(GraphQLString)))}, resolver=input_to_json, ), "listNN": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLList(GraphQLNonNull(GraphQLString)))}, resolver=input_to_json, ), "nnListNN": GraphQLField( GraphQLString, args={ "input": GraphQLArgument( GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString))) ) }, resolver=input_to_json, ), }, )
async def is_type_of_used_to_resolve_runtime_type_for_interface(): PetType = GraphQLInterfaceType("Pet", {"name": GraphQLField(GraphQLString)}) DogType = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, interfaces=[PetType], is_type_of=get_is_type_of(Dog), ) CatType = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, interfaces=[PetType], is_type_of=get_is_type_of(Cat), ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(PetType), resolve=lambda *_args: [ Dog("Odie", True), Cat("Garfield", False), ], ) }, ), types=[CatType, DogType], ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ result = await graphql(schema, query) assert result == ( { "pets": [ { "name": "Odie", "woofs": True }, { "name": "Garfield", "meows": False }, ] }, None, )
def print_single_field_schema(field_config): Root = GraphQLObjectType(name="Root", fields={"singleField": field_config}) return print_for_test(GraphQLSchema(Root))
}, ) Dog = GraphQLObjectType( "Dog", lambda: { "name": GraphQLField( GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)} ), "nickname": GraphQLField(GraphQLString), "barkVolume": GraphQLField(GraphQLInt), "barks": GraphQLField(GraphQLBoolean), "doesKnowCommand": GraphQLField( GraphQLBoolean, {"dogCommand": GraphQLArgument(DogCommand)} ), "isHouseTrained": GraphQLField( GraphQLBoolean, args={"atOtherHomes": GraphQLArgument(GraphQLBoolean, default_value=True)}, ), "isAtLocation": GraphQLField( GraphQLBoolean, args={"x": GraphQLArgument(GraphQLInt), "y": GraphQLArgument(GraphQLInt)}, ), "mother": GraphQLField(Dog), # type: ignore "father": GraphQLField(Dog), # type: ignore }, interfaces=[Being, Pet, Mammal, Canine], is_type_of=lambda *_args: True, ) FurColor: GraphQLEnumType
def test_print_introspection_schema(): Root = GraphQLObjectType( name="Root", fields={"onlyField": GraphQLField(GraphQLString)} ) Schema = GraphQLSchema(Root) output = "\n" + print_introspection_schema(Schema) assert ( output == """ schema { query: Root } directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE type __Directive { name: String! description: String locations: [__DirectiveLocation!]! args: [__InputValue!]! onOperation: Boolean! @deprecated(reason: "Use `locations`.") onFragment: Boolean! @deprecated(reason: "Use `locations`.") onField: Boolean! @deprecated(reason: "Use `locations`.") } enum __DirectiveLocation { QUERY MUTATION SUBSCRIPTION FIELD FRAGMENT_DEFINITION FRAGMENT_SPREAD INLINE_FRAGMENT SCHEMA SCALAR OBJECT FIELD_DEFINITION ARGUMENT_DEFINITION INTERFACE UNION ENUM ENUM_VALUE INPUT_OBJECT INPUT_FIELD_DEFINITION } type __EnumValue { name: String! description: String isDeprecated: Boolean! deprecationReason: String } type __Field { name: String! description: String args: [__InputValue!]! type: __Type! isDeprecated: Boolean! deprecationReason: String } type __InputValue { name: String! description: String type: __Type! defaultValue: String } type __Schema { types: [__Type!]! queryType: __Type! mutationType: __Type subscriptionType: __Type directives: [__Directive!]! } type __Type { kind: __TypeKind! name: String description: String fields(includeDeprecated: Boolean = false): [__Field!] interfaces: [__Type!] possibleTypes: [__Type!] enumValues(includeDeprecated: Boolean = false): [__EnumValue!] inputFields: [__InputValue!] ofType: __Type } enum __TypeKind { SCALAR OBJECT INTERFACE UNION ENUM INPUT_OBJECT LIST NON_NULL } """ )
def describe_execute_synchronously_when_possible(): def _resolve_sync(root_value, info_): return root_value async def _resolve_async(root_value, info_): return root_value schema = GraphQLSchema( GraphQLObjectType( "Query", { "syncField": GraphQLField(GraphQLString, resolve=_resolve_sync), "asyncField": GraphQLField(GraphQLString, resolve=_resolve_async), }, ), GraphQLObjectType( "Mutation", { "syncMutationField": GraphQLField(GraphQLString, resolve=_resolve_sync) }, ), ) def does_not_return_a_promise_for_initial_errors(): doc = "fragment Example on Query { syncField }" assert execute(schema, parse(doc), "rootValue") == ( None, [{ "message": "Must provide an operation." }], ) def does_not_return_a_promise_if_fields_are_all_synchronous(): doc = "query Example { syncField }" assert execute(schema, parse(doc), "rootValue") == ( { "syncField": "rootValue" }, None, ) def does_not_return_a_promise_if_mutation_fields_are_all_synchronous(): doc = "mutation Example { syncMutationField }" assert execute(schema, parse(doc), "rootValue") == ( { "syncMutationField": "rootValue" }, None, ) @mark.asyncio async def returns_a_promise_if_any_field_is_asynchronous(): doc = "query Example { syncField, asyncField }" result = execute(schema, parse(doc), "rootValue") assert isawaitable(result) assert await result == ( { "syncField": "rootValue", "asyncField": "rootValue" }, None, ) def describe_graphql_sync(): def does_not_return_a_promise_for_syntax_errors(): doc = "fragment Example on Query { { { syncField }" assert graphql_sync(schema, doc) == ( None, [{ "message": "Syntax Error: Expected Name, found {", "locations": [(1, 29)], }], ) def does_not_return_a_promise_for_validation_errors(): doc = "fragment Example on Query { unknownField }" assert graphql_sync(schema, doc) == ( None, [ { "message": "Cannot query field 'unknownField' on type 'Query'." " Did you mean 'syncField' or 'asyncField'?", "locations": [(1, 29)], }, { "message": "Fragment 'Example' is never used.", "locations": [(1, 1)], }, ], ) def does_not_return_a_promise_for_sync_execution(): doc = "query Example { syncField }" assert graphql_sync(schema, doc, "rootValue") == ( { "syncField": "rootValue" }, None, ) def throws_if_encountering_async_operation(): doc = "query Example { syncField, asyncField }" with raises(RuntimeError) as exc_info: graphql_sync(schema, doc, "rootValue") msg = str(exc_info.value) assert msg == "GraphQL execution failed to complete synchronously."
from collections import namedtuple from graphql import graphql from graphql.type import ( GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString, ) from graphql_relay.node.plural import plural_identifying_root_field userType = GraphQLObjectType('User', fields=lambda: { 'username': GraphQLField(GraphQLString), 'url': GraphQLField(GraphQLString), }) User = namedtuple('User', ['username', 'url']) queryType = GraphQLObjectType( 'Query', fields=lambda: { 'usernames': plural_identifying_root_field( 'usernames', description='Map from a username to the user', input_type=GraphQLString, output_type=userType, resolve_single_input=lambda info, username: User( username=username, url='www.facebook.com/' + username + '?lang=' + info.root_value
async def nulls_out_error_subtrees(): document = parse(""" { syncOk syncError syncRawError syncReturnError syncReturnErrorList asyncOk asyncError asyncRawError asyncReturnError asyncReturnErrorWithExtensions } """) schema = GraphQLSchema( GraphQLObjectType( "Type", { "syncOk": GraphQLField(GraphQLString), "syncError": GraphQLField(GraphQLString), "syncRawError": GraphQLField(GraphQLString), "syncReturnError": GraphQLField(GraphQLString), "syncReturnErrorList": GraphQLField( GraphQLList(GraphQLString)), "asyncOk": GraphQLField(GraphQLString), "asyncError": GraphQLField(GraphQLString), "asyncErrorWithExtensions": GraphQLField(GraphQLString), "asyncRawError": GraphQLField(GraphQLString), "asyncReturnError": GraphQLField(GraphQLString), "asyncReturnErrorWithExtensions": GraphQLField(GraphQLString), }, )) # noinspection PyPep8Naming,PyMethodMayBeStatic class Data: def syncOk(self, _info): return "sync ok" def syncError(self, _info): raise GraphQLError("Error getting syncError") def syncRawError(self, _info): raise Exception("Error getting syncRawError") def syncReturnError(self, _info): return Exception("Error getting syncReturnError") def syncReturnErrorList(self, _info): return [ "sync0", Exception("Error getting syncReturnErrorList1"), "sync2", Exception("Error getting syncReturnErrorList3"), ] async def asyncOk(self, _info): return "async ok" async def asyncError(self, _info): raise Exception("Error getting asyncError") async def asyncRawError(self, _info): raise Exception("Error getting asyncRawError") async def asyncReturnError(self, _info): return GraphQLError("Error getting asyncReturnError") async def asyncReturnErrorWithExtensions(self, _info): return GraphQLError( "Error getting asyncReturnErrorWithExtensions", extensions={"foo": "bar"}, ) awaitable_result = execute(schema, document, Data()) assert isinstance(awaitable_result, Awaitable) result = await awaitable_result assert result == ( { "syncOk": "sync ok", "syncError": None, "syncRawError": None, "syncReturnError": None, "syncReturnErrorList": ["sync0", None, "sync2", None], "asyncOk": "async ok", "asyncError": None, "asyncRawError": None, "asyncReturnError": None, "asyncReturnErrorWithExtensions": None, }, [ { "message": "Error getting syncError", "locations": [(4, 15)], "path": ["syncError"], }, { "message": "Error getting syncRawError", "locations": [(5, 15)], "path": ["syncRawError"], }, { "message": "Error getting syncReturnError", "locations": [(6, 15)], "path": ["syncReturnError"], }, { "message": "Error getting syncReturnErrorList1", "locations": [(7, 15)], "path": ["syncReturnErrorList", 1], }, { "message": "Error getting syncReturnErrorList3", "locations": [(7, 15)], "path": ["syncReturnErrorList", 3], }, { "message": "Error getting asyncError", "locations": [(9, 15)], "path": ["asyncError"], }, { "message": "Error getting asyncRawError", "locations": [(10, 15)], "path": ["asyncRawError"], }, { "message": "Error getting asyncReturnError", "locations": [(11, 15)], "path": ["asyncReturnError"], }, { "message": "Error getting asyncReturnErrorWithExtensions", "locations": [(12, 15)], "path": ["asyncReturnErrorWithExtensions"], "extensions": { "foo": "bar" }, }, ], )
async def is_type_of_with_async_error(): PetType = GraphQLInterfaceType("Pet", {"name": GraphQLField(GraphQLString)}) DogType = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, interfaces=[PetType], is_type_of=is_type_of_error, ) CatType = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, interfaces=[PetType], is_type_of=get_is_type_of(Cat), ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(PetType), resolve=lambda *_args: [ Dog("Odie", True), Cat("Garfield", False), ], ) }, ), types=[CatType, DogType], ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ result = await graphql(schema, query) # Note: we get two errors, because first all types are resolved # and only then they are checked sequentially assert result.data == {"pets": [None, None]} assert list(map(format_error, result.errors)) == [ # type: ignore { "message": "We are testing this error", "locations": [(3, 15)], "path": ["pets", 0], }, { "message": "We are testing this error", "locations": [(3, 15)], "path": ["pets", 1], }, ]
def builds_a_schema_with_an_enum(): food_enum = GraphQLEnumType( "Food", { "VEGETABLES": GraphQLEnumValue(1, description="Foods that are vegetables."), "FRUITS": GraphQLEnumValue(2, description="Foods that are fruits."), "OILS": GraphQLEnumValue(3, description="Foods that are oils."), "DAIRY": GraphQLEnumValue(4, description="Foods that are dairy."), "MEAT": GraphQLEnumValue(5, description="Foods that are meat."), }, description="Varieties of food stuffs", ) schema = GraphQLSchema( GraphQLObjectType( "EnumFields", { "food": GraphQLField( food_enum, args={ "kind": GraphQLArgument(food_enum, description="what kind of food?") }, description="Repeats the arg you give it", ) }, )) introspection = introspection_from_schema(schema) client_schema = build_client_schema(introspection) second_introspection = introspection_from_schema(client_schema) assert second_introspection == introspection # It's also an Enum type on the client. client_food_enum = assert_enum_type(client_schema.get_type("Food")) values_dict = client_food_enum.values descriptions = { name: value.description for name, value in values_dict.items() } assert descriptions == { "VEGETABLES": "Foods that are vegetables.", "FRUITS": "Foods that are fruits.", "OILS": "Foods that are oils.", "DAIRY": "Foods that are dairy.", "MEAT": "Foods that are meat.", } values = values_dict.values() assert all(value.value is None for value in values) assert all(value.is_deprecated is False for value in values) assert all(value.deprecation_reason is None for value in values) assert all(value.extensions is None for value in values) assert all(value.ast_node is None for value in values)
async def resolve_type_on_union_yields_useful_error(): HumanType = GraphQLObjectType("Human", {"name": GraphQLField(GraphQLString)}) DogType = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, ) CatType = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, ) PetType = GraphQLUnionType( "Pet", [DogType, CatType], resolve_type=get_type_resolver({ Dog: DogType, Cat: CatType, Human: HumanType }), ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(PetType), resolve=lambda *_: [ Dog("Odie", True), Cat("Garfield", False), Human("Jon"), ], ) }, )) query = """ { pets { ... on Dog { name woofs } ... on Cat { name meows } } } """ result = await graphql(schema, query) assert result.data == { "pets": [ { "name": "Odie", "woofs": True }, { "name": "Garfield", "meows": False }, None, ] } assert result.errors assert len(result.errors) == 1 assert format_error(result.errors[0]) == { "message": "Runtime Object type 'Human'" " is not a possible type for 'Pet'.", "locations": [(3, 15)], "path": ["pets", 2], }
if getHuman(character.id) else droidType, ) humanType = GraphQLObjectType( "Human", description="A humanoid creature in the Star Wars universe.", fields=lambda: { "id": GraphQLField( GraphQLNonNull(GraphQLString), description="The id of the human." ), "name": GraphQLField(GraphQLString, description="The name of the human."), "friends": GraphQLField( GraphQLList(characterInterface), description="The friends of the human, or an empty list if they have none.", resolver=lambda human, *_: getFriends(human), ), "appearsIn": GraphQLField( GraphQLList(episodeEnum), description="Which movies they appear in." ), "homePlanet": GraphQLField( GraphQLString, description="The home planet of the human, or null if unknown.", ), }, interfaces=[characterInterface], ) droidType = GraphQLObjectType( "Droid", description="A mechanical creature in the Star Wars universe.",
async def resolve_type_allows_resolving_with_type_name(): PetType = GraphQLInterfaceType( "Pet", {"name": GraphQLField(GraphQLString)}, resolve_type=get_type_resolver({ Dog: "Dog", Cat: "Cat" }), ) DogType = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, interfaces=[PetType], ) CatType = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, interfaces=[PetType], ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(PetType), resolve=lambda *_: [Dog("Odie", True), Cat("Garfield", False)], ) }, ), types=[CatType, DogType], ) query = """{ pets { name ... on Dog { woofs } ... on Cat { meows } } }""" result = await graphql(schema, query) assert result == ( { "pets": [ { "name": "Odie", "woofs": True }, { "name": "Garfield", "meows": False }, ] }, None, )
return self.numberHolder async def promise_to_change_the_number(self, new_number: int) -> NumberHolder: await asyncio.sleep(0) return self.immediately_change_the_number(new_number) def fail_to_change_the_number(self, newNumber: int): raise RuntimeError(f"Cannot change the number to {newNumber}") async def promise_and_fail_to_change_the_number(self, newNumber: int): await asyncio.sleep(0) self.fail_to_change_the_number(newNumber) numberHolderType = GraphQLObjectType("NumberHolder", {"theNumber": GraphQLField(GraphQLInt)}) # noinspection PyPep8Naming schema = GraphQLSchema( GraphQLObjectType("Query", {"numberHolder": GraphQLField(numberHolderType)}), GraphQLObjectType( "Mutation", { "immediatelyChangeTheNumber": GraphQLField( numberHolderType, args={"newNumber": GraphQLArgument(GraphQLInt)}, resolve=lambda obj, _info, newNumber: obj. immediately_change_the_number(newNumber), ),
async def resolve_type_can_be_caught(): PetType = GraphQLInterfaceType("Pet", {"name": GraphQLField(GraphQLString)}, resolve_type=is_type_of_error) DogType = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, interfaces=[PetType], ) CatType = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, interfaces=[PetType], ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(PetType), resolve=lambda *_: [Dog("Odie", True), Cat("Garfield", False)], ) }, ), types=[CatType, DogType], ) query = """{ pets { name ... on Dog { woofs } ... on Cat { meows } } }""" result = await graphql(schema, query) assert result == ( { "pets": [None, None] }, [ { "message": "We are testing this error", "locations": [(2, 11)], "path": ["pets", 0], }, { "message": "We are testing this error", "locations": [(2, 11)], "path": ["pets", 1], }, ], )
SomeScalarType = GraphQLScalarType(name="SomeScalar", serialize=lambda x: x) SomeInterfaceType = GraphQLInterfaceType( name="SomeInterface", fields=lambda: { "name": GraphQLField(GraphQLString), "some": GraphQLField(SomeInterfaceType), }, ) FooType = GraphQLObjectType( name="Foo", interfaces=[SomeInterfaceType], fields=lambda: { "name": GraphQLField(GraphQLString), "some": GraphQLField(SomeInterfaceType), "tree": GraphQLField(GraphQLNonNull(GraphQLList(FooType))), }, ) BarType = GraphQLObjectType( name="Bar", interfaces=[SomeInterfaceType], fields=lambda: { "name": GraphQLField(GraphQLString), "some": GraphQLField(SomeInterfaceType), "foo": GraphQLField(FooType), }, )
SomeScalarType = GraphQLScalarType( name="SomeScalar", serialize=_get(None), parse_value=_get(None), parse_literal=_get(None), ) SomeInterfaceType = GraphQLInterfaceType( name="SomeInterface", fields=lambda: {"f": GraphQLField(SomeObjectType)} ) SomeObjectType = GraphQLObjectType( name="SomeObject", fields=lambda: {"f": GraphQLField(SomeObjectType)}, interfaces=[SomeInterfaceType], ) SomeUnionType = GraphQLUnionType(name="SomeUnion", types=[SomeObjectType]) SomeEnumType = GraphQLEnumType(name="SomeEnum", values={"ONLY": GraphQLEnumValue()}) SomeInputObjectType = GraphQLInputObjectType( name="SomeInputObject", fields={"val": GraphQLInputField(GraphQLString, default_value="hello")}, ) def with_modifiers(types): return (