diff --git a/graphql/core/type/definition.py b/graphql/core/type/definition.py index 8d6b860d..013b89e0 100644 --- a/graphql/core/type/definition.py +++ b/graphql/core/type/definition.py @@ -265,13 +265,12 @@ def resolve_type(self, value): """ def __init__(self, name, types=None, resolve_type=None, description=None): assert name, 'Type must be named.' + assert types, 'Must provide types for Union {}.'.format(name) + self.name = name self.description = description - assert types, \ - 'Must provide types for Union {}.'.format(name) - self._possible_type_names = None - non_obj_types = [t for t in types - if not isinstance(t, GraphQLObjectType)] + + non_obj_types = [t for t in types if not isinstance(t, GraphQLObjectType)] if non_obj_types: raise Error( 'Union {} may only contain object types, it cannot ' @@ -280,6 +279,8 @@ def __init__(self, name, types=None, resolve_type=None, description=None): ', '.join(str(t) for t in non_obj_types) ) ) + + self._possible_type_names = None self._types = types self._resolve_type = resolve_type @@ -291,6 +292,7 @@ def is_possible_type(self, type): self._possible_type_names = set( t.name for t in self.get_possible_types() ) + return type.name in self._possible_type_names def resolve_type(self, value, info): @@ -326,37 +328,46 @@ def __init__(self, name, values, description=None): def get_values(self): if self._value_map is None: self._value_map = self._define_value_map() + return self._value_map def serialize(self, value): if isinstance(value, collections.Hashable): enum_value = self._get_value_lookup().get(value) + if enum_value: return enum_value.name + return None def parse_value(self, value): if isinstance(value, collections.Hashable): enum_value = self._get_value_lookup().get(value) + if enum_value: return enum_value.name + return None def parse_literal(self, value_ast): if isinstance(value_ast, ast.EnumValue): enum_value = self._get_name_lookup().get(value_ast.value) + if enum_value: return enum_value.value def _define_value_map(self): - value_map = {} + value_map = collections.OrderedDict() for value_name, value in self._values.items(): if not isinstance(value, GraphQLEnumValue): value = GraphQLEnumValue(value) + value.name = value_name if value.value is None: value.value = value_name + value_map[value_name] = value + return value_map def _get_value_lookup(self): @@ -364,7 +375,9 @@ def _get_value_lookup(self): lookup = {} for value_name, value in self.get_values().items(): lookup[value.value] = value + self._value_lookup = lookup + return self._value_lookup def _get_name_lookup(self): @@ -372,7 +385,9 @@ def _get_name_lookup(self): lookup = {} for value_name, value in self.get_values().items(): lookup[value.name] = value + self._name_lookup = lookup + return self._name_lookup @@ -409,6 +424,10 @@ def __init__(self, name, fields, description=None): assert name, 'Type must be named.' self.name = name self.description = description + + for field in fields.values(): + assert isinstance(field, GraphQLInputObjectField) + self._fields = fields self._field_map = None diff --git a/graphql/core/type/introspection.py b/graphql/core/type/introspection.py index e97fe02d..32ac5cd8 100644 --- a/graphql/core/type/introspection.py +++ b/graphql/core/type/introspection.py @@ -1,3 +1,4 @@ +from collections import OrderedDict from ..language.printer import print_ast from ..utils.ast_from_value import ast_from_value from .definition import ( @@ -21,67 +22,83 @@ 'server. It exposes all available types and directives on ' 'the server, as well as the entry points for query and ' 'mutation operations.', - fields=lambda: { - 'types': GraphQLField( + fields=lambda: OrderedDict([ + ('types', GraphQLField( description='A list of all types supported by this server.', type=GraphQLNonNull(GraphQLList(GraphQLNonNull(__Type))), resolver=lambda schema, *_: schema.get_type_map().values(), - ), - 'queryType': GraphQLField( + )), + ('queryType', GraphQLField( description='The type that query operations will be rooted at.', type=GraphQLNonNull(__Type), resolver=lambda schema, *_: schema.get_query_type(), - ), - 'mutationType': GraphQLField( + )), + ('mutationType', GraphQLField( description='If this server supports mutation, the type that ' 'mutation operations will be rooted at.', type=__Type, resolver=lambda schema, *_: schema.get_mutation_type(), - ), - 'directives': GraphQLField( + )), + ('directives', GraphQLField( description='A list of all directives supported by this server.', type=GraphQLNonNull(GraphQLList(GraphQLNonNull(__Directive))), resolver=lambda schema, *_: schema.get_directives(), - ), - }) + )), + ])) -__Directive = GraphQLObjectType('__Directive', lambda: { - 'name': GraphQLField(GraphQLNonNull(GraphQLString)), - 'description': GraphQLField(GraphQLString), - 'args': GraphQLField( - type=GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), - resolver=lambda directive, *args: directive.args or [], - ), - 'onOperation': GraphQLField( - type=GraphQLBoolean, - resolver=lambda directive, *args: directive.on_operation, - ), - 'onFragment': GraphQLField( - type=GraphQLBoolean, - resolver=lambda directive, *args: directive.on_fragment, - ), - 'onField': GraphQLField( - type=GraphQLBoolean, - resolver=lambda directive, *args: directive.on_field, - ), -}) +__Directive = GraphQLObjectType( + '__Directive', + fields=lambda: OrderedDict([ + ('name', GraphQLField(GraphQLNonNull(GraphQLString))), + ('description', GraphQLField(GraphQLString)), + ('args', GraphQLField( + type=GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), + resolver=lambda directive, *args: directive.args or [], + )), + ('onOperation', GraphQLField( + type=GraphQLNonNull(GraphQLBoolean), + resolver=lambda directive, *args: directive.on_operation, + )), + ('onFragment', GraphQLField( + type=GraphQLNonNull(GraphQLBoolean), + resolver=lambda directive, *args: directive.on_fragment, + )), + ('onField', GraphQLField( + type=GraphQLNonNull(GraphQLBoolean), + resolver=lambda directive, *args: directive.on_field, + )) + ])) + + +class TypeKind(object): + SCALAR = 0 + OBJECT = 1 + INTERFACE = 2 + UNION = 3 + ENUM = 4 + INPUT_OBJECT = 5 + LIST = 6 + NON_NULL = 7 class TypeFieldResolvers(object): - @staticmethod - def kind(type, *_): - for cls, kind in ( - (GraphQLScalarType, TypeKind.SCALAR), - (GraphQLObjectType, TypeKind.OBJECT), - (GraphQLInterfaceType, TypeKind.INTERFACE), - (GraphQLUnionType, TypeKind.UNION), - (GraphQLEnumType, TypeKind.ENUM), - (GraphQLInputObjectType, TypeKind.INPUT_OBJECT), - (GraphQLList, TypeKind.LIST), - (GraphQLNonNull, TypeKind.NON_NULL), - ): - if isinstance(type, cls): + _kinds = ( + (GraphQLScalarType, TypeKind.SCALAR), + (GraphQLObjectType, TypeKind.OBJECT), + (GraphQLInterfaceType, TypeKind.INTERFACE), + (GraphQLUnionType, TypeKind.UNION), + (GraphQLEnumType, TypeKind.ENUM), + (GraphQLInputObjectType, TypeKind.INPUT_OBJECT), + (GraphQLList, TypeKind.LIST), + (GraphQLNonNull, TypeKind.NON_NULL), + ) + + @classmethod + def kind(cls, type, *_): + for klass, kind in cls._kinds: + if isinstance(type, klass): return kind + raise Exception('Unknown kind of type: {}'.format(type)) @staticmethod @@ -116,149 +133,148 @@ def input_fields(type, *_): if isinstance(type, GraphQLInputObjectType): return type.get_fields().values() -__Type = GraphQLObjectType('__Type', lambda: { - 'kind': GraphQLField( - type=GraphQLNonNull(__TypeKind), - resolver=TypeFieldResolvers.kind - ), - 'name': GraphQLField(GraphQLString), - 'description': GraphQLField(GraphQLString), - 'fields': GraphQLField( - type=GraphQLList(GraphQLNonNull(__Field)), - args={ - 'includeDeprecated': GraphQLArgument( - GraphQLBoolean, - default_value=False - ) - }, - resolver=TypeFieldResolvers.fields - ), - 'interfaces': GraphQLField( - type=GraphQLList(GraphQLNonNull(__Type)), - resolver=TypeFieldResolvers.interfaces - ), - 'possibleTypes': GraphQLField( - type=GraphQLList(GraphQLNonNull(__Type)), - resolver=TypeFieldResolvers.possible_types - ), - 'enumValues': GraphQLField( - type=GraphQLList(GraphQLNonNull(__EnumValue)), - args={ - 'includeDeprecated': GraphQLArgument( - GraphQLBoolean, - default_value=False - ) - }, - resolver=TypeFieldResolvers.enum_values - ), - 'inputFields': GraphQLField( - type=GraphQLList(GraphQLNonNull(__InputValue)), - resolver=TypeFieldResolvers.input_fields - ), - 'ofType': GraphQLField( - type=__Type, - resolver=lambda type, *_: getattr(type, 'of_type', None) - ), -}) -__Field = GraphQLObjectType('__Field', lambda: { - 'name': GraphQLField(GraphQLNonNull(GraphQLString)), - 'description': GraphQLField(GraphQLString), - 'args': GraphQLField( - type=GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), - resolver=lambda field, *_: field.args or [] - ), - 'type': GraphQLField(GraphQLNonNull(__Type)), - 'isDeprecated': GraphQLField( - type=GraphQLNonNull(GraphQLBoolean), - resolver=lambda field, *_: bool(field.deprecation_reason) - ), - 'deprecationReason': GraphQLField( - type=GraphQLString, - resolver=lambda field, *_: field.deprecation_reason - ) -}) +__Type = GraphQLObjectType( + '__Type', + fields=lambda: OrderedDict([ + ('kind', GraphQLField( + type=GraphQLNonNull(__TypeKind), + resolver=TypeFieldResolvers.kind + )), + ('name', GraphQLField(GraphQLString)), + ('description', GraphQLField(GraphQLString)), + ('fields', GraphQLField( + type=GraphQLList(GraphQLNonNull(__Field)), + args={ + 'includeDeprecated': GraphQLArgument( + GraphQLBoolean, + default_value=False + ) + }, + resolver=TypeFieldResolvers.fields + )), + ('interfaces', GraphQLField( + type=GraphQLList(GraphQLNonNull(__Type)), + resolver=TypeFieldResolvers.interfaces + )), + ('possibleTypes', GraphQLField( + type=GraphQLList(GraphQLNonNull(__Type)), + resolver=TypeFieldResolvers.possible_types + )), + ('enumValues', GraphQLField( + type=GraphQLList(GraphQLNonNull(__EnumValue)), + args={ + 'includeDeprecated': GraphQLArgument( + GraphQLBoolean, + default_value=False + ) + }, + resolver=TypeFieldResolvers.enum_values + )), + ('inputFields', GraphQLField( + type=GraphQLList(GraphQLNonNull(__InputValue)), + resolver=TypeFieldResolvers.input_fields + )), + ('ofType', GraphQLField( + type=__Type, + resolver=lambda type, *_: getattr(type, 'of_type', None) + )), + ])) + +__Field = GraphQLObjectType( + '__Field', + fields=lambda: OrderedDict([ + ('name', GraphQLField(GraphQLNonNull(GraphQLString))), + ('description', GraphQLField(GraphQLString)), + ('args', GraphQLField( + type=GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), + resolver=lambda field, *_: field.args or [] + )), + ('type', GraphQLField(GraphQLNonNull(__Type))), + ('isDeprecated', GraphQLField( + type=GraphQLNonNull(GraphQLBoolean), + resolver=lambda field, *_: bool(field.deprecation_reason) + )), + ('deprecationReason', GraphQLField( + type=GraphQLString, + resolver=lambda field, *_: field.deprecation_reason + )) + ]) +) -__InputValue = GraphQLObjectType('__InputValue', lambda: { - 'name': GraphQLField(GraphQLNonNull(GraphQLString)), - 'description': GraphQLField(GraphQLString), - 'type': GraphQLField(GraphQLNonNull(__Type)), - 'defaultValue': GraphQLField( - type=GraphQLString, - resolver=lambda input_val, *_: +__InputValue = GraphQLObjectType( + '__InputValue', + fields=lambda: OrderedDict([ + ('name', GraphQLField(GraphQLNonNull(GraphQLString))), + ('description', GraphQLField(GraphQLString)), + ('type', GraphQLField(GraphQLNonNull(__Type))), + ('defaultValue', GraphQLField( + type=GraphQLString, + resolver=lambda input_val, *_: None if input_val.default_value is None else print_ast(ast_from_value(input_val.default_value, input_val)) - ) -}) + )) + ])) -__EnumValue = GraphQLObjectType('__EnumValue', lambda: { - 'name': GraphQLField(GraphQLNonNull(GraphQLString)), - 'description': GraphQLField(GraphQLString), - 'isDeprecated': GraphQLField( - type=GraphQLNonNull(GraphQLBoolean), - resolver=lambda field, *_: bool(field.deprecation_reason) - ), - 'deprecationReason': GraphQLField( - type=GraphQLString, - resolver=lambda enum_value, *_: enum_value.deprecation_reason, - ) -}) - - -class TypeKind(object): - SCALAR = 0 - OBJECT = 1 - INTERFACE = 2 - UNION = 3 - ENUM = 4 - INPUT_OBJECT = 5 - LIST = 6 - NON_NULL = 7 +__EnumValue = GraphQLObjectType( + '__EnumValue', + fields=lambda: OrderedDict([ + ('name', GraphQLField(GraphQLNonNull(GraphQLString))), + ('description', GraphQLField(GraphQLString)), + ('isDeprecated', GraphQLField( + type=GraphQLNonNull(GraphQLBoolean), + resolver=lambda field, *_: bool(field.deprecation_reason) + )), + ('deprecationReason', GraphQLField( + type=GraphQLString, + resolver=lambda enum_value, *_: enum_value.deprecation_reason, + )) + ])) __TypeKind = GraphQLEnumType( '__TypeKind', description='An enum describing what kind of type a given __Type is', - values={ - 'SCALAR': GraphQLEnumValue( + values=OrderedDict([ + ('SCALAR', GraphQLEnumValue( TypeKind.SCALAR, description='Indicates this type is a scalar.' - ), - 'OBJECT': GraphQLEnumValue( + )), + ('OBJECT', GraphQLEnumValue( TypeKind.OBJECT, description='Indicates this type is an object. ' '`fields` and `interfaces` are valid fields.' - ), - 'INTERFACE': GraphQLEnumValue( + )), + ('INTERFACE', GraphQLEnumValue( TypeKind.INTERFACE, description='Indicates this type is an interface. ' '`fields` and `possibleTypes` are valid fields.' - ), - 'UNION': GraphQLEnumValue( + )), + ('UNION', GraphQLEnumValue( TypeKind.UNION, description='Indicates this type is a union. ' '`possibleTypes` is a valid field.' - ), - 'ENUM': GraphQLEnumValue( + )), + ('ENUM', GraphQLEnumValue( TypeKind.ENUM, description='Indicates this type is an enum. ' '`enumValues` is a valid field.' - ), - 'INPUT_OBJECT': GraphQLEnumValue( + )), + ('INPUT_OBJECT', GraphQLEnumValue( TypeKind.INPUT_OBJECT, description='Indicates this type is an input object. ' '`inputFields` is a valid field.' - ), - 'LIST': GraphQLEnumValue( + )), + ('LIST', GraphQLEnumValue( TypeKind.LIST, description='Indicates this type is a list. ' '`ofType` is a valid field.' - ), - 'NON_NULL': GraphQLEnumValue( + )), + ('NON_NULL', GraphQLEnumValue( TypeKind.NON_NULL, description='Indicates this type is a non-null. ' '`ofType` is a valid field.' - ), - }) + )), + ])) IntrospectionSchema = __Schema diff --git a/graphql/core/utils/schema_printer.py b/graphql/core/utils/schema_printer.py new file mode 100644 index 00000000..d88ac7f6 --- /dev/null +++ b/graphql/core/utils/schema_printer.py @@ -0,0 +1,129 @@ +from ..language.printer import print_ast +from ..type.definition import ( + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLScalarType, + GraphQLUnionType +) +from .ast_from_value import ast_from_value +from .is_nullish import is_nullish + + +def print_schema(schema): + return _print_filtered_schema(schema, _is_defined_type) + + +def print_introspection_schema(schema): + return _print_filtered_schema(schema, _is_introspection_type) + + +def _is_defined_type(typename): + return not _is_introspection_type(typename) and not _is_builtin_scalar(typename) + + +def _is_introspection_type(typename): + return typename.startswith('__') + + +_builtin_scalars = frozenset(['String', 'Boolean', 'Int', 'Float', 'ID']) + + +def _is_builtin_scalar(typename): + return typename in _builtin_scalars + + +def _print_filtered_schema(schema, type_filter): + return '\n\n'.join( + _print_type(type) + for typename, type in sorted(schema.get_type_map().items()) + if type_filter(typename) + ) + '\n' + + +def _print_type(type): + if isinstance(type, GraphQLScalarType): + return _print_scalar(type) + + elif isinstance(type, GraphQLObjectType): + return _print_object(type) + + elif isinstance(type, GraphQLInterfaceType): + return _print_interface(type) + + elif isinstance(type, GraphQLUnionType): + return _print_union(type) + + elif isinstance(type, GraphQLEnumType): + return _print_enum(type) + + assert isinstance(type, GraphQLInputObjectType) + return _print_input_object(type) + + +def _print_scalar(type): + return 'scalar {}'.format(type.name) + + +def _print_object(type): + interfaces = type.get_interfaces() + implemented_interfaces = \ + ' implements {}'.format(', '.join(i.name for i in interfaces)) if interfaces else '' + + return ( + 'type {}{} {{\n' + '{}\n' + '}}' + ).format(type.name, implemented_interfaces, _print_fields(type)) + + +def _print_interface(type): + return ( + 'interface {} {{\n' + '{}\n' + '}}' + ).format(type.name, _print_fields(type)) + + +def _print_union(type): + return 'union {} = {}'.format(type.name, ' | '.join(str(t) for t in type.get_possible_types())) + + +def _print_enum(type): + return ( + 'enum {} {{\n' + '{}\n' + '}}' + ).format(type.name, '\n'.join(' ' + v.name for v in type.get_values().values())) + + +def _print_input_object(type): + return ( + 'input {} {{\n' + '{}\n' + '}}' + ).format(type.name, '\n'.join(' ' + _print_input_value(field) for field in type.get_fields().values())) + + +def _print_fields(type): + return '\n'.join(' {}{}: {}'.format(f.name, _print_args(f), f.type) for f in type.get_fields().values()) + + +def _print_args(field): + if not field.args: + return '' + + return '({})'.format(', '.join(_print_input_value(arg) for arg in field.args)) + + +def _print_input_value(arg): + if not is_nullish(arg.default_value): + default_value = ' = ' + print_ast(ast_from_value(arg.default_value, arg.type)) + else: + default_value = '' + + return '{}: {}{}'.format(arg.name, arg.type, default_value) + + +__all__ = ['print_schema', 'print_introspection_schema'] diff --git a/tests/core_execution/test_variables.py b/tests/core_execution/test_variables.py index b91512c0..a886335d 100644 --- a/tests/core_execution/test_variables.py +++ b/tests/core_execution/test_variables.py @@ -7,6 +7,7 @@ GraphQLObjectType, GraphQLField, GraphQLArgument, + GraphQLInputObjectField, GraphQLInputObjectType, GraphQLList, GraphQLString, @@ -15,9 +16,9 @@ from graphql.core.error import GraphQLError TestInputObject = GraphQLInputObjectType('TestInputObject', { - 'a': GraphQLField(GraphQLString), - 'b': GraphQLField(GraphQLList(GraphQLString)), - 'c': GraphQLField(GraphQLNonNull(GraphQLString)), + 'a': GraphQLInputObjectField(GraphQLString), + 'b': GraphQLInputObjectField(GraphQLList(GraphQLString)), + 'c': GraphQLInputObjectField(GraphQLNonNull(GraphQLString)), }) TestType = GraphQLObjectType('TestType', { diff --git a/tests/core_type/test_introspection.py b/tests/core_type/test_introspection.py index ad17eb80..699dfd2b 100644 --- a/tests/core_type/test_introspection.py +++ b/tests/core_type/test_introspection.py @@ -35,475 +35,523 @@ def test_executes_an_introspection_query(): result = graphql(EmptySchema, introspection_query) assert not result.errors - - expected = {'__schema': {'directives': [{'args': [{'defaultValue': None, - 'description': 'Directs the executor to include this field or fragment only when the `if` argument is true.', - 'name': 'if', - 'type': {'kind': 'NON_NULL', + expected = { + '__schema': {'directives': [{'args': [{'defaultValue': None, + 'description': 'Directs the executor ' + 'to include this field ' + 'or fragment only when ' + 'the `if` argument is ' + 'true.', + 'name': 'if', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'Boolean', + 'ofType': None}}}], + 'description': None, + 'name': 'include', + 'onField': True, + 'onFragment': True, + 'onOperation': False}, + {'args': [{'defaultValue': None, + 'description': 'Directs the executor ' + 'to skip this field or ' + 'fragment only when the ' + '`if` argument is true.', + 'name': 'if', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'Boolean', + 'ofType': None}}}], + 'description': None, + 'name': 'skip', + 'onField': True, + 'onFragment': True, + 'onOperation': False}], + 'mutationType': None, + 'queryType': {'name': 'QueryRoot'}, + 'types': [{'description': 'An enum describing what kind of type ' + 'a given __Type is', + 'enumValues': [{'deprecationReason': None, + 'description': 'Indicates this type ' + 'is a scalar.', + 'isDeprecated': False, + 'name': 'SCALAR'}, + {'deprecationReason': None, + 'description': 'Indicates this type ' + 'is an object. ' + '`fields` and ' + '`interfaces` are ' + 'valid fields.', + 'isDeprecated': False, + 'name': 'OBJECT'}, + {'deprecationReason': None, + 'description': 'Indicates this type ' + 'is an interface. ' + '`fields` and ' + '`possibleTypes` are ' + 'valid fields.', + 'isDeprecated': False, + 'name': 'INTERFACE'}, + {'deprecationReason': None, + 'description': 'Indicates this type ' + 'is a union. ' + '`possibleTypes` is a ' + 'valid field.', + 'isDeprecated': False, + 'name': 'UNION'}, + {'deprecationReason': None, + 'description': 'Indicates this type ' + 'is an enum. ' + '`enumValues` is a ' + 'valid field.', + 'isDeprecated': False, + 'name': 'ENUM'}, + {'deprecationReason': None, + 'description': 'Indicates this type ' + 'is an input object. ' + '`inputFields` is a ' + 'valid field.', + 'isDeprecated': False, + 'name': 'INPUT_OBJECT'}, + {'deprecationReason': None, + 'description': 'Indicates this type ' + 'is a list. `ofType` ' + 'is a valid field.', + 'isDeprecated': False, + 'name': 'LIST'}, + {'deprecationReason': None, + 'description': 'Indicates this type ' + 'is a non-null. ' + '`ofType` is a valid ' + 'field.', + 'isDeprecated': False, + 'name': 'NON_NULL'}], + 'fields': None, + 'inputFields': None, + 'interfaces': None, + 'kind': 'ENUM', + 'name': '__TypeKind', + 'possibleTypes': None}, + {'description': None, + 'enumValues': None, + 'fields': None, + 'inputFields': None, + 'interfaces': None, + 'kind': 'SCALAR', + 'name': 'String', + 'possibleTypes': None}, + {'description': None, + 'enumValues': None, + 'fields': [{'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'name', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'description', + 'type': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'args', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'LIST', + 'name': None, + 'ofType': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'OBJECT', + 'name': '__InputValue'}}}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'type', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'OBJECT', + 'name': '__Type', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'isDeprecated', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'Boolean', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'deprecationReason', + 'type': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}], + 'inputFields': None, + 'interfaces': [], + 'kind': 'OBJECT', + 'name': '__Field', + 'possibleTypes': None}, + {'description': 'A GraphQL Schema defines the ' + 'capabilities of a GraphQL server. It ' + 'exposes all available types and ' + 'directives on the server, as well as ' + 'the entry points for query and ' + 'mutation operations.', + 'enumValues': None, + 'fields': [{'args': [], + 'deprecationReason': None, + 'description': 'A list of all types ' + 'supported by this server.', + 'isDeprecated': False, + 'name': 'types', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'LIST', + 'name': None, + 'ofType': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'OBJECT', + 'name': '__Type'}}}}}, + {'args': [], + 'deprecationReason': None, + 'description': 'The type that query ' + 'operations will be rooted ' + 'at.', + 'isDeprecated': False, + 'name': 'queryType', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'OBJECT', + 'name': '__Type', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': 'If this server supports ' + 'mutation, the type that ' + 'mutation operations will ' + 'be rooted at.', + 'isDeprecated': False, + 'name': 'mutationType', + 'type': {'kind': 'OBJECT', + 'name': '__Type', + 'ofType': None}}, + {'args': [], + 'deprecationReason': None, + 'description': 'A list of all directives ' + 'supported by this server.', + 'isDeprecated': False, + 'name': 'directives', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'LIST', + 'name': None, + 'ofType': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'OBJECT', + 'name': '__Directive'}}}}}], + 'inputFields': None, + 'interfaces': [], + 'kind': 'OBJECT', + 'name': '__Schema', + 'possibleTypes': None}, + {'description': None, + 'enumValues': None, + 'fields': [{'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'kind', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'ENUM', + 'name': '__TypeKind', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'name', + 'type': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'description', + 'type': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}, + {'args': [{'defaultValue': 'false', + 'description': None, + 'name': 'includeDeprecated', + 'type': {'kind': 'SCALAR', + 'name': 'Boolean', + 'ofType': None}}], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'fields', + 'type': {'kind': 'LIST', + 'name': None, + 'ofType': {'kind': 'NON_NULL', 'name': None, - 'ofType': {'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None}}}], - 'description': None, - 'name': 'include', - 'onField': True, - 'onFragment': True, - 'onOperation': False}, - {'args': [{'defaultValue': None, - 'description': 'Directs the executor to skip this field or fragment only when the `if` argument is true.', - 'name': 'if', - 'type': {'kind': 'NON_NULL', + 'ofType': {'kind': 'OBJECT', + 'name': '__Field', + 'ofType': None}}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'interfaces', + 'type': {'kind': 'LIST', + 'name': None, + 'ofType': {'kind': 'NON_NULL', 'name': None, - 'ofType': {'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None}}}], - 'description': None, - 'name': 'skip', - 'onField': True, - 'onFragment': True, - 'onOperation': False}], - 'mutationType': None, - 'queryType': {'name': 'QueryRoot'}, - 'types': [{'description': None, - 'enumValues': None, - 'fields': [{'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'isDeprecated', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'deprecationReason', - 'type': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'description', - 'type': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'name', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}}], - 'inputFields': None, - 'interfaces': [], - 'kind': 'OBJECT', - 'name': '__EnumValue', - 'possibleTypes': None}, - {'description': None, - 'enumValues': None, - 'fields': [{'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'onFragment', - 'type': {'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'onOperation', - 'type': {'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'onField', - 'type': {'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'name', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'args', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'LIST', - 'name': None, - 'ofType': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__InputValue'}}}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'description', - 'type': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}], - 'inputFields': None, - 'interfaces': [], - 'kind': 'OBJECT', - 'name': '__Directive', - 'possibleTypes': None}, - {'description': None, - 'enumValues': None, - 'fields': [{'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'name', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'description', - 'type': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'isDeprecated', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'args', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'LIST', - 'name': None, - 'ofType': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__InputValue'}}}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'deprecationReason', - 'type': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'type', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None}}}], - 'inputFields': None, - 'interfaces': [], - 'kind': 'OBJECT', - 'name': '__Field', - 'possibleTypes': None}, - {'description': None, - 'enumValues': None, - 'fields': None, - 'inputFields': None, - 'interfaces': None, - 'kind': 'SCALAR', - 'name': 'Boolean', - 'possibleTypes': None}, - {'description': 'An enum describing what kind of type a given __Type is', - 'enumValues': [{'deprecationReason': None, - 'description': 'Indicates this type is a scalar.', - 'isDeprecated': False, - 'name': 'SCALAR'}, - {'deprecationReason': None, - 'description': 'Indicates this type is a union. `possibleTypes` is a valid field.', - 'isDeprecated': False, - 'name': 'UNION'}, - {'deprecationReason': None, - 'description': 'Indicates this type is an object. `fields` and `interfaces` are valid fields.', - 'isDeprecated': False, - 'name': 'OBJECT'}, - {'deprecationReason': None, - 'description': 'Indicates this type is a non-null. `ofType` is a valid field.', - 'isDeprecated': False, - 'name': 'NON_NULL'}, - {'deprecationReason': None, - 'description': 'Indicates this type is an input object. `inputFields` is a valid field.', - 'isDeprecated': False, - 'name': 'INPUT_OBJECT'}, - {'deprecationReason': None, - 'description': 'Indicates this type is an enum. `enumValues` is a valid field.', - 'isDeprecated': False, - 'name': 'ENUM'}, - {'deprecationReason': None, - 'description': 'Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.', - 'isDeprecated': False, - 'name': 'INTERFACE'}, - {'deprecationReason': None, - 'description': 'Indicates this type is a list. `ofType` is a valid field.', - 'isDeprecated': False, - 'name': 'LIST'}], - 'fields': None, - 'inputFields': None, - 'interfaces': None, - 'kind': 'ENUM', - 'name': '__TypeKind', - 'possibleTypes': None}, - {'description': None, - 'enumValues': None, - 'fields': None, - 'inputFields': None, - 'interfaces': None, - 'kind': 'SCALAR', - 'name': 'String', - 'possibleTypes': None}, - {'description': None, - 'enumValues': None, - 'fields': [{'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'possibleTypes', - 'type': {'kind': 'LIST', - 'name': None, - 'ofType': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None}}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'description', - 'type': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'kind', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'ENUM', - 'name': '__TypeKind', - 'ofType': None}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'ofType', - 'type': {'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'inputFields', - 'type': {'kind': 'LIST', - 'name': None, - 'ofType': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__InputValue', - 'ofType': None}}}}, - {'args': [{'defaultValue': 'false', - 'description': None, - 'name': 'includeDeprecated', - 'type': {'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None}}], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'enumValues', - 'type': {'kind': 'LIST', - 'name': None, - 'ofType': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__EnumValue', - 'ofType': None}}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'interfaces', - 'type': {'kind': 'LIST', - 'name': None, - 'ofType': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None}}}}, - {'args': [{'defaultValue': 'false', - 'description': None, - 'name': 'includeDeprecated', - 'type': {'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None}}], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'fields', - 'type': {'kind': 'LIST', - 'name': None, - 'ofType': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__Field', - 'ofType': None}}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'name', - 'type': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}], - 'inputFields': None, - 'interfaces': [], - 'kind': 'OBJECT', - 'name': '__Type', - 'possibleTypes': None}, - {'description': None, - 'enumValues': None, - 'fields': [], - 'inputFields': None, - 'interfaces': [], - 'kind': 'OBJECT', - 'name': 'QueryRoot', - 'possibleTypes': None}, - {'description': None, - 'enumValues': None, - 'fields': [{'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'defaultValue', - 'type': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'description', - 'type': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'name', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'SCALAR', - 'name': 'String', - 'ofType': None}}}, - {'args': [], - 'deprecationReason': None, - 'description': None, - 'isDeprecated': False, - 'name': 'type', - 'type': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None}}}], - 'inputFields': None, - 'interfaces': [], - 'kind': 'OBJECT', - 'name': '__InputValue', - 'possibleTypes': None}, - { - 'description': 'A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query and mutation operations.', - 'enumValues': None, - 'fields': [{'args': [], - 'deprecationReason': None, - 'description': 'The type that query operations will be rooted at.', - 'isDeprecated': False, - 'name': 'queryType', - 'type': {'kind': 'NON_NULL', + 'ofType': {'kind': 'OBJECT', + 'name': '__Type', + 'ofType': None}}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'possibleTypes', + 'type': {'kind': 'LIST', + 'name': None, + 'ofType': {'kind': 'NON_NULL', 'name': None, 'ofType': {'kind': 'OBJECT', 'name': '__Type', - 'ofType': None}}}, - {'args': [], - 'deprecationReason': None, - 'description': 'A list of all directives supported by this server.', - 'isDeprecated': False, - 'name': 'directives', - 'type': {'kind': 'NON_NULL', + 'ofType': None}}}}, + {'args': [{'defaultValue': 'false', + 'description': None, + 'name': 'includeDeprecated', + 'type': {'kind': 'SCALAR', + 'name': 'Boolean', + 'ofType': None}}], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'enumValues', + 'type': {'kind': 'LIST', + 'name': None, + 'ofType': {'kind': 'NON_NULL', 'name': None, - 'ofType': {'kind': 'LIST', - 'name': None, - 'ofType': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__Directive'}}}}}, - {'args': [], - 'deprecationReason': None, - 'description': 'If this server supports mutation, the type that mutation operations will be rooted at.', - 'isDeprecated': False, - 'name': 'mutationType', - 'type': {'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None}}, - {'args': [], - 'deprecationReason': None, - 'description': 'A list of all types supported by this server.', - 'isDeprecated': False, - 'name': 'types', - 'type': {'kind': 'NON_NULL', + 'ofType': {'kind': 'OBJECT', + 'name': '__EnumValue', + 'ofType': None}}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'inputFields', + 'type': {'kind': 'LIST', + 'name': None, + 'ofType': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'OBJECT', + 'name': '__InputValue', + 'ofType': None}}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'ofType', + 'type': {'kind': 'OBJECT', + 'name': '__Type', + 'ofType': None}}], + 'inputFields': None, + 'interfaces': [], + 'kind': 'OBJECT', + 'name': '__Type', + 'possibleTypes': None}, + {'description': None, + 'enumValues': None, + 'fields': [{'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'name', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'description', + 'type': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'isDeprecated', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'Boolean', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'deprecationReason', + 'type': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}], + 'inputFields': None, + 'interfaces': [], + 'kind': 'OBJECT', + 'name': '__EnumValue', + 'possibleTypes': None}, + {'description': None, + 'enumValues': None, + 'fields': [{'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'name', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'description', + 'type': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'args', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'LIST', 'name': None, - 'ofType': {'kind': 'LIST', + 'ofType': {'kind': 'NON_NULL', 'name': None, - 'ofType': {'kind': 'NON_NULL', - 'name': None, - 'ofType': {'kind': 'OBJECT', - 'name': '__Type'}}}}}], - 'inputFields': None, - 'interfaces': [], - 'kind': 'OBJECT', - 'name': '__Schema', - 'possibleTypes': None}]}} + 'ofType': {'kind': 'OBJECT', + 'name': '__InputValue'}}}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'onOperation', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'Boolean', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'onFragment', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'Boolean', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'onField', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'Boolean', + 'ofType': None}}}], + 'inputFields': None, + 'interfaces': [], + 'kind': 'OBJECT', + 'name': '__Directive', + 'possibleTypes': None}, + {'description': None, + 'enumValues': None, + 'fields': None, + 'inputFields': None, + 'interfaces': None, + 'kind': 'SCALAR', + 'name': 'Boolean', + 'possibleTypes': None}, + {'description': None, + 'enumValues': None, + 'fields': [{'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'name', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'description', + 'type': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'type', + 'type': {'kind': 'NON_NULL', + 'name': None, + 'ofType': {'kind': 'OBJECT', + 'name': '__Type', + 'ofType': None}}}, + {'args': [], + 'deprecationReason': None, + 'description': None, + 'isDeprecated': False, + 'name': 'defaultValue', + 'type': {'kind': 'SCALAR', + 'name': 'String', + 'ofType': None}}], + 'inputFields': None, + 'interfaces': [], + 'kind': 'OBJECT', + 'name': '__InputValue', + 'possibleTypes': None}, + {'description': None, + 'enumValues': None, + 'fields': [], + 'inputFields': None, + 'interfaces': [], + 'kind': 'OBJECT', + 'name': 'QueryRoot', + 'possibleTypes': None}]}} assert sort_lists(result.data) == sort_lists(expected) diff --git a/tests/core_utils/test_schema_printer.py b/tests/core_utils/test_schema_printer.py new file mode 100644 index 00000000..39fe1298 --- /dev/null +++ b/tests/core_utils/test_schema_printer.py @@ -0,0 +1,529 @@ +from collections import OrderedDict +from graphql.core.type.definition import GraphQLField, GraphQLArgument, GraphQLInputObjectField, GraphQLEnumValue +from graphql.core.utils.schema_printer import print_schema, print_introspection_schema +from graphql.core.utils.is_nullish import is_nullish +from graphql.core.language.printer import print_ast +from graphql.core.type import ( + GraphQLSchema, + GraphQLInputObjectType, + GraphQLScalarType, + GraphQLObjectType, + GraphQLInterfaceType, + GraphQLUnionType, + GraphQLEnumType, + GraphQLString, + GraphQLInt, + GraphQLBoolean, + GraphQLList, + GraphQLNonNull, +) + + +def print_for_test(schema): + return '\n' + print_schema(schema) + + +def print_single_field_schema(field_config): + Root = GraphQLObjectType( + name='Root', + fields={ + 'singleField': field_config + } + ) + return print_for_test(GraphQLSchema(Root)) + + +def test_prints_string_field(): + output = print_single_field_schema(GraphQLField(GraphQLString)) + assert output == ''' +type Root { + singleField: String +} +''' + + +def test_prints_list_string_field(): + output = print_single_field_schema(GraphQLField(GraphQLList(GraphQLString))) + assert output == ''' +type Root { + singleField: [String] +} +''' + + +def test_prints_non_null_list_string_field(): + output = print_single_field_schema(GraphQLField(GraphQLNonNull(GraphQLList(GraphQLString)))) + assert output == ''' +type Root { + singleField: [String]! +} +''' + + +def test_prints_list_non_null_string_field(): + output = print_single_field_schema(GraphQLField((GraphQLList(GraphQLNonNull(GraphQLString))))) + assert output == ''' +type Root { + singleField: [String!] +} +''' + + +def test_prints_non_null_list_non_null_string_field(): + output = print_single_field_schema(GraphQLField(GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString))))) + assert output == ''' +type Root { + singleField: [String!]! +} +''' + + +def test_prints_object_field(): + FooType = GraphQLObjectType( + name='Foo', + fields={ + 'str': GraphQLField(GraphQLString) + } + ) + + Root = GraphQLObjectType( + name='Root', + fields={ + 'foo': GraphQLField(FooType) + } + ) + + Schema = GraphQLSchema(Root) + + output = print_for_test(Schema) + + assert output == ''' +type Foo { + str: String +} + +type Root { + foo: Foo +} +''' + + +def test_prints_string_field_with_int_arg(): + output = print_single_field_schema(GraphQLField( + type=GraphQLString, + args={'argOne': GraphQLArgument(GraphQLInt)} + )) + assert output == ''' +type Root { + singleField(argOne: Int): String +} +''' + + +def test_prints_string_field_with_int_arg_with_default(): + output = print_single_field_schema(GraphQLField( + type=GraphQLString, + args={'argOne': GraphQLArgument(GraphQLInt, default_value=2)} + )) + assert output == ''' +type Root { + singleField(argOne: Int = 2): String +} +''' + + +def test_prints_string_field_with_non_null_int_arg(): + output = print_single_field_schema(GraphQLField( + type=GraphQLString, + args={'argOne': GraphQLArgument(GraphQLNonNull(GraphQLInt))} + )) + assert output == ''' +type Root { + singleField(argOne: Int!): String +} +''' + + +def test_prints_string_field_with_multiple_args(): + output = print_single_field_schema(GraphQLField( + type=GraphQLString, + args=OrderedDict([ + ('argOne', GraphQLArgument(GraphQLInt)), + ('argTwo', GraphQLArgument(GraphQLString)) + ]) + )) + + assert output == ''' +type Root { + singleField(argOne: Int, argTwo: String): String +} +''' + + +def test_prints_string_field_with_multiple_args_first_is_default(): + output = print_single_field_schema(GraphQLField( + type=GraphQLString, + args=OrderedDict([ + ('argOne', GraphQLArgument(GraphQLInt, default_value=1)), + ('argTwo', GraphQLArgument(GraphQLString)), + ('argThree', GraphQLArgument(GraphQLBoolean)) + ]) + )) + + assert output == ''' +type Root { + singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String +} +''' + + +def test_prints_string_field_with_multiple_args_second_is_default(): + output = print_single_field_schema(GraphQLField( + type=GraphQLString, + args=OrderedDict([ + ('argOne', GraphQLArgument(GraphQLInt)), + ('argTwo', GraphQLArgument(GraphQLString, default_value="foo")), + ('argThree', GraphQLArgument(GraphQLBoolean)) + ]) + )) + + assert output == ''' +type Root { + singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String +} +''' + + +def test_prints_string_field_with_multiple_args_last_is_default(): + output = print_single_field_schema(GraphQLField( + type=GraphQLString, + args=OrderedDict([ + ('argOne', GraphQLArgument(GraphQLInt)), + ('argTwo', GraphQLArgument(GraphQLString)), + ('argThree', GraphQLArgument(GraphQLBoolean, default_value=False)) + ]) + )) + + assert output == ''' +type Root { + singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String +} +''' + + +def test_prints_interface(): + FooType = GraphQLInterfaceType( + name='Foo', + resolve_type=lambda *_: None, + fields={ + 'str': GraphQLField(GraphQLString) + } + ) + + BarType = GraphQLObjectType( + name='Bar', + fields={ + 'str': GraphQLField(GraphQLString), + }, + interfaces=[FooType] + ) + + Root = GraphQLObjectType( + name='Root', + fields={ + 'bar': GraphQLField(BarType) + } + ) + + Schema = GraphQLSchema(Root) + output = print_for_test(Schema) + + assert output == ''' +type Bar implements Foo { + str: String +} + +interface Foo { + str: String +} + +type Root { + bar: Bar +} +''' + + +def test_prints_multiple_interfaces(): + FooType = GraphQLInterfaceType( + name='Foo', + resolve_type=lambda *_: None, + fields={ + 'str': GraphQLField(GraphQLString) + } + ) + BaazType = GraphQLInterfaceType( + name='Baaz', + resolve_type=lambda *_: None, + fields={ + 'int': GraphQLField(GraphQLInt) + } + ) + + BarType = GraphQLObjectType( + name='Bar', + fields=OrderedDict([ + ('str', GraphQLField(GraphQLString)), + ('int', GraphQLField(GraphQLInt)) + ]), + interfaces=[FooType, BaazType] + ) + + Root = GraphQLObjectType( + name='Root', + fields={ + 'bar': GraphQLField(BarType) + } + ) + + Schema = GraphQLSchema(Root) + output = print_for_test(Schema) + + assert output == ''' +interface Baaz { + int: Int +} + +type Bar implements Foo, Baaz { + str: String + int: Int +} + +interface Foo { + str: String +} + +type Root { + bar: Bar +} +''' + + +def test_prints_unions(): + FooType = GraphQLObjectType( + name='Foo', + fields={ + 'bool': GraphQLField(GraphQLBoolean), + }, + ) + + BarType = GraphQLObjectType( + name='Bar', + fields={ + 'str': GraphQLField(GraphQLString), + }, + ) + + SingleUnion = GraphQLUnionType( + name='SingleUnion', + resolve_type=lambda *_: None, + types=[FooType] + ) + + MultipleUnion = GraphQLUnionType( + name='MultipleUnion', + resolve_type=lambda *_: None, + types=[FooType, BarType], + ) + + Root = GraphQLObjectType( + name='Root', + fields=OrderedDict([ + ('single', GraphQLField(SingleUnion)), + ('multiple', GraphQLField(MultipleUnion)), + ]) + ) + + Schema = GraphQLSchema(Root) + output = print_for_test(Schema) + + assert output == ''' +type Bar { + str: String +} + +type Foo { + bool: Boolean +} + +union MultipleUnion = Foo | Bar + +type Root { + single: SingleUnion + multiple: MultipleUnion +} + +union SingleUnion = Foo +''' + + +def test_prints_input_type(): + InputType = GraphQLInputObjectType( + name='InputType', + fields={ + 'int': GraphQLInputObjectField(GraphQLInt) + } + ) + + Root = GraphQLObjectType( + name='Root', + fields={ + 'str': GraphQLField(GraphQLString, args={'argOne': GraphQLArgument(InputType)}) + } + ) + + Schema = GraphQLSchema(Root) + output = print_for_test(Schema) + + assert output == ''' +input InputType { + int: Int +} + +type Root { + str(argOne: InputType): String +} +''' + + +def test_prints_custom_scalar(): + OddType = GraphQLScalarType( + name='Odd', + serialize=lambda v: v if v % 2 == 1 else None + ) + + Root = GraphQLObjectType( + name='Root', + fields={ + 'odd': GraphQLField(OddType) + } + ) + + Schema = GraphQLSchema(Root) + output = print_for_test(Schema) + + assert output == ''' +scalar Odd + +type Root { + odd: Odd +} +''' + + +def test_print_enum(): + RGBType = GraphQLEnumType( + name='RGB', + values=OrderedDict([ + ('RED', GraphQLEnumValue(0)), + ('GREEN', GraphQLEnumValue(1)), + ('BLUE', GraphQLEnumValue(2)) + ]) + ) + + Root = GraphQLObjectType( + name='Root', + fields={ + 'rgb': GraphQLField(RGBType) + } + ) + + Schema = GraphQLSchema(Root) + output = print_for_test(Schema) + + assert output == ''' +enum RGB { + RED + GREEN + BLUE +} + +type Root { + rgb: RGB +} +''' + + +def test_prints_introspection_schema(): + Root = GraphQLObjectType( + name='Root', + fields={ + 'onlyField': GraphQLField(GraphQLString) + } + ) + + Schema = GraphQLSchema(Root) + output = '\n' + print_introspection_schema(Schema) + + assert output == ''' +type __Directive { + name: String! + description: String + args: [__InputValue!]! + onOperation: Boolean! + onFragment: Boolean! + onField: Boolean! +} + +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 + 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 +} +''' \ No newline at end of file diff --git a/tests/core_validation/utils.py b/tests/core_validation/utils.py index e24fd8ab..45effc7f 100644 --- a/tests/core_validation/utils.py +++ b/tests/core_validation/utils.py @@ -14,6 +14,7 @@ GraphQLInterfaceType, GraphQLEnumType, GraphQLEnumValue, + GraphQLInputObjectField, GraphQLInputObjectType, GraphQLUnionType, GraphQLList) @@ -95,11 +96,11 @@ }) ComplexInput = GraphQLInputObjectType('ComplexInput', { - 'requiredField': GraphQLField(GraphQLNonNull(GraphQLBoolean)), - 'intField': GraphQLField(GraphQLInt), - 'stringField': GraphQLField(GraphQLString), - 'booleanField': GraphQLField(GraphQLBoolean), - 'stringListField': GraphQLField(GraphQLList(GraphQLString)), + 'requiredField': GraphQLInputObjectField(GraphQLNonNull(GraphQLBoolean)), + 'intField': GraphQLInputObjectField(GraphQLInt), + 'stringField': GraphQLInputObjectField(GraphQLString), + 'booleanField': GraphQLInputObjectField(GraphQLBoolean), + 'stringListField': GraphQLInputObjectField(GraphQLList(GraphQLString)), }) ComplicatedArgs = GraphQLObjectType('ComplicatedArgs', {