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)) == [ { "message": "We are testing this error", "locations": [(3, 15)], "path": ["pets", 0], }, { "message": "We are testing this error", "locations": [(3, 15)], "path": ["pets", 1], }, ]
from pytest import raises # type: ignore from graphql.error import GraphQLError from graphql.language import ( parse, DocumentNode, OperationDefinitionNode, OperationTypeDefinitionNode, SchemaDefinitionNode, ) from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString from graphql.utilities import get_operation_root_type query_type = GraphQLObjectType("FooQuery", {"field": GraphQLField(GraphQLString)}) mutation_type = GraphQLObjectType("FooMutation", {"field": GraphQLField(GraphQLString)}) subscription_type = GraphQLObjectType("FooSubscription", {"field": GraphQLField(GraphQLString)}) def get_operation_node(doc: DocumentNode) -> OperationDefinitionNode: operation_node = doc.definitions[0] assert isinstance(operation_node, OperationDefinitionNode) return operation_node def describe_get_operation_root_type(): def gets_a_query_type_for_an_unnamed_operation_definition_node():
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 = graphql_sync(schema, query) assert result == ( { "pets": [ { "name": "Odie", "woofs": True }, { "name": "Garfield", "meows": False }, ] }, None, )
def stringifies_fields(): assert str(GraphQLField(GraphQLNonNull(GraphQLString))) == "Field: String!" assert str(GraphQLField(GraphQLList(GraphQLInt))) == "Field: [Int]"
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 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] }
def get_first(args, *keys): for key in keys: if key in args: return args[key] return None QueryType = GraphQLObjectType( name='Query', fields={ 'colorEnum': GraphQLField( type=ColorType, args={ 'fromEnum': GraphQLArgument(ColorType), 'fromInt': GraphQLArgument(GraphQLInt), 'fromString': GraphQLArgument(GraphQLString) }, resolver=lambda value, args, context, info: get_first(args, 'fromInt', 'fromString', 'fromEnum') ), 'colorInt': GraphQLField( type=GraphQLInt, args={ 'fromEnum': GraphQLArgument(ColorType), 'fromInt': GraphQLArgument(GraphQLInt), }, resolver=lambda value, args, context, info: get_first(args, 'fromInt', 'fromEnum') ) } )
def accepts_a_lambda_as_an_object_field_resolver(): obj_type = GraphQLObjectType( "SomeObject", {"f": GraphQLField(ScalarType, resolve=lambda _obj, _info: {})}, ) assert obj_type.fields
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),
def test_synchronous_error_nulls_out_error_subtrees(): # type: () -> None ast = parse(""" { sync syncError syncReturnError syncReturnErrorList asyncBasic asyncReject asyncEmptyReject asyncReturnError } """) class Data: def sync(self): # type: () -> str return "sync" def syncError(self): # type: () -> NoReturn raise Exception("Error getting syncError") def syncReturnError(self): # type: () -> Exception return Exception("Error getting syncReturnError") def syncReturnErrorList(self): # type: () -> List[Union[Exception, str]] return [ "sync0", Exception("Error getting syncReturnErrorList1"), "sync2", Exception("Error getting syncReturnErrorList3"), ] def asyncBasic(self): # type: () -> Promise return resolved("async") def asyncReject(self): # type: () -> Promise return rejected(Exception("Error getting asyncReject")) def asyncEmptyReject(self): # type: () -> Promise return rejected(Exception("An unknown error occurred.")) def asyncReturnError(self): # type: () -> Promise return resolved(Exception("Error getting asyncReturnError")) schema = GraphQLSchema(query=GraphQLObjectType( name="Type", fields={ "sync": GraphQLField(GraphQLString), "syncError": GraphQLField(GraphQLString), "syncReturnError": GraphQLField(GraphQLString), "syncReturnErrorList": GraphQLField(GraphQLList(GraphQLString)), "asyncBasic": GraphQLField(GraphQLString), "asyncReject": GraphQLField(GraphQLString), "asyncEmptyReject": GraphQLField(GraphQLString), "asyncReturnError": GraphQLField(GraphQLString), }, )) def sort_key(item): # type: (Dict[str, Any]) -> Tuple[int, int] locations = item["locations"][0] return (locations["line"], locations["column"]) def handle_results(result): # type: (ExecutionResult) -> None assert result.data == { "asyncBasic": "async", "asyncEmptyReject": None, "asyncReject": None, "asyncReturnError": None, "sync": "sync", "syncError": None, "syncReturnError": None, "syncReturnErrorList": ["sync0", None, "sync2", None], } assert sorted(list(map( format_error, result.errors)), key=sort_key) == sorted( [ { "locations": [{ "line": 4, "column": 9 }], "path": ["syncError"], "message": "Error getting syncError", }, { "locations": [{ "line": 5, "column": 9 }], "path": ["syncReturnError"], "message": "Error getting syncReturnError", }, { "locations": [{ "line": 6, "column": 9 }], "path": ["syncReturnErrorList", 1], "message": "Error getting syncReturnErrorList1", }, { "locations": [{ "line": 6, "column": 9 }], "path": ["syncReturnErrorList", 3], "message": "Error getting syncReturnErrorList3", }, { "locations": [{ "line": 8, "column": 9 }], "path": ["asyncReject"], "message": "Error getting asyncReject", }, { "locations": [{ "line": 9, "column": 9 }], "path": ["asyncEmptyReject"], "message": "An unknown error occurred.", }, { "locations": [{ "line": 10, "column": 9 }], "path": ["asyncReturnError"], "message": "Error getting asyncReturnError", }, ], key=sort_key, ) handle_results(execute(schema, ast, Data(), executor=ThreadExecutor()))
pets: Optional[List[Union[Dog, Cat]]] friends: Optional[List[Union[Dog, Cat, "Person"]]] def __init__( self, name: str, pets: Optional[List[Union[Dog, Cat]]] = None, friends: Optional[List[Union[Dog, Cat, "Person"]]] = None, ): self.name = name self.pets = pets self.friends = friends NamedType = GraphQLInterfaceType("Named", {"name": GraphQLField(GraphQLString)}) LifeType = GraphQLInterfaceType( "Life", lambda: {"progeny": GraphQLField(GraphQLList(LifeType))} # type: ignore ) MammalType = GraphQLInterfaceType( "Mammal", lambda: { "progeny": GraphQLField(GraphQLList(MammalType)), # type: ignore "mother": GraphQLField(MammalType), # type: ignore "father": GraphQLField(MammalType), # type: ignore }, interfaces=[LifeType], )
GraphQLString, GraphQLUnionType, ) from graphql.type.directives import ( DirectiveLocation, GraphQLDirective, GraphQLIncludeDirective, GraphQLSkipDirective, ) from graphql.validation import validate Being = GraphQLInterfaceType( "Being", { "name": GraphQLField(GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)}) }, ) Pet = GraphQLInterfaceType( "Pet", { "name": GraphQLField(GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)}) }, ) Canine = GraphQLInterfaceType( "Canine", {
GraphQLScalarType, ) from graphql.type.directives import ( DirectiveLocation, GraphQLDirective, GraphQLIncludeDirective, GraphQLSkipDirective, ) from graphql.validation import ValidationRule, SDLValidationRule from graphql.validation.validate import validate, validate_sdl Being = GraphQLInterfaceType( "Being", { "name": GraphQLField(GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)}) }, ) Mammal = GraphQLInterfaceType( "Mammal", lambda: { "mother": GraphQLField(Mammal), # type: ignore "father": GraphQLField(Mammal), # type: ignore }, interfaces=[], ) Pet = GraphQLInterfaceType( "Pet", {
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], }, ], )
async def is_type_of_used_to_resolve_runtime_type_for_union(): DogType = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, is_type_of=get_is_type_of(Dog), ) CatType = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, is_type_of=get_is_type_of(Cat), ) PetType = GraphQLUnionType("Pet", [CatType, DogType]) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(PetType), resolve=lambda *_args: [ Dog("Odie", True), Cat("Garfield", False), ], ) }, ) ) query = """ { pets { ... on Dog { name woofs } ... on Cat { name meows } } } """ result = await graphql(schema, query) assert result == ( { "pets": [ {"name": "Odie", "woofs": True}, {"name": "Garfield", "meows": False}, ] }, None, )
async def nulls_out_error_subtrees(): doc = """{ syncOk syncError syncRawError syncReturnError syncReturnErrorList asyncOk asyncError asyncRawError asyncReturnError asyncReturnErrorWithExtensions }""" # 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'}) ast = parse(doc) 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) })) assert await execute(schema, ast, Data()) == ({ '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': [(3, 15)], 'path': ['syncError'] }, { 'message': 'Error getting syncRawError', 'locations': [(4, 15)], 'path': ['syncRawError'] }, { 'message': 'Error getting syncReturnError', 'locations': [(5, 15)], 'path': ['syncReturnError'] }, { 'message': 'Error getting syncReturnErrorList1', 'locations': [(6, 15)], 'path': ['syncReturnErrorList', 1] }, { 'message': 'Error getting syncReturnErrorList3', 'locations': [(6, 15)], 'path': ['syncReturnErrorList', 3] }, { 'message': 'Error getting asyncError', 'locations': [(8, 15)], 'path': ['asyncError'] }, { 'message': 'Error getting asyncRawError', 'locations': [(9, 15)], 'path': ['asyncRawError'] }, { 'message': 'Error getting asyncReturnError', 'locations': [(10, 15)], 'path': ['asyncReturnError'] }, { 'message': 'Error getting asyncReturnErrorWithExtensions', 'locations': [(11, 15)], 'path': ['asyncReturnErrorWithExtensions'], 'extensions': { 'foo': 'bar' } }])
def test_executes_arbitary_code(): # type: () -> None class Data(object): a = "Apple" b = "Banana" c = "Cookie" d = "Donut" e = "Egg" @property def f(self): # type: () -> Promise return resolved("Fish") def pic(self, size=50): # type: (int) -> Promise return resolved("Pic of size: {}".format(size)) def deep(self): # type: () -> DeepData return DeepData() def promise(self): # type: () -> Promise return resolved(Data()) class DeepData(object): a = "Already Been Done" b = "Boring" c = ["Contrived", None, resolved("Confusing")] def deeper(self): # type: () -> List[Union[None, Data, Promise]] return [Data(), None, resolved(Data())] ast = parse(""" query Example($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 } """) expected = { "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" }, ], }, } DataType = GraphQLObjectType( "DataType", lambda: { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLString), "d": GraphQLField(GraphQLString), "e": GraphQLField(GraphQLString), "f": GraphQLField(GraphQLString), "pic": GraphQLField( args={"size": GraphQLArgument(GraphQLInt)}, type=GraphQLString, resolver=lambda obj, info, **args: obj.pic(args["size"]), ), "deep": GraphQLField(DeepDataType), "promise": GraphQLField(DataType), }, ) DeepDataType = GraphQLObjectType( "DeepDataType", { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLList(GraphQLString)), "deeper": GraphQLField(GraphQLList(DataType)), }, ) schema = GraphQLSchema(query=DataType) def handle_result(result): # type: (ExecutionResult) -> None assert not result.errors assert result.data == expected handle_result( execute( schema, ast, Data(), variable_values={"size": 100}, operation_name="Example", executor=ThreadExecutor(), )) handle_result( execute(schema, ast, Data(), variable_values={"size": 100}, operation_name="Example"))
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' 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() doc = """ query Example($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 } """ ast = parse(doc) expected = ({ '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) 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': GraphQLList(DataType) }) schema = GraphQLSchema(DataType) assert await execute(schema, ast, Data(), variable_values={'size': 100}, operation_name='Example') == expected
def builds_a_schema_with_an_enum(): food_enum = GraphQLEnumType( "Food", { "VEGETABLES": GraphQLEnumValue(1, description="Foods that are vegetables."), "FRUITS": GraphQLEnumValue(2), "OILS": GraphQLEnumValue(3, deprecation_reason="Too fatty."), }, 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")) # Client types do not get server-only values, so the values mirror the names, # rather than using the integers defined in the "server" schema. values = { name: value.to_kwargs() for name, value in client_food_enum.values.items() } assert values == { "VEGETABLES": { "value": "VEGETABLES", "description": "Foods that are vegetables.", "deprecation_reason": None, "extensions": {}, "ast_node": None, }, "FRUITS": { "value": "FRUITS", "description": None, "deprecation_reason": None, "extensions": {}, "ast_node": None, }, "OILS": { "value": "OILS", "description": None, "deprecation_reason": "Too fatty.", "extensions": {}, "ast_node": None, }, }
def fields(): nonlocal calls calls += 1 return {"f": GraphQLField(ScalarType)}
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), ),
def accepts_an_interface_type_defining_resolve_type(): assert GraphQLInterfaceType("AnotherInterface", {"f": GraphQLField(ScalarType)})
from graphql.type import (GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString) Query = GraphQLObjectType( 'Query', lambda: { 'hello': GraphQLField(GraphQLString, resolver=lambda *_: "World"), }) schema = GraphQLSchema(Query)
def get_graphql_schema_from_schema_graph(schema_graph, class_to_field_type_overrides, hidden_classes): """Return a GraphQL schema object corresponding to the schema of the given schema graph. Args: schema_graph: SchemaGraph class_to_field_type_overrides: 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: 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}). """ _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 sanity 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 cls_subclasses = schema_graph.get_subclass_set(non_graph_cls_name) # No need to add the possible abstract class if it doesn't have subclasses besides itself. if len(cls_subclasses) > 1: all_non_abstract_subclasses_are_vertices = True # Check all non-abstract subclasses are vertices. for subclass_name in cls_subclasses: subclass = schema_graph.get_element_by_class_name( subclass_name) if subclass_name != non_graph_cls_name: if not subclass.abstract and not subclass.is_vertex: all_non_abstract_subclasses_are_vertices = False break if all_non_abstract_subclasses_are_vertices: # 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( u'After evaluating all subclasses of V, we were not able to find ' u'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)
async def is_type_of_used_to_resolve_runtime_type_for_union(sync): dog_type = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, is_type_of=get_is_type_of(Dog, sync), ) cat_type = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, is_type_of=get_is_type_of(Cat, sync), ) pet_type = GraphQLUnionType("Pet", [cat_type, dog_type]) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(pet_type), resolve=lambda *_args: [ Dog("Odie", True), Cat("Garfield", False), ], ) }, )) query = """ { pets { ... on Dog { name woofs } ... on Cat { name meows } } } """ assert await execute_query(sync, schema, query) == ( { "pets": [ { "name": "Odie", "woofs": True }, { "name": "Garfield", "meows": False }, ] }, None, )
# type: () -> NullingData return NullingData() def promiseNest(self): # type: () -> Promise return resolved(NullingData()) def nonNullPromiseNest(self): # type: () -> Promise return resolved(NullingData()) DataType = GraphQLObjectType( "DataType", lambda: { "sync": GraphQLField(GraphQLString), "nonNullSync": GraphQLField(GraphQLNonNull(GraphQLString)), "promise": GraphQLField(GraphQLString), "nonNullPromise": GraphQLField(GraphQLNonNull(GraphQLString)), "nest": GraphQLField(DataType), "nonNullNest": GraphQLField(GraphQLNonNull(DataType)), "promiseNest": GraphQLField(DataType), "nonNullPromiseNest": GraphQLField(GraphQLNonNull(DataType)), }, ) schema = GraphQLSchema(DataType) def order_errors(error): # type: (Dict[str, Any]) -> Tuple[int, int]
async def deprecated_resolve_type_allows_resolving_with_type_object(sync): cat_type: GraphQLObjectType dog_type: GraphQLObjectType pet_type = GraphQLInterfaceType( "Pet", {"name": GraphQLField(GraphQLString)}, resolve_type=get_type_resolver( lambda: { Dog: dog_type, Cat: cat_type }, sync), ) dog_type = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], ) cat_type = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(pet_type), resolve=lambda *_args: [ Dog("Odie", True), Cat("Garfield", False), ], ) }, ), types=[cat_type, dog_type], ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ assert await execute_query(sync, schema, query) == ( { "pets": [ { "name": "Odie", "woofs": True }, { "name": "Garfield", "meows": False }, ] }, None, )
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 = graphql_sync(schema, query) assert result.data == { "pets": [ { "name": "Odie", "woofs": True }, { "name": "Garfield", "meows": False }, None, ] } 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], }
async def resolve_type_can_throw(sync): pet_type = GraphQLInterfaceType( "Pet", {"name": GraphQLField(GraphQLString)}, resolve_type=get_type_error(sync), ) dog_type = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], ) cat_type = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(pet_type), resolve=lambda *_args: [ Dog("Odie", True), Cat("Garfield", False), ], ) }, ), types=[dog_type, cat_type], ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ assert await execute_query(sync, schema, query) == ( { "pets": [None, None] }, [ { "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 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 = graphql_sync(schema, query) assert result == ( { "pets": [ { "name": "Odie", "woofs": True }, { "name": "Garfield", "meows": False }, ] }, None, )
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": 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 } """) result = await execute(GraphQLSchema(DataType), document, Data(), variable_values={"size": 100}) 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, )