diff --git a/.flake8 b/.flake8 index c8479de9..12b6f7d2 100644 --- a/.flake8 +++ b/.flake8 @@ -1,3 +1,4 @@ [flake8] +ignore = E203,W503,E704 exclude = .git,.mypy_cache,.pytest_cache,.tox,.venv,__pycache__,build,dist,docs max-line-length = 88 diff --git a/.travis.yml b/.travis.yml index 5c638166..ab722f25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,17 +4,18 @@ dist: xenial sudo: true python: - - 3.6 - - 3.7 + - 3.6 + - 3.7 install: - - pip install pipenv - - pipenv install --dev + - pip install pipenv black + - pipenv install --dev script: - - flake8 graphql tests - - mypy graphql - - pytest --cov-report term-missing --cov=graphql + - flake8 graphql tests + - black graphql tests --check + - mypy graphql + - pytest --cov-report term-missing --cov=graphql after_success: - - coveralls + - coveralls diff --git a/Pipfile b/Pipfile index 2e713c48..ffb6a081 100644 --- a/Pipfile +++ b/Pipfile @@ -5,6 +5,8 @@ name = "pypi" [dev-packages] graphql-core-next = {path = ".", editable = true} +# Line below commented as causes issues with Pipenv +# black = "18.6b4" flake8 = "*" mypy = "*" pytest = "*" diff --git a/graphql/__init__.py b/graphql/__init__.py index 0777b084..80049c3d 100644 --- a/graphql/__init__.py +++ b/graphql/__init__.py @@ -37,8 +37,8 @@ - `graphql/subscription`: Subscribe to data updates. """ -__version__ = '1.0.1' -__version_js__ = '14.0.2' +__version__ = "1.0.1" +__version_js__ = "14.0.2" # The primary entry point into fulfilling a GraphQL request. @@ -154,7 +154,8 @@ GraphQLIsTypeOfFn, GraphQLResolveInfo, ResponsePath, - GraphQLTypeResolver) + GraphQLTypeResolver, +) # Parse and operate on GraphQL language source files. from .language import ( @@ -173,7 +174,10 @@ Visitor, TokenKind, DirectiveLocation, - BREAK, SKIP, REMOVE, IDLE, + BREAK, + SKIP, + REMOVE, + IDLE, # Predicates is_definition_node, is_executable_definition_node, @@ -242,7 +246,8 @@ InterfaceTypeExtensionNode, UnionTypeExtensionNode, EnumTypeExtensionNode, - InputObjectTypeExtensionNode) + InputObjectTypeExtensionNode, +) # Execute GraphQL queries. from .execution import ( @@ -252,17 +257,19 @@ get_directive_values, # Types ExecutionContext, - ExecutionResult) + ExecutionResult, +) -from .subscription import ( - subscribe, create_source_event_stream) +from .subscription import subscribe, create_source_event_stream # Validate GraphQL queries. from .validation import ( validate, ValidationContext, - ValidationRule, ASTValidationRule, SDLValidationRule, + ValidationRule, + ASTValidationRule, + SDLValidationRule, # All validation rules in the GraphQL Specification. specified_rules, # Individual validation rules. @@ -290,11 +297,11 @@ UniqueVariableNamesRule, ValuesOfCorrectTypeRule, VariablesAreInputTypesRule, - VariablesInAllowedPositionRule) + VariablesInAllowedPositionRule, +) # Create, format, and print GraphQL errors. -from .error import ( - GraphQLError, format_error, print_error) +from .error import GraphQLError, format_error, print_error # Utilities for operating on GraphQL type schema and parsed sources. from .utilities import ( @@ -353,107 +360,268 @@ # Determine if a string is a valid GraphQL name. is_valid_name_error, # Compares two GraphQLSchemas and detects breaking changes. - find_breaking_changes, find_dangerous_changes, - BreakingChange, BreakingChangeType, - DangerousChange, DangerousChangeType) + find_breaking_changes, + find_dangerous_changes, + BreakingChange, + BreakingChangeType, + DangerousChange, + DangerousChangeType, +) __all__ = [ - 'graphql', 'graphql_sync', - 'GraphQLSchema', - 'GraphQLScalarType', 'GraphQLObjectType', 'GraphQLInterfaceType', - 'GraphQLUnionType', 'GraphQLEnumType', 'GraphQLInputObjectType', - 'GraphQLList', 'GraphQLNonNull', 'GraphQLDirective', - 'TypeKind', - 'specified_scalar_types', - 'GraphQLInt', 'GraphQLFloat', 'GraphQLString', 'GraphQLBoolean', - 'GraphQLID', - 'specified_directives', - 'GraphQLIncludeDirective', 'GraphQLSkipDirective', - 'GraphQLDeprecatedDirective', - 'DEFAULT_DEPRECATION_REASON', - 'SchemaMetaFieldDef', 'TypeMetaFieldDef', 'TypeNameMetaFieldDef', - 'introspection_types', 'is_schema', 'is_directive', 'is_type', - 'is_scalar_type', 'is_object_type', 'is_interface_type', - 'is_union_type', 'is_enum_type', 'is_input_object_type', - 'is_list_type', 'is_non_null_type', 'is_input_type', 'is_output_type', - 'is_leaf_type', 'is_composite_type', 'is_abstract_type', - 'is_wrapping_type', 'is_nullable_type', 'is_named_type', - 'is_required_argument', 'is_required_input_field', - 'is_specified_scalar_type', 'is_introspection_type', - 'is_specified_directive', - 'assert_type', 'assert_scalar_type', 'assert_object_type', - 'assert_interface_type', 'assert_union_type', 'assert_enum_type', - 'assert_input_object_type', 'assert_list_type', 'assert_non_null_type', - 'assert_input_type', 'assert_output_type', 'assert_leaf_type', - 'assert_composite_type', 'assert_abstract_type', 'assert_wrapping_type', - 'assert_nullable_type', 'assert_named_type', - 'get_nullable_type', 'get_named_type', - 'validate_schema', 'assert_valid_schema', - 'GraphQLType', 'GraphQLInputType', 'GraphQLOutputType', 'GraphQLLeafType', - 'GraphQLCompositeType', 'GraphQLAbstractType', - 'GraphQLWrappingType', 'GraphQLNullableType', 'GraphQLNamedType', - 'Thunk', 'GraphQLArgument', 'GraphQLArgumentMap', - 'GraphQLEnumValue', 'GraphQLEnumValueMap', - 'GraphQLField', 'GraphQLFieldMap', 'GraphQLFieldResolver', - 'GraphQLInputField', 'GraphQLInputFieldMap', - 'GraphQLScalarSerializer', 'GraphQLScalarValueParser', - 'GraphQLScalarLiteralParser', 'GraphQLIsTypeOfFn', - 'GraphQLResolveInfo', 'ResponsePath', 'GraphQLTypeResolver', - 'Source', 'get_location', - 'parse', 'parse_value', 'parse_type', - 'print_ast', 'visit', 'ParallelVisitor', 'TypeInfoVisitor', 'Visitor', - 'TokenKind', 'DirectiveLocation', 'BREAK', 'SKIP', 'REMOVE', 'IDLE', - 'is_definition_node', 'is_executable_definition_node', - 'is_selection_node', 'is_value_node', 'is_type_node', - 'is_type_system_definition_node', 'is_type_definition_node', - 'is_type_system_extension_node', 'is_type_extension_node', - 'Lexer', 'SourceLocation', 'Location', 'Token', - 'NameNode', 'DocumentNode', 'DefinitionNode', 'ExecutableDefinitionNode', - 'OperationDefinitionNode', 'OperationType', 'VariableDefinitionNode', - 'VariableNode', 'SelectionSetNode', 'SelectionNode', 'FieldNode', - 'ArgumentNode', 'FragmentSpreadNode', 'InlineFragmentNode', - 'FragmentDefinitionNode', 'ValueNode', 'IntValueNode', 'FloatValueNode', - 'StringValueNode', 'BooleanValueNode', 'NullValueNode', 'EnumValueNode', - 'ListValueNode', 'ObjectValueNode', 'ObjectFieldNode', 'DirectiveNode', - 'TypeNode', 'NamedTypeNode', 'ListTypeNode', 'NonNullTypeNode', - 'TypeSystemDefinitionNode', 'SchemaDefinitionNode', - 'OperationTypeDefinitionNode', 'TypeDefinitionNode', - 'ScalarTypeDefinitionNode', 'ObjectTypeDefinitionNode', - 'FieldDefinitionNode', 'InputValueDefinitionNode', - 'InterfaceTypeDefinitionNode', 'UnionTypeDefinitionNode', - 'EnumTypeDefinitionNode', 'EnumValueDefinitionNode', - 'InputObjectTypeDefinitionNode', 'DirectiveDefinitionNode', - 'TypeSystemExtensionNode', 'SchemaExtensionNode', 'TypeExtensionNode', - 'ScalarTypeExtensionNode', 'ObjectTypeExtensionNode', - 'InterfaceTypeExtensionNode', 'UnionTypeExtensionNode', - 'EnumTypeExtensionNode', 'InputObjectTypeExtensionNode', - 'execute', 'default_field_resolver', 'response_path_as_list', - 'get_directive_values', 'ExecutionContext', 'ExecutionResult', - 'subscribe', 'create_source_event_stream', - 'validate', 'ValidationContext', - 'ValidationRule', 'ASTValidationRule', 'SDLValidationRule', - 'specified_rules', - 'FieldsOnCorrectTypeRule', 'FragmentsOnCompositeTypesRule', - 'KnownArgumentNamesRule', 'KnownDirectivesRule', 'KnownFragmentNamesRule', - 'KnownTypeNamesRule', 'LoneAnonymousOperationRule', 'NoFragmentCyclesRule', - 'NoUndefinedVariablesRule', 'NoUnusedFragmentsRule', - 'NoUnusedVariablesRule', 'OverlappingFieldsCanBeMergedRule', - 'PossibleFragmentSpreadsRule', 'ProvidedRequiredArgumentsRule', - 'ScalarLeafsRule', 'SingleFieldSubscriptionsRule', - 'UniqueArgumentNamesRule', 'UniqueDirectivesPerLocationRule', - 'UniqueFragmentNamesRule', 'UniqueInputFieldNamesRule', - 'UniqueOperationNamesRule', 'UniqueVariableNamesRule', - 'ValuesOfCorrectTypeRule', 'VariablesAreInputTypesRule', - 'VariablesInAllowedPositionRule', - 'GraphQLError', 'format_error', 'print_error', - 'get_introspection_query', 'get_operation_ast', 'get_operation_root_type', - 'introspection_from_schema', 'build_client_schema', 'build_ast_schema', - 'build_schema', 'get_description', 'extend_schema', - 'lexicographic_sort_schema', 'print_schema', 'print_introspection_schema', - 'print_type', 'type_from_ast', 'value_from_ast', 'value_from_ast_untyped', - 'ast_from_value', 'TypeInfo', 'coerce_value', 'concat_ast', - 'separate_operations', 'is_equal_type', 'is_type_sub_type_of', - 'do_types_overlap', 'assert_valid_name', 'is_valid_name_error', - 'find_breaking_changes', 'find_dangerous_changes', - 'BreakingChange', 'BreakingChangeType', - 'DangerousChange', 'DangerousChangeType'] + "graphql", + "graphql_sync", + "GraphQLSchema", + "GraphQLScalarType", + "GraphQLObjectType", + "GraphQLInterfaceType", + "GraphQLUnionType", + "GraphQLEnumType", + "GraphQLInputObjectType", + "GraphQLList", + "GraphQLNonNull", + "GraphQLDirective", + "TypeKind", + "specified_scalar_types", + "GraphQLInt", + "GraphQLFloat", + "GraphQLString", + "GraphQLBoolean", + "GraphQLID", + "specified_directives", + "GraphQLIncludeDirective", + "GraphQLSkipDirective", + "GraphQLDeprecatedDirective", + "DEFAULT_DEPRECATION_REASON", + "SchemaMetaFieldDef", + "TypeMetaFieldDef", + "TypeNameMetaFieldDef", + "introspection_types", + "is_schema", + "is_directive", + "is_type", + "is_scalar_type", + "is_object_type", + "is_interface_type", + "is_union_type", + "is_enum_type", + "is_input_object_type", + "is_list_type", + "is_non_null_type", + "is_input_type", + "is_output_type", + "is_leaf_type", + "is_composite_type", + "is_abstract_type", + "is_wrapping_type", + "is_nullable_type", + "is_named_type", + "is_required_argument", + "is_required_input_field", + "is_specified_scalar_type", + "is_introspection_type", + "is_specified_directive", + "assert_type", + "assert_scalar_type", + "assert_object_type", + "assert_interface_type", + "assert_union_type", + "assert_enum_type", + "assert_input_object_type", + "assert_list_type", + "assert_non_null_type", + "assert_input_type", + "assert_output_type", + "assert_leaf_type", + "assert_composite_type", + "assert_abstract_type", + "assert_wrapping_type", + "assert_nullable_type", + "assert_named_type", + "get_nullable_type", + "get_named_type", + "validate_schema", + "assert_valid_schema", + "GraphQLType", + "GraphQLInputType", + "GraphQLOutputType", + "GraphQLLeafType", + "GraphQLCompositeType", + "GraphQLAbstractType", + "GraphQLWrappingType", + "GraphQLNullableType", + "GraphQLNamedType", + "Thunk", + "GraphQLArgument", + "GraphQLArgumentMap", + "GraphQLEnumValue", + "GraphQLEnumValueMap", + "GraphQLField", + "GraphQLFieldMap", + "GraphQLFieldResolver", + "GraphQLInputField", + "GraphQLInputFieldMap", + "GraphQLScalarSerializer", + "GraphQLScalarValueParser", + "GraphQLScalarLiteralParser", + "GraphQLIsTypeOfFn", + "GraphQLResolveInfo", + "ResponsePath", + "GraphQLTypeResolver", + "Source", + "get_location", + "parse", + "parse_value", + "parse_type", + "print_ast", + "visit", + "ParallelVisitor", + "TypeInfoVisitor", + "Visitor", + "TokenKind", + "DirectiveLocation", + "BREAK", + "SKIP", + "REMOVE", + "IDLE", + "is_definition_node", + "is_executable_definition_node", + "is_selection_node", + "is_value_node", + "is_type_node", + "is_type_system_definition_node", + "is_type_definition_node", + "is_type_system_extension_node", + "is_type_extension_node", + "Lexer", + "SourceLocation", + "Location", + "Token", + "NameNode", + "DocumentNode", + "DefinitionNode", + "ExecutableDefinitionNode", + "OperationDefinitionNode", + "OperationType", + "VariableDefinitionNode", + "VariableNode", + "SelectionSetNode", + "SelectionNode", + "FieldNode", + "ArgumentNode", + "FragmentSpreadNode", + "InlineFragmentNode", + "FragmentDefinitionNode", + "ValueNode", + "IntValueNode", + "FloatValueNode", + "StringValueNode", + "BooleanValueNode", + "NullValueNode", + "EnumValueNode", + "ListValueNode", + "ObjectValueNode", + "ObjectFieldNode", + "DirectiveNode", + "TypeNode", + "NamedTypeNode", + "ListTypeNode", + "NonNullTypeNode", + "TypeSystemDefinitionNode", + "SchemaDefinitionNode", + "OperationTypeDefinitionNode", + "TypeDefinitionNode", + "ScalarTypeDefinitionNode", + "ObjectTypeDefinitionNode", + "FieldDefinitionNode", + "InputValueDefinitionNode", + "InterfaceTypeDefinitionNode", + "UnionTypeDefinitionNode", + "EnumTypeDefinitionNode", + "EnumValueDefinitionNode", + "InputObjectTypeDefinitionNode", + "DirectiveDefinitionNode", + "TypeSystemExtensionNode", + "SchemaExtensionNode", + "TypeExtensionNode", + "ScalarTypeExtensionNode", + "ObjectTypeExtensionNode", + "InterfaceTypeExtensionNode", + "UnionTypeExtensionNode", + "EnumTypeExtensionNode", + "InputObjectTypeExtensionNode", + "execute", + "default_field_resolver", + "response_path_as_list", + "get_directive_values", + "ExecutionContext", + "ExecutionResult", + "subscribe", + "create_source_event_stream", + "validate", + "ValidationContext", + "ValidationRule", + "ASTValidationRule", + "SDLValidationRule", + "specified_rules", + "FieldsOnCorrectTypeRule", + "FragmentsOnCompositeTypesRule", + "KnownArgumentNamesRule", + "KnownDirectivesRule", + "KnownFragmentNamesRule", + "KnownTypeNamesRule", + "LoneAnonymousOperationRule", + "NoFragmentCyclesRule", + "NoUndefinedVariablesRule", + "NoUnusedFragmentsRule", + "NoUnusedVariablesRule", + "OverlappingFieldsCanBeMergedRule", + "PossibleFragmentSpreadsRule", + "ProvidedRequiredArgumentsRule", + "ScalarLeafsRule", + "SingleFieldSubscriptionsRule", + "UniqueArgumentNamesRule", + "UniqueDirectivesPerLocationRule", + "UniqueFragmentNamesRule", + "UniqueInputFieldNamesRule", + "UniqueOperationNamesRule", + "UniqueVariableNamesRule", + "ValuesOfCorrectTypeRule", + "VariablesAreInputTypesRule", + "VariablesInAllowedPositionRule", + "GraphQLError", + "format_error", + "print_error", + "get_introspection_query", + "get_operation_ast", + "get_operation_root_type", + "introspection_from_schema", + "build_client_schema", + "build_ast_schema", + "build_schema", + "get_description", + "extend_schema", + "lexicographic_sort_schema", + "print_schema", + "print_introspection_schema", + "print_type", + "type_from_ast", + "value_from_ast", + "value_from_ast_untyped", + "ast_from_value", + "TypeInfo", + "coerce_value", + "concat_ast", + "separate_operations", + "is_equal_type", + "is_type_sub_type_of", + "do_types_overlap", + "assert_valid_name", + "is_valid_name_error", + "find_breaking_changes", + "find_dangerous_changes", + "BreakingChange", + "BreakingChangeType", + "DangerousChange", + "DangerousChangeType", +] diff --git a/graphql/error/__init__.py b/graphql/error/__init__.py index 7b834b25..4dc13a4c 100644 --- a/graphql/error/__init__.py +++ b/graphql/error/__init__.py @@ -12,5 +12,11 @@ from .invalid import INVALID, InvalidType __all__ = [ - 'INVALID', 'InvalidType', 'GraphQLError', 'GraphQLSyntaxError', - 'format_error', 'print_error', 'located_error'] + "INVALID", + "InvalidType", + "GraphQLError", + "GraphQLSyntaxError", + "format_error", + "print_error", + "located_error", +] diff --git a/graphql/error/format_error.py b/graphql/error/format_error.py index 7ebcc3f4..7b43dcb1 100644 --- a/graphql/error/format_error.py +++ b/graphql/error/format_error.py @@ -4,20 +4,22 @@ from .graphql_error import GraphQLError # noqa: F401 -__all__ = ['format_error'] +__all__ = ["format_error"] -def format_error(error: 'GraphQLError') -> dict: +def format_error(error: "GraphQLError") -> dict: """Format a GraphQL error Given a GraphQLError, format it according to the rules described by the Response Format, Errors section of the GraphQL Specification. """ if not error: - raise ValueError('Received null or undefined error.') + raise ValueError("Received null or undefined error.") formatted: Dict[str, Any] = dict( # noqa: E701 (pycqa/flake8#394) - message=error.message or 'An unknown error occurred.', - locations=error.locations, path=error.path) + message=error.message or "An unknown error occurred.", + locations=error.locations, + path=error.path, + ) if error.extensions: formatted.update(extensions=error.extensions) return formatted diff --git a/graphql/error/graphql_error.py b/graphql/error/graphql_error.py index d7214967..f828999b 100644 --- a/graphql/error/graphql_error.py +++ b/graphql/error/graphql_error.py @@ -8,7 +8,7 @@ from ..language.location import SourceLocation # noqa from ..language.source import Source # noqa -__all__ = ['GraphQLError'] +__all__ = ["GraphQLError"] class GraphQLError(Exception): @@ -26,7 +26,7 @@ class GraphQLError(Exception): Note: should be treated as readonly, despite invariant usage. """ - locations: Optional[List['SourceLocation']] + locations: Optional[List["SourceLocation"]] """Source locations A list of (line, column) locations within the source @@ -40,14 +40,14 @@ class GraphQLError(Exception): path: Optional[List[Union[str, int]]] """A list of GraphQL AST Nodes corresponding to this error""" - nodes: Optional[List['Node']] + nodes: Optional[List["Node"]] """The source GraphQL document for the first location of this error Note that if this Error represents more than one node, the source may not represent nodes after the first node. """ - source: Optional['Source'] + source: Optional["Source"] """The source GraphQL document for the first location of this error Note that if this Error represents more than one node, the source may @@ -67,16 +67,27 @@ class GraphQLError(Exception): extensions: Optional[Dict[str, Any]] """Extension fields to add to the formatted error""" - __slots__ = ('message', 'nodes', 'source', 'positions', 'locations', - 'path', 'original_error', 'extensions') - - def __init__(self, message: str, - nodes: Union[Sequence['Node'], 'Node']=None, - source: 'Source'=None, - positions: Sequence[int]=None, - path: Sequence[Union[str, int]]=None, - original_error: Exception=None, - extensions: Dict[str, Any]=None) -> None: + __slots__ = ( + "message", + "nodes", + "source", + "positions", + "locations", + "path", + "original_error", + "extensions", + ) + + def __init__( + self, + message: str, + nodes: Union[Sequence["Node"], "Node"] = None, + source: "Source" = None, + positions: Sequence[int] = None, + path: Sequence[Union[str, int]] = None, + original_error: Exception = None, + extensions: Dict[str, Any] = None, + ) -> None: super(GraphQLError, self).__init__(message) self.message = message if nodes and not isinstance(nodes, list): @@ -88,15 +99,18 @@ def __init__(self, message: str, if node and node.loc and node.loc.source: self.source = node.loc.source if not positions and nodes: - positions = [node.loc.start - for node in nodes if node.loc] # type: ignore + positions = [node.loc.start for node in nodes if node.loc] # type: ignore self.positions = positions or None if positions and source: - locations: Optional[List['SourceLocation']] = [ - source.get_location(pos) for pos in positions] + locations: Optional[List["SourceLocation"]] = [ + source.get_location(pos) for pos in positions + ] elif nodes: - locations = [node.loc.source.get_location(node.loc.start) - for node in nodes if node.loc] # type: ignore + locations = [ + node.loc.source.get_location(node.loc.start) + for node in nodes # type: ignore + if node.loc + ] else: locations = None self.locations = locations @@ -117,21 +131,28 @@ def __str__(self): def __repr__(self): args = [repr(self.message)] if self.locations: - args.append(f'locations={self.locations!r}') + args.append(f"locations={self.locations!r}") if self.path: - args.append(f'path={self.path!r}') + args.append(f"path={self.path!r}") if self.extensions: - args.append(f'extensions={self.extensions!r}') + args.append(f"extensions={self.extensions!r}") return f"{self.__class__.__name__}({', '.join(args)})" def __eq__(self, other): - return (isinstance(other, GraphQLError) and - self.__class__ == other.__class__ and - all(getattr(self, slot) == getattr(other, slot) - for slot in self.__slots__)) or ( - isinstance(other, dict) and 'message' in other and - all(slot in self.__slots__ and - getattr(self, slot) == other.get(slot) for slot in other)) + return ( + isinstance(other, GraphQLError) + and self.__class__ == other.__class__ + and all( + getattr(self, slot) == getattr(other, slot) for slot in self.__slots__ + ) + ) or ( + isinstance(other, dict) + and "message" in other + and all( + slot in self.__slots__ and getattr(self, slot) == other.get(slot) + for slot in other + ) + ) def __ne__(self, other): return not self.__eq__(other) diff --git a/graphql/error/invalid.py b/graphql/error/invalid.py index a7000a13..ca991508 100644 --- a/graphql/error/invalid.py +++ b/graphql/error/invalid.py @@ -1,14 +1,14 @@ -__all__ = ['INVALID', 'InvalidType'] +__all__ = ["INVALID", "InvalidType"] class InvalidType(ValueError): """Auxiliary class for creating the INVALID singleton.""" def __repr__(self): - return '' + return "" def __str__(self): - return 'INVALID' + return "INVALID" def __bool__(self): return False diff --git a/graphql/error/located_error.py b/graphql/error/located_error.py index 96aba4fd..209c03ae 100644 --- a/graphql/error/located_error.py +++ b/graphql/error/located_error.py @@ -5,12 +5,14 @@ if TYPE_CHECKING: # pragma: no cover from ..language.ast import Node # noqa -__all__ = ['located_error'] +__all__ = ["located_error"] -def located_error(original_error: Union[Exception, GraphQLError], - nodes: Sequence['Node'], - path: Sequence[Union[str, int]]) -> GraphQLError: +def located_error( + original_error: Union[Exception, GraphQLError], + nodes: Sequence["Node"], + path: Sequence[Union[str, int]], +) -> GraphQLError: """Located GraphQL Error Given an arbitrary Error, presumably thrown while attempting to execute a @@ -41,5 +43,4 @@ def located_error(original_error: Union[Exception, GraphQLError], nodes = original_error.nodes or nodes # type: ignore except AttributeError: pass - return GraphQLError( - message, nodes, source, positions, path, original_error) + return GraphQLError(message, nodes, source, positions, path, original_error) diff --git a/graphql/error/print_error.py b/graphql/error/print_error.py index 3283cbc8..833559db 100644 --- a/graphql/error/print_error.py +++ b/graphql/error/print_error.py @@ -7,10 +7,10 @@ from ..language import Source, SourceLocation # noqa: F401 -__all__ = ['print_error'] +__all__ = ["print_error"] -def print_error(error: 'GraphQLError') -> str: +def print_error(error: "GraphQLError") -> str: """Print a GraphQLError to a string. The printed string will contain useful location information about the @@ -21,30 +21,31 @@ def print_error(error: 'GraphQLError') -> str: if error.nodes: for node in error.nodes: if node.loc: - print_location(highlight_source_at_location( - node.loc.source, - node.loc.source.get_location(node.loc.start))) + print_location( + highlight_source_at_location( + node.loc.source, node.loc.source.get_location(node.loc.start) + ) + ) elif error.source and error.locations: source = error.source for location in error.locations: print_location(highlight_source_at_location(source, location)) if printed_locations: - return '\n\n'.join([error.message] + printed_locations) + '\n' + return "\n\n".join([error.message] + printed_locations) + "\n" return error.message -_re_newline = re.compile(r'\r\n|[\n\r]') +_re_newline = re.compile(r"\r\n|[\n\r]") -def highlight_source_at_location( - source: 'Source', location: 'SourceLocation') -> str: +def highlight_source_at_location(source: "Source", location: "SourceLocation") -> str: """Highlight source at given location. This renders a helpful description of the location of the error in the GraphQL Source document. """ first_line_column_offset = source.location_offset.column - 1 - body = ' ' * first_line_column_offset + source.body + body = " " * first_line_column_offset + source.body line_index = location.line - 1 line_offset = source.location_offset.line - 1 @@ -59,20 +60,22 @@ def highlight_source_at_location( def get_line(index: int) -> Optional[str]: return lines[index] if 0 <= index < len_lines else None - return ( - f'{source.name} ({line_num}:{column_num})\n' + - print_prefixed_lines([ - (f'{line_num - 1}: ', get_line(line_index - 1)), - (f'{line_num}: ', get_line(line_index)), - ('', ' ' * (column_num - 1) + '^'), - (f'{line_num + 1}: ', get_line(line_index + 1))])) + return f"{source.name} ({line_num}:{column_num})\n" + print_prefixed_lines( + [ + (f"{line_num - 1}: ", get_line(line_index - 1)), + (f"{line_num}: ", get_line(line_index)), + ("", " " * (column_num - 1) + "^"), + (f"{line_num + 1}: ", get_line(line_index + 1)), + ] + ) def print_prefixed_lines(lines: List[Tuple[str, Optional[str]]]) -> str: """Print lines specified like this: ["prefix", "string"]""" existing_lines = [line for line in lines if line[1] is not None] - pad_len = reduce( - lambda pad, line: max(pad, len(line[0])), existing_lines, 0) - return '\n'.join(map( - lambda line: line[0].rjust(pad_len) + line[1], # type:ignore - existing_lines)) + pad_len = reduce(lambda pad, line: max(pad, len(line[0])), existing_lines, 0) + return "\n".join( + map( + lambda line: line[0].rjust(pad_len) + line[1], existing_lines # type:ignore + ) + ) diff --git a/graphql/error/syntax_error.py b/graphql/error/syntax_error.py index acac11a4..50479c87 100644 --- a/graphql/error/syntax_error.py +++ b/graphql/error/syntax_error.py @@ -1,12 +1,13 @@ from .graphql_error import GraphQLError -__all__ = ['GraphQLSyntaxError'] +__all__ = ["GraphQLSyntaxError"] class GraphQLSyntaxError(GraphQLError): """A GraphQLError representing a syntax error.""" def __init__(self, source, position, description): - super().__init__(f'Syntax Error: {description}', - source=source, positions=[position]) + super().__init__( + f"Syntax Error: {description}", source=source, positions=[position] + ) self.description = description diff --git a/graphql/execution/__init__.py b/graphql/execution/__init__.py index c6f55b12..09496689 100644 --- a/graphql/execution/__init__.py +++ b/graphql/execution/__init__.py @@ -5,13 +5,23 @@ """ from .execute import ( - execute, default_field_resolver, response_path_as_list, - ExecutionContext, ExecutionResult, Middleware) + execute, + default_field_resolver, + response_path_as_list, + ExecutionContext, + ExecutionResult, + Middleware, +) from .middleware import MiddlewareManager from .values import get_directive_values __all__ = [ - 'execute', 'default_field_resolver', 'response_path_as_list', - 'ExecutionContext', 'ExecutionResult', - 'Middleware', 'MiddlewareManager', - 'get_directive_values'] + "execute", + "default_field_resolver", + "response_path_as_list", + "ExecutionContext", + "ExecutionResult", + "Middleware", + "MiddlewareManager", + "get_directive_values", +] diff --git a/graphql/execution/execute.py b/graphql/execution/execute.py index 11881a84..f60b00e3 100644 --- a/graphql/execution/execute.py +++ b/graphql/execution/execute.py @@ -1,31 +1,70 @@ from inspect import isawaitable from typing import ( - Any, Awaitable, Dict, Iterable, List, NamedTuple, Optional, Set, Union, - Tuple, Type, cast) + Any, + Awaitable, + Dict, + Iterable, + List, + NamedTuple, + Optional, + Set, + Union, + Tuple, + Type, + cast, +) from ..error import GraphQLError, INVALID, located_error from ..language import ( - DocumentNode, FieldNode, FragmentDefinitionNode, - FragmentSpreadNode, InlineFragmentNode, OperationDefinitionNode, - OperationType, SelectionSetNode) + DocumentNode, + FieldNode, + FragmentDefinitionNode, + FragmentSpreadNode, + InlineFragmentNode, + OperationDefinitionNode, + OperationType, + SelectionSetNode, +) from .middleware import MiddlewareManager from ..pyutils import is_invalid, is_nullish, MaybeAwaitable from ..utilities import get_operation_root_type, type_from_ast from ..type import ( - GraphQLAbstractType, GraphQLField, GraphQLIncludeDirective, - GraphQLLeafType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLOutputType, GraphQLSchema, GraphQLSkipDirective, - GraphQLFieldResolver, GraphQLResolveInfo, ResponsePath, - SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, - assert_valid_schema, is_abstract_type, is_leaf_type, is_list_type, - is_non_null_type, is_object_type) -from .values import ( - get_argument_values, get_directive_values, get_variable_values) + GraphQLAbstractType, + GraphQLField, + GraphQLIncludeDirective, + GraphQLLeafType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLOutputType, + GraphQLSchema, + GraphQLSkipDirective, + GraphQLFieldResolver, + GraphQLResolveInfo, + ResponsePath, + SchemaMetaFieldDef, + TypeMetaFieldDef, + TypeNameMetaFieldDef, + assert_valid_schema, + is_abstract_type, + is_leaf_type, + is_list_type, + is_non_null_type, + is_object_type, +) +from .values import get_argument_values, get_directive_values, get_variable_values __all__ = [ - 'add_path', 'assert_valid_execution_arguments', 'default_field_resolver', - 'execute', 'get_field_def', 'response_path_as_list', - 'ExecutionResult', 'ExecutionContext', 'Middleware'] + "add_path", + "assert_valid_execution_arguments", + "default_field_resolver", + "execute", + "get_field_def", + "response_path_as_list", + "ExecutionResult", + "ExecutionContext", + "Middleware", +] # Terminology @@ -64,14 +103,16 @@ class ExecutionResult(NamedTuple): def execute( - schema: GraphQLSchema, document: DocumentNode, - root_value: Any=None, context_value: Any=None, - variable_values: Dict[str, Any]=None, - operation_name: str=None, - field_resolver: GraphQLFieldResolver=None, - execution_context_class: Type[ExecutionContext]=ExecutionContext, - middleware: Middleware=None - ) -> MaybeAwaitable[ExecutionResult]: + schema: GraphQLSchema, + document: DocumentNode, + root_value: Any = None, + context_value: Any = None, + variable_values: Dict[str, Any] = None, + operation_name: str = None, + field_resolver: GraphQLFieldResolver = None, + middleware: Middleware = None, + execution_context_class: Type["ExecutionContext"] = None, +) -> MaybeAwaitable[ExecutionResult]: """Execute a GraphQL operation. Implements the "Evaluating requests" section of the GraphQL specification. @@ -86,11 +127,21 @@ def execute( # If arguments are missing or incorrect, throw an error. assert_valid_execution_arguments(schema, document, variable_values) + if execution_context_class is None: + execution_context_class = ExecutionContext + # If a valid execution context cannot be created due to incorrect # arguments, a "Response" with only errors is returned. exe_context = execution_context_class.build( - schema, document, root_value, context_value, - variable_values, operation_name, field_resolver, middleware) + schema, + document, + root_value, + context_value, + variable_values, + operation_name, + field_resolver, + middleware, + ) # Return early errors if execution context failed. if isinstance(exe_context, list): @@ -126,14 +177,17 @@ class ExecutionContext: errors: List[GraphQLError] def __init__( - self, schema: GraphQLSchema, - fragments: Dict[str, FragmentDefinitionNode], - root_value: Any, context_value: Any, - operation: OperationDefinitionNode, - variable_values: Dict[str, Any], - field_resolver: GraphQLFieldResolver, - middleware_manager: Optional[MiddlewareManager], - errors: List[GraphQLError]) -> None: + self, + schema: GraphQLSchema, + fragments: Dict[str, FragmentDefinitionNode], + root_value: Any, + context_value: Any, + operation: OperationDefinitionNode, + variable_values: Dict[str, Any], + field_resolver: GraphQLFieldResolver, + middleware_manager: Optional[MiddlewareManager], + errors: List[GraphQLError], + ) -> None: self.schema = schema self.fragments = fragments self.root_value = root_value @@ -144,18 +198,21 @@ def __init__( self.middleware_manager = middleware_manager self.errors = errors self._subfields_cache: Dict[ - Tuple[GraphQLObjectType, Tuple[FieldNode, ...]], - Dict[str, List[FieldNode]]] = {} + Tuple[GraphQLObjectType, Tuple[FieldNode, ...]], Dict[str, List[FieldNode]] + ] = {} @classmethod def build( - cls, schema: GraphQLSchema, document: DocumentNode, - root_value: Any=None, context_value: Any=None, - raw_variable_values: Dict[str, Any]=None, - operation_name: str=None, - field_resolver: GraphQLFieldResolver=None, - middleware: Middleware=None - ) -> Union[List[GraphQLError], 'ExecutionContext']: + cls, + schema: GraphQLSchema, + document: DocumentNode, + root_value: Any = None, + context_value: Any = None, + raw_variable_values: Dict[str, Any] = None, + operation_name: str = None, + field_resolver: GraphQLFieldResolver = None, + middleware: Middleware = None, + ) -> Union[List[GraphQLError], "ExecutionContext"]: """Build an execution context Constructs a ExecutionContext object from the arguments passed to @@ -177,36 +234,40 @@ def build( raise TypeError( "Middleware must be passed as a list or tuple of functions" " or objects, or as a single MiddlewareManager object." - f" Got {middleware!r} instead.") + f" Got {middleware!r} instead." + ) for definition in document.definitions: if isinstance(definition, OperationDefinitionNode): if not operation_name and operation: has_multiple_assumed_operations = True - elif (not operation_name or ( - definition.name and - definition.name.value == operation_name)): + elif not operation_name or ( + definition.name and definition.name.value == operation_name + ): operation = definition elif isinstance(definition, FragmentDefinitionNode): fragments[definition.name.value] = definition if not operation: if operation_name: - errors.append(GraphQLError( - f"Unknown operation named '{operation_name}'.")) + errors.append( + GraphQLError(f"Unknown operation named '{operation_name}'.") + ) else: - errors.append(GraphQLError('Must provide an operation.')) + errors.append(GraphQLError("Must provide an operation.")) elif has_multiple_assumed_operations: - errors.append(GraphQLError( - 'Must provide operation name' - ' if query contains multiple operations.')) + errors.append( + GraphQLError( + "Must provide operation name" + " if query contains multiple operations." + ) + ) variable_values = None if operation: coerced_variable_values = get_variable_values( - schema, - operation.variable_definitions or [], - raw_variable_values or {}) + schema, operation.variable_definitions or [], raw_variable_values or {} + ) if coerced_variable_values.errors: errors.extend(coerced_variable_values.errors) @@ -217,14 +278,21 @@ def build( return errors if operation is None: - raise TypeError('Has operation if no errors.') + raise TypeError("Has operation if no errors.") if variable_values is None: - raise TypeError('Has variables if no errors.') + raise TypeError("Has variables if no errors.") return cls( - schema, fragments, root_value, context_value, operation, - variable_values, field_resolver or default_field_resolver, - middleware_manager, errors) + schema, + fragments, + root_value, + context_value, + operation, + variable_values, + field_resolver or default_field_resolver, + middleware_manager, + errors, + ) def build_response( self, data: MaybeAwaitable[Optional[Dict[str, Any]]] @@ -235,15 +303,17 @@ def build_response( response defined by the "Response" section of the GraphQL spec. """ if isawaitable(data): + async def build_response_async(): return self.build_response(await data) + return build_response_async() data = cast(Optional[Dict[str, Any]], data) return ExecutionResult(data=data, errors=self.errors or None) def execute_operation( - self, operation: OperationDefinitionNode, - root_value: Any) -> Optional[MaybeAwaitable[Any]]: + self, operation: OperationDefinitionNode, root_value: Any + ) -> Optional[MaybeAwaitable[Any]]: """Execute an operation. Implements the "Evaluating operations" section of the spec. @@ -259,10 +329,11 @@ def execute_operation( # # Similar to complete_value_catching_error. try: - result = (self.execute_fields_serially - if operation.operation == OperationType.MUTATION - else self.execute_fields - )(type_, root_value, path, fields) + result = ( + self.execute_fields_serially + if operation.operation == OperationType.MUTATION + else self.execute_fields + )(type_, root_value, path, fields) except GraphQLError as error: self.errors.append(error) return None @@ -281,13 +352,17 @@ async def await_result(): except Exception as error: error = GraphQLError(str(error), original_error=error) self.errors.append(error) + return await_result() return result def execute_fields_serially( - self, parent_type: GraphQLObjectType, source_value: Any, - path: Optional[ResponsePath], fields: Dict[str, List[FieldNode]] - ) -> MaybeAwaitable[Dict[str, Any]]: + self, + parent_type: GraphQLObjectType, + source_value: Any, + path: Optional[ResponsePath], + fields: Dict[str, List[FieldNode]], + ) -> MaybeAwaitable[Dict[str, Any]]: """Execute the given fields serially. Implements the "Evaluating selection sets" section of the spec @@ -297,7 +372,8 @@ def execute_fields_serially( for response_name, field_nodes in fields.items(): field_path = add_path(path, response_name) result = self.resolve_field( - parent_type, source_value, field_nodes, field_path) + parent_type, source_value, field_nodes, field_path + ) if result is INVALID: continue if isawaitable(results): @@ -305,16 +381,19 @@ def execute_fields_serially( async def await_and_set_result(results, response_name, result): awaited_results = await results awaited_results[response_name] = ( - await result if isawaitable(result) - else result) + await result if isawaitable(result) else result + ) return awaited_results + results = await_and_set_result( - cast(Awaitable, results), response_name, result) + cast(Awaitable, results), response_name, result + ) elif isawaitable(result): # noinspection PyShadowingNames async def set_result(results, response_name, result): results[response_name] = await result return results + results = set_result(results, response_name, result) else: results[response_name] = result @@ -322,14 +401,17 @@ async def set_result(results, response_name, result): # noinspection PyShadowingNames async def get_results(): return await cast(Awaitable, results) + return get_results() return results def execute_fields( - self, parent_type: GraphQLObjectType, - source_value: Any, path: Optional[ResponsePath], - fields: Dict[str, List[FieldNode]] - ) -> MaybeAwaitable[Dict[str, Any]]: + self, + parent_type: GraphQLObjectType, + source_value: Any, + path: Optional[ResponsePath], + fields: Dict[str, List[FieldNode]], + ) -> MaybeAwaitable[Dict[str, Any]]: """Execute the given fields concurrently. Implements the "Evaluating selection sets" section of the spec @@ -341,7 +423,8 @@ def execute_fields( for response_name, field_nodes in fields.items(): field_path = add_path(path, response_name) result = self.resolve_field( - parent_type, source_value, field_nodes, field_path) + parent_type, source_value, field_nodes, field_path + ) if result is not INVALID: results[response_name] = result if not is_async and isawaitable(result): @@ -356,15 +439,20 @@ def execute_fields( # Return a coroutine object that will yield this same map, but with # any coroutines awaited and replaced with the values they yielded. async def get_results(): - return {key: await value if isawaitable(value) else value - for key, value in results.items()} + return { + key: await value if isawaitable(value) else value + for key, value in results.items() + } + return get_results() def collect_fields( - self, runtime_type: GraphQLObjectType, - selection_set: SelectionSetNode, - fields: Dict[str, List[FieldNode]], - visited_fragment_names: Set[str]) -> Dict[str, List[FieldNode]]: + self, + runtime_type: GraphQLObjectType, + selection_set: SelectionSetNode, + fields: Dict[str, List[FieldNode]], + visited_fragment_names: Set[str], + ) -> Dict[str, List[FieldNode]]: """Collect fields. Given a selection_set, adds all of the fields in that selection to @@ -381,52 +469,58 @@ def collect_fields( name = get_field_entry_key(selection) fields.setdefault(name, []).append(selection) elif isinstance(selection, InlineFragmentNode): - if (not self.should_include_node(selection) or - not self.does_fragment_condition_match( - selection, runtime_type)): + if not self.should_include_node( + selection + ) or not self.does_fragment_condition_match(selection, runtime_type): continue self.collect_fields( - runtime_type, selection.selection_set, - fields, visited_fragment_names) + runtime_type, + selection.selection_set, + fields, + visited_fragment_names, + ) elif isinstance(selection, FragmentSpreadNode): frag_name = selection.name.value - if (frag_name in visited_fragment_names or - not self.should_include_node(selection)): + if frag_name in visited_fragment_names or not self.should_include_node( + selection + ): continue visited_fragment_names.add(frag_name) fragment = self.fragments.get(frag_name) - if (not fragment or - not self.does_fragment_condition_match( - fragment, runtime_type)): + if not fragment or not self.does_fragment_condition_match( + fragment, runtime_type + ): continue self.collect_fields( - runtime_type, fragment.selection_set, - fields, visited_fragment_names) + runtime_type, fragment.selection_set, fields, visited_fragment_names + ) return fields def should_include_node( - self, node: Union[ - FragmentSpreadNode, FieldNode, InlineFragmentNode]) -> bool: + self, node: Union[FragmentSpreadNode, FieldNode, InlineFragmentNode] + ) -> bool: """Check if node should be included Determines if a field should be included based on the @include and @skip directives, where @skip has higher precedence than @include. """ - skip = get_directive_values( - GraphQLSkipDirective, node, self.variable_values) - if skip and skip['if']: + skip = get_directive_values(GraphQLSkipDirective, node, self.variable_values) + if skip and skip["if"]: return False include = get_directive_values( - GraphQLIncludeDirective, node, self.variable_values) - if include and not include['if']: + GraphQLIncludeDirective, node, self.variable_values + ) + if include and not include["if"]: return False return True def does_fragment_condition_match( - self, fragment: Union[FragmentDefinitionNode, InlineFragmentNode], - type_: GraphQLObjectType) -> bool: + self, + fragment: Union[FragmentDefinitionNode, InlineFragmentNode], + type_: GraphQLObjectType, + ) -> bool: """Determine if a fragment is applicable to the given type.""" type_condition_node = fragment.type_condition if not type_condition_node: @@ -436,24 +530,40 @@ def does_fragment_condition_match( return True if is_abstract_type(conditional_type): return self.schema.is_possible_type( - cast(GraphQLAbstractType, conditional_type), type_) + cast(GraphQLAbstractType, conditional_type), type_ + ) return False def build_resolve_info( - self, field_def: GraphQLField, field_nodes: List[FieldNode], - parent_type: GraphQLObjectType, path: ResponsePath - ) -> GraphQLResolveInfo: + self, + field_def: GraphQLField, + field_nodes: List[FieldNode], + parent_type: GraphQLObjectType, + path: ResponsePath, + ) -> GraphQLResolveInfo: # The resolve function's first argument is a collection of # information about the current execution state. return GraphQLResolveInfo( - field_nodes[0].name.value, field_nodes, field_def.type, - parent_type, path, self.schema, self.fragments, self.root_value, - self.operation, self.variable_values, self.context_value) + field_nodes[0].name.value, + field_nodes, + field_def.type, + parent_type, + path, + self.schema, + self.fragments, + self.root_value, + self.operation, + self.variable_values, + self.context_value, + ) def resolve_field( - self, parent_type: GraphQLObjectType, source: Any, - field_nodes: List[FieldNode], path: ResponsePath - ) -> MaybeAwaitable[Any]: + self, + parent_type: GraphQLObjectType, + source: Any, + field_nodes: List[FieldNode], + path: ResponsePath, + ) -> MaybeAwaitable[Any]: """Resolve the field on the given source object. In particular, this figures out the value that the field returns @@ -473,26 +583,30 @@ def resolve_field( if self.middleware_manager: resolve_fn = self.middleware_manager.get_field_resolver(resolve_fn) - info = self.build_resolve_info( - field_def, field_nodes, parent_type, path) + info = self.build_resolve_info(field_def, field_nodes, parent_type, path) # Get the resolve function, regardless of if its result is normal # or abrupt (error). result = self.resolve_field_value_or_error( - field_def, field_nodes, resolve_fn, source, info) + field_def, field_nodes, resolve_fn, source, info + ) return self.complete_value_catching_error( - field_def.type, field_nodes, info, path, result) + field_def.type, field_nodes, info, path, result + ) def resolve_field_value_or_error( - self, field_def: GraphQLField, field_nodes: List[FieldNode], - resolve_fn: GraphQLFieldResolver, source: Any, - info: GraphQLResolveInfo) -> Union[Exception, Any]: + self, + field_def: GraphQLField, + field_nodes: List[FieldNode], + resolve_fn: GraphQLFieldResolver, + source: Any, + info: GraphQLResolveInfo, + ) -> Union[Exception, Any]: try: # Build a dictionary of arguments from the field.arguments AST, # using the variables scope to fulfill any variable references. - args = get_argument_values( - field_def, field_nodes[0], self.variable_values) + args = get_argument_values(field_def, field_nodes[0], self.variable_values) # Note that contrary to the JavaScript implementation, # we pass the context value as part of the resolve info. @@ -505,8 +619,8 @@ async def await_result(): except GraphQLError as error: return error except Exception as error: - return GraphQLError( - str(error), original_error=error) + return GraphQLError(str(error), original_error=error) + return await_result() return result except GraphQLError as error: @@ -515,9 +629,13 @@ async def await_result(): return GraphQLError(str(error), original_error=error) def complete_value_catching_error( - self, return_type: GraphQLOutputType, field_nodes: List[FieldNode], - info: GraphQLResolveInfo, path: ResponsePath, result: Any - ) -> MaybeAwaitable[Any]: + self, + return_type: GraphQLOutputType, + field_nodes: List[FieldNode], + info: GraphQLResolveInfo, + path: ResponsePath, + result: Any, + ) -> MaybeAwaitable[Any]: """Complete a value while catching an error. This is a small wrapper around completeValue which detects and logs @@ -525,38 +643,44 @@ def complete_value_catching_error( """ try: if isawaitable(result): + async def await_result(): value = self.complete_value( - return_type, field_nodes, info, path, await result) + return_type, field_nodes, info, path, await result + ) if isawaitable(value): return await value return value + completed = await_result() else: completed = self.complete_value( - return_type, field_nodes, info, path, result) + return_type, field_nodes, info, path, result + ) if isawaitable(completed): # noinspection PyShadowingNames async def await_completed(): try: return await completed except Exception as error: - self.handle_field_error( - error, field_nodes, path, return_type) + self.handle_field_error(error, field_nodes, path, return_type) + return await_completed() return completed except Exception as error: - self.handle_field_error( - error, field_nodes, path, return_type) + self.handle_field_error(error, field_nodes, path, return_type) return None def handle_field_error( - self, raw_error: Exception, field_nodes: List[FieldNode], - path: ResponsePath, return_type: GraphQLOutputType) -> None: + self, + raw_error: Exception, + field_nodes: List[FieldNode], + path: ResponsePath, + return_type: GraphQLOutputType, + ) -> None: if not isinstance(raw_error, GraphQLError): raw_error = GraphQLError(str(raw_error), original_error=raw_error) - error = located_error( - raw_error, field_nodes, response_path_as_list(path)) + error = located_error(raw_error, field_nodes, response_path_as_list(path)) # If the field type is non-nullable, then it is resolved without any # protection from errors, however it still properly locates the error. @@ -568,9 +692,13 @@ def handle_field_error( return None def complete_value( - self, return_type: GraphQLOutputType, field_nodes: List[FieldNode], - info: GraphQLResolveInfo, path: ResponsePath, result: Any - ) -> MaybeAwaitable[Any]: + self, + return_type: GraphQLOutputType, + field_nodes: List[FieldNode], + info: GraphQLResolveInfo, + path: ResponsePath, + result: Any, + ) -> MaybeAwaitable[Any]: """Complete a value. Implements the instructions for completeValue as defined in the @@ -602,11 +730,16 @@ def complete_value( if is_non_null_type(return_type): completed = self.complete_value( cast(GraphQLNonNull, return_type).of_type, - field_nodes, info, path, result) + field_nodes, + info, + path, + result, + ) if completed is None: raise TypeError( - 'Cannot return null for non-nullable field' - f' {info.parent_type.name}.{info.field_name}.') + "Cannot return null for non-nullable field" + f" {info.parent_type.name}.{info.field_name}." + ) return completed # If result value is null-ish (null, INVALID, or NaN) then return null. @@ -616,37 +749,38 @@ def complete_value( # If field type is List, complete each item in the list with inner type if is_list_type(return_type): return self.complete_list_value( - cast(GraphQLList, return_type), - field_nodes, info, path, result) + cast(GraphQLList, return_type), field_nodes, info, path, result + ) # If field type is a leaf type, Scalar or Enum, serialize to a valid # value, returning null if serialization is not possible. if is_leaf_type(return_type): - return self.complete_leaf_value( - cast(GraphQLLeafType, return_type), result) + return self.complete_leaf_value(cast(GraphQLLeafType, return_type), result) # If field type is an abstract type, Interface or Union, determine the # runtime Object type and complete for that type. if is_abstract_type(return_type): return self.complete_abstract_value( - cast(GraphQLAbstractType, return_type), - field_nodes, info, path, result) + cast(GraphQLAbstractType, return_type), field_nodes, info, path, result + ) # If field type is Object, execute and complete all sub-selections. if is_object_type(return_type): return self.complete_object_value( - cast(GraphQLObjectType, return_type), - field_nodes, info, path, result) + cast(GraphQLObjectType, return_type), field_nodes, info, path, result + ) # Not reachable. All possible output types have been considered. - raise TypeError( - f'Cannot complete value of unexpected type {return_type}.') + raise TypeError(f"Cannot complete value of unexpected type {return_type}.") def complete_list_value( - self, return_type: GraphQLList[GraphQLOutputType], - field_nodes: List[FieldNode], info: GraphQLResolveInfo, - path: ResponsePath, result: Iterable[Any] - ) -> MaybeAwaitable[Any]: + self, + return_type: GraphQLList[GraphQLOutputType], + field_nodes: List[FieldNode], + info: GraphQLResolveInfo, + path: ResponsePath, + result: Iterable[Any], + ) -> MaybeAwaitable[Any]: """Complete a list value. Complete a list value by completing each item in the list with the @@ -654,8 +788,9 @@ def complete_list_value( """ if not isinstance(result, Iterable) or isinstance(result, str): raise TypeError( - 'Expected Iterable, but did not find one for field' - f' {info.parent_type.name}.{info.field_name}.') + "Expected Iterable, but did not find one for field" + f" {info.parent_type.name}.{info.field_name}." + ) # This is specified as a simple map, however we're optimizing the path # where the list contains no coroutine objects by avoiding creating @@ -669,23 +804,26 @@ def complete_list_value( # since from here on it is not ever accessed by resolver functions. field_path = add_path(path, index) completed_item = self.complete_value_catching_error( - item_type, field_nodes, info, field_path, item) + item_type, field_nodes, info, field_path, item + ) if not is_async and isawaitable(completed_item): is_async = True append(completed_item) if is_async: + async def get_completed_results(): - return [await value if isawaitable(value) else value - for value in completed_results] + return [ + await value if isawaitable(value) else value + for value in completed_results + ] + return get_completed_results() return completed_results @staticmethod - def complete_leaf_value( - return_type: GraphQLLeafType, - result: Any) -> Any: + def complete_leaf_value(return_type: GraphQLLeafType, result: Any) -> Any: """Complete a leaf value. Complete a Scalar or Enum by serializing to a valid value, returning @@ -694,76 +832,103 @@ def complete_leaf_value( serialized_result = return_type.serialize(result) if is_invalid(serialized_result): raise TypeError( - f"Expected a value of type '{return_type}'" - f' but received: {result!r}') + f"Expected a value of type '{return_type}'" f" but received: {result!r}" + ) return serialized_result def complete_abstract_value( - self, return_type: GraphQLAbstractType, - field_nodes: List[FieldNode], info: GraphQLResolveInfo, - path: ResponsePath, result: Any - ) -> MaybeAwaitable[Any]: + self, + return_type: GraphQLAbstractType, + field_nodes: List[FieldNode], + info: GraphQLResolveInfo, + path: ResponsePath, + result: Any, + ) -> MaybeAwaitable[Any]: """Complete an abstract value. Complete a value of an abstract type by determining the runtime object type of that value, then complete the value for that type. """ resolve_type = return_type.resolve_type - runtime_type = resolve_type( - result, info) if resolve_type else default_resolve_type_fn( - result, info, return_type) + runtime_type = ( + resolve_type(result, info) + if resolve_type + else default_resolve_type_fn(result, info, return_type) + ) if isawaitable(runtime_type): + async def await_complete_object_value(): value = self.complete_object_value( self.ensure_valid_runtime_type( - await runtime_type, return_type, - field_nodes, info, result), - field_nodes, info, path, result) + await runtime_type, return_type, field_nodes, info, result + ), + field_nodes, + info, + path, + result, + ) if isawaitable(value): return await value return value + return await_complete_object_value() - runtime_type = cast( - Optional[Union[GraphQLObjectType, str]], runtime_type) + runtime_type = cast(Optional[Union[GraphQLObjectType, str]], runtime_type) return self.complete_object_value( self.ensure_valid_runtime_type( - runtime_type, return_type, - field_nodes, info, result), - field_nodes, info, path, result) + runtime_type, return_type, field_nodes, info, result + ), + field_nodes, + info, + path, + result, + ) def ensure_valid_runtime_type( - self, runtime_type_or_name: Optional[ - Union[GraphQLObjectType, str]], - return_type: GraphQLAbstractType, field_nodes: List[FieldNode], - info: GraphQLResolveInfo, result: Any) -> GraphQLObjectType: - runtime_type = self.schema.get_type( - runtime_type_or_name) if isinstance( - runtime_type_or_name, str) else runtime_type_or_name + self, + runtime_type_or_name: Optional[Union[GraphQLObjectType, str]], + return_type: GraphQLAbstractType, + field_nodes: List[FieldNode], + info: GraphQLResolveInfo, + result: Any, + ) -> GraphQLObjectType: + runtime_type = ( + self.schema.get_type(runtime_type_or_name) + if isinstance(runtime_type_or_name, str) + else runtime_type_or_name + ) if not is_object_type(runtime_type): raise GraphQLError( - f'Abstract type {return_type.name} must resolve' - ' to an Object type at runtime' - f' for field {info.parent_type.name}.{info.field_name}' + f"Abstract type {return_type.name} must resolve" + " to an Object type at runtime" + f" for field {info.parent_type.name}.{info.field_name}" f" with value {result!r}, received '{runtime_type}'." - f' Either the {return_type.name} type should provide' + f" Either the {return_type.name} type should provide" ' a "resolve_type" function or each possible type should' - ' provide an "is_type_of" function.', field_nodes) + ' provide an "is_type_of" function.', + field_nodes, + ) runtime_type = cast(GraphQLObjectType, runtime_type) if not self.schema.is_possible_type(return_type, runtime_type): raise GraphQLError( f"Runtime Object type '{runtime_type.name}' is not a possible" - f" type for '{return_type.name}'.", field_nodes) + f" type for '{return_type.name}'.", + field_nodes, + ) return runtime_type def complete_object_value( - self, return_type: GraphQLObjectType, field_nodes: List[FieldNode], - info: GraphQLResolveInfo, path: ResponsePath, result: Any - ) -> MaybeAwaitable[Dict[str, Any]]: + self, + return_type: GraphQLObjectType, + field_nodes: List[FieldNode], + info: GraphQLResolveInfo, + path: ResponsePath, + result: Any, + ) -> MaybeAwaitable[Dict[str, Any]]: """Complete an Object value by executing all sub-selections.""" # If there is an is_type_of predicate function, call it with the # current result. If is_type_of returns false, then raise an error @@ -772,32 +937,39 @@ def complete_object_value( is_type_of = return_type.is_type_of(result, info) if isawaitable(is_type_of): + async def collect_and_execute_subfields_async(): if not await is_type_of: raise invalid_return_type_error( - return_type, result, field_nodes) + return_type, result, field_nodes + ) return self.collect_and_execute_subfields( - return_type, field_nodes, path, result) + return_type, field_nodes, path, result + ) + return collect_and_execute_subfields_async() if not is_type_of: - raise invalid_return_type_error( - return_type, result, field_nodes) + raise invalid_return_type_error(return_type, result, field_nodes) return self.collect_and_execute_subfields( - return_type, field_nodes, path, result) + return_type, field_nodes, path, result + ) def collect_and_execute_subfields( - self, return_type: GraphQLObjectType, - field_nodes: List[FieldNode], path: ResponsePath, - result: Any) -> MaybeAwaitable[Dict[str, Any]]: + self, + return_type: GraphQLObjectType, + field_nodes: List[FieldNode], + path: ResponsePath, + result: Any, + ) -> MaybeAwaitable[Dict[str, Any]]: """Collect sub-fields to execute to complete this value.""" sub_field_nodes = self.collect_subfields(return_type, field_nodes) return self.execute_fields(return_type, result, path, sub_field_nodes) def collect_subfields( - self, return_type: GraphQLObjectType, - field_nodes: List[FieldNode]) -> Dict[str, List[FieldNode]]: + self, return_type: GraphQLObjectType, field_nodes: List[FieldNode] + ) -> Dict[str, List[FieldNode]]: """Collect subfields. # A cached collection of relevant subfields with regard to the @@ -814,33 +986,38 @@ def collect_subfields( selection_set = field_node.selection_set if selection_set: sub_field_nodes = self.collect_fields( - return_type, selection_set, - sub_field_nodes, visited_fragment_names) + return_type, + selection_set, + sub_field_nodes, + visited_fragment_names, + ) self._subfields_cache[cache_key] = sub_field_nodes return sub_field_nodes def assert_valid_execution_arguments( - schema: GraphQLSchema, document: DocumentNode, - raw_variable_values: Dict[str, Any]=None) -> None: + schema: GraphQLSchema, + document: DocumentNode, + raw_variable_values: Dict[str, Any] = None, +) -> None: """Check that the arguments are acceptable. Essential assertions before executing to provide developer feedback for improper use of the GraphQL library. """ if not document: - raise TypeError('Must provide document') + raise TypeError("Must provide document") # If the schema used for execution is invalid, throw an error. assert_valid_schema(schema) # Variables, if provided, must be a dictionary. - if not (raw_variable_values is None or - isinstance(raw_variable_values, dict)): + if not (raw_variable_values is None or isinstance(raw_variable_values, dict)): raise TypeError( - 'Variables must be provided as a dictionary where each property is' - ' a variable value. Perhaps look to see if an unparsed JSON string' - ' was provided.') + "Variables must be provided as a dictionary where each property is" + " a variable value. Perhaps look to see if an unparsed JSON string" + " was provided." + ) def response_path_as_list(path: ResponsePath) -> List[Union[str, int]]: @@ -858,8 +1035,7 @@ def response_path_as_list(path: ResponsePath) -> List[Union[str, int]]: return flattened[::-1] -def add_path( - prev: Optional[ResponsePath], key: Union[str, int]) -> ResponsePath: +def add_path(prev: Optional[ResponsePath], key: Union[str, int]) -> ResponsePath: """Add a key to a response path. Given a ResponsePath and a key, return a new ResponsePath containing the @@ -869,9 +1045,8 @@ def add_path( def get_field_def( - schema: GraphQLSchema, - parent_type: GraphQLObjectType, - field_name: str) -> GraphQLField: + schema: GraphQLSchema, parent_type: GraphQLObjectType, field_name: str +) -> GraphQLField: """Get field definition. This method looks up the field on the given type definition. @@ -882,13 +1057,11 @@ def get_field_def( added to the query type, but that would require mutating type definitions, which would cause issues. """ - if (field_name == '__schema' and - schema.query_type == parent_type): + if field_name == "__schema" and schema.query_type == parent_type: return SchemaMetaFieldDef - elif (field_name == '__type' and - schema.query_type == parent_type): + elif field_name == "__type" and schema.query_type == parent_type: return TypeMetaFieldDef - elif field_name == '__typename': + elif field_name == "__typename": return TypeNameMetaFieldDef return parent_type.fields.get(field_name) @@ -899,20 +1072,18 @@ def get_field_entry_key(node: FieldNode) -> str: def invalid_return_type_error( - return_type: GraphQLObjectType, - result: Any, - field_nodes: List[FieldNode]) -> GraphQLError: + return_type: GraphQLObjectType, result: Any, field_nodes: List[FieldNode] +) -> GraphQLError: """Create a GraphQLError for an invalid return type.""" return GraphQLError( - f"Expected value of type '{return_type.name}'" - f' but got: {result!r}.', field_nodes) + f"Expected value of type '{return_type.name}'" f" but got: {result!r}.", + field_nodes, + ) def default_resolve_type_fn( - value: Any, - info: GraphQLResolveInfo, - abstract_type: GraphQLAbstractType - ) -> MaybeAwaitable[Optional[Union[GraphQLObjectType, str]]]: + value: Any, info: GraphQLResolveInfo, abstract_type: GraphQLAbstractType +) -> MaybeAwaitable[Optional[Union[GraphQLObjectType, str]]]: """Default type resolver function. If a resolveType function is not given, then a default resolve behavior is @@ -927,8 +1098,8 @@ def default_resolve_type_fn( """ # First, look for `__typename`. - if isinstance(value, dict) and isinstance(value.get('__typename'), str): - return value['__typename'] + if isinstance(value, dict) and isinstance(value.get("__typename"), str): + return value["__typename"] # Otherwise, test each possible type. possible_types = info.schema.get_possible_types(abstract_type) @@ -948,10 +1119,12 @@ def default_resolve_type_fn( async def get_type(): is_type_of_results = [ (await is_type_of_result, type_) - for is_type_of_result, type_ in is_type_of_results_async] + for is_type_of_result, type_ in is_type_of_results_async + ] for is_type_of_result, type_ in is_type_of_results: if is_type_of_result: return type_ + return get_type() return None @@ -970,8 +1143,11 @@ def default_field_resolver(source, info, **args): """ # ensure source is a value for which property access is acceptable. field_name = info.field_name - value = source.get(field_name) if isinstance( - source, dict) else getattr(source, field_name, None) + value = ( + source.get(field_name) + if isinstance(source, dict) + else getattr(source, field_name, None) + ) if callable(value): return value(info, **args) return value diff --git a/graphql/execution/middleware.py b/graphql/execution/middleware.py index 42740cb0..6a95b65e 100644 --- a/graphql/execution/middleware.py +++ b/graphql/execution/middleware.py @@ -2,10 +2,9 @@ from inspect import isfunction from itertools import chain -from typing import ( - Callable, Iterator, Dict, Tuple, Any, Iterable, Optional, cast) +from typing import Callable, Iterator, Dict, Tuple, Any, Iterable, Optional, cast -__all__ = ['MiddlewareManager'] +__all__ = ["MiddlewareManager"] GraphQLFieldResolver = Callable[..., Any] @@ -19,20 +18,21 @@ class MiddlewareManager: a method 'resolve' that is used as the middleware function. """ - __slots__ = 'middlewares', '_middleware_resolvers', '_cached_resolvers' + __slots__ = "middlewares", "_middleware_resolvers", "_cached_resolvers" _cached_resolvers: Dict[GraphQLFieldResolver, GraphQLFieldResolver] _middleware_resolvers: Optional[Iterator[Callable]] def __init__(self, *middlewares: Any) -> None: self.middlewares = middlewares - self._middleware_resolvers = get_middleware_resolvers( - middlewares) if middlewares else None + self._middleware_resolvers = ( + get_middleware_resolvers(middlewares) if middlewares else None + ) self._cached_resolvers = {} def get_field_resolver( - self, field_resolver: GraphQLFieldResolver - ) -> GraphQLFieldResolver: + self, field_resolver: GraphQLFieldResolver + ) -> GraphQLFieldResolver: """Wrap the provided resolver with the middleware. Returns a function that chains the middleware functions with the @@ -42,25 +42,25 @@ def get_field_resolver( return field_resolver if field_resolver not in self._cached_resolvers: self._cached_resolvers[field_resolver] = middleware_chain( - field_resolver, self._middleware_resolvers) + field_resolver, self._middleware_resolvers + ) return self._cached_resolvers[field_resolver] -def get_middleware_resolvers( - middlewares: Tuple[Any, ...]) -> Iterator[Callable]: +def get_middleware_resolvers(middlewares: Tuple[Any, ...]) -> Iterator[Callable]: """Get a list of resolver functions from a list of classes or functions.""" for middleware in middlewares: if isfunction(middleware): yield middleware else: # middleware provided as object with 'resolve' method - resolver_func = getattr(middleware, 'resolve', None) + resolver_func = getattr(middleware, "resolve", None) if resolver_func is not None: yield resolver_func def middleware_chain( - func: GraphQLFieldResolver, middlewares: Iterable[Callable] - ) -> GraphQLFieldResolver: + func: GraphQLFieldResolver, middlewares: Iterable[Callable] +) -> GraphQLFieldResolver: """Chain the given function with the provided middlewares. Returns a new resolver function that is the chain of both. diff --git a/graphql/execution/values.py b/graphql/execution/values.py index ffcb0e85..e6423569 100644 --- a/graphql/execution/values.py +++ b/graphql/execution/values.py @@ -2,16 +2,30 @@ from ..error import GraphQLError, INVALID from ..language import ( - ArgumentNode, DirectiveNode, ExecutableDefinitionNode, FieldNode, - NullValueNode, SchemaDefinitionNode, SelectionNode, TypeDefinitionNode, - TypeExtensionNode, VariableDefinitionNode, VariableNode, print_ast) + ArgumentNode, + DirectiveNode, + ExecutableDefinitionNode, + FieldNode, + NullValueNode, + SchemaDefinitionNode, + SelectionNode, + TypeDefinitionNode, + TypeExtensionNode, + VariableDefinitionNode, + VariableNode, + print_ast, +) from ..type import ( - GraphQLDirective, GraphQLField, GraphQLInputType, GraphQLSchema, - is_input_type, is_non_null_type) + GraphQLDirective, + GraphQLField, + GraphQLInputType, + GraphQLSchema, + is_input_type, + is_non_null_type, +) from ..utilities import coerce_value, type_from_ast, value_from_ast -__all__ = [ - 'get_variable_values', 'get_argument_values', 'get_directive_values'] +__all__ = ["get_variable_values", "get_argument_values", "get_directive_values"] class CoercedVariableValues(NamedTuple): @@ -20,8 +34,10 @@ class CoercedVariableValues(NamedTuple): def get_variable_values( - schema: GraphQLSchema, var_def_nodes: List[VariableDefinitionNode], - inputs: Dict[str, Any]) -> CoercedVariableValues: + schema: GraphQLSchema, + var_def_nodes: List[VariableDefinitionNode], + inputs: Dict[str, Any], +) -> CoercedVariableValues: """Get coerced variable values based on provided definitions. Prepares a dict of variable values of the correct type based on the @@ -36,11 +52,14 @@ def get_variable_values( if not is_input_type(var_type): # Must use input types for variables. This should be caught during # validation, however is checked again here for safety. - errors.append(GraphQLError( - f"Variable '${var_name}' expected value of type" - f" '{print_ast(var_def_node.type)}'" - ' which cannot be used as an input type.', - [var_def_node.type])) + errors.append( + GraphQLError( + f"Variable '${var_name}' expected value of type" + f" '{print_ast(var_def_node.type)}'" + " which cannot be used as an input type.", + [var_def_node.type], + ) + ) else: var_type = cast(GraphQLInputType, var_type) has_value = var_name in inputs @@ -49,15 +68,19 @@ def get_variable_values( # If no value was provided to a variable with a default value, # use the default value coerced_values[var_name] = value_from_ast( - var_def_node.default_value, var_type) - elif (not has_value or value is None) and is_non_null_type( - var_type): - errors.append(GraphQLError( - f"Variable '${var_name}' of non-null type" - f" '{var_type}' must not be null." if has_value else - f"Variable '${var_name}' of required type" - f" '{var_type}' was not provided.", - [var_def_node])) + var_def_node.default_value, var_type + ) + elif (not has_value or value is None) and is_non_null_type(var_type): + errors.append( + GraphQLError( + f"Variable '${var_name}' of non-null type" + f" '{var_type}' must not be null." + if has_value + else f"Variable '${var_name}' of required type" + f" '{var_type}' was not provided.", + [var_def_node], + ) + ) elif has_value: if value is None: # If the explicit value `None` was provided, an entry in @@ -72,18 +95,23 @@ def get_variable_values( for error in coercion_errors: error.message = ( f"Variable '${var_name}' got invalid" - f" value {value!r}; {error.message}") + f" value {value!r}; {error.message}" + ) errors.extend(coercion_errors) else: coerced_values[var_name] = coerced.value - return (CoercedVariableValues(errors, None) if errors else - CoercedVariableValues(None, coerced_values)) + return ( + CoercedVariableValues(errors, None) + if errors + else CoercedVariableValues(None, coerced_values) + ) def get_argument_values( - type_def: Union[GraphQLField, GraphQLDirective], - node: Union[FieldNode, DirectiveNode], - variable_values: Dict[str, Any]=None) -> Dict[str, Any]: + type_def: Union[GraphQLField, GraphQLDirective], + node: Union[FieldNode, DirectiveNode], + variable_values: Dict[str, Any] = None, +) -> Dict[str, Any]: """Get coerced argument values based on provided definitions and nodes. Prepares an dict of argument values given a list of argument definitions @@ -105,8 +133,7 @@ def get_argument_values( is_null = has_value and variable_values[variable_name] is None else: has_value = argument_node is not None - is_null = has_value and isinstance( - argument_node.value, NullValueNode) + is_null = has_value and isinstance(argument_node.value, NullValueNode) if not has_value and arg_def.default_value is not INVALID: # If no argument was provided where the definition has a default # value, use the default value. @@ -117,19 +144,23 @@ def get_argument_values( if is_null: raise GraphQLError( f"Argument '{name}' of non-null type" - f" '{arg_type}' must not be null.", [argument_node.value]) - elif argument_node and isinstance( - argument_node.value, VariableNode): + f" '{arg_type}' must not be null.", + [argument_node.value], + ) + elif argument_node and isinstance(argument_node.value, VariableNode): raise GraphQLError( f"Argument '{name}' of required type" f" '{arg_type}' was provided the variable" f" '${variable_name}'" - ' which was not provided a runtime value.', - [argument_node.value]) + " which was not provided a runtime value.", + [argument_node.value], + ) else: raise GraphQLError( f"Argument '{name}' of required type '{arg_type}'" - ' was not provided.', [node]) + " was not provided.", + [node], + ) elif has_value: if isinstance(argument_node.value, NullValueNode): # If the explicit value `None` was provided, an entry in the @@ -143,8 +174,7 @@ def get_argument_values( coerced_values[name] = variable_values[variable_name] else: value_node = argument_node.value - coerced_value = value_from_ast( - value_node, arg_type, variable_values) + coerced_value = value_from_ast(value_node, arg_type, variable_values) if coerced_value is INVALID: # Note: values_of_correct_type validation should catch # this before execution. This is a runtime check to @@ -153,19 +183,26 @@ def get_argument_values( raise GraphQLError( f"Argument '{name}'" f" has invalid value {print_ast(value_node)}.", - [argument_node.value]) + [argument_node.value], + ) coerced_values[name] = coerced_value return coerced_values NodeWithDirective = Union[ - ExecutableDefinitionNode, SelectionNode, - SchemaDefinitionNode, TypeDefinitionNode, TypeExtensionNode] + ExecutableDefinitionNode, + SelectionNode, + SchemaDefinitionNode, + TypeDefinitionNode, + TypeExtensionNode, +] def get_directive_values( - directive_def: GraphQLDirective, node: NodeWithDirective, - variable_values: Dict[str, Any] = None) -> Optional[Dict[str, Any]]: + directive_def: GraphQLDirective, + node: NodeWithDirective, + variable_values: Dict[str, Any] = None, +) -> Optional[Dict[str, Any]]: """Get coerced argument values based on provided nodes. Prepares a dict of argument values given a directive definition and @@ -179,6 +216,5 @@ def get_directive_values( directive_name = directive_def.name for directive in directives: if directive.name.value == directive_name: - return get_argument_values( - directive_def, directive, variable_values) + return get_argument_values(directive_def, directive, variable_values) return None diff --git a/graphql/graphql.py b/graphql/graphql.py index cb3b6fc8..f94439e1 100644 --- a/graphql/graphql.py +++ b/graphql/graphql.py @@ -3,11 +3,10 @@ from typing import Any, Awaitable, Callable, Dict, Union, Type, cast from .error import GraphQLError -from .execution import execute, ExecutionResult, Middleware +from .execution import execute, ExecutionResult, ExecutionContext, Middleware from .language import parse, Source from .pyutils import MaybeAwaitable from .type import GraphQLSchema, validate_schema -from .execution.execute import ExecutionResult, ExecutionContext __all__ = ["graphql", "graphql_sync"] @@ -15,12 +14,12 @@ async def graphql( schema: GraphQLSchema, source: Union[str, Source], - root_value: Any=None, - context_value: Any=None, - variable_values: Dict[str, Any]=None, - operation_name: str=None, - field_resolver: Callable=None, - middleware: Middleware=None, + root_value: Any = None, + context_value: Any = None, + variable_values: Dict[str, Any] = None, + operation_name: str = None, + field_resolver: Callable = None, + middleware: Middleware = None, execution_context_class: Type[ExecutionContext] = ExecutionContext, ) -> ExecutionResult: """Execute a GraphQL operation asynchronously. @@ -86,12 +85,12 @@ async def graphql( def graphql_sync( schema: GraphQLSchema, source: Union[str, Source], - root_value: Any=None, - context_value: Any=None, - variable_values: Dict[str, Any]=None, - operation_name: str=None, - field_resolver: Callable=None, - middleware: Middleware=None, + root_value: Any = None, + context_value: Any = None, + variable_values: Dict[str, Any] = None, + operation_name: str = None, + field_resolver: Callable = None, + middleware: Middleware = None, execution_context_class: Type[ExecutionContext] = ExecutionContext, ) -> ExecutionResult: """Execute a GraphQL operation synchronously. @@ -116,8 +115,7 @@ def graphql_sync( # Assert that the execution was synchronous. if isawaitable(result): ensure_future(cast(Awaitable[ExecutionResult], result)).cancel() - raise RuntimeError( - "GraphQL execution failed to complete synchronously.") + raise RuntimeError("GraphQL execution failed to complete synchronously.") return cast(ExecutionResult, result) diff --git a/graphql/language/__init__.py b/graphql/language/__init__.py index 0cecabd2..b76c2b46 100644 --- a/graphql/language/__init__.py +++ b/graphql/language/__init__.py @@ -10,73 +10,168 @@ from .printer import print_ast from .source import Source from .visitor import ( - visit, Visitor, ParallelVisitor, TypeInfoVisitor, - BREAK, SKIP, REMOVE, IDLE) + visit, + Visitor, + ParallelVisitor, + TypeInfoVisitor, + BREAK, + SKIP, + REMOVE, + IDLE, +) from .ast import ( - Location, Node, + Location, + Node, # Each kind of AST node - NameNode, DocumentNode, DefinitionNode, + NameNode, + DocumentNode, + DefinitionNode, ExecutableDefinitionNode, - OperationDefinitionNode, OperationType, - VariableDefinitionNode, VariableNode, - SelectionSetNode, SelectionNode, - FieldNode, ArgumentNode, - FragmentSpreadNode, InlineFragmentNode, FragmentDefinitionNode, - ValueNode, IntValueNode, FloatValueNode, StringValueNode, - BooleanValueNode, NullValueNode, EnumValueNode, ListValueNode, - ObjectValueNode, ObjectFieldNode, DirectiveNode, - TypeNode, NamedTypeNode, ListTypeNode, NonNullTypeNode, - TypeSystemDefinitionNode, SchemaDefinitionNode, - OperationTypeDefinitionNode, TypeDefinitionNode, - ScalarTypeDefinitionNode, ObjectTypeDefinitionNode, - FieldDefinitionNode, InputValueDefinitionNode, - InterfaceTypeDefinitionNode, UnionTypeDefinitionNode, - EnumTypeDefinitionNode, EnumValueDefinitionNode, + OperationDefinitionNode, + OperationType, + VariableDefinitionNode, + VariableNode, + SelectionSetNode, + SelectionNode, + FieldNode, + ArgumentNode, + FragmentSpreadNode, + InlineFragmentNode, + FragmentDefinitionNode, + ValueNode, + IntValueNode, + FloatValueNode, + StringValueNode, + BooleanValueNode, + NullValueNode, + EnumValueNode, + ListValueNode, + ObjectValueNode, + ObjectFieldNode, + DirectiveNode, + TypeNode, + NamedTypeNode, + ListTypeNode, + NonNullTypeNode, + TypeSystemDefinitionNode, + SchemaDefinitionNode, + OperationTypeDefinitionNode, + TypeDefinitionNode, + ScalarTypeDefinitionNode, + ObjectTypeDefinitionNode, + FieldDefinitionNode, + InputValueDefinitionNode, + InterfaceTypeDefinitionNode, + UnionTypeDefinitionNode, + EnumTypeDefinitionNode, + EnumValueDefinitionNode, InputObjectTypeDefinitionNode, - DirectiveDefinitionNode, TypeSystemExtensionNode, - SchemaExtensionNode, TypeExtensionNode, ScalarTypeExtensionNode, - ObjectTypeExtensionNode, InterfaceTypeExtensionNode, - UnionTypeExtensionNode, EnumTypeExtensionNode, - InputObjectTypeExtensionNode) + DirectiveDefinitionNode, + TypeSystemExtensionNode, + SchemaExtensionNode, + TypeExtensionNode, + ScalarTypeExtensionNode, + ObjectTypeExtensionNode, + InterfaceTypeExtensionNode, + UnionTypeExtensionNode, + EnumTypeExtensionNode, + InputObjectTypeExtensionNode, +) from .predicates import ( - is_definition_node, is_executable_definition_node, - is_selection_node, is_value_node, is_type_node, - is_type_system_definition_node, is_type_definition_node, - is_type_system_extension_node, is_type_extension_node) + is_definition_node, + is_executable_definition_node, + is_selection_node, + is_value_node, + is_type_node, + is_type_system_definition_node, + is_type_definition_node, + is_type_system_extension_node, + is_type_extension_node, +) from .directive_locations import DirectiveLocation __all__ = [ - 'get_location', 'SourceLocation', - 'Lexer', 'TokenKind', 'Token', - 'parse', 'parse_value', 'parse_type', - 'print_ast', 'Source', - 'visit', 'Visitor', 'ParallelVisitor', 'TypeInfoVisitor', - 'BREAK', 'SKIP', 'REMOVE', 'IDLE', - 'Location', 'DirectiveLocation', 'Node', - 'NameNode', 'DocumentNode', 'DefinitionNode', - 'ExecutableDefinitionNode', - 'OperationDefinitionNode', 'OperationType', - 'VariableDefinitionNode', 'VariableNode', - 'SelectionSetNode', 'SelectionNode', - 'FieldNode', 'ArgumentNode', - 'FragmentSpreadNode', 'InlineFragmentNode', 'FragmentDefinitionNode', - 'ValueNode', 'IntValueNode', 'FloatValueNode', 'StringValueNode', - 'BooleanValueNode', 'NullValueNode', 'EnumValueNode', 'ListValueNode', - 'ObjectValueNode', 'ObjectFieldNode', 'DirectiveNode', - 'TypeNode', 'NamedTypeNode', 'ListTypeNode', 'NonNullTypeNode', - 'TypeSystemDefinitionNode', 'SchemaDefinitionNode', - 'OperationTypeDefinitionNode', 'TypeDefinitionNode', - 'ScalarTypeDefinitionNode', 'ObjectTypeDefinitionNode', - 'FieldDefinitionNode', 'InputValueDefinitionNode', - 'InterfaceTypeDefinitionNode', 'UnionTypeDefinitionNode', - 'EnumTypeDefinitionNode', 'EnumValueDefinitionNode', - 'InputObjectTypeDefinitionNode', - 'DirectiveDefinitionNode', 'TypeSystemExtensionNode', - 'SchemaExtensionNode', 'TypeExtensionNode', 'ScalarTypeExtensionNode', - 'ObjectTypeExtensionNode', 'InterfaceTypeExtensionNode', - 'UnionTypeExtensionNode', 'EnumTypeExtensionNode', - 'InputObjectTypeExtensionNode', - 'is_definition_node', 'is_executable_definition_node', - 'is_selection_node', 'is_value_node', 'is_type_node', - 'is_type_system_definition_node', 'is_type_definition_node', - 'is_type_system_extension_node', 'is_type_extension_node'] + "get_location", + "SourceLocation", + "Lexer", + "TokenKind", + "Token", + "parse", + "parse_value", + "parse_type", + "print_ast", + "Source", + "visit", + "Visitor", + "ParallelVisitor", + "TypeInfoVisitor", + "BREAK", + "SKIP", + "REMOVE", + "IDLE", + "Location", + "DirectiveLocation", + "Node", + "NameNode", + "DocumentNode", + "DefinitionNode", + "ExecutableDefinitionNode", + "OperationDefinitionNode", + "OperationType", + "VariableDefinitionNode", + "VariableNode", + "SelectionSetNode", + "SelectionNode", + "FieldNode", + "ArgumentNode", + "FragmentSpreadNode", + "InlineFragmentNode", + "FragmentDefinitionNode", + "ValueNode", + "IntValueNode", + "FloatValueNode", + "StringValueNode", + "BooleanValueNode", + "NullValueNode", + "EnumValueNode", + "ListValueNode", + "ObjectValueNode", + "ObjectFieldNode", + "DirectiveNode", + "TypeNode", + "NamedTypeNode", + "ListTypeNode", + "NonNullTypeNode", + "TypeSystemDefinitionNode", + "SchemaDefinitionNode", + "OperationTypeDefinitionNode", + "TypeDefinitionNode", + "ScalarTypeDefinitionNode", + "ObjectTypeDefinitionNode", + "FieldDefinitionNode", + "InputValueDefinitionNode", + "InterfaceTypeDefinitionNode", + "UnionTypeDefinitionNode", + "EnumTypeDefinitionNode", + "EnumValueDefinitionNode", + "InputObjectTypeDefinitionNode", + "DirectiveDefinitionNode", + "TypeSystemExtensionNode", + "SchemaExtensionNode", + "TypeExtensionNode", + "ScalarTypeExtensionNode", + "ObjectTypeExtensionNode", + "InterfaceTypeExtensionNode", + "UnionTypeExtensionNode", + "EnumTypeExtensionNode", + "InputObjectTypeExtensionNode", + "is_definition_node", + "is_executable_definition_node", + "is_selection_node", + "is_value_node", + "is_type_node", + "is_type_system_definition_node", + "is_type_definition_node", + "is_type_system_extension_node", + "is_type_extension_node", +] diff --git a/graphql/language/ast.py b/graphql/language/ast.py index bf239e13..20490a63 100644 --- a/graphql/language/ast.py +++ b/graphql/language/ast.py @@ -7,32 +7,62 @@ from ..pyutils import camel_to_snake __all__ = [ - 'Location', 'Node', - 'NameNode', 'DocumentNode', 'DefinitionNode', - 'ExecutableDefinitionNode', 'OperationDefinitionNode', - 'VariableDefinitionNode', - 'SelectionSetNode', 'SelectionNode', - 'FieldNode', 'ArgumentNode', - 'FragmentSpreadNode', 'InlineFragmentNode', 'FragmentDefinitionNode', - 'ValueNode', 'VariableNode', - 'IntValueNode', 'FloatValueNode', 'StringValueNode', - 'BooleanValueNode', 'NullValueNode', - 'EnumValueNode', 'ListValueNode', 'ObjectValueNode', 'ObjectFieldNode', - 'DirectiveNode', 'TypeNode', 'NamedTypeNode', - 'ListTypeNode', 'NonNullTypeNode', - 'TypeSystemDefinitionNode', 'SchemaDefinitionNode', - 'OperationType', 'OperationTypeDefinitionNode', - 'TypeDefinitionNode', - 'ScalarTypeDefinitionNode', 'ObjectTypeDefinitionNode', - 'FieldDefinitionNode', 'InputValueDefinitionNode', - 'InterfaceTypeDefinitionNode', 'UnionTypeDefinitionNode', - 'EnumTypeDefinitionNode', 'EnumValueDefinitionNode', - 'InputObjectTypeDefinitionNode', - 'DirectiveDefinitionNode', 'SchemaExtensionNode', - 'TypeExtensionNode', 'TypeSystemExtensionNode', 'ScalarTypeExtensionNode', - 'ObjectTypeExtensionNode', 'InterfaceTypeExtensionNode', - 'UnionTypeExtensionNode', 'EnumTypeExtensionNode', - 'InputObjectTypeExtensionNode'] + "Location", + "Node", + "NameNode", + "DocumentNode", + "DefinitionNode", + "ExecutableDefinitionNode", + "OperationDefinitionNode", + "VariableDefinitionNode", + "SelectionSetNode", + "SelectionNode", + "FieldNode", + "ArgumentNode", + "FragmentSpreadNode", + "InlineFragmentNode", + "FragmentDefinitionNode", + "ValueNode", + "VariableNode", + "IntValueNode", + "FloatValueNode", + "StringValueNode", + "BooleanValueNode", + "NullValueNode", + "EnumValueNode", + "ListValueNode", + "ObjectValueNode", + "ObjectFieldNode", + "DirectiveNode", + "TypeNode", + "NamedTypeNode", + "ListTypeNode", + "NonNullTypeNode", + "TypeSystemDefinitionNode", + "SchemaDefinitionNode", + "OperationType", + "OperationTypeDefinitionNode", + "TypeDefinitionNode", + "ScalarTypeDefinitionNode", + "ObjectTypeDefinitionNode", + "FieldDefinitionNode", + "InputValueDefinitionNode", + "InterfaceTypeDefinitionNode", + "UnionTypeDefinitionNode", + "EnumTypeDefinitionNode", + "EnumValueDefinitionNode", + "InputObjectTypeDefinitionNode", + "DirectiveDefinitionNode", + "SchemaExtensionNode", + "TypeExtensionNode", + "TypeSystemExtensionNode", + "ScalarTypeExtensionNode", + "ObjectTypeExtensionNode", + "InterfaceTypeExtensionNode", + "UnionTypeExtensionNode", + "EnumTypeExtensionNode", + "InputObjectTypeExtensionNode", +] class Location(NamedTuple): @@ -48,7 +78,7 @@ class Location(NamedTuple): source: Source # Source document the AST represents def __str__(self): - return f'{self.start}:{self.end}' + return f"{self.start}:{self.end}" def __eq__(self, other): if isinstance(other, Location): @@ -63,21 +93,23 @@ def __ne__(self, other): class OperationType(Enum): - QUERY = 'query' - MUTATION = 'mutation' - SUBSCRIPTION = 'subscription' + QUERY = "query" + MUTATION = "mutation" + SUBSCRIPTION = "subscription" # Base AST Node + class Node: """AST nodes""" - __slots__ = 'loc', + + __slots__ = ("loc",) loc: Optional[Location] - kind: str = 'ast' # the kind of the node as a snake_case string - keys = ['loc'] # the names of the attributes of this node + kind: str = "ast" # the kind of the node as a snake_case string + keys = ["loc"] # the names of the attributes of this node def __init__(self, **kwargs): """Initialize the node with the given keyword arguments.""" @@ -86,15 +118,16 @@ def __init__(self, **kwargs): def __repr__(self): """Get a simple representation of the node.""" - name, loc = self.__class__.__name__, getattr(self, 'loc', None) - return f'{name} at {loc}' if loc else name + name, loc = self.__class__.__name__, getattr(self, "loc", None) + return f"{name} at {loc}" if loc else name def __eq__(self, other): """Test whether two nodes are equal (recursively).""" - return (isinstance(other, Node) and - self.__class__ == other.__class__ and - all(getattr(self, key) == getattr(other, key) - for key in self.keys)) + return ( + isinstance(other, Node) + and self.__class__ == other.__class__ + and all(getattr(self, key) == getattr(other, key) for key in self.keys) + ) def __hash__(self): return id(self) @@ -107,12 +140,13 @@ def __deepcopy__(self, memo): """Create a deep copy of the node""" # noinspection PyArgumentList return self.__class__( - **{key: deepcopy(getattr(self, key), memo) for key in self.keys}) + **{key: deepcopy(getattr(self, key), memo) for key in self.keys} + ) def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) name = cls.__name__ - if name.endswith('Node'): + if name.endswith("Node"): name = name[:-4] cls.kind = camel_to_snake(name) keys = [] @@ -125,18 +159,20 @@ def __init_subclass__(cls, **kwargs): # Name + class NameNode(Node): - __slots__ = 'value', + __slots__ = ("value",) value: str # Document + class DocumentNode(Node): - __slots__ = 'definitions', + __slots__ = ("definitions",) - definitions: List['DefinitionNode'] + definitions: List["DefinitionNode"] class DefinitionNode(Node): @@ -144,112 +180,114 @@ class DefinitionNode(Node): class ExecutableDefinitionNode(DefinitionNode): - __slots__ = 'name', 'directives', 'variable_definitions', 'selection_set' + __slots__ = "name", "directives", "variable_definitions", "selection_set" name: Optional[NameNode] - directives: Optional[List['DirectiveNode']] - variable_definitions: List['VariableDefinitionNode'] - selection_set: 'SelectionSetNode' + directives: Optional[List["DirectiveNode"]] + variable_definitions: List["VariableDefinitionNode"] + selection_set: "SelectionSetNode" class OperationDefinitionNode(ExecutableDefinitionNode): - __slots__ = 'operation', + __slots__ = ("operation",) operation: OperationType class VariableDefinitionNode(Node): - __slots__ = 'variable', 'type', 'default_value', 'directives' + __slots__ = "variable", "type", "default_value", "directives" - variable: 'VariableNode' - type: 'TypeNode' - default_value: Optional['ValueNode'] - directives: Optional[List['DirectiveNode']] + variable: "VariableNode" + type: "TypeNode" + default_value: Optional["ValueNode"] + directives: Optional[List["DirectiveNode"]] class SelectionSetNode(Node): - __slots__ = 'selections', + __slots__ = ("selections",) - selections: List['SelectionNode'] + selections: List["SelectionNode"] class SelectionNode(Node): - __slots__ = 'directives', + __slots__ = ("directives",) - directives: Optional[List['DirectiveNode']] + directives: Optional[List["DirectiveNode"]] class FieldNode(SelectionNode): - __slots__ = 'alias', 'name', 'arguments', 'selection_set' + __slots__ = "alias", "name", "arguments", "selection_set" alias: Optional[NameNode] name: NameNode - arguments: Optional[List['ArgumentNode']] + arguments: Optional[List["ArgumentNode"]] selection_set: Optional[SelectionSetNode] class ArgumentNode(Node): - __slots__ = 'name', 'value' + __slots__ = "name", "value" name: NameNode - value: 'ValueNode' + value: "ValueNode" # Fragments + class FragmentSpreadNode(SelectionNode): - __slots__ = 'name', + __slots__ = ("name",) name: NameNode class InlineFragmentNode(SelectionNode): - __slots__ = 'type_condition', 'selection_set' + __slots__ = "type_condition", "selection_set" - type_condition: 'NamedTypeNode' + type_condition: "NamedTypeNode" selection_set: SelectionSetNode class FragmentDefinitionNode(ExecutableDefinitionNode): - __slots__ = 'type_condition', + __slots__ = ("type_condition",) name: NameNode - type_condition: 'NamedTypeNode' + type_condition: "NamedTypeNode" # Values + class ValueNode(Node): __slots__ = () class VariableNode(ValueNode): - __slots__ = 'name', + __slots__ = ("name",) name: NameNode class IntValueNode(ValueNode): - __slots__ = 'value', + __slots__ = ("value",) value: str class FloatValueNode(ValueNode): - __slots__ = 'value', + __slots__ = ("value",) value: str class StringValueNode(ValueNode): - __slots__ = 'value', 'block' + __slots__ = "value", "block" value: str block: Optional[bool] class BooleanValueNode(ValueNode): - __slots__ = 'value', + __slots__ = ("value",) value: bool @@ -259,25 +297,25 @@ class NullValueNode(ValueNode): class EnumValueNode(ValueNode): - __slots__ = 'value', + __slots__ = ("value",) value: str class ListValueNode(ValueNode): - __slots__ = 'values', + __slots__ = ("values",) values: List[ValueNode] class ObjectValueNode(ValueNode): - __slots__ = 'fields', + __slots__ = ("fields",) - fields: List['ObjectFieldNode'] + fields: List["ObjectFieldNode"] class ObjectFieldNode(Node): - __slots__ = 'name', 'value' + __slots__ = "name", "value" name: NameNode value: ValueNode @@ -285,8 +323,9 @@ class ObjectFieldNode(Node): # Directives + class DirectiveNode(Node): - __slots__ = 'name', 'arguments' + __slots__ = "name", "arguments" name: NameNode arguments: List[ArgumentNode] @@ -294,43 +333,45 @@ class DirectiveNode(Node): # Type Reference + class TypeNode(Node): __slots__ = () class NamedTypeNode(TypeNode): - __slots__ = 'name', + __slots__ = ("name",) name: NameNode class ListTypeNode(TypeNode): - __slots__ = 'type', + __slots__ = ("type",) type: TypeNode class NonNullTypeNode(TypeNode): - __slots__ = 'type', + __slots__ = ("type",) type: Union[NamedTypeNode, ListTypeNode] # Type System Definition + class TypeSystemDefinitionNode(DefinitionNode): __slots__ = () class SchemaDefinitionNode(TypeSystemDefinitionNode): - __slots__ = 'directives', 'operation_types' + __slots__ = "directives", "operation_types" directives: Optional[List[DirectiveNode]] - operation_types: List['OperationTypeDefinitionNode'] + operation_types: List["OperationTypeDefinitionNode"] class OperationTypeDefinitionNode(Node): - __slots__ = 'operation', 'type' + __slots__ = "operation", "type" operation: OperationType type: NamedTypeNode @@ -338,8 +379,9 @@ class OperationTypeDefinitionNode(Node): # Type Definition + class TypeDefinitionNode(TypeSystemDefinitionNode): - __slots__ = 'description', 'name', 'directives' + __slots__ = "description", "name", "directives" description: Optional[StringValueNode] name: NameNode @@ -351,42 +393,42 @@ class ScalarTypeDefinitionNode(TypeDefinitionNode): class ObjectTypeDefinitionNode(TypeDefinitionNode): - __slots__ = 'interfaces', 'fields' + __slots__ = "interfaces", "fields" interfaces: Optional[List[NamedTypeNode]] - fields: Optional[List['FieldDefinitionNode']] + fields: Optional[List["FieldDefinitionNode"]] class FieldDefinitionNode(TypeDefinitionNode): - __slots__ = 'arguments', 'type' + __slots__ = "arguments", "type" - arguments: Optional[List['InputValueDefinitionNode']] + arguments: Optional[List["InputValueDefinitionNode"]] type: TypeNode class InputValueDefinitionNode(TypeDefinitionNode): - __slots__ = 'type', 'default_value' + __slots__ = "type", "default_value" type: TypeNode default_value: Optional[ValueNode] class InterfaceTypeDefinitionNode(TypeDefinitionNode): - __slots__ = 'fields', + __slots__ = ("fields",) - fields: Optional[List['FieldDefinitionNode']] + fields: Optional[List["FieldDefinitionNode"]] class UnionTypeDefinitionNode(TypeDefinitionNode): - __slots__ = 'types', + __slots__ = ("types",) types: Optional[List[NamedTypeNode]] class EnumTypeDefinitionNode(TypeDefinitionNode): - __slots__ = 'values', + __slots__ = ("values",) - values: Optional[List['EnumValueDefinitionNode']] + values: Optional[List["EnumValueDefinitionNode"]] class EnumValueDefinitionNode(TypeDefinitionNode): @@ -394,15 +436,16 @@ class EnumValueDefinitionNode(TypeDefinitionNode): class InputObjectTypeDefinitionNode(TypeDefinitionNode): - __slots__ = 'fields', + __slots__ = ("fields",) fields: Optional[List[InputValueDefinitionNode]] # Directive Definitions + class DirectiveDefinitionNode(TypeSystemDefinitionNode): - __slots__ = 'description', 'name', 'arguments', 'locations' + __slots__ = "description", "name", "arguments", "locations" description: Optional[StringValueNode] name: NameNode @@ -412,8 +455,9 @@ class DirectiveDefinitionNode(TypeSystemDefinitionNode): # Type System Extensions + class SchemaExtensionNode(Node): - __slots__ = 'directives', 'operation_types' + __slots__ = "directives", "operation_types" directives: Optional[List[DirectiveNode]] operation_types: Optional[List[OperationTypeDefinitionNode]] @@ -421,8 +465,9 @@ class SchemaExtensionNode(Node): # Type Extensions + class TypeExtensionNode(TypeSystemDefinitionNode): - __slots__ = 'name', 'directives' + __slots__ = "name", "directives" name: NameNode directives: Optional[List[DirectiveNode]] @@ -436,31 +481,31 @@ class ScalarTypeExtensionNode(TypeExtensionNode): class ObjectTypeExtensionNode(TypeExtensionNode): - __slots__ = 'interfaces', 'fields' + __slots__ = "interfaces", "fields" interfaces: Optional[List[NamedTypeNode]] fields: Optional[List[FieldDefinitionNode]] class InterfaceTypeExtensionNode(TypeExtensionNode): - __slots__ = 'fields', + __slots__ = ("fields",) fields: Optional[List[FieldDefinitionNode]] class UnionTypeExtensionNode(TypeExtensionNode): - __slots__ = 'types', + __slots__ = ("types",) types: Optional[List[NamedTypeNode]] class EnumTypeExtensionNode(TypeExtensionNode): - __slots__ = 'values', + __slots__ = ("values",) values: Optional[List[EnumValueDefinitionNode]] class InputObjectTypeExtensionNode(TypeExtensionNode): - __slots__ = 'fields', + __slots__ = ("fields",) fields: Optional[List[InputValueDefinitionNode]] diff --git a/graphql/language/block_string_value.py b/graphql/language/block_string_value.py index 0f13bbe0..3df02552 100644 --- a/graphql/language/block_string_value.py +++ b/graphql/language/block_string_value.py @@ -1,4 +1,4 @@ -__all__ = ['block_string_value'] +__all__ = ["block_string_value"] def block_string_value(raw_string: str) -> str: @@ -15,8 +15,7 @@ def block_string_value(raw_string: str) -> str: common_indent = None for line in lines[1:]: indent = leading_whitespace(line) - if indent < len(line) and ( - common_indent is None or indent < common_indent): + if indent < len(line) and (common_indent is None or indent < common_indent): common_indent = indent if common_indent == 0: break @@ -30,12 +29,12 @@ def block_string_value(raw_string: str) -> str: while lines and not lines[-1].strip(): lines = lines[:-1] - return '\n'.join(lines) + return "\n".join(lines) def leading_whitespace(s): i = 0 n = len(s) - while i < n and s[i] in ' \t': + while i < n and s[i] in " \t": i += 1 return i diff --git a/graphql/language/directive_locations.py b/graphql/language/directive_locations.py index da81edeb..dfce34d9 100644 --- a/graphql/language/directive_locations.py +++ b/graphql/language/directive_locations.py @@ -1,30 +1,30 @@ from enum import Enum -__all__ = ['DirectiveLocation'] +__all__ = ["DirectiveLocation"] class DirectiveLocation(Enum): """The enum type representing the directive location values.""" # Request Definitions - QUERY = 'query' - MUTATION = 'mutation' - SUBSCRIPTION = 'subscription' - FIELD = 'field' - FRAGMENT_DEFINITION = 'fragment definition' - FRAGMENT_SPREAD = 'fragment spread' - VARIABLE_DEFINITION = 'variable definition' - INLINE_FRAGMENT = 'inline fragment' + QUERY = "query" + MUTATION = "mutation" + SUBSCRIPTION = "subscription" + FIELD = "field" + FRAGMENT_DEFINITION = "fragment definition" + FRAGMENT_SPREAD = "fragment spread" + VARIABLE_DEFINITION = "variable definition" + INLINE_FRAGMENT = "inline fragment" # Type System Definitions - SCHEMA = 'schema' - SCALAR = 'scalar' - OBJECT = 'object' - FIELD_DEFINITION = 'field definition' - ARGUMENT_DEFINITION = 'argument definition' - INTERFACE = 'interface' - UNION = 'union' - ENUM = 'enum' - ENUM_VALUE = 'enum value' - INPUT_OBJECT = 'input object' - INPUT_FIELD_DEFINITION = 'input field definition' + SCHEMA = "schema" + SCALAR = "scalar" + OBJECT = "object" + FIELD_DEFINITION = "field definition" + ARGUMENT_DEFINITION = "argument definition" + INTERFACE = "interface" + UNION = "union" + ENUM = "enum" + ENUM_VALUE = "enum value" + INPUT_OBJECT = "input object" + INPUT_FIELD_DEFINITION = "input field definition" diff --git a/graphql/language/lexer.py b/graphql/language/lexer.py index a992af33..45f83682 100644 --- a/graphql/language/lexer.py +++ b/graphql/language/lexer.py @@ -6,42 +6,49 @@ from .source import Source from .block_string_value import block_string_value -__all__ = ['Lexer', 'TokenKind', 'Token'] +__all__ = ["Lexer", "TokenKind", "Token"] class TokenKind(Enum): """Each kind of token""" - SOF = '' - EOF = '' - BANG = '!' - DOLLAR = '$' - AMP = '&' - PAREN_L = '(' - PAREN_R = ')' - SPREAD = '...' - COLON = ':' - EQUALS = '=' - AT = '@' - BRACKET_L = '[' - BRACKET_R = ']' - BRACE_L = '{' - PIPE = '|' - BRACE_R = '}' - NAME = 'Name' - INT = 'Int' - FLOAT = 'Float' - STRING = 'String' - BLOCK_STRING = 'BlockString' - COMMENT = 'Comment' + SOF = "" + EOF = "" + BANG = "!" + DOLLAR = "$" + AMP = "&" + PAREN_L = "(" + PAREN_R = ")" + SPREAD = "..." + COLON = ":" + EQUALS = "=" + AT = "@" + BRACKET_L = "[" + BRACKET_R = "]" + BRACE_L = "{" + PIPE = "|" + BRACE_R = "}" + NAME = "Name" + INT = "Int" + FLOAT = "Float" + STRING = "String" + BLOCK_STRING = "BlockString" + COMMENT = "Comment" -class Token: - __slots__ = ('kind', 'start', 'end', 'line', 'column', - 'prev', 'next', 'value') - def __init__(self, kind: TokenKind, start: int, end: int, - line: int, column: int, - prev: 'Token'=None, value: str=None) -> None: +class Token: + __slots__ = ("kind", "start", "end", "line", "column", "prev", "next", "value") + + def __init__( + self, + kind: TokenKind, + start: int, + end: int, + line: int, + column: int, + prev: "Token" = None, + value: str = None, + ) -> None: self.kind = kind self.start, self.end = start, end self.line, self.column = line, column @@ -50,17 +57,20 @@ def __init__(self, kind: TokenKind, start: int, end: int, self.value: Optional[str] = value or None def __repr__(self): - return ''.format( - self.desc, self.start, self.end, self.line, self.column) + return "".format( + self.desc, self.start, self.end, self.line, self.column + ) def __eq__(self, other): if isinstance(other, Token): - return (self.kind == other.kind and - self.start == other.start and - self.end == other.end and - self.line == other.line and - self.column == other.column and - self.value == other.value) + return ( + self.kind == other.kind + and self.start == other.start + and self.end == other.end + and self.line == other.line + and self.column == other.column + and self.value == other.value + ) elif isinstance(other, str): return other == self.desc return False @@ -68,8 +78,14 @@ def __eq__(self, other): def __copy__(self): """Create a shallow copy of the token""" return self.__class__( - self.kind, self.start, self.end, self.line, self.column, - self.prev, self.value) + self.kind, + self.start, + self.end, + self.line, + self.column, + self.prev, + self.value, + ) def __deepcopy__(self, memo): """Allow only shallow copies to avoid recursion.""" @@ -79,7 +95,7 @@ def __deepcopy__(self, memo): def desc(self) -> str: """A helper property to describe a token as a string for debugging""" kind, value = self.kind.value, self.value - return f'{kind} {value!r}' if value else kind + return f"{kind} {value!r}" if value else kind def char_at(s, pos): @@ -94,19 +110,19 @@ def print_char(char): _KIND_FOR_PUNCT = { - '!': TokenKind.BANG, - '$': TokenKind.DOLLAR, - '&': TokenKind.AMP, - '(': TokenKind.PAREN_L, - ')': TokenKind.PAREN_R, - ':': TokenKind.COLON, - '=': TokenKind.EQUALS, - '@': TokenKind.AT, - '[': TokenKind.BRACKET_L, - ']': TokenKind.BRACKET_R, - '{': TokenKind.BRACE_L, - '}': TokenKind.BRACE_R, - '|': TokenKind.PIPE + "!": TokenKind.BANG, + "$": TokenKind.DOLLAR, + "&": TokenKind.AMP, + "(": TokenKind.PAREN_L, + ")": TokenKind.PAREN_R, + ":": TokenKind.COLON, + "=": TokenKind.EQUALS, + "@": TokenKind.AT, + "[": TokenKind.BRACKET_L, + "]": TokenKind.BRACKET_R, + "{": TokenKind.BRACE_L, + "}": TokenKind.BRACE_R, + "|": TokenKind.PIPE, } @@ -121,18 +137,22 @@ class Lexer: """ - def __init__(self, source: Source, - no_location=False, - experimental_fragment_variables=False, - experimental_variable_definition_directives=False) -> None: + def __init__( + self, + source: Source, + no_location=False, + experimental_fragment_variables=False, + experimental_variable_definition_directives=False, + ) -> None: """Given a Source object, this returns a Lexer for that source.""" self.source = source self.token = self.last_token = Token(TokenKind.SOF, 0, 0, 0, 0) self.line, self.line_start = 1, 0 self.no_location = no_location self.experimental_fragment_variables = experimental_fragment_variables - self.experimental_variable_definition_directives = \ + self.experimental_variable_definition_directives = ( experimental_variable_definition_directives + ) def advance(self): self.last_token = self.token @@ -167,33 +187,28 @@ def read_token(self, prev: Token) -> Token: col = 1 + pos - self.line_start if pos >= body_length: - return Token( - TokenKind.EOF, body_length, body_length, line, col, prev) + return Token(TokenKind.EOF, body_length, body_length, line, col, prev) char = char_at(body, pos) if char is not None: kind = _KIND_FOR_PUNCT.get(char) if kind: return Token(kind, pos, pos + 1, line, col, prev) - if char == '#': + if char == "#": return read_comment(source, pos, line, col, prev) - elif char == '.': - if (char == char_at(body, pos + 1) == - char_at(body, pos + 2)): - return Token(TokenKind.SPREAD, pos, pos + 3, - line, col, prev) - elif 'A' <= char <= 'Z' or 'a' <= char <= 'z' or char == '_': + elif char == ".": + if char == char_at(body, pos + 1) == char_at(body, pos + 2): + return Token(TokenKind.SPREAD, pos, pos + 3, line, col, prev) + elif "A" <= char <= "Z" or "a" <= char <= "z" or char == "_": return read_name(source, pos, line, col, prev) - elif '0' <= char <= '9' or char == '-': + elif "0" <= char <= "9" or char == "-": return read_number(source, pos, char, line, col, prev) elif char == '"': - if (char == char_at(body, pos + 1) == - char_at(body, pos + 2)): + if char == char_at(body, pos + 1) == char_at(body, pos + 2): return read_block_string(source, pos, line, col, prev) return read_string(source, pos, line, col, prev) - raise GraphQLSyntaxError( - source, pos, unexpected_character_message(char)) + raise GraphQLSyntaxError(source, pos, unexpected_character_message(char)) def position_after_whitespace(self, body, start_position: int) -> int: """Go to next position after a whitespace. @@ -207,14 +222,14 @@ def position_after_whitespace(self, body, start_position: int) -> int: position = start_position while position < body_length: char = char_at(body, position) - if char is not None and char in ' \t,\ufeff': + if char is not None and char in " \t,\ufeff": position += 1 - elif char == '\n': + elif char == "\n": position += 1 self.line += 1 self.line_start = position - elif char == '\r': - if char_at(body, position + 1) == '\n': + elif char == "\r": + if char_at(body, position + 1) == "\n": position += 2 else: position += 1 @@ -226,12 +241,14 @@ def position_after_whitespace(self, body, start_position: int) -> int: def unexpected_character_message(char): - if char < ' ' and char not in '\t\n\r': - return f'Cannot contain the invalid character {print_char(char)}.' + if char < " " and char not in "\t\n\r": + return f"Cannot contain the invalid character {print_char(char)}." if char == "'": - return ("Unexpected single quote character (')," - ' did you mean to use a double quote (")?') - return f'Cannot parse the unexpected character {print_char(char)}.' + return ( + "Unexpected single quote character (')," + ' did you mean to use a double quote (")?' + ) + return f"Cannot parse the unexpected character {print_char(char)}." def read_comment(source: Source, start, line, col, prev) -> Token: @@ -241,10 +258,11 @@ def read_comment(source: Source, start, line, col, prev) -> Token: while True: position += 1 char = char_at(body, position) - if char is None or (char < ' ' and char != '\t'): + if char is None or (char < " " and char != "\t"): break - return Token(TokenKind.COMMENT, start, position, line, col, prev, - body[start + 1:position]) + return Token( + TokenKind.COMMENT, start, position, line, col, prev, body[start + 1 : position] + ) def read_number(source: Source, start, char, line, col, prev) -> Token: @@ -256,60 +274,71 @@ def read_number(source: Source, start, char, line, col, prev) -> Token: body = source.body position = start is_float = False - if char == '-': + if char == "-": position += 1 char = char_at(body, position) - if char == '0': + if char == "0": position += 1 char = char_at(body, position) - if char is not None and '0' <= char <= '9': + if char is not None and "0" <= char <= "9": raise GraphQLSyntaxError( - source, position, 'Invalid number,' - f' unexpected digit after 0: {print_char(char)}.') + source, + position, + "Invalid number," f" unexpected digit after 0: {print_char(char)}.", + ) else: position = read_digits(source, position, char) char = char_at(body, position) - if char == '.': + if char == ".": is_float = True position += 1 char = char_at(body, position) position = read_digits(source, position, char) char = char_at(body, position) - if char is not None and char in 'Ee': + if char is not None and char in "Ee": is_float = True position += 1 char = char_at(body, position) - if char is not None and char in '+-': + if char is not None and char in "+-": position += 1 char = char_at(body, position) position = read_digits(source, position, char) - return Token(TokenKind.FLOAT if is_float else TokenKind.INT, - start, position, line, col, prev, body[start:position]) + return Token( + TokenKind.FLOAT if is_float else TokenKind.INT, + start, + position, + line, + col, + prev, + body[start:position], + ) def read_digits(source: Source, start, char) -> int: """Return the new position in the source after reading digits.""" body = source.body position = start - while char is not None and '0' <= char <= '9': + while char is not None and "0" <= char <= "9": position += 1 char = char_at(body, position) if position == start: raise GraphQLSyntaxError( - source, position, - f'Invalid number, expected digit but got: {print_char(char)}.') + source, + position, + f"Invalid number, expected digit but got: {print_char(char)}.", + ) return position _ESCAPED_CHARS = { '"': '"', - '/': '/', - '\\': '\\', - 'b': '\b', - 'f': '\f', - 'n': '\n', - 'r': '\r', - 't': '\t', + "/": "/", + "\\": "\\", + "b": "\b", + "f": "\f", + "n": "\n", + "r": "\r", + "t": "\t", } @@ -323,79 +352,99 @@ def read_string(source: Source, start, line, col, prev) -> Token: while position < len(body): char = char_at(body, position) - if char is None or char in '\n\r': + if char is None or char in "\n\r": break if char == '"': append(body[chunk_start:position]) - return Token(TokenKind.STRING, start, position + 1, line, col, - prev, ''.join(value)) - if char < ' ' and char != '\t': + return Token( + TokenKind.STRING, start, position + 1, line, col, prev, "".join(value) + ) + if char < " " and char != "\t": raise GraphQLSyntaxError( - source, position, - f'Invalid character within String: {print_char(char)}.') + source, + position, + f"Invalid character within String: {print_char(char)}.", + ) position += 1 - if char == '\\': - append(body[chunk_start:position - 1]) + if char == "\\": + append(body[chunk_start : position - 1]) char = char_at(body, position) escaped = _ESCAPED_CHARS.get(char) if escaped: value.append(escaped) - elif char == 'u': + elif char == "u": code = uni_char_code( char_at(body, position + 1), char_at(body, position + 2), char_at(body, position + 3), - char_at(body, position + 4)) + char_at(body, position + 4), + ) if code < 0: - escape = repr(body[position:position + 5]) - escape = escape[:1] + '\\' + escape[1:] + escape = repr(body[position : position + 5]) + escape = escape[:1] + "\\" + escape[1:] raise GraphQLSyntaxError( - source, position, - f'Invalid character escape sequence: {escape}.') + source, + position, + f"Invalid character escape sequence: {escape}.", + ) append(chr(code)) position += 4 else: escape = repr(char) - escape = escape[:1] + '\\' + escape[1:] + escape = escape[:1] + "\\" + escape[1:] raise GraphQLSyntaxError( - source, position, - f'Invalid character escape sequence: {escape}.') + source, position, f"Invalid character escape sequence: {escape}." + ) position += 1 chunk_start = position - raise GraphQLSyntaxError( - source, position, 'Unterminated string.') + raise GraphQLSyntaxError(source, position, "Unterminated string.") def read_block_string(source: Source, start, line, col, prev) -> Token: body = source.body position = start + 3 chunk_start = position - raw_value = '' + raw_value = "" while position < len(body): char = char_at(body, position) if char is None: break - if (char == '"' and char_at(body, position + 1) == '"' - and char_at(body, position + 2) == '"'): + if ( + char == '"' + and char_at(body, position + 1) == '"' + and char_at(body, position + 2) == '"' + ): raw_value += body[chunk_start:position] - return Token(TokenKind.BLOCK_STRING, start, position + 3, - line, col, prev, block_string_value(raw_value)) - if char < ' ' and char not in '\t\n\r': + return Token( + TokenKind.BLOCK_STRING, + start, + position + 3, + line, + col, + prev, + block_string_value(raw_value), + ) + if char < " " and char not in "\t\n\r": raise GraphQLSyntaxError( - source, position, - f'Invalid character within String: {print_char(char)}.') - if (char == '\\' and char_at(body, position + 1) == '"' - and char_at(body, position + 2) == '"' - and char_at(body, position + 3) == '"'): + source, + position, + f"Invalid character within String: {print_char(char)}.", + ) + if ( + char == "\\" + and char_at(body, position + 1) == '"' + and char_at(body, position + 2) == '"' + and char_at(body, position + 3) == '"' + ): raw_value += body[chunk_start:position] + '"""' position += 4 chunk_start = position else: position += 1 - raise GraphQLSyntaxError(source, position, 'Unterminated string.') + raise GraphQLSyntaxError(source, position, "Unterminated string.") def uni_char_code(a, b, c, d): @@ -410,8 +459,7 @@ def uni_char_code(a, b, c, d): This is implemented by noting that char2hex() returns -1 on error, which means the result of ORing the char2hex() will also be negative. """ - return (char2hex(a) << 12 | char2hex(b) << 8 | - char2hex(c) << 4 | char2hex(d)) + return char2hex(a) << 12 | char2hex(b) << 8 | char2hex(c) << 4 | char2hex(d) def char2hex(a): @@ -424,11 +472,11 @@ def char2hex(a): Returns -1 on error. """ - if '0' <= a <= '9': + if "0" <= a <= "9": return ord(a) - 48 - elif 'A' <= a <= 'F': + elif "A" <= a <= "F": return ord(a) - 55 - elif 'a' <= a <= 'f': # a-f + elif "a" <= a <= "f": # a-f return ord(a) - 87 return -1 @@ -441,9 +489,11 @@ def read_name(source: Source, start, line, col, prev) -> Token: while position < body_length: char = char_at(body, position) if char is None or not ( - char == '_' or '0' <= char <= '9' or - 'A' <= char <= 'Z' or 'a' <= char <= 'z'): + char == "_" + or "0" <= char <= "9" + or "A" <= char <= "Z" + or "a" <= char <= "z" + ): break position += 1 - return Token(TokenKind.NAME, start, position, line, col, - prev, body[start:position]) + return Token(TokenKind.NAME, start, position, line, col, prev, body[start:position]) diff --git a/graphql/language/location.py b/graphql/language/location.py index 8fcc056d..b330fda1 100644 --- a/graphql/language/location.py +++ b/graphql/language/location.py @@ -3,16 +3,17 @@ if TYPE_CHECKING: # pragma: no cover from .source import Source # noqa: F401 -__all__ = ['get_location', 'SourceLocation'] +__all__ = ["get_location", "SourceLocation"] class SourceLocation(NamedTuple): """Represents a location in a Source.""" + line: int column: int -def get_location(source: 'Source', position: int) -> SourceLocation: +def get_location(source: "Source", position: int) -> SourceLocation: """Get the line and column for a character position in the source. Takes a Source and a UTF-8 character offset, and returns the corresponding diff --git a/graphql/language/parser.py b/graphql/language/parser.py index cccc15e4..c1e336ed 100644 --- a/graphql/language/parser.py +++ b/graphql/language/parser.py @@ -1,36 +1,76 @@ from typing import Callable, List, Optional, Union, cast, Dict from .ast import ( - ArgumentNode, BooleanValueNode, DefinitionNode, - DirectiveDefinitionNode, DirectiveNode, DocumentNode, - EnumTypeDefinitionNode, EnumTypeExtensionNode, EnumValueDefinitionNode, - EnumValueNode, ExecutableDefinitionNode, FieldDefinitionNode, FieldNode, - FloatValueNode, FragmentDefinitionNode, FragmentSpreadNode, - InlineFragmentNode, InputObjectTypeDefinitionNode, - InputObjectTypeExtensionNode, InputValueDefinitionNode, IntValueNode, - InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, ListTypeNode, - ListValueNode, Location, NameNode, NamedTypeNode, Node, NonNullTypeNode, - NullValueNode, ObjectFieldNode, ObjectTypeDefinitionNode, - ObjectTypeExtensionNode, ObjectValueNode, OperationDefinitionNode, - OperationType, OperationTypeDefinitionNode, ScalarTypeDefinitionNode, - ScalarTypeExtensionNode, SchemaDefinitionNode, SchemaExtensionNode, - SelectionNode, SelectionSetNode, StringValueNode, - TypeNode, TypeSystemDefinitionNode, TypeSystemExtensionNode, - UnionTypeDefinitionNode, UnionTypeExtensionNode, ValueNode, - VariableDefinitionNode, VariableNode) + ArgumentNode, + BooleanValueNode, + DefinitionNode, + DirectiveDefinitionNode, + DirectiveNode, + DocumentNode, + EnumTypeDefinitionNode, + EnumTypeExtensionNode, + EnumValueDefinitionNode, + EnumValueNode, + ExecutableDefinitionNode, + FieldDefinitionNode, + FieldNode, + FloatValueNode, + FragmentDefinitionNode, + FragmentSpreadNode, + InlineFragmentNode, + InputObjectTypeDefinitionNode, + InputObjectTypeExtensionNode, + InputValueDefinitionNode, + IntValueNode, + InterfaceTypeDefinitionNode, + InterfaceTypeExtensionNode, + ListTypeNode, + ListValueNode, + Location, + NameNode, + NamedTypeNode, + Node, + NonNullTypeNode, + NullValueNode, + ObjectFieldNode, + ObjectTypeDefinitionNode, + ObjectTypeExtensionNode, + ObjectValueNode, + OperationDefinitionNode, + OperationType, + OperationTypeDefinitionNode, + ScalarTypeDefinitionNode, + ScalarTypeExtensionNode, + SchemaDefinitionNode, + SchemaExtensionNode, + SelectionNode, + SelectionSetNode, + StringValueNode, + TypeNode, + TypeSystemDefinitionNode, + TypeSystemExtensionNode, + UnionTypeDefinitionNode, + UnionTypeExtensionNode, + ValueNode, + VariableDefinitionNode, + VariableNode, +) from .directive_locations import DirectiveLocation from .lexer import Lexer, Token, TokenKind from .source import Source from ..error import GraphQLError, GraphQLSyntaxError -__all__ = ['parse', 'parse_type', 'parse_value'] +__all__ = ["parse", "parse_type", "parse_value"] SourceType = Union[Source, str] -def parse(source: SourceType, no_location=False, - experimental_fragment_variables=False, - experimental_variable_definition_directives=False) -> DocumentNode: +def parse( + source: SourceType, + no_location=False, + experimental_fragment_variables=False, + experimental_variable_definition_directives=False, +) -> DocumentNode: """Given a GraphQL source, parse it into a Document. Throws GraphQLError if a syntax error is encountered. @@ -62,12 +102,13 @@ def parse(source: SourceType, no_location=False, if isinstance(source, str): source = Source(source) elif not isinstance(source, Source): - raise TypeError(f'Must provide Source. Received: {source!r}') + raise TypeError(f"Must provide Source. Received: {source!r}") lexer = Lexer( - source, no_location=no_location, + source, + no_location=no_location, experimental_fragment_variables=experimental_fragment_variables, - experimental_variable_definition_directives # noqa - =experimental_variable_definition_directives) + experimental_variable_definition_directives=experimental_variable_definition_directives, # noqa + ) return parse_document(lexer) @@ -117,12 +158,14 @@ def parse_name(lexer: Lexer) -> NameNode: # Implement the parsing rules in the Document section. + def parse_document(lexer: Lexer) -> DocumentNode: """Document: Definition+""" start = lexer.token - return DocumentNode(definitions=many_nodes( - lexer, TokenKind.SOF, parse_definition, TokenKind.EOF), - loc=loc(lexer, start)) + return DocumentNode( + definitions=many_nodes(lexer, TokenKind.SOF, parse_definition, TokenKind.EOF), + loc=loc(lexer, start), + ) def parse_definition(lexer: Lexer) -> DefinitionNode: @@ -141,8 +184,7 @@ def parse_definition(lexer: Lexer) -> DefinitionNode: def parse_executable_definition(lexer: Lexer) -> ExecutableDefinitionNode: """ExecutableDefinition: OperationDefinition or FragmentDefinition""" if peek(lexer, TokenKind.NAME): - func = _parse_executable_definition_functions.get( - cast(str, lexer.token.value)) + func = _parse_executable_definition_functions.get(cast(str, lexer.token.value)) if func: return func(lexer) elif peek(lexer, TokenKind.BRACE_L): @@ -152,23 +194,29 @@ def parse_executable_definition(lexer: Lexer) -> ExecutableDefinitionNode: # Implement the parsing rules in the Operations section. + def parse_operation_definition(lexer: Lexer) -> OperationDefinitionNode: """OperationDefinition""" start = lexer.token if peek(lexer, TokenKind.BRACE_L): return OperationDefinitionNode( - operation=OperationType.QUERY, name=None, - variable_definitions=[], directives=[], + operation=OperationType.QUERY, + name=None, + variable_definitions=[], + directives=[], selection_set=parse_selection_set(lexer), - loc=loc(lexer, start)) + loc=loc(lexer, start), + ) operation = parse_operation_type(lexer) name = parse_name(lexer) if peek(lexer, TokenKind.NAME) else None return OperationDefinitionNode( - operation=operation, name=name, + operation=operation, + name=name, variable_definitions=parse_variable_definitions(lexer), directives=parse_directives(lexer, False), selection_set=parse_selection_set(lexer), - loc=loc(lexer, start)) + loc=loc(lexer, start), + ) def parse_operation_type(lexer: Lexer) -> OperationType: @@ -182,9 +230,16 @@ def parse_operation_type(lexer: Lexer) -> OperationType: def parse_variable_definitions(lexer: Lexer) -> List[VariableDefinitionNode]: """VariableDefinitions: (VariableDefinition+)""" - return cast(List[VariableDefinitionNode], many_nodes( - lexer, TokenKind.PAREN_L, parse_variable_definition, TokenKind.PAREN_R - )) if peek(lexer, TokenKind.PAREN_L) else [] + return ( + cast( + List[VariableDefinitionNode], + many_nodes( + lexer, TokenKind.PAREN_L, parse_variable_definition, TokenKind.PAREN_R + ), + ) + if peek(lexer, TokenKind.PAREN_L) + else [] + ) def parse_variable_definition(lexer: Lexer) -> VariableDefinitionNode: @@ -193,19 +248,21 @@ def parse_variable_definition(lexer: Lexer) -> VariableDefinitionNode: if lexer.experimental_variable_definition_directives: return VariableDefinitionNode( variable=parse_variable(lexer), - type=expect(lexer, TokenKind.COLON) - and parse_type_reference(lexer), + type=expect(lexer, TokenKind.COLON) and parse_type_reference(lexer), default_value=parse_value_literal(lexer, True) - if skip(lexer, TokenKind.EQUALS) else None, + if skip(lexer, TokenKind.EQUALS) + else None, directives=parse_directives(lexer, True), - loc=loc(lexer, start)) + loc=loc(lexer, start), + ) return VariableDefinitionNode( variable=parse_variable(lexer), - type=expect(lexer, TokenKind.COLON) and parse_type_reference( - lexer), + type=expect(lexer, TokenKind.COLON) and parse_type_reference(lexer), default_value=parse_value_literal(lexer, True) - if skip(lexer, TokenKind.EQUALS) else None, - loc=loc(lexer, start)) + if skip(lexer, TokenKind.EQUALS) + else None, + loc=loc(lexer, start), + ) def parse_variable(lexer: Lexer) -> VariableNode: @@ -220,14 +277,15 @@ def parse_selection_set(lexer: Lexer) -> SelectionSetNode: start = lexer.token return SelectionSetNode( selections=many_nodes( - lexer, TokenKind.BRACE_L, parse_selection, TokenKind.BRACE_R), - loc=loc(lexer, start)) + lexer, TokenKind.BRACE_L, parse_selection, TokenKind.BRACE_R + ), + loc=loc(lexer, start), + ) def parse_selection(lexer: Lexer) -> SelectionNode: """Selection: Field or FragmentSpread or InlineFragment""" - return (parse_fragment if peek(lexer, TokenKind.SPREAD) - else parse_field)(lexer) + return (parse_fragment if peek(lexer, TokenKind.SPREAD) else parse_field)(lexer) def parse_field(lexer: Lexer) -> FieldNode: @@ -241,20 +299,28 @@ def parse_field(lexer: Lexer) -> FieldNode: alias = None name = name_or_alias return FieldNode( - alias=alias, name=name, + alias=alias, + name=name, arguments=parse_arguments(lexer, False), directives=parse_directives(lexer, False), selection_set=parse_selection_set(lexer) - if peek(lexer, TokenKind.BRACE_L) else None, - loc=loc(lexer, start)) + if peek(lexer, TokenKind.BRACE_L) + else None, + loc=loc(lexer, start), + ) def parse_arguments(lexer: Lexer, is_const: bool) -> List[ArgumentNode]: """Arguments[Const]: (Argument[?Const]+)""" item = parse_const_argument if is_const else parse_argument - return cast(List[ArgumentNode], many_nodes( - lexer, TokenKind.PAREN_L, item, - TokenKind.PAREN_R)) if peek(lexer, TokenKind.PAREN_L) else [] + return ( + cast( + List[ArgumentNode], + many_nodes(lexer, TokenKind.PAREN_L, item, TokenKind.PAREN_R), + ) + if peek(lexer, TokenKind.PAREN_L) + else [] + ) def parse_argument(lexer: Lexer) -> ArgumentNode: @@ -262,9 +328,9 @@ def parse_argument(lexer: Lexer) -> ArgumentNode: start = lexer.token return ArgumentNode( name=parse_name(lexer), - value=expect(lexer, TokenKind.COLON) and - parse_value_literal(lexer, False), - loc=loc(lexer, start)) + value=expect(lexer, TokenKind.COLON) and parse_value_literal(lexer, False), + loc=loc(lexer, start), + ) def parse_const_argument(lexer: Lexer) -> ArgumentNode: @@ -272,15 +338,15 @@ def parse_const_argument(lexer: Lexer) -> ArgumentNode: start = lexer.token return ArgumentNode( name=parse_name(lexer), - value=expect(lexer, TokenKind.COLON) - and parse_const_value(lexer), - loc=loc(lexer, start)) + value=expect(lexer, TokenKind.COLON) and parse_const_value(lexer), + loc=loc(lexer, start), + ) # Implement the parsing rules in the Fragments section. -def parse_fragment( - lexer: Lexer) -> Union[FragmentSpreadNode, InlineFragmentNode]: + +def parse_fragment(lexer: Lexer) -> Union[FragmentSpreadNode, InlineFragmentNode]: """Corresponds to both FragmentSpread and InlineFragment in the spec. FragmentSpread: ... FragmentName Directives? @@ -288,12 +354,13 @@ def parse_fragment( """ start = lexer.token expect(lexer, TokenKind.SPREAD) - if peek(lexer, TokenKind.NAME) and lexer.token.value != 'on': + if peek(lexer, TokenKind.NAME) and lexer.token.value != "on": return FragmentSpreadNode( name=parse_fragment_name(lexer), directives=parse_directives(lexer, False), - loc=loc(lexer, start)) - if lexer.token.value == 'on': + loc=loc(lexer, start), + ) + if lexer.token.value == "on": lexer.advance() type_condition: Optional[NamedTypeNode] = parse_named_type(lexer) else: @@ -302,48 +369,50 @@ def parse_fragment( type_condition=type_condition, directives=parse_directives(lexer, False), selection_set=parse_selection_set(lexer), - loc=loc(lexer, start)) + loc=loc(lexer, start), + ) def parse_fragment_definition(lexer: Lexer) -> FragmentDefinitionNode: """FragmentDefinition""" start = lexer.token - expect_keyword(lexer, 'fragment') + expect_keyword(lexer, "fragment") # Experimental support for defining variables within fragments changes # the grammar of FragmentDefinition if lexer.experimental_fragment_variables: return FragmentDefinitionNode( name=parse_fragment_name(lexer), variable_definitions=parse_variable_definitions(lexer), - type_condition=expect_keyword(lexer, 'on') and - parse_named_type(lexer), + type_condition=expect_keyword(lexer, "on") and parse_named_type(lexer), directives=parse_directives(lexer, False), selection_set=parse_selection_set(lexer), - loc=loc(lexer, start)) + loc=loc(lexer, start), + ) return FragmentDefinitionNode( name=parse_fragment_name(lexer), - type_condition=expect_keyword(lexer, 'on') and - parse_named_type(lexer), + type_condition=expect_keyword(lexer, "on") and parse_named_type(lexer), directives=parse_directives(lexer, False), selection_set=parse_selection_set(lexer), - loc=loc(lexer, start)) + loc=loc(lexer, start), + ) -_parse_executable_definition_functions: Dict[str, Callable] = {**dict.fromkeys( - ('query', 'mutation', 'subscription'), - parse_operation_definition), **dict.fromkeys( - ('fragment',), parse_fragment_definition)} +_parse_executable_definition_functions: Dict[str, Callable] = { + **dict.fromkeys(("query", "mutation", "subscription"), parse_operation_definition), + **dict.fromkeys(("fragment",), parse_fragment_definition), +} def parse_fragment_name(lexer: Lexer) -> NameNode: """FragmentName: Name but not `on`""" - if lexer.token.value == 'on': + if lexer.token.value == "on": raise unexpected(lexer) return parse_name(lexer) # Implement the parsing rules in the Values section. + def parse_value_literal(lexer: Lexer, is_const: bool) -> ValueNode: func = _parse_value_literal_functions.get(lexer.token.kind) if func: @@ -357,7 +426,8 @@ def parse_string_literal(lexer: Lexer, _is_const=True) -> StringValueNode: return StringValueNode( value=token.value, block=token.kind == TokenKind.BLOCK_STRING, - loc=loc(lexer, token)) + loc=loc(lexer, token), + ) def parse_const_value(lexer: Lexer) -> ValueNode: @@ -373,18 +443,18 @@ def parse_list(lexer: Lexer, is_const: bool) -> ListValueNode: start = lexer.token item = parse_const_value if is_const else parse_value_value return ListValueNode( - values=any_nodes( - lexer, TokenKind.BRACKET_L, item, TokenKind.BRACKET_R), - loc=loc(lexer, start)) + values=any_nodes(lexer, TokenKind.BRACKET_L, item, TokenKind.BRACKET_R), + loc=loc(lexer, start), + ) def parse_object_field(lexer: Lexer, is_const: bool) -> ObjectFieldNode: start = lexer.token return ObjectFieldNode( name=parse_name(lexer), - value=expect(lexer, TokenKind.COLON) and - parse_value_literal(lexer, is_const), - loc=loc(lexer, start)) + value=expect(lexer, TokenKind.COLON) and parse_value_literal(lexer, is_const), + loc=loc(lexer, start), + ) def parse_object(lexer: Lexer, is_const: bool) -> ObjectValueNode: @@ -414,9 +484,9 @@ def parse_named_values(lexer: Lexer, _is_const=True) -> ValueNode: token = lexer.token value = token.value lexer.advance() - if value in ('true', 'false'): - return BooleanValueNode(value=value == 'true', loc=loc(lexer, token)) - elif value == 'null': + if value in ("true", "false"): + return BooleanValueNode(value=value == "true", loc=loc(lexer, token)) + elif value == "null": return NullValueNode(loc=loc(lexer, token)) else: return EnumValueNode(value=value, loc=loc(lexer, token)) @@ -436,11 +506,13 @@ def parse_variable_value(lexer: Lexer, is_const) -> VariableNode: TokenKind.STRING: parse_string_literal, TokenKind.BLOCK_STRING: parse_string_literal, TokenKind.NAME: parse_named_values, - TokenKind.DOLLAR: parse_variable_value} + TokenKind.DOLLAR: parse_variable_value, +} # Implement the parsing rules in the Directives section. + def parse_directives(lexer: Lexer, is_const: bool) -> List[DirectiveNode]: """Directives[Const]: Directive[?Const]+""" directives: List[DirectiveNode] = [] @@ -457,11 +529,13 @@ def parse_directive(lexer: Lexer, is_const: bool) -> DirectiveNode: return DirectiveNode( name=parse_name(lexer), arguments=parse_arguments(lexer, is_const), - loc=loc(lexer, start)) + loc=loc(lexer, start), + ) # Implement the parsing rules in the Types section. + def parse_type_reference(lexer: Lexer) -> TypeNode: """Type: NamedType or ListType or NonNullType""" start = lexer.token @@ -484,11 +558,11 @@ def parse_named_type(lexer: Lexer) -> NamedTypeNode: # Implement the parsing rules in the Type Definition section. + def parse_type_system_definition(lexer: Lexer) -> TypeSystemDefinitionNode: """TypeSystemDefinition""" # Many definitions begin with a description and require a lookahead. - keyword_token = lexer.lookahead( - ) if peek_description(lexer) else lexer.token + keyword_token = lexer.lookahead() if peek_description(lexer) else lexer.token func = _parse_type_system_definition_functions.get(keyword_token.value) if func: return func(lexer) @@ -505,12 +579,25 @@ def parse_type_system_extension(lexer: Lexer) -> TypeSystemExtensionNode: raise unexpected(lexer, keyword_token) -_parse_definition_functions: Dict[str, Callable] = {**dict.fromkeys( - ('query', 'mutation', 'subscription', 'fragment'), - parse_executable_definition), **dict.fromkeys( - ('schema', 'scalar', 'type', 'interface', 'union', 'enum', - 'input', 'directive'), parse_type_system_definition), - 'extend': parse_type_system_extension} +_parse_definition_functions: Dict[str, Callable] = { + **dict.fromkeys( + ("query", "mutation", "subscription", "fragment"), parse_executable_definition + ), + **dict.fromkeys( + ( + "schema", + "scalar", + "type", + "interface", + "union", + "enum", + "input", + "directive", + ), + parse_type_system_definition, + ), + "extend": parse_type_system_extension, +} def peek_description(lexer: Lexer) -> bool: @@ -527,57 +614,62 @@ def parse_description(lexer: Lexer) -> Optional[StringValueNode]: def parse_schema_definition(lexer: Lexer) -> SchemaDefinitionNode: """SchemaDefinition""" start = lexer.token - expect_keyword(lexer, 'schema') + expect_keyword(lexer, "schema") directives = parse_directives(lexer, True) operation_types = many_nodes( - lexer, TokenKind.BRACE_L, - parse_operation_type_definition, TokenKind.BRACE_R) + lexer, TokenKind.BRACE_L, parse_operation_type_definition, TokenKind.BRACE_R + ) return SchemaDefinitionNode( - directives=directives, operation_types=operation_types, - loc=loc(lexer, start)) + directives=directives, operation_types=operation_types, loc=loc(lexer, start) + ) -def parse_operation_type_definition( - lexer: Lexer) -> OperationTypeDefinitionNode: +def parse_operation_type_definition(lexer: Lexer) -> OperationTypeDefinitionNode: """OperationTypeDefinition: OperationType : NamedType""" start = lexer.token operation = parse_operation_type(lexer) expect(lexer, TokenKind.COLON) type_ = parse_named_type(lexer) return OperationTypeDefinitionNode( - operation=operation, type=type_, loc=loc(lexer, start)) + operation=operation, type=type_, loc=loc(lexer, start) + ) def parse_scalar_type_definition(lexer: Lexer) -> ScalarTypeDefinitionNode: """ScalarTypeDefinition: Description? scalar Name Directives[Const]?""" start = lexer.token description = parse_description(lexer) - expect_keyword(lexer, 'scalar') + expect_keyword(lexer, "scalar") name = parse_name(lexer) directives = parse_directives(lexer, True) return ScalarTypeDefinitionNode( - description=description, name=name, directives=directives, - loc=loc(lexer, start)) + description=description, name=name, directives=directives, loc=loc(lexer, start) + ) def parse_object_type_definition(lexer: Lexer) -> ObjectTypeDefinitionNode: """ObjectTypeDefinition""" start = lexer.token description = parse_description(lexer) - expect_keyword(lexer, 'type') + expect_keyword(lexer, "type") name = parse_name(lexer) interfaces = parse_implements_interfaces(lexer) directives = parse_directives(lexer, True) fields = parse_fields_definition(lexer) return ObjectTypeDefinitionNode( - description=description, name=name, interfaces=interfaces, - directives=directives, fields=fields, loc=loc(lexer, start)) + description=description, + name=name, + interfaces=interfaces, + directives=directives, + fields=fields, + loc=loc(lexer, start), + ) def parse_implements_interfaces(lexer: Lexer) -> List[NamedTypeNode]: """ImplementsInterfaces""" types: List[NamedTypeNode] = [] - if lexer.token.value == 'implements': + if lexer.token.value == "implements": lexer.advance() # optional leading ampersand skip(lexer, TokenKind.AMP) @@ -591,9 +683,16 @@ def parse_implements_interfaces(lexer: Lexer) -> List[NamedTypeNode]: def parse_fields_definition(lexer: Lexer) -> List[FieldDefinitionNode]: """FieldsDefinition: {FieldDefinition+}""" - return cast(List[FieldDefinitionNode], many_nodes( - lexer, TokenKind.BRACE_L, parse_field_definition, - TokenKind.BRACE_R)) if peek(lexer, TokenKind.BRACE_L) else [] + return ( + cast( + List[FieldDefinitionNode], + many_nodes( + lexer, TokenKind.BRACE_L, parse_field_definition, TokenKind.BRACE_R + ), + ) + if peek(lexer, TokenKind.BRACE_L) + else [] + ) def parse_field_definition(lexer: Lexer) -> FieldDefinitionNode: @@ -606,15 +705,27 @@ def parse_field_definition(lexer: Lexer) -> FieldDefinitionNode: type_ = parse_type_reference(lexer) directives = parse_directives(lexer, True) return FieldDefinitionNode( - description=description, name=name, arguments=args, type=type_, - directives=directives, loc=loc(lexer, start)) + description=description, + name=name, + arguments=args, + type=type_, + directives=directives, + loc=loc(lexer, start), + ) def parse_argument_defs(lexer: Lexer) -> List[InputValueDefinitionNode]: """ArgumentsDefinition: (InputValueDefinition+)""" - return cast(List[InputValueDefinitionNode], many_nodes( - lexer, TokenKind.PAREN_L, parse_input_value_def, - TokenKind.PAREN_R)) if peek(lexer, TokenKind.PAREN_L) else [] + return ( + cast( + List[InputValueDefinitionNode], + many_nodes( + lexer, TokenKind.PAREN_L, parse_input_value_def, TokenKind.PAREN_R + ), + ) + if peek(lexer, TokenKind.PAREN_L) + else [] + ) def parse_input_value_def(lexer: Lexer) -> InputValueDefinitionNode: @@ -624,40 +735,50 @@ def parse_input_value_def(lexer: Lexer) -> InputValueDefinitionNode: name = parse_name(lexer) expect(lexer, TokenKind.COLON) type_ = parse_type_reference(lexer) - default_value = parse_const_value(lexer) if skip( - lexer, TokenKind.EQUALS) else None + default_value = parse_const_value(lexer) if skip(lexer, TokenKind.EQUALS) else None directives = parse_directives(lexer, True) return InputValueDefinitionNode( - description=description, name=name, type=type_, - default_value=default_value, directives=directives, - loc=loc(lexer, start)) + description=description, + name=name, + type=type_, + default_value=default_value, + directives=directives, + loc=loc(lexer, start), + ) -def parse_interface_type_definition( - lexer: Lexer) -> InterfaceTypeDefinitionNode: +def parse_interface_type_definition(lexer: Lexer) -> InterfaceTypeDefinitionNode: """InterfaceTypeDefinition""" start = lexer.token description = parse_description(lexer) - expect_keyword(lexer, 'interface') + expect_keyword(lexer, "interface") name = parse_name(lexer) directives = parse_directives(lexer, True) fields = parse_fields_definition(lexer) return InterfaceTypeDefinitionNode( - description=description, name=name, directives=directives, - fields=fields, loc=loc(lexer, start)) + description=description, + name=name, + directives=directives, + fields=fields, + loc=loc(lexer, start), + ) def parse_union_type_definition(lexer: Lexer) -> UnionTypeDefinitionNode: """UnionTypeDefinition""" start = lexer.token description = parse_description(lexer) - expect_keyword(lexer, 'union') + expect_keyword(lexer, "union") name = parse_name(lexer) directives = parse_directives(lexer, True) types = parse_union_member_types(lexer) return UnionTypeDefinitionNode( - description=description, name=name, directives=directives, types=types, - loc=loc(lexer, start)) + description=description, + name=name, + directives=directives, + types=types, + loc=loc(lexer, start), + ) def parse_union_member_types(lexer: Lexer) -> List[NamedTypeNode]: @@ -678,21 +799,31 @@ def parse_enum_type_definition(lexer: Lexer) -> EnumTypeDefinitionNode: """UnionTypeDefinition""" start = lexer.token description = parse_description(lexer) - expect_keyword(lexer, 'enum') + expect_keyword(lexer, "enum") name = parse_name(lexer) directives = parse_directives(lexer, True) values = parse_enum_values_definition(lexer) return EnumTypeDefinitionNode( - description=description, name=name, directives=directives, - values=values, loc=loc(lexer, start)) + description=description, + name=name, + directives=directives, + values=values, + loc=loc(lexer, start), + ) -def parse_enum_values_definition( - lexer: Lexer) -> List[EnumValueDefinitionNode]: +def parse_enum_values_definition(lexer: Lexer) -> List[EnumValueDefinitionNode]: """EnumValuesDefinition: {EnumValueDefinition+}""" - return cast(List[EnumValueDefinitionNode], many_nodes( - lexer, TokenKind.BRACE_L, parse_enum_value_definition, - TokenKind.BRACE_R)) if peek(lexer, TokenKind.BRACE_L) else [] + return ( + cast( + List[EnumValueDefinitionNode], + many_nodes( + lexer, TokenKind.BRACE_L, parse_enum_value_definition, TokenKind.BRACE_R + ), + ) + if peek(lexer, TokenKind.BRACE_L) + else [] + ) def parse_enum_value_definition(lexer: Lexer) -> EnumValueDefinitionNode: @@ -702,66 +833,80 @@ def parse_enum_value_definition(lexer: Lexer) -> EnumValueDefinitionNode: name = parse_name(lexer) directives = parse_directives(lexer, True) return EnumValueDefinitionNode( - description=description, name=name, directives=directives, - loc=loc(lexer, start)) + description=description, name=name, directives=directives, loc=loc(lexer, start) + ) -def parse_input_object_type_definition( - lexer: Lexer) -> InputObjectTypeDefinitionNode: +def parse_input_object_type_definition(lexer: Lexer) -> InputObjectTypeDefinitionNode: """InputObjectTypeDefinition""" start = lexer.token description = parse_description(lexer) - expect_keyword(lexer, 'input') + expect_keyword(lexer, "input") name = parse_name(lexer) directives = parse_directives(lexer, True) fields = parse_input_fields_definition(lexer) return InputObjectTypeDefinitionNode( - description=description, name=name, directives=directives, - fields=fields, loc=loc(lexer, start)) + description=description, + name=name, + directives=directives, + fields=fields, + loc=loc(lexer, start), + ) -def parse_input_fields_definition( - lexer: Lexer) -> List[InputValueDefinitionNode]: +def parse_input_fields_definition(lexer: Lexer) -> List[InputValueDefinitionNode]: """InputFieldsDefinition: {InputValueDefinition+}""" - return cast(List[InputValueDefinitionNode], many_nodes( - lexer, TokenKind.BRACE_L, parse_input_value_def, - TokenKind.BRACE_R)) if peek(lexer, TokenKind.BRACE_L) else [] + return ( + cast( + List[InputValueDefinitionNode], + many_nodes( + lexer, TokenKind.BRACE_L, parse_input_value_def, TokenKind.BRACE_R + ), + ) + if peek(lexer, TokenKind.BRACE_L) + else [] + ) def parse_schema_extension(lexer: Lexer) -> SchemaExtensionNode: """SchemaExtension""" start = lexer.token - expect_keyword(lexer, 'extend') - expect_keyword(lexer, 'schema') + expect_keyword(lexer, "extend") + expect_keyword(lexer, "schema") directives = parse_directives(lexer, True) - operation_types = many_nodes( - lexer, TokenKind.BRACE_L, parse_operation_type_definition, - TokenKind.BRACE_R) if peek(lexer, TokenKind.BRACE_L) else [] + operation_types = ( + many_nodes( + lexer, TokenKind.BRACE_L, parse_operation_type_definition, TokenKind.BRACE_R + ) + if peek(lexer, TokenKind.BRACE_L) + else [] + ) if not directives and not operation_types: raise unexpected(lexer) return SchemaExtensionNode( - directives=directives, operation_types=operation_types, - loc=loc(lexer, start)) + directives=directives, operation_types=operation_types, loc=loc(lexer, start) + ) def parse_scalar_type_extension(lexer: Lexer) -> ScalarTypeExtensionNode: """ScalarTypeExtension""" start = lexer.token - expect_keyword(lexer, 'extend') - expect_keyword(lexer, 'scalar') + expect_keyword(lexer, "extend") + expect_keyword(lexer, "scalar") name = parse_name(lexer) directives = parse_directives(lexer, True) if not directives: raise unexpected(lexer) return ScalarTypeExtensionNode( - name=name, directives=directives, loc=loc(lexer, start)) + name=name, directives=directives, loc=loc(lexer, start) + ) def parse_object_type_extension(lexer: Lexer) -> ObjectTypeExtensionNode: """ObjectTypeExtension""" start = lexer.token - expect_keyword(lexer, 'extend') - expect_keyword(lexer, 'type') + expect_keyword(lexer, "extend") + expect_keyword(lexer, "type") name = parse_name(lexer) interfaces = parse_implements_interfaces(lexer) directives = parse_directives(lexer, True) @@ -769,76 +914,84 @@ def parse_object_type_extension(lexer: Lexer) -> ObjectTypeExtensionNode: if not (interfaces or directives or fields): raise unexpected(lexer) return ObjectTypeExtensionNode( - name=name, interfaces=interfaces, directives=directives, fields=fields, - loc=loc(lexer, start)) + name=name, + interfaces=interfaces, + directives=directives, + fields=fields, + loc=loc(lexer, start), + ) def parse_interface_type_extension(lexer: Lexer) -> InterfaceTypeExtensionNode: """InterfaceTypeExtension""" start = lexer.token - expect_keyword(lexer, 'extend') - expect_keyword(lexer, 'interface') + expect_keyword(lexer, "extend") + expect_keyword(lexer, "interface") name = parse_name(lexer) directives = parse_directives(lexer, True) fields = parse_fields_definition(lexer) if not (directives or fields): raise unexpected(lexer) return InterfaceTypeExtensionNode( - name=name, directives=directives, fields=fields, loc=loc(lexer, start)) + name=name, directives=directives, fields=fields, loc=loc(lexer, start) + ) def parse_union_type_extension(lexer: Lexer) -> UnionTypeExtensionNode: """UnionTypeExtension""" start = lexer.token - expect_keyword(lexer, 'extend') - expect_keyword(lexer, 'union') + expect_keyword(lexer, "extend") + expect_keyword(lexer, "union") name = parse_name(lexer) directives = parse_directives(lexer, True) types = parse_union_member_types(lexer) if not (directives or types): raise unexpected(lexer) return UnionTypeExtensionNode( - name=name, directives=directives, types=types, loc=loc(lexer, start)) + name=name, directives=directives, types=types, loc=loc(lexer, start) + ) def parse_enum_type_extension(lexer: Lexer) -> EnumTypeExtensionNode: """EnumTypeExtension""" start = lexer.token - expect_keyword(lexer, 'extend') - expect_keyword(lexer, 'enum') + expect_keyword(lexer, "extend") + expect_keyword(lexer, "enum") name = parse_name(lexer) directives = parse_directives(lexer, True) values = parse_enum_values_definition(lexer) if not (directives or values): raise unexpected(lexer) return EnumTypeExtensionNode( - name=name, directives=directives, values=values, loc=loc(lexer, start)) + name=name, directives=directives, values=values, loc=loc(lexer, start) + ) -def parse_input_object_type_extension( - lexer: Lexer) -> InputObjectTypeExtensionNode: +def parse_input_object_type_extension(lexer: Lexer) -> InputObjectTypeExtensionNode: """InputObjectTypeExtension""" start = lexer.token - expect_keyword(lexer, 'extend') - expect_keyword(lexer, 'input') + expect_keyword(lexer, "extend") + expect_keyword(lexer, "input") name = parse_name(lexer) directives = parse_directives(lexer, True) fields = parse_input_fields_definition(lexer) if not (directives or fields): raise unexpected(lexer) return InputObjectTypeExtensionNode( - name=name, directives=directives, fields=fields, loc=loc(lexer, start)) + name=name, directives=directives, fields=fields, loc=loc(lexer, start) + ) _parse_type_extension_functions: Dict[ - str, Callable[[Lexer], TypeSystemExtensionNode]] = { - 'schema': parse_schema_extension, - 'scalar': parse_scalar_type_extension, - 'type': parse_object_type_extension, - 'interface': parse_interface_type_extension, - 'union': parse_union_type_extension, - 'enum': parse_enum_type_extension, - 'input': parse_input_object_type_extension + str, Callable[[Lexer], TypeSystemExtensionNode] +] = { + "schema": parse_schema_extension, + "scalar": parse_scalar_type_extension, + "type": parse_object_type_extension, + "interface": parse_interface_type_extension, + "union": parse_union_type_extension, + "enum": parse_enum_type_extension, + "input": parse_input_object_type_extension, } @@ -846,26 +999,30 @@ def parse_directive_definition(lexer: Lexer) -> DirectiveDefinitionNode: """InputObjectTypeExtension""" start = lexer.token description = parse_description(lexer) - expect_keyword(lexer, 'directive') + expect_keyword(lexer, "directive") expect(lexer, TokenKind.AT) name = parse_name(lexer) args = parse_argument_defs(lexer) - expect_keyword(lexer, 'on') + expect_keyword(lexer, "on") locations = parse_directive_locations(lexer) return DirectiveDefinitionNode( - description=description, name=name, arguments=args, - locations=locations, loc=loc(lexer, start)) + description=description, + name=name, + arguments=args, + locations=locations, + loc=loc(lexer, start), + ) _parse_type_system_definition_functions = { - 'schema': parse_schema_definition, - 'scalar': parse_scalar_type_definition, - 'type': parse_object_type_definition, - 'interface': parse_interface_type_definition, - 'union': parse_union_type_definition, - 'enum': parse_enum_type_definition, - 'input': parse_input_object_type_definition, - 'directive': parse_directive_definition + "schema": parse_schema_definition, + "scalar": parse_scalar_type_definition, + "type": parse_object_type_definition, + "interface": parse_interface_type_definition, + "union": parse_union_type_definition, + "enum": parse_enum_type_definition, + "input": parse_input_object_type_definition, + "directive": parse_directive_definition, } @@ -893,6 +1050,7 @@ def parse_directive_location(lexer: Lexer) -> NameNode: # Core parsing utility functions + def loc(lexer: Lexer, start_token: Token) -> Optional[Location]: """Return a location object. @@ -903,7 +1061,8 @@ def loc(lexer: Lexer, start_token: Token) -> Optional[Location]: end_token = lexer.last_token source = lexer.source return Location( - start_token.start, end_token.end, start_token, end_token, source) + start_token.start, end_token.end, start_token, end_token, source + ) return None @@ -935,8 +1094,8 @@ def expect(lexer: Lexer, kind: TokenKind) -> Token: lexer.advance() return token raise GraphQLSyntaxError( - lexer.source, token.start, - f'Expected {kind.value}, found {token.kind.value}') + lexer.source, token.start, f"Expected {kind.value}, found {token.kind.value}" + ) def expect_keyword(lexer: Lexer, value: str) -> Token: @@ -951,20 +1110,22 @@ def expect_keyword(lexer: Lexer, value: str) -> Token: lexer.advance() return token raise GraphQLSyntaxError( - lexer.source, token.start, - f'Expected {value!r}, found {token.desc}') + lexer.source, token.start, f"Expected {value!r}, found {token.desc}" + ) -def unexpected(lexer: Lexer, at_token: Token=None) -> GraphQLError: +def unexpected(lexer: Lexer, at_token: Token = None) -> GraphQLError: """Create an error when an unexpected lexed token is encountered.""" token = at_token or lexer.token - return GraphQLSyntaxError( - lexer.source, token.start, f'Unexpected {token.desc}') + return GraphQLSyntaxError(lexer.source, token.start, f"Unexpected {token.desc}") -def any_nodes(lexer: Lexer, open_kind: TokenKind, - parse_fn: Callable[[Lexer], Node], - close_kind: TokenKind) -> List[Node]: +def any_nodes( + lexer: Lexer, + open_kind: TokenKind, + parse_fn: Callable[[Lexer], Node], + close_kind: TokenKind, +) -> List[Node]: """Fetch any matching nodes, possibly none. Returns a possibly empty list of parse nodes, determined by the `parse_fn`. @@ -980,9 +1141,12 @@ def any_nodes(lexer: Lexer, open_kind: TokenKind, return nodes -def many_nodes(lexer: Lexer, open_kind: TokenKind, - parse_fn: Callable[[Lexer], Node], - close_kind: TokenKind) -> List[Node]: +def many_nodes( + lexer: Lexer, + open_kind: TokenKind, + parse_fn: Callable[[Lexer], Node], + close_kind: TokenKind, +) -> List[Node]: """Fetch matching nodes, at least one. Returns a non-empty list of parse nodes, determined by the `parse_fn`. diff --git a/graphql/language/predicates.py b/graphql/language/predicates.py index c399652b..db3c8552 100644 --- a/graphql/language/predicates.py +++ b/graphql/language/predicates.py @@ -1,13 +1,27 @@ from .ast import ( - Node, DefinitionNode, ExecutableDefinitionNode, SchemaExtensionNode, - SelectionNode, TypeDefinitionNode, TypeExtensionNode, TypeNode, - TypeSystemDefinitionNode, ValueNode) + Node, + DefinitionNode, + ExecutableDefinitionNode, + SchemaExtensionNode, + SelectionNode, + TypeDefinitionNode, + TypeExtensionNode, + TypeNode, + TypeSystemDefinitionNode, + ValueNode, +) __all__ = [ - 'is_definition_node', 'is_executable_definition_node', - 'is_selection_node', 'is_value_node', 'is_type_node', - 'is_type_system_definition_node', 'is_type_definition_node', - 'is_type_system_extension_node', 'is_type_extension_node'] + "is_definition_node", + "is_executable_definition_node", + "is_selection_node", + "is_value_node", + "is_type_node", + "is_type_system_definition_node", + "is_type_definition_node", + "is_type_system_extension_node", + "is_type_extension_node", +] def is_definition_node(node: Node) -> bool: diff --git a/graphql/language/printer.py b/graphql/language/printer.py index 7ab71d58..db37673d 100644 --- a/graphql/language/printer.py +++ b/graphql/language/printer.py @@ -5,7 +5,7 @@ from .ast import Node, OperationType from .visitor import visit, Visitor -__all__ = ['print_ast'] +__all__ = ["print_ast"] def print_ast(ast: Node): @@ -18,52 +18,63 @@ def print_ast(ast: Node): def add_description(method): """Decorator adding the description to the output of a visitor method.""" + @wraps(method) def wrapped(self, node, *args): - return join([node.description, method(self, node, *args)], '\n') + return join([node.description, method(self, node, *args)], "\n") + return wrapped # noinspection PyMethodMayBeStatic class PrintAstVisitor(Visitor): - def leave_name(self, node, *_args): return node.value def leave_variable(self, node, *_args): - return f'${node.name}' + return f"${node.name}" # Document def leave_document(self, node, *_args): - return join(node.definitions, '\n\n') + '\n' + return join(node.definitions, "\n\n") + "\n" def leave_operation_definition(self, node, *_args): name, op, selection_set = node.name, node.operation, node.selection_set - var_defs = wrap('(', join(node.variable_definitions, ', '), ')') - directives = join(node.directives, ' ') + var_defs = wrap("(", join(node.variable_definitions, ", "), ")") + directives = join(node.directives, " ") # Anonymous queries with no directives or variable definitions can use # the query short form. - return join([op.value, join([name, var_defs]), - directives, selection_set], ' ') if ( - name or directives or var_defs or op != OperationType.QUERY - ) else selection_set + return ( + join([op.value, join([name, var_defs]), directives, selection_set], " ") + if (name or directives or var_defs or op != OperationType.QUERY) + else selection_set + ) def leave_variable_definition(self, node, *_args): - return (f"{node.variable}: {node.type}" - f"{wrap(' = ', node.default_value)}" - f"{wrap(' ', join(node.directives, ' '))}") + return ( + f"{node.variable}: {node.type}" + f"{wrap(' = ', node.default_value)}" + f"{wrap(' ', join(node.directives, ' '))}" + ) def leave_selection_set(self, node, *_args): return block(node.selections) def leave_field(self, node, *_args): - return join([wrap('', node.alias, ': ') + node.name + - wrap('(', join(node.arguments, ', '), ')'), - join(node.directives, ' '), node.selection_set], ' ') + return join( + [ + wrap("", node.alias, ": ") + + node.name + + wrap("(", join(node.arguments, ", "), ")"), + join(node.directives, " "), + node.selection_set, + ], + " ", + ) def leave_argument(self, node, *_args): - return f'{node.name}: {node.value}' + return f"{node.name}: {node.value}" # Fragments @@ -71,17 +82,26 @@ def leave_fragment_spread(self, node, *_args): return f"...{node.name}{wrap(' ', join(node.directives, ' '))}" def leave_inline_fragment(self, node, *_args): - return join(['...', wrap('on ', node.type_condition), - join(node.directives, ' '), node.selection_set], ' ') + return join( + [ + "...", + wrap("on ", node.type_condition), + join(node.directives, " "), + node.selection_set, + ], + " ", + ) def leave_fragment_definition(self, node, *_args): # Note: fragment variable definitions are experimental and may b # changed or removed in the future. - return (f'fragment {node.name}' - f"{wrap('(', join(node.variable_definitions, ', '), ')')}" - f" on {node.type_condition}" - f" {wrap('', join(node.directives, ' '), ' ')}" - f'{node.selection_set}') + return ( + f"fragment {node.name}" + f"{wrap('(', join(node.variable_definitions, ', '), ')')}" + f" on {node.type_condition}" + f" {wrap('', join(node.directives, ' '), ' ')}" + f"{node.selection_set}" + ) # Value @@ -93,14 +113,14 @@ def leave_float_value(self, node, *_args): def leave_string_value(self, node, key, *_args): if node.block: - return print_block_string(node.value, key == 'description') + return print_block_string(node.value, key == "description") return dumps(node.value) def leave_boolean_value(self, node, *_args): - return 'true' if node.value else 'false' + return "true" if node.value else "false" def leave_null_value(self, _node, *_args): - return 'null' + return "null" def leave_enum_value(self, node, *_args): return node.value @@ -112,7 +132,7 @@ def leave_object_value(self, node, *_args): return f"{{{join(node.fields, ', ')}}}" def leave_object_field(self, node, *_args): - return f'{node.name}: {node.value}' + return f"{node.name}: {node.value}" # Directive @@ -125,109 +145,163 @@ def leave_named_type(self, node, *_args): return node.name def leave_list_type(self, node, *_args): - return f'[{node.type}]' + return f"[{node.type}]" def leave_non_null_type(self, node, *_args): - return f'{node.type}!' + return f"{node.type}!" # Type System Definitions def leave_schema_definition(self, node, *_args): - return join(['schema', join(node.directives, ' '), - block(node.operation_types)], ' ') + return join( + ["schema", join(node.directives, " "), block(node.operation_types)], " " + ) def leave_operation_type_definition(self, node, *_args): - return f'{node.operation.value}: {node.type}' + return f"{node.operation.value}: {node.type}" @add_description def leave_scalar_type_definition(self, node, *_args): - return join(['scalar', node.name, join(node.directives, ' ')], ' ') + return join(["scalar", node.name, join(node.directives, " ")], " ") @add_description def leave_object_type_definition(self, node, *_args): - return join(['type', node.name, wrap('implements ', - join(node.interfaces, ' & ')), - join(node.directives, ' '), block(node.fields)], ' ') + return join( + [ + "type", + node.name, + wrap("implements ", join(node.interfaces, " & ")), + join(node.directives, " "), + block(node.fields), + ], + " ", + ) @add_description def leave_field_definition(self, node, *_args): args = node.arguments - args = (wrap('(\n', indent(join(args, '\n')), '\n)') - if any('\n' in arg for arg in args) - else wrap('(', join(args, ', '), ')')) - directives = wrap(' ', join(node.directives, ' ')) + args = ( + wrap("(\n", indent(join(args, "\n")), "\n)") + if any("\n" in arg for arg in args) + else wrap("(", join(args, ", "), ")") + ) + directives = wrap(" ", join(node.directives, " ")) return f"{node.name}{args}: {node.type}{directives}" @add_description def leave_input_value_definition(self, node, *_args): - return join([f'{node.name}: {node.type}', - wrap('= ', node.default_value), - join(node.directives, ' ')], ' ') + return join( + [ + f"{node.name}: {node.type}", + wrap("= ", node.default_value), + join(node.directives, " "), + ], + " ", + ) @add_description def leave_interface_type_definition(self, node, *_args): - return join(['interface', node.name, - join(node.directives, ' '), block(node.fields)], ' ') + return join( + ["interface", node.name, join(node.directives, " "), block(node.fields)], + " ", + ) @add_description def leave_union_type_definition(self, node, *_args): - return join(['union', node.name, join(node.directives, ' '), - '= ' + join(node.types, ' | ') if node.types else ''], ' ') + return join( + [ + "union", + node.name, + join(node.directives, " "), + "= " + join(node.types, " | ") if node.types else "", + ], + " ", + ) @add_description def leave_enum_type_definition(self, node, *_args): - return join(['enum', node.name, join(node.directives, ' '), - block(node.values)], ' ') + return join( + ["enum", node.name, join(node.directives, " "), block(node.values)], " " + ) @add_description def leave_enum_value_definition(self, node, *_args): - return join([node.name, join(node.directives, ' ')], ' ') + return join([node.name, join(node.directives, " ")], " ") @add_description def leave_input_object_type_definition(self, node, *_args): - return join(['input', node.name, join(node.directives, ' '), - block(node.fields)], ' ') + return join( + ["input", node.name, join(node.directives, " "), block(node.fields)], " " + ) @add_description def leave_directive_definition(self, node, *_args): args = node.arguments - args = (wrap('(\n', indent(join(args, '\n')), '\n)') - if any('\n' in arg for arg in args) - else wrap('(', join(args, ', '), ')')) - locations = join(node.locations, ' | ') - return f'directive @{node.name}{args} on {locations}' + args = ( + wrap("(\n", indent(join(args, "\n")), "\n)") + if any("\n" in arg for arg in args) + else wrap("(", join(args, ", "), ")") + ) + locations = join(node.locations, " | ") + return f"directive @{node.name}{args} on {locations}" def leave_schema_extension(self, node, *_args): - return join(['extend schema', join(node.directives, ' '), - block(node.operation_types)], ' ') + return join( + ["extend schema", join(node.directives, " "), block(node.operation_types)], + " ", + ) def leave_scalar_type_extension(self, node, *_args): - return join(['extend scalar', node.name, join(node.directives, ' ')], - ' ') + return join(["extend scalar", node.name, join(node.directives, " ")], " ") def leave_object_type_extension(self, node, *_args): - return join(['extend type', node.name, - wrap('implements ', join(node.interfaces, ' & ')), - join(node.directives, ' '), block(node.fields)], ' ') + return join( + [ + "extend type", + node.name, + wrap("implements ", join(node.interfaces, " & ")), + join(node.directives, " "), + block(node.fields), + ], + " ", + ) def leave_interface_type_extension(self, node, *_args): - return join(['extend interface', node.name, join(node.directives, ' '), - block(node.fields)], ' ') + return join( + [ + "extend interface", + node.name, + join(node.directives, " "), + block(node.fields), + ], + " ", + ) def leave_union_type_extension(self, node, *_args): - return join(['extend union', node.name, join(node.directives, ' '), - '= ' + join(node.types, ' | ') if node.types else ''], ' ') + return join( + [ + "extend union", + node.name, + join(node.directives, " "), + "= " + join(node.types, " | ") if node.types else "", + ], + " ", + ) def leave_enum_type_extension(self, node, *_args): - return join(['extend enum', node.name, join(node.directives, ' '), - block(node.values)], ' ') + return join( + ["extend enum", node.name, join(node.directives, " "), block(node.values)], + " ", + ) def leave_input_object_type_extension(self, node, *_args): - return join(['extend input', node.name, join(node.directives, ' '), - block(node.fields)], ' ') + return join( + ["extend input", node.name, join(node.directives, " "), block(node.fields)], + " ", + ) -def print_block_string(value: str, is_description: bool=False) -> str: +def print_block_string(value: str, is_description: bool = False) -> str: """Print a block string. Prints a block string in the indented block form by adding a leading and @@ -235,9 +309,9 @@ def print_block_string(value: str, is_description: bool=False) -> str: is a single-line, adding a leading blank line would strip that whitespace. """ escaped = value.replace('"""', '\\"""') - if value.startswith((' ', '\t')) and '\n' not in value: + if value.startswith((" ", "\t")) and "\n" not in value: if escaped.endswith('"'): - escaped += '\n' + escaped += "\n" return f'"""{escaped}"""' else: if not is_description: @@ -245,13 +319,13 @@ def print_block_string(value: str, is_description: bool=False) -> str: return f'"""\n{escaped}\n"""' -def join(strings: Optional[Sequence[str]], separator: str='') -> str: +def join(strings: Optional[Sequence[str]], separator: str = "") -> str: """Join strings in a given sequence. Return an empty string if it is None or empty, otherwise join all items together separated by separator if provided. """ - return separator.join(s for s in strings if s) if strings else '' + return separator.join(s for s in strings if s) if strings else "" def block(strings: Sequence[str]) -> str: @@ -260,16 +334,16 @@ def block(strings: Sequence[str]) -> str: Given a sequence of strings, return a string with each item on its own line, wrapped in an indented "{ }" block. """ - return '{\n' + indent(join(strings, '\n')) + '\n}' if strings else '' + return "{\n" + indent(join(strings, "\n")) + "\n}" if strings else "" -def wrap(start: str, string: str, end: str='') -> str: +def wrap(start: str, string: str, end: str = "") -> str: """Wrap string inside other strings at start and end. If the string is not None or empty, then wrap with start and end, otherwise return an empty string. """ - return f'{start}{string}{end}' if string else '' + return f"{start}{string}{end}" if string else "" def indent(string): @@ -278,4 +352,4 @@ def indent(string): If the string is not None or empty, add two spaces at the beginning of every line inside the string. """ - return ' ' + string.replace('\n', '\n ') if string else string + return " " + string.replace("\n", "\n ") if string else string diff --git a/graphql/language/source.py b/graphql/language/source.py index f2672fdc..1bc0356a 100644 --- a/graphql/language/source.py +++ b/graphql/language/source.py @@ -1,15 +1,16 @@ from .location import SourceLocation -__all__ = ['Source'] +__all__ = ["Source"] class Source: """A representation of source input to GraphQL.""" - __slots__ = 'body', 'name', 'location_offset' + __slots__ = "body", "name", "location_offset" - def __init__(self, body: str, name: str=None, - location_offset: SourceLocation=None) -> None: + def __init__( + self, body: str, name: str = None, location_offset: SourceLocation = None + ) -> None: """Initialize source input. @@ -22,7 +23,7 @@ def __init__(self, body: str, name: str=None, """ self.body = body - self.name = name or 'GraphQL request' + self.name = name or "GraphQL request" if not location_offset: location_offset = SourceLocation(1, 1) elif not isinstance(location_offset, SourceLocation): @@ -30,10 +31,12 @@ def __init__(self, body: str, name: str=None, location_offset = SourceLocation._make(location_offset) if location_offset.line <= 0: raise ValueError( - 'line in location_offset is 1-indexed and must be positive') + "line in location_offset is 1-indexed and must be positive" + ) if location_offset.column <= 0: raise ValueError( - 'column in location_offset is 1-indexed and must be positive') + "column in location_offset is 1-indexed and must be positive" + ) self.location_offset = location_offset def get_location(self, position: int) -> SourceLocation: diff --git a/graphql/language/visitor.py b/graphql/language/visitor.py index db5ff166..2adf45d5 100644 --- a/graphql/language/visitor.py +++ b/graphql/language/visitor.py @@ -1,6 +1,14 @@ from copy import copy from typing import ( - TYPE_CHECKING, Any, Callable, List, NamedTuple, Sequence, Tuple, Union) + TYPE_CHECKING, + Any, + Callable, + List, + NamedTuple, + Sequence, + Tuple, + Union, +) from ..pyutils import snake_to_camel from . import ast @@ -11,8 +19,15 @@ from ..utilities import TypeInfo # noqa: F401 __all__ = [ - 'Visitor', 'ParallelVisitor', 'TypeInfoVisitor', 'visit', - 'BREAK', 'SKIP', 'REMOVE', 'IDLE'] + "Visitor", + "ParallelVisitor", + "TypeInfoVisitor", + "visit", + "BREAK", + "SKIP", + "REMOVE", + "IDLE", +] # Special return values for the visitor function: @@ -22,67 +37,73 @@ # Default map from visitor kinds to their traversable node attributes: QUERY_DOCUMENT_KEYS = { - 'name': (), - - 'document': ('definitions',), - 'operation_definition': ( - 'name', 'variable_definitions', 'directives', 'selection_set'), - 'variable_definition': ('variable', 'type', 'default_value', 'directives'), - 'variable': ('name',), - 'selection_set': ('selections',), - 'field': ('alias', 'name', 'arguments', 'directives', 'selection_set'), - 'argument': ('name', 'value'), - - 'fragment_spread': ('name', 'directives'), - 'inline_fragment': ('type_condition', 'directives', 'selection_set'), - 'fragment_definition': ( + "name": (), + "document": ("definitions",), + "operation_definition": ( + "name", + "variable_definitions", + "directives", + "selection_set", + ), + "variable_definition": ("variable", "type", "default_value", "directives"), + "variable": ("name",), + "selection_set": ("selections",), + "field": ("alias", "name", "arguments", "directives", "selection_set"), + "argument": ("name", "value"), + "fragment_spread": ("name", "directives"), + "inline_fragment": ("type_condition", "directives", "selection_set"), + "fragment_definition": ( # Note: fragment variable definitions are experimental and may be # changed or removed in the future. - 'name', 'variable_definitions', - 'type_condition', 'directives', 'selection_set'), - 'int_value': (), - 'float_value': (), - 'string_value': (), - 'boolean_value': (), - 'enum_value': (), - 'list_value': ('values',), - 'object_value': ('fields',), - 'object_field': ('name', 'value'), - - 'directive': ('name', 'arguments'), - - 'named_type': ('name',), - 'list_type': ('type',), - 'non_null_type': ('type',), - - 'schema_definition': ('directives', 'operation_types',), - 'operation_type_definition': ('type',), - - 'scalar_type_definition': ('description', 'name', 'directives',), - 'object_type_definition': ( - 'description', 'name', 'interfaces', 'directives', 'fields'), - 'field_definition': ( - 'description', 'name', 'arguments', 'type', 'directives'), - 'input_value_definition': ( - 'description', 'name', 'type', 'default_value', 'directives'), - 'interface_type_definition': ( - 'description', 'name', 'directives', 'fields'), - 'union_type_definition': ('description', 'name', 'directives', 'types'), - 'enum_type_definition': ('description', 'name', 'directives', 'values'), - 'enum_value_definition': ('description', 'name', 'directives',), - 'input_object_type_definition': ( - 'description', 'name', 'directives', 'fields'), - - 'directive_definition': ('description', 'name', 'arguments', 'locations'), - - 'schema_extension': ('directives', 'operation_types'), - - 'scalar_type_extension': ('name', 'directives'), - 'object_type_extension': ('name', 'interfaces', 'directives', 'fields'), - 'interface_type_extension': ('name', 'directives', 'fields'), - 'union_type_extension': ('name', 'directives', 'types'), - 'enum_type_extension': ('name', 'directives', 'values'), - 'input_object_type_extension': ('name', 'directives', 'fields') + "name", + "variable_definitions", + "type_condition", + "directives", + "selection_set", + ), + "int_value": (), + "float_value": (), + "string_value": (), + "boolean_value": (), + "enum_value": (), + "list_value": ("values",), + "object_value": ("fields",), + "object_field": ("name", "value"), + "directive": ("name", "arguments"), + "named_type": ("name",), + "list_type": ("type",), + "non_null_type": ("type",), + "schema_definition": ("directives", "operation_types"), + "operation_type_definition": ("type",), + "scalar_type_definition": ("description", "name", "directives"), + "object_type_definition": ( + "description", + "name", + "interfaces", + "directives", + "fields", + ), + "field_definition": ("description", "name", "arguments", "type", "directives"), + "input_value_definition": ( + "description", + "name", + "type", + "default_value", + "directives", + ), + "interface_type_definition": ("description", "name", "directives", "fields"), + "union_type_definition": ("description", "name", "directives", "types"), + "enum_type_definition": ("description", "name", "directives", "values"), + "enum_value_definition": ("description", "name", "directives"), + "input_object_type_definition": ("description", "name", "directives", "fields"), + "directive_definition": ("description", "name", "arguments", "locations"), + "schema_extension": ("directives", "operation_types"), + "scalar_type_extension": ("name", "directives"), + "object_type_extension": ("name", "interfaces", "directives", "fields"), + "interface_type_extension": ("name", "directives", "fields"), + "union_type_extension": ("name", "directives", "types"), + "enum_type_extension": ("name", "directives", "values"), + "input_object_type_extension": ("name", "directives", "fields"), } @@ -137,25 +158,25 @@ def __init_subclass__(cls, **kwargs): """Verify that all defined handlers are valid.""" super().__init_subclass__(**kwargs) for attr, val in cls.__dict__.items(): - if attr.startswith('_'): + if attr.startswith("_"): continue - attr = attr.split('_', 1) + attr = attr.split("_", 1) attr, kind = attr if len(attr) > 1 else (attr[0], None) - if attr in ('enter', 'leave'): + if attr in ("enter", "leave"): if kind: - name = snake_to_camel(kind) + 'Node' + name = snake_to_camel(kind) + "Node" try: node_cls = getattr(ast, name) if not issubclass(node_cls, Node): raise AttributeError except AttributeError: - raise AttributeError(f'Invalid AST node kind: {kind}') + raise AttributeError(f"Invalid AST node kind: {kind}") @classmethod def get_visit_fn(cls, kind, is_leaving=False) -> Callable: """Get the visit function for the given node kind and direction.""" - method = 'leave' if is_leaving else 'enter' - visit_fn = getattr(cls, f'{method}_{kind}', None) + method = "leave" if is_leaving else "enter" + visit_fn = getattr(cls, f"{method}_{kind}", None) if not visit_fn: visit_fn = getattr(cls, method, None) return visit_fn @@ -192,9 +213,9 @@ def visit(root: Node, visitor: Visitor, visitor_keys=None) -> Node: a dictionary visitor_keys mapping node kinds to node attributes. """ if not isinstance(root, Node): - raise TypeError(f'Not an AST Node: {root!r}') + raise TypeError(f"Not an AST Node: {root!r}") if not isinstance(visitor, Visitor): - raise TypeError(f'Not an AST Visitor class: {visitor!r}') + raise TypeError(f"Not an AST Visitor class: {visitor!r}") if visitor_keys is None: visitor_keys = QUERY_DOCUMENT_KEYS stack: Any = None @@ -262,7 +283,7 @@ def visit(root: Node, visitor: Visitor, visitor_keys=None) -> Node: result = None else: if not isinstance(node, Node): - raise TypeError(f'Not an AST Node: {node!r}') + raise TypeError(f"Not an AST Node: {node!r}") visit_fn = visitor.get_visit_fn(node.kind, is_leaving) if visit_fn: result = visit_fn(visitor, node, key, parent, path, ancestors) @@ -356,7 +377,7 @@ def leave(self, node, *args): class TypeInfoVisitor(Visitor): """A visitor which maintains a provided TypeInfo.""" - def __init__(self, type_info: 'TypeInfo', visitor: Visitor) -> None: + def __init__(self, type_info: "TypeInfo", visitor: Visitor) -> None: self.type_info = type_info self.visitor = visitor diff --git a/graphql/pyutils/__init__.py b/graphql/pyutils/__init__.py index 17bbd760..9f74fa22 100644 --- a/graphql/pyutils/__init__.py +++ b/graphql/pyutils/__init__.py @@ -23,8 +23,19 @@ from .suggestion_list import suggestion_list __all__ = [ - 'camel_to_snake', 'snake_to_camel', 'cached_property', - 'contain_subset', 'dedent', - 'EventEmitter', 'EventEmitterAsyncIterator', - 'is_finite', 'is_integer', 'is_invalid', 'is_nullish', 'MaybeAwaitable', - 'or_list', 'quoted_or_list', 'suggestion_list'] + "camel_to_snake", + "snake_to_camel", + "cached_property", + "contain_subset", + "dedent", + "EventEmitter", + "EventEmitterAsyncIterator", + "is_finite", + "is_integer", + "is_invalid", + "is_nullish", + "MaybeAwaitable", + "or_list", + "quoted_or_list", + "suggestion_list", +] diff --git a/graphql/pyutils/cached_property.py b/graphql/pyutils/cached_property.py index 0727c194..bbf81d78 100644 --- a/graphql/pyutils/cached_property.py +++ b/graphql/pyutils/cached_property.py @@ -1,6 +1,6 @@ # Code taken from https://github.com/bottlepy/bottle -__all__ = ['cached_property'] +__all__ = ["cached_property"] class CachedProperty: @@ -11,7 +11,7 @@ class CachedProperty: """ def __init__(self, func): - self.__doc__ = getattr(func, '__doc__') + self.__doc__ = getattr(func, "__doc__") self.func = func def __get__(self, obj, cls): diff --git a/graphql/pyutils/contain_subset.py b/graphql/pyutils/contain_subset.py index 57bf5627..d18c4a4d 100644 --- a/graphql/pyutils/contain_subset.py +++ b/graphql/pyutils/contain_subset.py @@ -1,4 +1,4 @@ -__all__ = ['contain_subset'] +__all__ = ["contain_subset"] def contain_subset(actual, expected): @@ -11,8 +11,10 @@ def contain_subset(actual, expected): if isinstance(expected, list): if not isinstance(actual, list): return False - return all(any(contain_subset(actual_value, expected_value) - for actual_value in actual) for expected_value in expected) + return all( + any(contain_subset(actual_value, expected_value) for actual_value in actual) + for expected_value in expected + ) if not isinstance(expected, dict): return False if not isinstance(actual, dict): diff --git a/graphql/pyutils/convert_case.py b/graphql/pyutils/convert_case.py index 84cf0427..8a213f29 100644 --- a/graphql/pyutils/convert_case.py +++ b/graphql/pyutils/convert_case.py @@ -2,15 +2,15 @@ import re -__all__ = ['camel_to_snake', 'snake_to_camel'] +__all__ = ["camel_to_snake", "snake_to_camel"] -_re_camel_to_snake = re.compile(r'([a-z]|[A-Z]+)(?=[A-Z])') -_re_snake_to_camel = re.compile(r'(_)([a-z\d])') +_re_camel_to_snake = re.compile(r"([a-z]|[A-Z]+)(?=[A-Z])") +_re_snake_to_camel = re.compile(r"(_)([a-z\d])") def camel_to_snake(s): """Convert from CamelCase to snake_case""" - return _re_camel_to_snake.sub(r'\1_', s).lower() + return _re_camel_to_snake.sub(r"\1_", s).lower() def snake_to_camel(s, upper=True): diff --git a/graphql/pyutils/dedent.py b/graphql/pyutils/dedent.py index 977f88d4..99bb2cef 100644 --- a/graphql/pyutils/dedent.py +++ b/graphql/pyutils/dedent.py @@ -1,6 +1,6 @@ from textwrap import dedent as _dedent -__all__ = ['dedent'] +__all__ = ["dedent"] def dedent(text: str) -> str: @@ -9,4 +9,4 @@ def dedent(text: str) -> str: Also removes leading newlines and trailing spaces and tabs, but keeps trailing newlines. """ - return _dedent(text.lstrip('\n').rstrip(' \t')) + return _dedent(text.lstrip("\n").rstrip(" \t")) diff --git a/graphql/pyutils/event_emitter.py b/graphql/pyutils/event_emitter.py index 1a37ff93..4d0a07b0 100644 --- a/graphql/pyutils/event_emitter.py +++ b/graphql/pyutils/event_emitter.py @@ -5,13 +5,13 @@ from collections import defaultdict -__all__ = ['EventEmitter', 'EventEmitterAsyncIterator'] +__all__ = ["EventEmitter", "EventEmitterAsyncIterator"] class EventEmitter: """A very simple EventEmitter.""" - def __init__(self, loop: Optional[AbstractEventLoop]=None) -> None: + def __init__(self, loop: Optional[AbstractEventLoop] = None) -> None: self.loop = loop self.listeners: Dict[str, List[Callable]] = defaultdict(list) @@ -44,11 +44,11 @@ class EventEmitterAsyncIterator: """ def __init__(self, event_emitter: EventEmitter, event_name: str) -> None: - self.queue: Queue = Queue( - loop=cast(AbstractEventLoop, event_emitter.loop)) + self.queue: Queue = Queue(loop=cast(AbstractEventLoop, event_emitter.loop)) event_emitter.add_listener(event_name, self.queue.put) self.remove_listener = lambda: event_emitter.remove_listener( - event_name, self.queue.put) + event_name, self.queue.put + ) self.closed = False def __aiter__(self): diff --git a/graphql/pyutils/is_finite.py b/graphql/pyutils/is_finite.py index 77029382..132776c3 100644 --- a/graphql/pyutils/is_finite.py +++ b/graphql/pyutils/is_finite.py @@ -1,10 +1,9 @@ from typing import Any from math import isfinite -__all__ = ['is_finite'] +__all__ = ["is_finite"] def is_finite(value: Any) -> bool: """Return true if a value is a finite number.""" - return isinstance(value, int) or ( - isinstance(value, float) and isfinite(value)) + return isinstance(value, int) or (isinstance(value, float) and isfinite(value)) diff --git a/graphql/pyutils/is_integer.py b/graphql/pyutils/is_integer.py index 3f07e2b7..af8bef56 100644 --- a/graphql/pyutils/is_integer.py +++ b/graphql/pyutils/is_integer.py @@ -1,10 +1,11 @@ from typing import Any from math import isfinite -__all__ = ['is_integer'] +__all__ = ["is_integer"] def is_integer(value: Any) -> bool: """Return true if a value is an integer number.""" return (isinstance(value, int) and not isinstance(value, bool)) or ( - isinstance(value, float) and isfinite(value) and int(value) == value) + isinstance(value, float) and isfinite(value) and int(value) == value + ) diff --git a/graphql/pyutils/is_invalid.py b/graphql/pyutils/is_invalid.py index ed9d509e..efe9cdf6 100644 --- a/graphql/pyutils/is_invalid.py +++ b/graphql/pyutils/is_invalid.py @@ -2,7 +2,7 @@ from ..error import INVALID -__all__ = ['is_invalid'] +__all__ = ["is_invalid"] def is_invalid(value: Any) -> bool: diff --git a/graphql/pyutils/is_nullish.py b/graphql/pyutils/is_nullish.py index 650a2504..3e4f2a0d 100644 --- a/graphql/pyutils/is_nullish.py +++ b/graphql/pyutils/is_nullish.py @@ -2,7 +2,7 @@ from ..error import INVALID -__all__ = ['is_nullish'] +__all__ = ["is_nullish"] def is_nullish(value: Any) -> bool: diff --git a/graphql/pyutils/maybe_awaitable.py b/graphql/pyutils/maybe_awaitable.py index 0adab473..6c1dc49e 100644 --- a/graphql/pyutils/maybe_awaitable.py +++ b/graphql/pyutils/maybe_awaitable.py @@ -1,8 +1,8 @@ from typing import Awaitable, TypeVar, Union -__all__ = ['MaybeAwaitable'] +__all__ = ["MaybeAwaitable"] -T = TypeVar('T') +T = TypeVar("T") MaybeAwaitable = Union[Awaitable[T], T] diff --git a/graphql/pyutils/or_list.py b/graphql/pyutils/or_list.py index 6ddacf96..4a65353c 100644 --- a/graphql/pyutils/or_list.py +++ b/graphql/pyutils/or_list.py @@ -1,6 +1,6 @@ from typing import Optional, Sequence -__all__ = ['or_list'] +__all__ = ["or_list"] MAX_LENGTH = 5 @@ -9,8 +9,8 @@ def or_list(items: Sequence[str]) -> Optional[str]: """Given [A, B, C] return 'A, B, or C'.""" if not items: - raise TypeError('List must not be empty') + raise TypeError("List must not be empty") if len(items) == 1: return items[0] selected = items[:MAX_LENGTH] - return ', '.join(selected[:-1]) + ' or ' + selected[-1] + return ", ".join(selected[:-1]) + " or " + selected[-1] diff --git a/graphql/pyutils/quoted_or_list.py b/graphql/pyutils/quoted_or_list.py index 731f6afd..339cc0bf 100644 --- a/graphql/pyutils/quoted_or_list.py +++ b/graphql/pyutils/quoted_or_list.py @@ -2,7 +2,7 @@ from .or_list import or_list -__all__ = ['quoted_or_list'] +__all__ = ["quoted_or_list"] def quoted_or_list(items: List[str]) -> Optional[str]: diff --git a/graphql/pyutils/suggestion_list.py b/graphql/pyutils/suggestion_list.py index ccb8025e..b61b7a15 100644 --- a/graphql/pyutils/suggestion_list.py +++ b/graphql/pyutils/suggestion_list.py @@ -1,6 +1,6 @@ from typing import Collection -__all__ = ['suggestion_list'] +__all__ = ["suggestion_list"] def suggestion_list(input_: str, options: Collection[str]): @@ -49,14 +49,9 @@ def lexical_distance(a_str: str, b_str: str) -> int: for j in range(1, b_len + 1): cost = 0 if a[i - 1] == b[j - 1] else 1 - d[i][j] = min( - d[i - 1][j] + 1, - d[i][j - 1] + 1, - d[i - 1][j - 1] + cost) + d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost) - if (i > 1 and j > 1 and - a[i - 1] == b[j - 2] and - a[i - 2] == b[j - 1]): + if i > 1 and j > 1 and a[i - 1] == b[j - 2] and a[i - 2] == b[j - 1]: d[i][j] = min(d[i][j], d[i - 2][j - 2] + cost) return d[a_len][b_len] diff --git a/graphql/subscription/__init__.py b/graphql/subscription/__init__.py index 8fb0823c..739f4528 100644 --- a/graphql/subscription/__init__.py +++ b/graphql/subscription/__init__.py @@ -6,4 +6,4 @@ from .subscribe import subscribe, create_source_event_stream -__all__ = ['subscribe', 'create_source_event_stream'] +__all__ = ["subscribe", "create_source_event_stream"] diff --git a/graphql/subscription/map_async_iterator.py b/graphql/subscription/map_async_iterator.py index 1d28782e..b6e9a72a 100644 --- a/graphql/subscription/map_async_iterator.py +++ b/graphql/subscription/map_async_iterator.py @@ -3,7 +3,7 @@ from inspect import isasyncgen, isawaitable from typing import AsyncIterable, Callable -__all__ = ['MapAsyncIterator'] +__all__ = ["MapAsyncIterator"] # noinspection PyAttributeOutsideInit @@ -17,8 +17,12 @@ class MapAsyncIterator: will also be closed. """ - def __init__(self, iterable: AsyncIterable, callback: Callable, - reject_callback: Callable=None) -> None: + def __init__( + self, + iterable: AsyncIterable, + callback: Callable, + reject_callback: Callable = None, + ) -> None: self.iterator = iterable.__aiter__() self.callback = callback self.reject_callback = reject_callback @@ -38,8 +42,7 @@ async def __anext__(self): aclose = ensure_future(self._close_event.wait()) anext = ensure_future(self.iterator.__anext__()) - done, pending = await wait( - [aclose, anext], return_when=FIRST_COMPLETED) + done, pending = await wait([aclose, anext], return_when=FIRST_COMPLETED) for task in pending: task.cancel() @@ -48,8 +51,9 @@ async def __anext__(self): error = anext.exception() if error: - if not self.reject_callback or isinstance(error, ( - StopAsyncIteration, GeneratorExit)): + if not self.reject_callback or isinstance( + error, (StopAsyncIteration, GeneratorExit) + ): raise error result = self.reject_callback(error) else: @@ -60,7 +64,7 @@ async def __anext__(self): async def athrow(self, type_, value=None, traceback=None): if not self.is_closed: - athrow = getattr(self.iterator, 'athrow', None) + athrow = getattr(self.iterator, "athrow", None) if athrow: await athrow(type_, value, traceback) else: @@ -75,7 +79,7 @@ async def athrow(self, type_, value=None, traceback=None): async def aclose(self): if not self.is_closed: - aclose = getattr(self.iterator, 'aclose', None) + aclose = getattr(self.iterator, "aclose", None) if aclose: try: await aclose() diff --git a/graphql/subscription/subscribe.py b/graphql/subscription/subscribe.py index 4143a3e4..d66a3799 100644 --- a/graphql/subscription/subscribe.py +++ b/graphql/subscription/subscribe.py @@ -1,29 +1,34 @@ from inspect import isawaitable -from typing import ( - Any, AsyncIterable, AsyncIterator, Awaitable, Dict, Union, cast) +from typing import Any, AsyncIterable, AsyncIterator, Awaitable, Dict, Union, cast from ..error import GraphQLError, located_error from ..execution.execute import ( - add_path, assert_valid_execution_arguments, execute, get_field_def, - response_path_as_list, ExecutionContext, ExecutionResult) + add_path, + assert_valid_execution_arguments, + execute, + get_field_def, + response_path_as_list, + ExecutionContext, + ExecutionResult, +) from ..language import DocumentNode from ..type import GraphQLFieldResolver, GraphQLSchema from ..utilities import get_operation_root_type from .map_async_iterator import MapAsyncIterator -__all__ = ['subscribe', 'create_source_event_stream'] +__all__ = ["subscribe", "create_source_event_stream"] async def subscribe( - schema: GraphQLSchema, - document: DocumentNode, - root_value: Any=None, - context_value: Any=None, - variable_values: Dict[str, Any]=None, - operation_name: str = None, - field_resolver: GraphQLFieldResolver=None, - subscribe_field_resolver: GraphQLFieldResolver=None - ) -> Union[AsyncIterator[ExecutionResult], ExecutionResult]: + schema: GraphQLSchema, + document: DocumentNode, + root_value: Any = None, + context_value: Any = None, + variable_values: Dict[str, Any] = None, + operation_name: str = None, + field_resolver: GraphQLFieldResolver = None, + subscribe_field_resolver: GraphQLFieldResolver = None, +) -> Union[AsyncIterator[ExecutionResult], ExecutionResult]: """Create a GraphQL subscription. Implements the "Subscribe" algorithm described in the GraphQL spec. @@ -45,8 +50,14 @@ async def subscribe( """ try: result_or_stream = await create_source_event_stream( - schema, document, root_value, context_value, variable_values, - operation_name, subscribe_field_resolver) + schema, + document, + root_value, + context_value, + variable_values, + operation_name, + subscribe_field_resolver, + ) except GraphQLError as error: return ExecutionResult(data=None, errors=[error]) if isinstance(result_or_stream, ExecutionResult): @@ -63,21 +74,28 @@ async def map_source_to_response(payload): "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the "ExecuteQuery" algorithm, for which `execute` is also used. """ - return execute(schema, document, payload, context_value, - variable_values, operation_name, field_resolver) + return execute( + schema, + document, + payload, + context_value, + variable_values, + operation_name, + field_resolver, + ) return MapAsyncIterator(result_or_stream, map_source_to_response) async def create_source_event_stream( - schema: GraphQLSchema, - document: DocumentNode, - root_value: Any=None, - context_value: Any=None, - variable_values: Dict[str, Any]=None, - operation_name: str = None, - field_resolver: GraphQLFieldResolver=None - ) -> Union[AsyncIterable[Any], ExecutionResult]: + schema: GraphQLSchema, + document: DocumentNode, + root_value: Any = None, + context_value: Any = None, + variable_values: Dict[str, Any] = None, + operation_name: str = None, + field_resolver: GraphQLFieldResolver = None, +) -> Union[AsyncIterable[Any], ExecutionResult]: """Create source even stream Implements the "CreateSourceEventStream" algorithm described in the @@ -104,16 +122,21 @@ async def create_source_event_stream( # If a valid context cannot be created due to incorrect arguments, # this will throw an error. context = ExecutionContext.build( - schema, document, root_value, context_value, - variable_values, operation_name, field_resolver) + schema, + document, + root_value, + context_value, + variable_values, + operation_name, + field_resolver, + ) # Return early errors if execution context failed. if isinstance(context, list): return ExecutionResult(data=None, errors=context) type_ = get_operation_root_type(schema, context.operation) - fields = context.collect_fields( - type_, context.operation.selection_set, {}, set()) + fields = context.collect_fields(type_, context.operation.selection_set, {}, set()) response_names = list(fields) response_name = response_names[0] field_nodes = fields[response_name] @@ -123,8 +146,8 @@ async def create_source_event_stream( if not field_def: raise GraphQLError( - f"The subscription field '{field_name}' is not defined.", - field_nodes) + f"The subscription field '{field_name}' is not defined.", field_nodes + ) # Call the `subscribe()` resolver or the default resolver to produce an # AsyncIterable yielding raw payloads. @@ -139,17 +162,16 @@ async def create_source_event_stream( # algorithm from GraphQL specification. It differs from # "resolve_field_value" due to providing a different `resolve_fn`. result = context.resolve_field_value_or_error( - field_def, field_nodes, resolve_fn, root_value, info) - event_stream = (await cast(Awaitable, result) if isawaitable(result) - else result) + field_def, field_nodes, resolve_fn, root_value, info + ) + event_stream = await cast(Awaitable, result) if isawaitable(result) else result # If event_stream is an Error, rethrow a located error. if isinstance(event_stream, Exception): - raise located_error( - event_stream, field_nodes, response_path_as_list(path)) + raise located_error(event_stream, field_nodes, response_path_as_list(path)) # Assert field returned an event stream, otherwise yield an error. if isinstance(event_stream, AsyncIterable): return cast(AsyncIterable, event_stream) raise TypeError( - 'Subscription field must return AsyncIterable.' - f' Received: {event_stream!r}') + "Subscription field must return AsyncIterable." f" Received: {event_stream!r}" + ) diff --git a/graphql/type/__init__.py b/graphql/type/__init__.py index 9a77094d..0f4209d7 100644 --- a/graphql/type/__init__.py +++ b/graphql/type/__init__.py @@ -8,43 +8,90 @@ # Predicate is_schema, # GraphQL Schema definition - GraphQLSchema) + GraphQLSchema, +) from .definition import ( # Predicates - is_type, is_scalar_type, is_object_type, is_interface_type, - is_union_type, is_enum_type, is_input_object_type, is_list_type, - is_non_null_type, is_input_type, is_output_type, is_leaf_type, - is_composite_type, is_abstract_type, is_wrapping_type, - is_nullable_type, is_named_type, - is_required_argument, is_required_input_field, + is_type, + is_scalar_type, + is_object_type, + is_interface_type, + is_union_type, + is_enum_type, + is_input_object_type, + is_list_type, + is_non_null_type, + is_input_type, + is_output_type, + is_leaf_type, + is_composite_type, + is_abstract_type, + is_wrapping_type, + is_nullable_type, + is_named_type, + is_required_argument, + is_required_input_field, # Assertions - assert_type, assert_scalar_type, assert_object_type, - assert_interface_type, assert_union_type, assert_enum_type, - assert_input_object_type, assert_list_type, assert_non_null_type, - assert_input_type, assert_output_type, assert_leaf_type, - assert_composite_type, assert_abstract_type, assert_wrapping_type, - assert_nullable_type, assert_named_type, + assert_type, + assert_scalar_type, + assert_object_type, + assert_interface_type, + assert_union_type, + assert_enum_type, + assert_input_object_type, + assert_list_type, + assert_non_null_type, + assert_input_type, + assert_output_type, + assert_leaf_type, + assert_composite_type, + assert_abstract_type, + assert_wrapping_type, + assert_nullable_type, + assert_named_type, # Un-modifiers - get_nullable_type, get_named_type, + get_nullable_type, + get_named_type, # Definitions - GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, - GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, + GraphQLScalarType, + GraphQLObjectType, + GraphQLInterfaceType, + GraphQLUnionType, + GraphQLEnumType, + GraphQLInputObjectType, # Type Wrappers - GraphQLList, GraphQLNonNull, + GraphQLList, + GraphQLNonNull, # Types - GraphQLType, GraphQLInputType, GraphQLOutputType, - GraphQLLeafType, GraphQLCompositeType, GraphQLAbstractType, - GraphQLWrappingType, GraphQLNullableType, GraphQLNamedType, - Thunk, GraphQLArgument, GraphQLArgumentMap, - GraphQLEnumValue, GraphQLEnumValueMap, - GraphQLField, GraphQLFieldMap, - GraphQLInputField, GraphQLInputFieldMap, - GraphQLScalarSerializer, GraphQLScalarValueParser, + GraphQLType, + GraphQLInputType, + GraphQLOutputType, + GraphQLLeafType, + GraphQLCompositeType, + GraphQLAbstractType, + GraphQLWrappingType, + GraphQLNullableType, + GraphQLNamedType, + Thunk, + GraphQLArgument, + GraphQLArgumentMap, + GraphQLEnumValue, + GraphQLEnumValueMap, + GraphQLField, + GraphQLFieldMap, + GraphQLInputField, + GraphQLInputFieldMap, + GraphQLScalarSerializer, + GraphQLScalarValueParser, GraphQLScalarLiteralParser, # Resolvers - GraphQLFieldResolver, GraphQLTypeResolver, GraphQLIsTypeOfFn, - GraphQLResolveInfo, ResponsePath) + GraphQLFieldResolver, + GraphQLTypeResolver, + GraphQLIsTypeOfFn, + GraphQLResolveInfo, + ResponsePath, +) from .directives import ( # Predicate @@ -58,60 +105,132 @@ GraphQLSkipDirective, GraphQLDeprecatedDirective, # Constant Deprecation Reason - DEFAULT_DEPRECATION_REASON) + DEFAULT_DEPRECATION_REASON, +) # Common built-in scalar instances. from .scalars import ( - is_specified_scalar_type, specified_scalar_types, - GraphQLInt, GraphQLFloat, GraphQLString, - GraphQLBoolean, GraphQLID) + is_specified_scalar_type, + specified_scalar_types, + GraphQLInt, + GraphQLFloat, + GraphQLString, + GraphQLBoolean, + GraphQLID, +) from .introspection import ( # "Enum" of Type Kinds TypeKind, # GraphQL Types for introspection. - is_introspection_type, introspection_types, + is_introspection_type, + introspection_types, # Meta-field definitions. - SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef) + SchemaMetaFieldDef, + TypeMetaFieldDef, + TypeNameMetaFieldDef, +) from .validate import validate_schema, assert_valid_schema __all__ = [ - 'is_schema', 'GraphQLSchema', - 'is_type', 'is_scalar_type', 'is_object_type', 'is_interface_type', - 'is_union_type', 'is_enum_type', 'is_input_object_type', 'is_list_type', - 'is_non_null_type', 'is_input_type', 'is_output_type', 'is_leaf_type', - 'is_composite_type', 'is_abstract_type', 'is_wrapping_type', - 'is_nullable_type', 'is_named_type', - 'is_required_argument', 'is_required_input_field', - 'assert_type', 'assert_scalar_type', 'assert_object_type', - 'assert_interface_type', 'assert_union_type', 'assert_enum_type', - 'assert_input_object_type', 'assert_list_type', 'assert_non_null_type', - 'assert_input_type', 'assert_output_type', 'assert_leaf_type', - 'assert_composite_type', 'assert_abstract_type', 'assert_wrapping_type', - 'assert_nullable_type', 'assert_named_type', - 'get_nullable_type', 'get_named_type', - 'GraphQLScalarType', 'GraphQLObjectType', 'GraphQLInterfaceType', - 'GraphQLUnionType', 'GraphQLEnumType', - 'GraphQLInputObjectType', 'GraphQLInputType', 'GraphQLArgument', - 'GraphQLList', 'GraphQLNonNull', - 'GraphQLType', 'GraphQLInputType', 'GraphQLOutputType', - 'GraphQLLeafType', 'GraphQLCompositeType', 'GraphQLAbstractType', - 'GraphQLWrappingType', 'GraphQLNullableType', 'GraphQLNamedType', - 'Thunk', 'GraphQLArgument', 'GraphQLArgumentMap', - 'GraphQLEnumValue', 'GraphQLEnumValueMap', - 'GraphQLField', 'GraphQLFieldMap', - 'GraphQLInputField', 'GraphQLInputFieldMap', - 'GraphQLScalarSerializer', 'GraphQLScalarValueParser', - 'GraphQLScalarLiteralParser', - 'GraphQLFieldResolver', 'GraphQLTypeResolver', 'GraphQLIsTypeOfFn', - 'GraphQLResolveInfo', 'ResponsePath', - 'is_directive', 'is_specified_directive', 'specified_directives', - 'GraphQLDirective', 'GraphQLIncludeDirective', 'GraphQLSkipDirective', - 'GraphQLDeprecatedDirective', 'DEFAULT_DEPRECATION_REASON', - 'is_specified_scalar_type', 'specified_scalar_types', - 'GraphQLInt', 'GraphQLFloat', 'GraphQLString', - 'GraphQLBoolean', 'GraphQLID', - 'TypeKind', 'is_introspection_type', 'introspection_types', - 'SchemaMetaFieldDef', 'TypeMetaFieldDef', 'TypeNameMetaFieldDef', - 'validate_schema', 'assert_valid_schema'] + "is_schema", + "GraphQLSchema", + "is_type", + "is_scalar_type", + "is_object_type", + "is_interface_type", + "is_union_type", + "is_enum_type", + "is_input_object_type", + "is_list_type", + "is_non_null_type", + "is_input_type", + "is_output_type", + "is_leaf_type", + "is_composite_type", + "is_abstract_type", + "is_wrapping_type", + "is_nullable_type", + "is_named_type", + "is_required_argument", + "is_required_input_field", + "assert_type", + "assert_scalar_type", + "assert_object_type", + "assert_interface_type", + "assert_union_type", + "assert_enum_type", + "assert_input_object_type", + "assert_list_type", + "assert_non_null_type", + "assert_input_type", + "assert_output_type", + "assert_leaf_type", + "assert_composite_type", + "assert_abstract_type", + "assert_wrapping_type", + "assert_nullable_type", + "assert_named_type", + "get_nullable_type", + "get_named_type", + "GraphQLScalarType", + "GraphQLObjectType", + "GraphQLInterfaceType", + "GraphQLUnionType", + "GraphQLEnumType", + "GraphQLInputObjectType", + "GraphQLInputType", + "GraphQLArgument", + "GraphQLList", + "GraphQLNonNull", + "GraphQLType", + "GraphQLInputType", + "GraphQLOutputType", + "GraphQLLeafType", + "GraphQLCompositeType", + "GraphQLAbstractType", + "GraphQLWrappingType", + "GraphQLNullableType", + "GraphQLNamedType", + "Thunk", + "GraphQLArgument", + "GraphQLArgumentMap", + "GraphQLEnumValue", + "GraphQLEnumValueMap", + "GraphQLField", + "GraphQLFieldMap", + "GraphQLInputField", + "GraphQLInputFieldMap", + "GraphQLScalarSerializer", + "GraphQLScalarValueParser", + "GraphQLScalarLiteralParser", + "GraphQLFieldResolver", + "GraphQLTypeResolver", + "GraphQLIsTypeOfFn", + "GraphQLResolveInfo", + "ResponsePath", + "is_directive", + "is_specified_directive", + "specified_directives", + "GraphQLDirective", + "GraphQLIncludeDirective", + "GraphQLSkipDirective", + "GraphQLDeprecatedDirective", + "DEFAULT_DEPRECATION_REASON", + "is_specified_scalar_type", + "specified_scalar_types", + "GraphQLInt", + "GraphQLFloat", + "GraphQLString", + "GraphQLBoolean", + "GraphQLID", + "TypeKind", + "is_introspection_type", + "introspection_types", + "SchemaMetaFieldDef", + "TypeMetaFieldDef", + "TypeNameMetaFieldDef", + "validate_schema", + "assert_valid_schema", +] diff --git a/graphql/type/definition.py b/graphql/type/definition.py index 9b20c65b..63b2ada3 100644 --- a/graphql/type/definition.py +++ b/graphql/type/definition.py @@ -1,20 +1,47 @@ from enum import Enum from typing import ( - Any, Callable, Dict, Generic, List, NamedTuple, Optional, - Sequence, TYPE_CHECKING, Tuple, Type, TypeVar, Union, cast, overload) + Any, + Callable, + Dict, + Generic, + List, + NamedTuple, + Optional, + Sequence, + TYPE_CHECKING, + Tuple, + Type, + TypeVar, + Union, + cast, + overload, +) from ..error import GraphQLError, INVALID, InvalidType from ..language import ( - EnumTypeDefinitionNode, EnumValueDefinitionNode, - EnumTypeExtensionNode, EnumValueNode, - FieldDefinitionNode, FieldNode, FragmentDefinitionNode, - InputObjectTypeDefinitionNode, InputObjectTypeExtensionNode, - InputValueDefinitionNode, InterfaceTypeDefinitionNode, - InterfaceTypeExtensionNode, ObjectTypeDefinitionNode, - ObjectTypeExtensionNode, OperationDefinitionNode, - ScalarTypeDefinitionNode, ScalarTypeExtensionNode, - TypeDefinitionNode, TypeExtensionNode, - UnionTypeDefinitionNode, UnionTypeExtensionNode, ValueNode) + EnumTypeDefinitionNode, + EnumValueDefinitionNode, + EnumTypeExtensionNode, + EnumValueNode, + FieldDefinitionNode, + FieldNode, + FragmentDefinitionNode, + InputObjectTypeDefinitionNode, + InputObjectTypeExtensionNode, + InputValueDefinitionNode, + InterfaceTypeDefinitionNode, + InterfaceTypeExtensionNode, + ObjectTypeDefinitionNode, + ObjectTypeExtensionNode, + OperationDefinitionNode, + ScalarTypeDefinitionNode, + ScalarTypeExtensionNode, + TypeDefinitionNode, + TypeExtensionNode, + UnionTypeDefinitionNode, + UnionTypeExtensionNode, + ValueNode, +) from ..pyutils import MaybeAwaitable, cached_property from ..utilities.value_from_ast_untyped import value_from_ast_untyped @@ -22,31 +49,79 @@ from .schema import GraphQLSchema # noqa: F401 __all__ = [ - 'is_type', 'is_scalar_type', 'is_object_type', 'is_interface_type', - 'is_union_type', 'is_enum_type', 'is_input_object_type', 'is_list_type', - 'is_non_null_type', 'is_input_type', 'is_output_type', 'is_leaf_type', - 'is_composite_type', 'is_abstract_type', 'is_wrapping_type', - 'is_nullable_type', 'is_named_type', - 'is_required_argument', 'is_required_input_field', - 'assert_type', 'assert_scalar_type', 'assert_object_type', - 'assert_interface_type', 'assert_union_type', 'assert_enum_type', - 'assert_input_object_type', 'assert_list_type', 'assert_non_null_type', - 'assert_input_type', 'assert_output_type', 'assert_leaf_type', - 'assert_composite_type', 'assert_abstract_type', 'assert_wrapping_type', - 'assert_nullable_type', 'assert_named_type', - 'get_nullable_type', 'get_named_type', - 'GraphQLAbstractType', 'GraphQLArgument', 'GraphQLArgumentMap', - 'GraphQLCompositeType', 'GraphQLEnumType', 'GraphQLEnumValue', - 'GraphQLEnumValueMap', 'GraphQLField', 'GraphQLFieldMap', - 'GraphQLFieldResolver', 'GraphQLInputField', 'GraphQLInputFieldMap', - 'GraphQLInputObjectType', 'GraphQLInputType', 'GraphQLIsTypeOfFn', - 'GraphQLLeafType', 'GraphQLList', 'GraphQLNamedType', - 'GraphQLNullableType', 'GraphQLNonNull', 'GraphQLResolveInfo', - 'GraphQLScalarType', 'GraphQLScalarSerializer', 'GraphQLScalarValueParser', - 'GraphQLScalarLiteralParser', 'GraphQLObjectType', 'GraphQLOutputType', - 'GraphQLInterfaceType', 'GraphQLType', 'GraphQLTypeResolver', - 'GraphQLUnionType', 'GraphQLWrappingType', - 'ResponsePath', 'Thunk'] + "is_type", + "is_scalar_type", + "is_object_type", + "is_interface_type", + "is_union_type", + "is_enum_type", + "is_input_object_type", + "is_list_type", + "is_non_null_type", + "is_input_type", + "is_output_type", + "is_leaf_type", + "is_composite_type", + "is_abstract_type", + "is_wrapping_type", + "is_nullable_type", + "is_named_type", + "is_required_argument", + "is_required_input_field", + "assert_type", + "assert_scalar_type", + "assert_object_type", + "assert_interface_type", + "assert_union_type", + "assert_enum_type", + "assert_input_object_type", + "assert_list_type", + "assert_non_null_type", + "assert_input_type", + "assert_output_type", + "assert_leaf_type", + "assert_composite_type", + "assert_abstract_type", + "assert_wrapping_type", + "assert_nullable_type", + "assert_named_type", + "get_nullable_type", + "get_named_type", + "GraphQLAbstractType", + "GraphQLArgument", + "GraphQLArgumentMap", + "GraphQLCompositeType", + "GraphQLEnumType", + "GraphQLEnumValue", + "GraphQLEnumValueMap", + "GraphQLField", + "GraphQLFieldMap", + "GraphQLFieldResolver", + "GraphQLInputField", + "GraphQLInputFieldMap", + "GraphQLInputObjectType", + "GraphQLInputType", + "GraphQLIsTypeOfFn", + "GraphQLLeafType", + "GraphQLList", + "GraphQLNamedType", + "GraphQLNullableType", + "GraphQLNonNull", + "GraphQLResolveInfo", + "GraphQLScalarType", + "GraphQLScalarSerializer", + "GraphQLScalarValueParser", + "GraphQLScalarLiteralParser", + "GraphQLObjectType", + "GraphQLOutputType", + "GraphQLInterfaceType", + "GraphQLType", + "GraphQLTypeResolver", + "GraphQLUnionType", + "GraphQLWrappingType", + "ResponsePath", + "Thunk", +] class GraphQLType: @@ -59,19 +134,20 @@ class GraphQLType: # There are predicates for each kind of GraphQL type. + def is_type(type_: Any) -> bool: return isinstance(type_, GraphQLType) def assert_type(type_: Any) -> GraphQLType: if not is_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL type.') + raise TypeError(f"Expected {type_} to be a GraphQL type.") return type_ # These types wrap and modify other types -GT = TypeVar('GT', bound=GraphQLType) +GT = TypeVar("GT", bound=GraphQLType) class GraphQLWrappingType(GraphQLType, Generic[GT]): @@ -82,8 +158,8 @@ class GraphQLWrappingType(GraphQLType, Generic[GT]): def __init__(self, type_: GT) -> None: if not is_type(type_): raise TypeError( - 'Can only create a wrapper for a GraphQLType, but got:' - f' {type_}.') + "Can only create a wrapper for a GraphQLType, but got:" f" {type_}." + ) self.of_type = type_ @@ -93,12 +169,13 @@ def is_wrapping_type(type_: Any) -> bool: def assert_wrapping_type(type_: Any) -> GraphQLWrappingType: if not is_wrapping_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL wrapping type.') + raise TypeError(f"Expected {type_} to be a GraphQL wrapping type.") return type_ # These named types do not include modifiers like List or NonNull. + class GraphQLNamedType(GraphQLType): """Base class for all GraphQL named types""" @@ -107,29 +184,32 @@ class GraphQLNamedType(GraphQLType): ast_node: Optional[TypeDefinitionNode] extension_ast_nodes: Optional[Tuple[TypeExtensionNode]] - def __init__(self, name: str, description: str=None, - ast_node: TypeDefinitionNode=None, - extension_ast_nodes: Sequence[TypeExtensionNode]=None - ) -> None: + def __init__( + self, + name: str, + description: str = None, + ast_node: TypeDefinitionNode = None, + extension_ast_nodes: Sequence[TypeExtensionNode] = None, + ) -> None: if not name: - raise TypeError('Must provide name.') + raise TypeError("Must provide name.") if not isinstance(name, str): - raise TypeError('The name must be a string.') + raise TypeError("The name must be a string.") if description is not None and not isinstance(description, str): - raise TypeError('The description must be a string.') + raise TypeError("The description must be a string.") if ast_node and not isinstance(ast_node, TypeDefinitionNode): - raise TypeError( - f'{name} AST node must be a TypeDefinitionNode.') + raise TypeError(f"{name} AST node must be a TypeDefinitionNode.") if extension_ast_nodes: if isinstance(extension_ast_nodes, list): extension_ast_nodes = tuple(extension_ast_nodes) if not isinstance(extension_ast_nodes, tuple): + raise TypeError(f"{name} extension AST nodes must be a list/tuple.") + if not all( + isinstance(node, TypeExtensionNode) for node in extension_ast_nodes + ): raise TypeError( - f'{name} extension AST nodes must be a list/tuple.') - if not all(isinstance(node, TypeExtensionNode) - for node in extension_ast_nodes): - raise TypeError( - f'{name} extension AST nodes must be TypeExtensionNode.') + f"{name} extension AST nodes must be TypeExtensionNode." + ) self.name = name self.description = description self.ast_node = ast_node @@ -139,7 +219,7 @@ def __str__(self): return self.name def __repr__(self): - return f'<{self.__class__.__name__}({self})>' + return f"<{self.__class__.__name__}({self})>" def is_named_type(type_: Any) -> bool: @@ -148,7 +228,7 @@ def is_named_type(type_: Any) -> bool: def assert_named_type(type_: Any) -> GraphQLNamedType: if not is_named_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL named type.') + raise TypeError(f"Expected {type_} to be a GraphQL named type.") return type_ @@ -223,36 +303,43 @@ def serialize_odd(value): ast_node: Optional[ScalarTypeDefinitionNode] extension_ast_nodes: Optional[Tuple[ScalarTypeExtensionNode]] - def __init__(self, name: str, serialize: GraphQLScalarSerializer, - description: str=None, - parse_value: GraphQLScalarValueParser=None, - parse_literal: GraphQLScalarLiteralParser=None, - ast_node: ScalarTypeDefinitionNode=None, - extension_ast_nodes: Sequence[ScalarTypeExtensionNode]=None - ) -> None: + def __init__( + self, + name: str, + serialize: GraphQLScalarSerializer, + description: str = None, + parse_value: GraphQLScalarValueParser = None, + parse_literal: GraphQLScalarLiteralParser = None, + ast_node: ScalarTypeDefinitionNode = None, + extension_ast_nodes: Sequence[ScalarTypeExtensionNode] = None, + ) -> None: super().__init__( - name=name, description=description, - ast_node=ast_node, extension_ast_nodes=extension_ast_nodes) + name=name, + description=description, + ast_node=ast_node, + extension_ast_nodes=extension_ast_nodes, + ) if not callable(serialize): raise TypeError( f"{name} must provide 'serialize' function." - ' If this custom Scalar is also used as an input type,' + " If this custom Scalar is also used as an input type," " ensure 'parse_value' and 'parse_literal' functions" - ' are also provided.') + " are also provided." + ) if parse_value is not None or parse_literal is not None: if not callable(parse_value) or not callable(parse_literal): raise TypeError( - f'{name} must provide' - " both 'parse_value' and 'parse_literal' functions.") + f"{name} must provide" + " both 'parse_value' and 'parse_literal' functions." + ) if ast_node and not isinstance(ast_node, ScalarTypeDefinitionNode): - raise TypeError( - f'{name} AST node must be a ScalarTypeDefinitionNode.') + raise TypeError(f"{name} AST node must be a ScalarTypeDefinitionNode.") if extension_ast_nodes and not all( - isinstance(node, ScalarTypeExtensionNode) - for node in extension_ast_nodes): + isinstance(node, ScalarTypeExtensionNode) for node in extension_ast_nodes + ): raise TypeError( - f'{name} extension AST nodes' - ' must be ScalarTypeExtensionNode.') + f"{name} extension AST nodes" " must be ScalarTypeExtensionNode." + ) self.serialize = serialize # type: ignore self.parse_value = parse_value or default_value_parser self.parse_literal = parse_literal or value_from_ast_untyped @@ -264,57 +351,63 @@ def is_scalar_type(type_: Any) -> bool: def assert_scalar_type(type_: Any) -> GraphQLScalarType: if not is_scalar_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL Scalar type.') + raise TypeError(f"Expected {type_} to be a GraphQL Scalar type.") return type_ -GraphQLArgumentMap = Dict[str, 'GraphQLArgument'] +GraphQLArgumentMap = Dict[str, "GraphQLArgument"] class GraphQLField: """Definition of a GraphQL field""" - type: 'GraphQLOutputType' - args: Dict[str, 'GraphQLArgument'] - resolve: Optional['GraphQLFieldResolver'] - subscribe: Optional['GraphQLFieldResolver'] + type: "GraphQLOutputType" + args: Dict[str, "GraphQLArgument"] + resolve: Optional["GraphQLFieldResolver"] + subscribe: Optional["GraphQLFieldResolver"] description: Optional[str] deprecation_reason: Optional[str] ast_node: Optional[FieldDefinitionNode] - def __init__(self, type_: 'GraphQLOutputType', - args: GraphQLArgumentMap=None, - resolve: 'GraphQLFieldResolver'=None, - subscribe: 'GraphQLFieldResolver'=None, - description: str=None, deprecation_reason: str=None, - ast_node: FieldDefinitionNode=None) -> None: + def __init__( + self, + type_: "GraphQLOutputType", + args: GraphQLArgumentMap = None, + resolve: "GraphQLFieldResolver" = None, + subscribe: "GraphQLFieldResolver" = None, + description: str = None, + deprecation_reason: str = None, + ast_node: FieldDefinitionNode = None, + ) -> None: if not is_output_type(type_): - raise TypeError('Field type must be an output type.') + raise TypeError("Field type must be an output type.") if args is None: args = {} elif not isinstance(args, dict): - raise TypeError( - 'Field args must be a dict with argument names as keys.') - elif not all(isinstance(value, GraphQLArgument) or is_input_type(value) - for value in args.values()): - raise TypeError( - 'Field args must be GraphQLArgument or input type objects.') + raise TypeError("Field args must be a dict with argument names as keys.") + elif not all( + isinstance(value, GraphQLArgument) or is_input_type(value) + for value in args.values() + ): + raise TypeError("Field args must be GraphQLArgument or input type objects.") else: - args = {name: cast(GraphQLArgument, value) - if isinstance(value, GraphQLArgument) - else GraphQLArgument(cast(GraphQLInputType, value)) - for name, value in args.items()} + args = { + name: cast(GraphQLArgument, value) + if isinstance(value, GraphQLArgument) + else GraphQLArgument(cast(GraphQLInputType, value)) + for name, value in args.items() + } if resolve is not None and not callable(resolve): raise TypeError( - 'Field resolver must be a function if provided, ' - f' but got: {resolve!r}.') + "Field resolver must be a function if provided, " + f" but got: {resolve!r}." + ) if description is not None and not isinstance(description, str): - raise TypeError('The description must be a string.') - if deprecation_reason is not None and not isinstance( - deprecation_reason, str): - raise TypeError('The deprecation reason must be a string.') + raise TypeError("The description must be a string.") + if deprecation_reason is not None and not isinstance(deprecation_reason, str): + raise TypeError("The deprecation reason must be a string.") if ast_node and not isinstance(ast_node, FieldDefinitionNode): - raise TypeError('Field AST node must be a FieldDefinitionNode.') + raise TypeError("Field AST node must be a FieldDefinitionNode.") self.type = type_ self.args = args or {} self.resolve = resolve @@ -324,13 +417,14 @@ def __init__(self, type_: 'GraphQLOutputType', self.ast_node = ast_node def __eq__(self, other): - return (self is other or ( - isinstance(other, GraphQLField) and - self.type == other.type and - self.args == other.args and - self.resolve == other.resolve and - self.description == other.description and - self.deprecation_reason == other.deprecation_reason)) + return self is other or ( + isinstance(other, GraphQLField) + and self.type == other.type + and self.args == other.args + and self.resolve == other.resolve + and self.description == other.description + and self.deprecation_reason == other.deprecation_reason + ) @property def is_deprecated(self) -> bool: @@ -355,10 +449,10 @@ class GraphQLResolveInfo(NamedTuple): field_name: str field_nodes: List[FieldNode] - return_type: 'GraphQLOutputType' - parent_type: 'GraphQLObjectType' + return_type: "GraphQLOutputType" + parent_type: "GraphQLObjectType" path: ResponsePath - schema: 'GraphQLSchema' + schema: "GraphQLSchema" fragments: Dict[str, FragmentDefinitionNode] root_value: Any operation: OperationDefinitionNode @@ -377,54 +471,58 @@ class GraphQLResolveInfo(NamedTuple): # Note: Contrary to the Javascript implementation of GraphQLTypeResolver, # the context is passed as part of the GraphQLResolveInfo: GraphQLTypeResolver = Callable[ - [Any, GraphQLResolveInfo], MaybeAwaitable[Union['GraphQLObjectType', str]]] + [Any, GraphQLResolveInfo], MaybeAwaitable[Union["GraphQLObjectType", str]] +] # Note: Contrary to the Javascript implementation of GraphQLIsTypeOfFn, # the context is passed as part of the GraphQLResolveInfo: -GraphQLIsTypeOfFn = Callable[ - [Any, GraphQLResolveInfo], MaybeAwaitable[bool]] +GraphQLIsTypeOfFn = Callable[[Any, GraphQLResolveInfo], MaybeAwaitable[bool]] class GraphQLArgument: """Definition of a GraphQL argument""" - type: 'GraphQLInputType' + type: "GraphQLInputType" default_value: Any description: Optional[str] ast_node: Optional[InputValueDefinitionNode] - def __init__(self, type_: 'GraphQLInputType', default_value: Any=INVALID, - description: str=None, - ast_node: InputValueDefinitionNode=None) -> None: + def __init__( + self, + type_: "GraphQLInputType", + default_value: Any = INVALID, + description: str = None, + ast_node: InputValueDefinitionNode = None, + ) -> None: if not is_input_type(type_): - raise TypeError(f'Argument type must be a GraphQL input type.') + raise TypeError(f"Argument type must be a GraphQL input type.") if description is not None and not isinstance(description, str): - raise TypeError('The description must be a string.') + raise TypeError("The description must be a string.") if ast_node and not isinstance(ast_node, InputValueDefinitionNode): - raise TypeError( - 'Argument AST node must be an InputValueDefinitionNode.') + raise TypeError("Argument AST node must be an InputValueDefinitionNode.") self.type = type_ self.default_value = default_value self.description = description self.ast_node = ast_node def __eq__(self, other): - return (self is other or ( - isinstance(other, GraphQLArgument) and - self.type == other.type and - self.default_value == other.default_value and - self.description == other.description)) + return self is other or ( + isinstance(other, GraphQLArgument) + and self.type == other.type + and self.default_value == other.default_value + and self.description == other.description + ) def is_required_argument(arg: GraphQLArgument) -> bool: return is_non_null_type(arg.type) and arg.default_value is INVALID -T = TypeVar('T') +T = TypeVar("T") Thunk = Union[Callable[[], T], T] GraphQLFieldMap = Dict[str, GraphQLField] -GraphQLInterfaceList = Sequence['GraphQLInterfaceType'] +GraphQLInterfaceList = Sequence["GraphQLInterfaceType"] class GraphQLObjectType(GraphQLNamedType): @@ -459,29 +557,35 @@ class GraphQLObjectType(GraphQLNamedType): ast_node: Optional[ObjectTypeDefinitionNode] extension_ast_nodes: Optional[Tuple[ObjectTypeExtensionNode]] - def __init__(self, name: str, - fields: Thunk[GraphQLFieldMap], - interfaces: Thunk[GraphQLInterfaceList]=None, - is_type_of: GraphQLIsTypeOfFn=None, description: str=None, - ast_node: ObjectTypeDefinitionNode=None, - extension_ast_nodes: Sequence[ObjectTypeExtensionNode]=None - ) -> None: + def __init__( + self, + name: str, + fields: Thunk[GraphQLFieldMap], + interfaces: Thunk[GraphQLInterfaceList] = None, + is_type_of: GraphQLIsTypeOfFn = None, + description: str = None, + ast_node: ObjectTypeDefinitionNode = None, + extension_ast_nodes: Sequence[ObjectTypeExtensionNode] = None, + ) -> None: super().__init__( - name=name, description=description, - ast_node=ast_node, extension_ast_nodes=extension_ast_nodes) + name=name, + description=description, + ast_node=ast_node, + extension_ast_nodes=extension_ast_nodes, + ) if is_type_of is not None and not callable(is_type_of): raise TypeError( f"{name} must provide 'is_type_of' as a function," - f' but got: {is_type_of!r}.') + f" but got: {is_type_of!r}." + ) if ast_node and not isinstance(ast_node, ObjectTypeDefinitionNode): - raise TypeError( - f'{name} AST node must be an ObjectTypeDefinitionNode.') + raise TypeError(f"{name} AST node must be an ObjectTypeDefinitionNode.") if extension_ast_nodes and not all( - isinstance(node, ObjectTypeExtensionNode) - for node in extension_ast_nodes): + isinstance(node, ObjectTypeExtensionNode) for node in extension_ast_nodes + ): raise TypeError( - f'{name} extension AST nodes' - ' must be ObjectTypeExtensionNodes.') + f"{name} extension AST nodes" " must be ObjectTypeExtensionNodes." + ) self._fields = fields self._interfaces = interfaces self.is_type_of = is_type_of @@ -494,20 +598,25 @@ def fields(self) -> GraphQLFieldMap: except GraphQLError: raise except Exception as error: - raise TypeError(f'{self.name} fields cannot be resolved: {error}') + raise TypeError(f"{self.name} fields cannot be resolved: {error}") if not isinstance(fields, dict) or not all( - isinstance(key, str) for key in fields): + isinstance(key, str) for key in fields + ): raise TypeError( - f'{self.name} fields must be a dict with field names as keys' - ' or a function which returns such an object.') - if not all(isinstance(value, GraphQLField) or is_output_type(value) - for value in fields.values()): + f"{self.name} fields must be a dict with field names as keys" + " or a function which returns such an object." + ) + if not all( + isinstance(value, GraphQLField) or is_output_type(value) + for value in fields.values() + ): raise TypeError( - f'{self.name} fields must be' - ' GraphQLField or output type objects.') - return {name: value if isinstance(value, GraphQLField) - else GraphQLField(value) - for name, value in fields.items()} + f"{self.name} fields must be" " GraphQLField or output type objects." + ) + return { + name: value if isinstance(value, GraphQLField) else GraphQLField(value) + for name, value in fields.items() + } @cached_property def interfaces(self) -> GraphQLInterfaceList: @@ -517,18 +626,16 @@ def interfaces(self) -> GraphQLInterfaceList: except GraphQLError: raise except Exception as error: - raise TypeError( - f'{self.name} interfaces cannot be resolved: {error}') + raise TypeError(f"{self.name} interfaces cannot be resolved: {error}") if interfaces is None: interfaces = [] if not isinstance(interfaces, (list, tuple)): raise TypeError( - f'{self.name} interfaces must be a list/tuple' - ' or a function which returns a list/tuple.') - if not all(isinstance(value, GraphQLInterfaceType) - for value in interfaces): - raise TypeError( - f'{self.name} interfaces must be GraphQLInterface objects.') + f"{self.name} interfaces must be a list/tuple" + " or a function which returns a list/tuple." + ) + if not all(isinstance(value, GraphQLInterfaceType) for value in interfaces): + raise TypeError(f"{self.name} interfaces must be GraphQLInterface objects.") return interfaces[:] @@ -538,7 +645,7 @@ def is_object_type(type_: Any) -> bool: def assert_object_type(type_: Any) -> GraphQLObjectType: if not is_object_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL Object type.') + raise TypeError(f"Expected {type_} to be a GraphQL Object type.") return type_ @@ -561,29 +668,34 @@ class GraphQLInterfaceType(GraphQLNamedType): ast_node: Optional[InterfaceTypeDefinitionNode] extension_ast_nodes: Optional[Tuple[InterfaceTypeExtensionNode]] - def __init__(self, name: str, fields: Thunk[GraphQLFieldMap]=None, - resolve_type: GraphQLTypeResolver=None, - description: str=None, - ast_node: InterfaceTypeDefinitionNode=None, - extension_ast_nodes: Sequence[InterfaceTypeExtensionNode]=None - ) -> None: + def __init__( + self, + name: str, + fields: Thunk[GraphQLFieldMap] = None, + resolve_type: GraphQLTypeResolver = None, + description: str = None, + ast_node: InterfaceTypeDefinitionNode = None, + extension_ast_nodes: Sequence[InterfaceTypeExtensionNode] = None, + ) -> None: super().__init__( - name=name, description=description, - ast_node=ast_node, extension_ast_nodes=extension_ast_nodes) + name=name, + description=description, + ast_node=ast_node, + extension_ast_nodes=extension_ast_nodes, + ) if resolve_type is not None and not callable(resolve_type): raise TypeError( f"{name} must provide 'resolve_type' as a function," - f' but got: {resolve_type!r}.') - if ast_node and not isinstance( - ast_node, InterfaceTypeDefinitionNode): - raise TypeError( - f'{name} AST node must be an InterfaceTypeDefinitionNode.') - if extension_ast_nodes and not all(isinstance( - node, InterfaceTypeExtensionNode) - for node in extension_ast_nodes): + f" but got: {resolve_type!r}." + ) + if ast_node and not isinstance(ast_node, InterfaceTypeDefinitionNode): + raise TypeError(f"{name} AST node must be an InterfaceTypeDefinitionNode.") + if extension_ast_nodes and not all( + isinstance(node, InterfaceTypeExtensionNode) for node in extension_ast_nodes + ): raise TypeError( - f'{name} extension AST nodes' - ' must be InterfaceTypeExtensionNodes.') + f"{name} extension AST nodes" " must be InterfaceTypeExtensionNodes." + ) self._fields = fields self.resolve_type = resolve_type self.description = description @@ -596,20 +708,25 @@ def fields(self) -> GraphQLFieldMap: except GraphQLError: raise except Exception as error: - raise TypeError(f'{self.name} fields cannot be resolved: {error}') + raise TypeError(f"{self.name} fields cannot be resolved: {error}") if not isinstance(fields, dict) or not all( - isinstance(key, str) for key in fields): + isinstance(key, str) for key in fields + ): raise TypeError( - f'{self.name} fields must be a dict with field names as keys' - ' or a function which returns such an object.') - if not all(isinstance(value, GraphQLField) or is_output_type(value) - for value in fields.values()): + f"{self.name} fields must be a dict with field names as keys" + " or a function which returns such an object." + ) + if not all( + isinstance(value, GraphQLField) or is_output_type(value) + for value in fields.values() + ): raise TypeError( - f'{self.name} fields must be' - ' GraphQLField or output type objects.') - return {name: value if isinstance(value, GraphQLField) - else GraphQLField(value) - for name, value in fields.items()} + f"{self.name} fields must be" " GraphQLField or output type objects." + ) + return { + name: value if isinstance(value, GraphQLField) else GraphQLField(value) + for name, value in fields.items() + } def is_interface_type(type_: Any) -> bool: @@ -618,7 +735,7 @@ def is_interface_type(type_: Any) -> bool: def assert_interface_type(type_: Any) -> GraphQLInterfaceType: if not is_interface_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL Interface type.') + raise TypeError(f"Expected {type_} to be a GraphQL Interface type.") return type_ @@ -649,27 +766,34 @@ def resolve_type(self, value): ast_node: Optional[UnionTypeDefinitionNode] extension_ast_nodes: Optional[Tuple[UnionTypeExtensionNode]] - def __init__(self, name, types: Thunk[GraphQLTypeList], - resolve_type: GraphQLFieldResolver=None, - description: str=None, - ast_node: UnionTypeDefinitionNode=None, - extension_ast_nodes: Sequence[UnionTypeExtensionNode]=None - ) -> None: + def __init__( + self, + name, + types: Thunk[GraphQLTypeList], + resolve_type: GraphQLFieldResolver = None, + description: str = None, + ast_node: UnionTypeDefinitionNode = None, + extension_ast_nodes: Sequence[UnionTypeExtensionNode] = None, + ) -> None: super().__init__( - name=name, description=description, - ast_node=ast_node, extension_ast_nodes=extension_ast_nodes) + name=name, + description=description, + ast_node=ast_node, + extension_ast_nodes=extension_ast_nodes, + ) if resolve_type is not None and not callable(resolve_type): raise TypeError( f"{name} must provide 'resolve_type' as a function," - f' but got: {resolve_type!r}.') + f" but got: {resolve_type!r}." + ) if ast_node and not isinstance(ast_node, UnionTypeDefinitionNode): - raise TypeError( - f'{name} AST node must be a UnionTypeDefinitionNode.') + raise TypeError(f"{name} AST node must be a UnionTypeDefinitionNode.") if extension_ast_nodes and not all( - isinstance(node, UnionTypeExtensionNode) - for node in extension_ast_nodes): + isinstance(node, UnionTypeExtensionNode) for node in extension_ast_nodes + ): raise TypeError( - f'{name} extension AST nodes must be UnionTypeExtensionNode.') + f"{name} extension AST nodes must be UnionTypeExtensionNode." + ) self._types = types self.resolve_type = resolve_type @@ -681,16 +805,16 @@ def types(self) -> GraphQLTypeList: except GraphQLError: raise except Exception as error: - raise TypeError(f'{self.name} types cannot be resolved: {error}') + raise TypeError(f"{self.name} types cannot be resolved: {error}") if types is None: types = [] if not isinstance(types, (list, tuple)): raise TypeError( - f'{self.name} types must be a list/tuple' - ' or a function which returns a list/tuple.') + f"{self.name} types must be a list/tuple" + " or a function which returns a list/tuple." + ) if not all(isinstance(value, GraphQLObjectType) for value in types): - raise TypeError( - f'{self.name} types must be GraphQLObjectType objects.') + raise TypeError(f"{self.name} types must be GraphQLObjectType objects.") return types[:] @@ -700,11 +824,11 @@ def is_union_type(type_: Any) -> bool: def assert_union_type(type_: Any) -> GraphQLUnionType: if not is_union_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL Union type.') + raise TypeError(f"Expected {type_} to be a GraphQL Union type.") return type_ -GraphQLEnumValueMap = Dict[str, 'GraphQLEnumValue'] +GraphQLEnumValueMap = Dict[str, "GraphQLEnumValue"] class GraphQLEnumType(GraphQLNamedType): @@ -742,42 +866,52 @@ class RGBEnum(enum.Enum): ast_node: Optional[EnumTypeDefinitionNode] extension_ast_nodes: Optional[Tuple[EnumTypeExtensionNode]] - def __init__(self, name: str, - values: Union[GraphQLEnumValueMap, - Dict[str, Any], Type[Enum]], - description: str=None, - ast_node: EnumTypeDefinitionNode=None, - extension_ast_nodes: Sequence[EnumTypeExtensionNode]=None - ) -> None: + def __init__( + self, + name: str, + values: Union[GraphQLEnumValueMap, Dict[str, Any], Type[Enum]], + description: str = None, + ast_node: EnumTypeDefinitionNode = None, + extension_ast_nodes: Sequence[EnumTypeExtensionNode] = None, + ) -> None: super().__init__( - name=name, description=description, - ast_node=ast_node, extension_ast_nodes=extension_ast_nodes) + name=name, + description=description, + ast_node=ast_node, + extension_ast_nodes=extension_ast_nodes, + ) try: # check for enum values = cast(Enum, values).__members__ # type: ignore except AttributeError: if not isinstance(values, dict) or not all( - isinstance(name, str) for name in values): + isinstance(name, str) for name in values + ): try: # noinspection PyTypeChecker values = dict(values) # type: ignore except (TypeError, ValueError): raise TypeError( - f'{name} values must be an Enum or a dict' - ' with value names as keys.') + f"{name} values must be an Enum or a dict" + " with value names as keys." + ) values = cast(Dict, values) else: values = cast(Dict, values) values = {key: value.value for key, value in values.items()} - values = {key: value if isinstance(value, GraphQLEnumValue) else - GraphQLEnumValue(value) for key, value in values.items()} + values = { + key: value + if isinstance(value, GraphQLEnumValue) + else GraphQLEnumValue(value) + for key, value in values.items() + } if ast_node and not isinstance(ast_node, EnumTypeDefinitionNode): - raise TypeError( - f'{name} AST node must be an EnumTypeDefinitionNode.') + raise TypeError(f"{name} AST node must be an EnumTypeDefinitionNode.") if extension_ast_nodes and not all( - isinstance(node, EnumTypeExtensionNode) - for node in extension_ast_nodes): + isinstance(node, EnumTypeExtensionNode) for node in extension_ast_nodes + ): raise TypeError( - f'{name} extension AST nodes must be EnumTypeExtensionNode.') + f"{name} extension AST nodes must be EnumTypeExtensionNode." + ) self.values = values @cached_property @@ -816,8 +950,8 @@ def parse_value(self, value: str) -> Any: return INVALID def parse_literal( - self, value_node: ValueNode, - _variables: Dict[str, Any]=None) -> Any: + self, value_node: ValueNode, _variables: Dict[str, Any] = None + ) -> Any: # Note: variables will be resolved before calling this method. if isinstance(value_node, EnumValueNode): value = value_node.value @@ -837,7 +971,7 @@ def is_enum_type(type_: Any) -> bool: def assert_enum_type(type_: Any) -> GraphQLEnumType: if not is_enum_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL Enum type.') + raise TypeError(f"Expected {type_} to be a GraphQL Enum type.") return type_ @@ -848,35 +982,38 @@ class GraphQLEnumValue: deprecation_reason: Optional[str] ast_node: Optional[EnumValueDefinitionNode] - def __init__(self, value: Any=None, description: str=None, - deprecation_reason: str=None, - ast_node: EnumValueDefinitionNode=None) -> None: + def __init__( + self, + value: Any = None, + description: str = None, + deprecation_reason: str = None, + ast_node: EnumValueDefinitionNode = None, + ) -> None: if description is not None and not isinstance(description, str): - raise TypeError('The description must be a string.') - if deprecation_reason is not None and not isinstance( - deprecation_reason, str): - raise TypeError('The deprecation reason must be a string.') + raise TypeError("The description must be a string.") + if deprecation_reason is not None and not isinstance(deprecation_reason, str): + raise TypeError("The deprecation reason must be a string.") if ast_node and not isinstance(ast_node, EnumValueDefinitionNode): - raise TypeError( - 'AST node must be an EnumValueDefinitionNode.') + raise TypeError("AST node must be an EnumValueDefinitionNode.") self.value = value self.description = description self.deprecation_reason = deprecation_reason self.ast_node = ast_node def __eq__(self, other): - return (self is other or ( - isinstance(other, GraphQLEnumValue) and - self.value == other.value and - self.description == other.description and - self.deprecation_reason == other.deprecation_reason)) + return self is other or ( + isinstance(other, GraphQLEnumValue) + and self.value == other.value + and self.description == other.description + and self.deprecation_reason == other.deprecation_reason + ) @property def is_deprecated(self) -> bool: return bool(self.deprecation_reason) -GraphQLInputFieldMap = Dict[str, 'GraphQLInputField'] +GraphQLInputFieldMap = Dict[str, "GraphQLInputField"] class GraphQLInputObjectType(GraphQLNamedType): @@ -904,24 +1041,31 @@ class GeoPoint(GraphQLInputObjectType): ast_node: Optional[InputObjectTypeDefinitionNode] extension_ast_nodes: Optional[Tuple[InputObjectTypeExtensionNode]] - def __init__(self, name: str, fields: Thunk[GraphQLInputFieldMap], - description: str=None, - ast_node: InputObjectTypeDefinitionNode=None, - extension_ast_nodes: Sequence[ - InputObjectTypeExtensionNode]=None) -> None: + def __init__( + self, + name: str, + fields: Thunk[GraphQLInputFieldMap], + description: str = None, + ast_node: InputObjectTypeDefinitionNode = None, + extension_ast_nodes: Sequence[InputObjectTypeExtensionNode] = None, + ) -> None: super().__init__( - name=name, description=description, - ast_node=ast_node, extension_ast_nodes=extension_ast_nodes) - if ast_node and not isinstance( - ast_node, InputObjectTypeDefinitionNode): + name=name, + description=description, + ast_node=ast_node, + extension_ast_nodes=extension_ast_nodes, + ) + if ast_node and not isinstance(ast_node, InputObjectTypeDefinitionNode): raise TypeError( - f'{name} AST node must be an InputObjectTypeDefinitionNode.') + f"{name} AST node must be an InputObjectTypeDefinitionNode." + ) if extension_ast_nodes and not all( - isinstance(node, InputObjectTypeExtensionNode) - for node in extension_ast_nodes): + isinstance(node, InputObjectTypeExtensionNode) + for node in extension_ast_nodes + ): raise TypeError( - f'{name} extension AST nodes' - ' must be InputObjectTypeExtensionNode.') + f"{name} extension AST nodes" " must be InputObjectTypeExtensionNode." + ) self._fields = fields @cached_property @@ -932,20 +1076,28 @@ def fields(self) -> GraphQLInputFieldMap: except GraphQLError: raise except Exception as error: - raise TypeError(f'{self.name} fields cannot be resolved: {error}') + raise TypeError(f"{self.name} fields cannot be resolved: {error}") if not isinstance(fields, dict) or not all( - isinstance(key, str) for key in fields): + isinstance(key, str) for key in fields + ): raise TypeError( - f'{self.name} fields must be a dict with field names as keys' - ' or a function which returns such an object.') - if not all(isinstance(value, GraphQLInputField) or is_input_type(value) - for value in fields.values()): + f"{self.name} fields must be a dict with field names as keys" + " or a function which returns such an object." + ) + if not all( + isinstance(value, GraphQLInputField) or is_input_type(value) + for value in fields.values() + ): raise TypeError( - f'{self.name} fields must be' - ' GraphQLInputField or input type objects.') - return {name: value if isinstance(value, GraphQLInputField) - else GraphQLInputField(value) - for name, value in fields.items()} + f"{self.name} fields must be" + " GraphQLInputField or input type objects." + ) + return { + name: value + if isinstance(value, GraphQLInputField) + else GraphQLInputField(value) + for name, value in fields.items() + } def is_input_object_type(type_: Any) -> bool: @@ -954,36 +1106,40 @@ def is_input_object_type(type_: Any) -> bool: def assert_input_object_type(type_: Any) -> GraphQLInputObjectType: if not is_input_object_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL Input Object type.') + raise TypeError(f"Expected {type_} to be a GraphQL Input Object type.") return type_ class GraphQLInputField: """Definition of a GraphQL input field""" - type: 'GraphQLInputType' + type: "GraphQLInputType" description: Optional[str] default_value: Any ast_node: Optional[InputValueDefinitionNode] - def __init__(self, type_: 'GraphQLInputType', description: str=None, - default_value: Any=INVALID, - ast_node: InputValueDefinitionNode=None) -> None: + def __init__( + self, + type_: "GraphQLInputType", + description: str = None, + default_value: Any = INVALID, + ast_node: InputValueDefinitionNode = None, + ) -> None: if not is_input_type(type_): - raise TypeError(f'Input field type must be a GraphQL input type.') + raise TypeError(f"Input field type must be a GraphQL input type.") if ast_node and not isinstance(ast_node, InputValueDefinitionNode): - raise TypeError( - 'Input field AST node must be an InputValueDefinitionNode.') + raise TypeError("Input field AST node must be an InputValueDefinitionNode.") self.type = type_ self.default_value = default_value self.description = description self.ast_node = ast_node def __eq__(self, other): - return (self is other or ( - isinstance(other, GraphQLInputField) and - self.type == other.type and - self.description == other.description)) + return self is other or ( + isinstance(other, GraphQLInputField) + and self.type == other.type + and self.description == other.description + ) def is_required_input_field(field: GraphQLInputField) -> bool: @@ -992,6 +1148,7 @@ def is_required_input_field(field: GraphQLInputField) -> bool: # Wrapper types + class GraphQLList(Generic[GT], GraphQLWrappingType[GT]): """List Type Wrapper @@ -1016,7 +1173,7 @@ def __init__(self, type_: GT) -> None: super().__init__(type_=type_) def __str__(self): - return f'[{self.of_type}]' + return f"[{self.of_type}]" def is_list_type(type_: Any) -> bool: @@ -1025,11 +1182,11 @@ def is_list_type(type_: Any) -> bool: def assert_list_type(type_: Any) -> GraphQLList: if not is_list_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL List type.') + raise TypeError(f"Expected {type_} to be a GraphQL List type.") return type_ -GNT = TypeVar('GNT', bound='GraphQLNullableType') +GNT = TypeVar("GNT", bound="GraphQLNullableType") class GraphQLNonNull(GraphQLWrappingType[GNT], Generic[GNT]): @@ -1056,11 +1213,12 @@ def __init__(self, type_: GNT) -> None: super().__init__(type_=type_) if isinstance(type_, GraphQLNonNull): raise TypeError( - 'Can only create NonNull of a Nullable GraphQLType but got:' - f' {type_}.') + "Can only create NonNull of a Nullable GraphQLType but got:" + f" {type_}." + ) def __str__(self): - return f'{self.of_type}!' + return f"{self.of_type}!" def is_non_null_type(type_: Any) -> bool: @@ -1069,19 +1227,31 @@ def is_non_null_type(type_: Any) -> bool: def assert_non_null_type(type_: Any) -> GraphQLNonNull: if not is_non_null_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL Non-Null type.') + raise TypeError(f"Expected {type_} to be a GraphQL Non-Null type.") return type_ # These types can all accept null as a value. graphql_nullable_types = ( - GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, - GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, GraphQLList) + GraphQLScalarType, + GraphQLObjectType, + GraphQLInterfaceType, + GraphQLUnionType, + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLList, +) GraphQLNullableType = Union[ - GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, - GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, GraphQLList] + GraphQLScalarType, + GraphQLObjectType, + GraphQLInterfaceType, + GraphQLUnionType, + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLList, +] def is_nullable_type(type_: Any) -> bool: @@ -1090,7 +1260,7 @@ def is_nullable_type(type_: Any) -> bool: def assert_nullable_type(type_: Any) -> GraphQLNullableType: if not is_nullable_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL nullable type.') + raise TypeError(f"Expected {type_} to be a GraphQL nullable type.") return type_ @@ -1119,44 +1289,54 @@ def get_nullable_type(type_): # noqa: F811 # These types may be used as input types for arguments and directives. -graphql_input_types = ( - GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType) +graphql_input_types = (GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType) GraphQLInputType = Union[ - GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType, - GraphQLWrappingType] + GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType, GraphQLWrappingType +] def is_input_type(type_: Any) -> bool: - return isinstance(type_, graphql_input_types) or (isinstance( - type_, GraphQLWrappingType) and is_input_type(type_.of_type)) + return isinstance(type_, graphql_input_types) or ( + isinstance(type_, GraphQLWrappingType) and is_input_type(type_.of_type) + ) def assert_input_type(type_: Any) -> GraphQLInputType: if not is_input_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL input type.') + raise TypeError(f"Expected {type_} to be a GraphQL input type.") return type_ # These types may be used as output types as the result of fields. graphql_output_types = ( - GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, - GraphQLUnionType, GraphQLEnumType) + GraphQLScalarType, + GraphQLObjectType, + GraphQLInterfaceType, + GraphQLUnionType, + GraphQLEnumType, +) GraphQLOutputType = Union[ - GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, - GraphQLUnionType, GraphQLEnumType, GraphQLWrappingType] + GraphQLScalarType, + GraphQLObjectType, + GraphQLInterfaceType, + GraphQLUnionType, + GraphQLEnumType, + GraphQLWrappingType, +] def is_output_type(type_: Any) -> bool: - return isinstance(type_, graphql_output_types) or (isinstance( - type_, GraphQLWrappingType) and is_output_type(type_.of_type)) + return isinstance(type_, graphql_output_types) or ( + isinstance(type_, GraphQLWrappingType) and is_output_type(type_.of_type) + ) def assert_output_type(type_: Any) -> GraphQLOutputType: if not is_output_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL output type.') + raise TypeError(f"Expected {type_} to be a GraphQL output type.") return type_ @@ -1173,17 +1353,15 @@ def is_leaf_type(type_: Any) -> bool: def assert_leaf_type(type_: Any) -> GraphQLLeafType: if not is_leaf_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL leaf type.') + raise TypeError(f"Expected {type_} to be a GraphQL leaf type.") return type_ # These types may describe the parent context of a selection set. -graphql_composite_types = ( - GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType) +graphql_composite_types = (GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType) -GraphQLCompositeType = Union[ - GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType] +GraphQLCompositeType = Union[GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType] def is_composite_type(type_: Any) -> bool: @@ -1192,7 +1370,7 @@ def is_composite_type(type_: Any) -> bool: def assert_composite_type(type_: Any) -> GraphQLType: if not is_composite_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL composite type.') + raise TypeError(f"Expected {type_} to be a GraphQL composite type.") return type_ @@ -1209,5 +1387,5 @@ def is_abstract_type(type_: Any) -> bool: def assert_abstract_type(type_: Any) -> GraphQLAbstractType: if not is_abstract_type(type_): - raise TypeError(f'Expected {type_} to be a GraphQL composite type.') + raise TypeError(f"Expected {type_} to be a GraphQL composite type.") return type_ diff --git a/graphql/type/directives.py b/graphql/type/directives.py index e71f2df1..cec172fb 100644 --- a/graphql/type/directives.py +++ b/graphql/type/directives.py @@ -1,15 +1,20 @@ from typing import Any, Dict, Sequence, cast from ..language import ast, DirectiveLocation -from .definition import ( - GraphQLArgument, GraphQLInputType, GraphQLNonNull, is_input_type) +from .definition import GraphQLArgument, GraphQLInputType, GraphQLNonNull, is_input_type from .scalars import GraphQLBoolean, GraphQLString __all__ = [ - 'is_directive', 'is_specified_directive', 'specified_directives', - 'GraphQLDirective', 'GraphQLIncludeDirective', 'GraphQLSkipDirective', - 'GraphQLDeprecatedDirective', - 'DirectiveLocation', 'DEFAULT_DEPRECATION_REASON'] + "is_directive", + "is_specified_directive", + "specified_directives", + "GraphQLDirective", + "GraphQLIncludeDirective", + "GraphQLSkipDirective", + "GraphQLDeprecatedDirective", + "DirectiveLocation", + "DEFAULT_DEPRECATION_REASON", +] def is_directive(directive: Any) -> bool: @@ -24,46 +29,54 @@ class GraphQLDirective: behavior. Type system creators will usually not create these directly. """ - def __init__(self, name: str, - locations: Sequence[DirectiveLocation], - args: Dict[str, GraphQLArgument]=None, - description: str=None, - ast_node: ast.DirectiveDefinitionNode=None) -> None: + def __init__( + self, + name: str, + locations: Sequence[DirectiveLocation], + args: Dict[str, GraphQLArgument] = None, + description: str = None, + ast_node: ast.DirectiveDefinitionNode = None, + ) -> None: if not name: - raise TypeError('Directive must be named.') + raise TypeError("Directive must be named.") elif not isinstance(name, str): - raise TypeError('The directive name must be a string.') + raise TypeError("The directive name must be a string.") if not isinstance(locations, (list, tuple)): - raise TypeError(f'{name} locations must be a list/tuple.') - if not all(isinstance(value, DirectiveLocation) - for value in locations): + raise TypeError(f"{name} locations must be a list/tuple.") + if not all(isinstance(value, DirectiveLocation) for value in locations): try: locations = [ - value if isinstance(value, DirectiveLocation) - else DirectiveLocation[value] for value in locations] + value + if isinstance(value, DirectiveLocation) + else DirectiveLocation[value] + for value in locations + ] except (KeyError, TypeError): - raise TypeError( - f'{name} locations must be DirectiveLocation objects.') + raise TypeError(f"{name} locations must be DirectiveLocation objects.") if args is None: args = {} elif not isinstance(args, dict) or not all( - isinstance(key, str) for key in args): + isinstance(key, str) for key in args + ): + raise TypeError(f"{name} args must be a dict with argument names as keys.") + elif not all( + isinstance(value, GraphQLArgument) or is_input_type(value) + for value in args.values() + ): raise TypeError( - f'{name} args must be a dict with argument names as keys.') - elif not all(isinstance(value, GraphQLArgument) or is_input_type(value) - for value in args.values()): - raise TypeError( - f'{name} args must be GraphQLArgument or input type objects.') + f"{name} args must be GraphQLArgument or input type objects." + ) else: - args = {name: cast(GraphQLArgument, value) - if isinstance(value, GraphQLArgument) - else GraphQLArgument(cast(GraphQLInputType, value)) - for name, value in args.items()} + args = { + name: cast(GraphQLArgument, value) + if isinstance(value, GraphQLArgument) + else GraphQLArgument(cast(GraphQLInputType, value)) + for name, value in args.items() + } if description is not None and not isinstance(description, str): - raise TypeError(f'{name} description must be a string.') + raise TypeError(f"{name} description must be a string.") if ast_node and not isinstance(ast_node, ast.DirectiveDefinitionNode): - raise TypeError( - f'{name} AST node must be a DirectiveDefinitionNode.') + raise TypeError(f"{name} AST node must be a DirectiveDefinitionNode.") self.name = name self.locations = locations self.args = args @@ -71,66 +84,81 @@ def __init__(self, name: str, self.ast_node = ast_node def __str__(self): - return f'@{self.name}' + return f"@{self.name}" def __repr__(self): - return f'<{self.__class__.__name__}({self})>' + return f"<{self.__class__.__name__}({self})>" # Used to conditionally include fields or fragments. GraphQLIncludeDirective = GraphQLDirective( - name='include', + name="include", locations=[ DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, - DirectiveLocation.INLINE_FRAGMENT], - args={'if': GraphQLArgument( - GraphQLNonNull(GraphQLBoolean), - description='Included when true.')}, - description='Directs the executor to include this field or fragment' - ' only when the `if` argument is true.') + DirectiveLocation.INLINE_FRAGMENT, + ], + args={ + "if": GraphQLArgument( + GraphQLNonNull(GraphQLBoolean), description="Included when true." + ) + }, + description="Directs the executor to include this field or fragment" + " only when the `if` argument is true.", +) # Used to conditionally skip (exclude) fields or fragments: GraphQLSkipDirective = GraphQLDirective( - name='skip', + name="skip", locations=[ DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, - DirectiveLocation.INLINE_FRAGMENT], - args={'if': GraphQLArgument( - GraphQLNonNull(GraphQLBoolean), - description='Skipped when true.')}, - description='Directs the executor to skip this field or fragment' - ' when the `if` argument is true.') + DirectiveLocation.INLINE_FRAGMENT, + ], + args={ + "if": GraphQLArgument( + GraphQLNonNull(GraphQLBoolean), description="Skipped when true." + ) + }, + description="Directs the executor to skip this field or fragment" + " when the `if` argument is true.", +) # Constant string used for default reason for a deprecation: -DEFAULT_DEPRECATION_REASON = 'No longer supported' +DEFAULT_DEPRECATION_REASON = "No longer supported" # Used to declare element of a GraphQL schema as deprecated: GraphQLDeprecatedDirective = GraphQLDirective( - name='deprecated', - locations=[DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.ENUM_VALUE], - args={'reason': GraphQLArgument( - GraphQLString, - description='Explains why this element was deprecated,' - ' usually also including a suggestion for how to access' - ' supported similar data.' - ' Formatted using the Markdown syntax, as specified by' - ' [CommonMark](https://commonmark.org/).', - default_value=DEFAULT_DEPRECATION_REASON)}, - description='Marks an element of a GraphQL schema as no longer supported.') + name="deprecated", + locations=[DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.ENUM_VALUE], + args={ + "reason": GraphQLArgument( + GraphQLString, + description="Explains why this element was deprecated," + " usually also including a suggestion for how to access" + " supported similar data." + " Formatted using the Markdown syntax, as specified by" + " [CommonMark](https://commonmark.org/).", + default_value=DEFAULT_DEPRECATION_REASON, + ) + }, + description="Marks an element of a GraphQL schema as no longer supported.", +) # The full list of specified directives. specified_directives = ( GraphQLIncludeDirective, GraphQLSkipDirective, - GraphQLDeprecatedDirective) + GraphQLDeprecatedDirective, +) def is_specified_directive(directive: GraphQLDirective): """Check whether the given directive is one of the specified directives.""" - return any(specified_directive.name == directive.name - for specified_directive in specified_directives) + return any( + specified_directive.name == directive.name + for specified_directive in specified_directives + ) diff --git a/graphql/type/introspection.py b/graphql/type/introspection.py index ba09fd91..f8937641 100644 --- a/graphql/type/introspection.py +++ b/graphql/type/introspection.py @@ -2,195 +2,253 @@ from typing import Any from .definition import ( - GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, - GraphQLInputType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - is_abstract_type, is_enum_type, is_input_object_type, - is_interface_type, is_list_type, is_named_type, is_non_null_type, - is_object_type, is_scalar_type, is_union_type) + GraphQLArgument, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLInputType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + is_abstract_type, + is_enum_type, + is_input_object_type, + is_interface_type, + is_list_type, + is_named_type, + is_non_null_type, + is_object_type, + is_scalar_type, + is_union_type, +) from ..pyutils import is_invalid from .scalars import GraphQLBoolean, GraphQLString from ..language import DirectiveLocation __all__ = [ - 'SchemaMetaFieldDef', 'TypeKind', - 'TypeMetaFieldDef', 'TypeNameMetaFieldDef', - 'introspection_types', 'is_introspection_type'] + "SchemaMetaFieldDef", + "TypeKind", + "TypeMetaFieldDef", + "TypeNameMetaFieldDef", + "introspection_types", + "is_introspection_type", +] def print_value(value: Any, type_: GraphQLInputType) -> str: # Since print_value needs graphql.type, it can only be imported later from ..utilities.schema_printer import print_value + return print_value(value, type_) __Schema: GraphQLObjectType = GraphQLObjectType( - name='__Schema', - 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,' - ' mutation, and subscription operations.', + name="__Schema", + 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," + " mutation, and subscription operations.", fields=lambda: { - 'types': GraphQLField( + "types": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(__Type))), resolve=lambda schema, _info: schema.type_map.values(), - description='A list of all types supported by this server.'), - 'queryType': GraphQLField( + description="A list of all types supported by this server.", + ), + "queryType": GraphQLField( GraphQLNonNull(__Type), resolve=lambda schema, _info: schema.query_type, - description='The type that query operations will be rooted at.'), - 'mutationType': GraphQLField( + description="The type that query operations will be rooted at.", + ), + "mutationType": GraphQLField( __Type, resolve=lambda schema, _info: schema.mutation_type, - description='If this server supports mutation, the type that' - ' mutation operations will be rooted at.'), - 'subscriptionType': GraphQLField( + description="If this server supports mutation, the type that" + " mutation operations will be rooted at.", + ), + "subscriptionType": GraphQLField( __Type, resolve=lambda schema, _info: schema.subscription_type, - description='If this server support subscription, the type that' - ' subscription operations will be rooted at.'), - 'directives': GraphQLField( + description="If this server support subscription, the type that" + " subscription operations will be rooted at.", + ), + "directives": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(__Directive))), resolve=lambda schema, _info: schema.directives, - description='A list of all directives supported by this server.') - }) + description="A list of all directives supported by this server.", + ), + }, +) __Directive: GraphQLObjectType = GraphQLObjectType( - name='__Directive', - description='A Directive provides a way to describe alternate runtime' - ' execution and type validation behavior in a GraphQL' - ' document.\n\nIn some cases, you need to provide options' - " to alter GraphQL's execution behavior in ways field" - ' arguments will not suffice, such as conditionally including' - ' or skipping a field. Directives provide this by describing' - ' additional information to the executor.', + name="__Directive", + description="A Directive provides a way to describe alternate runtime" + " execution and type validation behavior in a GraphQL" + " document.\n\nIn some cases, you need to provide options" + " to alter GraphQL's execution behavior in ways field" + " arguments will not suffice, such as conditionally including" + " or skipping a field. Directives provide this by describing" + " additional information to the executor.", fields=lambda: { # Note: The fields onOperation, onFragment and onField are deprecated - 'name': GraphQLField( - GraphQLNonNull(GraphQLString), - resolve=lambda obj, _info: obj.name), - 'description': GraphQLField( - GraphQLString, resolve=lambda obj, _info: obj.description), - 'locations': GraphQLField( + "name": GraphQLField( + GraphQLNonNull(GraphQLString), resolve=lambda obj, _info: obj.name + ), + "description": GraphQLField( + GraphQLString, resolve=lambda obj, _info: obj.description + ), + "locations": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(__DirectiveLocation))), - resolve=lambda obj, _info: obj.locations), - 'args': GraphQLField( + resolve=lambda obj, _info: obj.locations, + ), + "args": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), - resolve=lambda directive, _info: (directive.args or {}).items())}) + resolve=lambda directive, _info: (directive.args or {}).items(), + ), + }, +) __DirectiveLocation: GraphQLEnumType = GraphQLEnumType( - name='__DirectiveLocation', - description='A Directive can be adjacent to many parts of the GraphQL' - ' language, a __DirectiveLocation describes one such possible' - ' adjacencies.', + name="__DirectiveLocation", + description="A Directive can be adjacent to many parts of the GraphQL" + " language, a __DirectiveLocation describes one such possible" + " adjacencies.", values={ - 'QUERY': GraphQLEnumValue( + "QUERY": GraphQLEnumValue( DirectiveLocation.QUERY, - description='Location adjacent to a query operation.'), - 'MUTATION': GraphQLEnumValue( + description="Location adjacent to a query operation.", + ), + "MUTATION": GraphQLEnumValue( DirectiveLocation.MUTATION, - description='Location adjacent to a mutation operation.'), - 'SUBSCRIPTION': GraphQLEnumValue( + description="Location adjacent to a mutation operation.", + ), + "SUBSCRIPTION": GraphQLEnumValue( DirectiveLocation.SUBSCRIPTION, - description='Location adjacent to a subscription operation.'), - 'FIELD': GraphQLEnumValue( - DirectiveLocation.FIELD, - description='Location adjacent to a field.'), - 'FRAGMENT_DEFINITION': GraphQLEnumValue( + description="Location adjacent to a subscription operation.", + ), + "FIELD": GraphQLEnumValue( + DirectiveLocation.FIELD, description="Location adjacent to a field." + ), + "FRAGMENT_DEFINITION": GraphQLEnumValue( DirectiveLocation.FRAGMENT_DEFINITION, - description='Location adjacent to a fragment definition.'), - 'FRAGMENT_SPREAD': GraphQLEnumValue( + description="Location adjacent to a fragment definition.", + ), + "FRAGMENT_SPREAD": GraphQLEnumValue( DirectiveLocation.FRAGMENT_SPREAD, - description='Location adjacent to a fragment spread.'), - 'INLINE_FRAGMENT': GraphQLEnumValue( + description="Location adjacent to a fragment spread.", + ), + "INLINE_FRAGMENT": GraphQLEnumValue( DirectiveLocation.INLINE_FRAGMENT, - description='Location adjacent to an inline fragment.'), - 'VARIABLE_DEFINITION': GraphQLEnumValue( + description="Location adjacent to an inline fragment.", + ), + "VARIABLE_DEFINITION": GraphQLEnumValue( DirectiveLocation.VARIABLE_DEFINITION, - description='Location adjacent to a variable definition.'), - 'SCHEMA': GraphQLEnumValue( + description="Location adjacent to a variable definition.", + ), + "SCHEMA": GraphQLEnumValue( DirectiveLocation.SCHEMA, - description='Location adjacent to a schema definition.'), - 'SCALAR': GraphQLEnumValue( + description="Location adjacent to a schema definition.", + ), + "SCALAR": GraphQLEnumValue( DirectiveLocation.SCALAR, - description='Location adjacent to a scalar definition.'), - 'OBJECT': GraphQLEnumValue( + description="Location adjacent to a scalar definition.", + ), + "OBJECT": GraphQLEnumValue( DirectiveLocation.OBJECT, - description='Location adjacent to an object type definition.'), - 'FIELD_DEFINITION': GraphQLEnumValue( + description="Location adjacent to an object type definition.", + ), + "FIELD_DEFINITION": GraphQLEnumValue( DirectiveLocation.FIELD_DEFINITION, - description='Location adjacent to a field definition.'), - 'ARGUMENT_DEFINITION': GraphQLEnumValue( + description="Location adjacent to a field definition.", + ), + "ARGUMENT_DEFINITION": GraphQLEnumValue( DirectiveLocation.ARGUMENT_DEFINITION, - description='Location adjacent to an argument definition.'), - 'INTERFACE': GraphQLEnumValue( + description="Location adjacent to an argument definition.", + ), + "INTERFACE": GraphQLEnumValue( DirectiveLocation.INTERFACE, - description='Location adjacent to an interface definition.'), - 'UNION': GraphQLEnumValue( + description="Location adjacent to an interface definition.", + ), + "UNION": GraphQLEnumValue( DirectiveLocation.UNION, - description='Location adjacent to a union definition.'), - 'ENUM': GraphQLEnumValue( + description="Location adjacent to a union definition.", + ), + "ENUM": GraphQLEnumValue( DirectiveLocation.ENUM, - description='Location adjacent to an enum definition.'), - 'ENUM_VALUE': GraphQLEnumValue( + description="Location adjacent to an enum definition.", + ), + "ENUM_VALUE": GraphQLEnumValue( DirectiveLocation.ENUM_VALUE, - description='Location adjacent to an enum value definition.'), - 'INPUT_OBJECT': GraphQLEnumValue( + description="Location adjacent to an enum value definition.", + ), + "INPUT_OBJECT": GraphQLEnumValue( DirectiveLocation.INPUT_OBJECT, - description='Location adjacent to' - ' an input object type definition.'), - 'INPUT_FIELD_DEFINITION': GraphQLEnumValue( + description="Location adjacent to" " an input object type definition.", + ), + "INPUT_FIELD_DEFINITION": GraphQLEnumValue( DirectiveLocation.INPUT_FIELD_DEFINITION, - description='Location adjacent to' - ' an input object field definition.')}) + description="Location adjacent to" " an input object field definition.", + ), + }, +) __Type: GraphQLObjectType = GraphQLObjectType( - name='__Type', - description='The fundamental unit of any GraphQL Schema is the type.' - ' There are many kinds of types in GraphQL as represented' - ' by the `__TypeKind` enum.\n\nDepending on the kind of a' - ' type, certain fields describe information about that type.' - ' Scalar types provide no information beyond a name and' - ' description, while Enum types provide their values.' - ' Object and Interface types provide the fields they describe.' - ' Abstract types, Union and Interface, provide the Object' - ' types possible at runtime. List and NonNull types compose' - ' other types.', + name="__Type", + description="The fundamental unit of any GraphQL Schema is the type." + " There are many kinds of types in GraphQL as represented" + " by the `__TypeKind` enum.\n\nDepending on the kind of a" + " type, certain fields describe information about that type." + " Scalar types provide no information beyond a name and" + " description, while Enum types provide their values." + " Object and Interface types provide the fields they describe." + " Abstract types, Union and Interface, provide the Object" + " types possible at runtime. List and NonNull types compose" + " other types.", fields=lambda: { - 'kind': GraphQLField( - GraphQLNonNull(__TypeKind), - resolve=TypeFieldResolvers.kind), - 'name': GraphQLField( - GraphQLString, resolve=TypeFieldResolvers.name), - 'description': GraphQLField( - GraphQLString, resolve=TypeFieldResolvers.description), - 'fields': GraphQLField( + "kind": GraphQLField( + GraphQLNonNull(__TypeKind), resolve=TypeFieldResolvers.kind + ), + "name": GraphQLField(GraphQLString, resolve=TypeFieldResolvers.name), + "description": GraphQLField( + GraphQLString, resolve=TypeFieldResolvers.description + ), + "fields": GraphQLField( GraphQLList(GraphQLNonNull(__Field)), - args={'includeDeprecated': GraphQLArgument( - GraphQLBoolean, default_value=False)}, - resolve=TypeFieldResolvers.fields), - 'interfaces': GraphQLField( - GraphQLList(GraphQLNonNull(__Type)), - resolve=TypeFieldResolvers.interfaces), - 'possibleTypes': GraphQLField( + args={ + "includeDeprecated": GraphQLArgument( + GraphQLBoolean, default_value=False + ) + }, + resolve=TypeFieldResolvers.fields, + ), + "interfaces": GraphQLField( + GraphQLList(GraphQLNonNull(__Type)), resolve=TypeFieldResolvers.interfaces + ), + "possibleTypes": GraphQLField( GraphQLList(GraphQLNonNull(__Type)), - resolve=TypeFieldResolvers.possible_types), - 'enumValues': GraphQLField( + resolve=TypeFieldResolvers.possible_types, + ), + "enumValues": GraphQLField( GraphQLList(GraphQLNonNull(__EnumValue)), - args={'includeDeprecated': GraphQLArgument( - GraphQLBoolean, default_value=False)}, - resolve=TypeFieldResolvers.enum_values), - 'inputFields': GraphQLField( + args={ + "includeDeprecated": GraphQLArgument( + GraphQLBoolean, default_value=False + ) + }, + resolve=TypeFieldResolvers.enum_values, + ), + "inputFields": GraphQLField( GraphQLList(GraphQLNonNull(__InputValue)), - resolve=TypeFieldResolvers.input_fields), - 'ofType': GraphQLField( - __Type, resolve=TypeFieldResolvers.of_type)}) + resolve=TypeFieldResolvers.input_fields, + ), + "ofType": GraphQLField(__Type, resolve=TypeFieldResolvers.of_type), + }, +) class TypeFieldResolvers: - @staticmethod def kind(type_, _info): if is_scalar_type(type_): @@ -209,15 +267,15 @@ def kind(type_, _info): return TypeKind.LIST if is_non_null_type(type_): return TypeKind.NON_NULL - raise TypeError(f'Unknown kind of type: {type_}') + raise TypeError(f"Unknown kind of type: {type_}") @staticmethod def name(type_, _info): - return getattr(type_, 'name', None) + return getattr(type_, "name", None) @staticmethod def description(type_, _info): - return getattr(type_, 'description', None) + return getattr(type_, "description", None) # noinspection PyPep8Naming @staticmethod @@ -225,8 +283,7 @@ def fields(type_, _info, includeDeprecated=False): if is_object_type(type_) or is_interface_type(type_): items = type_.fields.items() if not includeDeprecated: - return [item for item in items - if not item[1].deprecation_reason] + return [item for item in items if not item[1].deprecation_reason] return list(items) @staticmethod @@ -245,8 +302,7 @@ def enum_values(type_, _info, includeDeprecated=False): if is_enum_type(type_): items = type_.values.items() if not includeDeprecated: - return [item for item in items - if not item[1].deprecation_reason] + return [item for item in items if not item[1].deprecation_reason] return items @staticmethod @@ -256,160 +312,182 @@ def input_fields(type_, _info): @staticmethod def of_type(type_, _info): - return getattr(type_, 'of_type', None) + return getattr(type_, "of_type", None) __Field: GraphQLObjectType = GraphQLObjectType( - name='__Field', - description='Object and Interface types are described by a list of Fields,' - ' each of which has a name, potentially a list of arguments,' - ' and a return type.', + name="__Field", + description="Object and Interface types are described by a list of Fields," + " each of which has a name, potentially a list of arguments," + " and a return type.", fields=lambda: { - 'name': GraphQLField( - GraphQLNonNull(GraphQLString), - resolve=lambda item, _info: item[0]), - 'description': GraphQLField( - GraphQLString, - resolve=lambda item, _info: item[1].description), - 'args': GraphQLField( + "name": GraphQLField( + GraphQLNonNull(GraphQLString), resolve=lambda item, _info: item[0] + ), + "description": GraphQLField( + GraphQLString, resolve=lambda item, _info: item[1].description + ), + "args": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), - resolve=lambda item, _info: (item[1].args or {}).items()), - 'type': GraphQLField( - GraphQLNonNull(__Type), - resolve=lambda item, _info: item[1].type), - 'isDeprecated': GraphQLField( + resolve=lambda item, _info: (item[1].args or {}).items(), + ), + "type": GraphQLField( + GraphQLNonNull(__Type), resolve=lambda item, _info: item[1].type + ), + "isDeprecated": GraphQLField( GraphQLNonNull(GraphQLBoolean), - resolve=lambda item, _info: item[1].is_deprecated), - 'deprecationReason': GraphQLField( - GraphQLString, - resolve=lambda item, _info: item[1].deprecation_reason)}) + resolve=lambda item, _info: item[1].is_deprecated, + ), + "deprecationReason": GraphQLField( + GraphQLString, resolve=lambda item, _info: item[1].deprecation_reason + ), + }, +) __InputValue: GraphQLObjectType = GraphQLObjectType( - name='__InputValue', - description='Arguments provided to Fields or Directives and the input' - ' fields of an InputObject are represented as Input Values' - ' which describe their type and optionally a default value.', + name="__InputValue", + description="Arguments provided to Fields or Directives and the input" + " fields of an InputObject are represented as Input Values" + " which describe their type and optionally a default value.", fields=lambda: { - 'name': GraphQLField( - GraphQLNonNull(GraphQLString), - resolve=lambda item, _info: item[0]), - 'description': GraphQLField( - GraphQLString, - resolve=lambda item, _info: item[1].description), - 'type': GraphQLField( - GraphQLNonNull(__Type), - resolve=lambda item, _info: item[1].type), - 'defaultValue': GraphQLField( + "name": GraphQLField( + GraphQLNonNull(GraphQLString), resolve=lambda item, _info: item[0] + ), + "description": GraphQLField( + GraphQLString, resolve=lambda item, _info: item[1].description + ), + "type": GraphQLField( + GraphQLNonNull(__Type), resolve=lambda item, _info: item[1].type + ), + "defaultValue": GraphQLField( GraphQLString, - description='A GraphQL-formatted string representing' - ' the default value for this input value.', - resolve=lambda item, _info: - None if is_invalid(item[1].default_value) else print_value( - item[1].default_value, item[1].type))}) + description="A GraphQL-formatted string representing" + " the default value for this input value.", + resolve=lambda item, _info: None + if is_invalid(item[1].default_value) + else print_value(item[1].default_value, item[1].type), + ), + }, +) __EnumValue: GraphQLObjectType = GraphQLObjectType( - name='__EnumValue', - description='One possible value for a given Enum. Enum values are unique' - ' values, not a placeholder for a string or numeric value.' - ' However an Enum value is returned in a JSON response as a' - ' string.', + name="__EnumValue", + description="One possible value for a given Enum. Enum values are unique" + " values, not a placeholder for a string or numeric value." + " However an Enum value is returned in a JSON response as a" + " string.", fields=lambda: { - 'name': GraphQLField( - GraphQLNonNull(GraphQLString), - resolve=lambda item, _info: item[0]), - 'description': GraphQLField( - GraphQLString, - resolve=lambda item, _info: item[1].description), - 'isDeprecated': GraphQLField( + "name": GraphQLField( + GraphQLNonNull(GraphQLString), resolve=lambda item, _info: item[0] + ), + "description": GraphQLField( + GraphQLString, resolve=lambda item, _info: item[1].description + ), + "isDeprecated": GraphQLField( GraphQLNonNull(GraphQLBoolean), - resolve=lambda item, _info: item[1].is_deprecated), - 'deprecationReason': GraphQLField( - GraphQLString, - resolve=lambda item, _info: item[1].deprecation_reason)}) + resolve=lambda item, _info: item[1].is_deprecated, + ), + "deprecationReason": GraphQLField( + GraphQLString, resolve=lambda item, _info: item[1].deprecation_reason + ), + }, +) class TypeKind(Enum): - SCALAR = 'scalar' - OBJECT = 'object' - INTERFACE = 'interface' - UNION = 'union' - ENUM = 'enum' - INPUT_OBJECT = 'input object' - LIST = 'list' - NON_NULL = 'non-null' + SCALAR = "scalar" + OBJECT = "object" + INTERFACE = "interface" + UNION = "union" + ENUM = "enum" + INPUT_OBJECT = "input object" + LIST = "list" + NON_NULL = "non-null" __TypeKind: GraphQLEnumType = GraphQLEnumType( - name='__TypeKind', - description='An enum describing what kind of type a given `__Type` is.', + name="__TypeKind", + description="An enum describing what kind of type a given `__Type` is.", values={ - 'SCALAR': GraphQLEnumValue( - TypeKind.SCALAR, - description='Indicates this type is a scalar.'), - 'OBJECT': GraphQLEnumValue( + "SCALAR": GraphQLEnumValue( + TypeKind.SCALAR, description="Indicates this type is a scalar." + ), + "OBJECT": GraphQLEnumValue( TypeKind.OBJECT, - description='Indicates this type is an object. ' - '`fields` and `interfaces` are valid fields.'), - 'INTERFACE': GraphQLEnumValue( + description="Indicates this type is an object. " + "`fields` and `interfaces` are valid fields.", + ), + "INTERFACE": GraphQLEnumValue( TypeKind.INTERFACE, - description='Indicates this type is an interface. ' - '`fields` and `possibleTypes` are valid fields.'), - 'UNION': GraphQLEnumValue( + description="Indicates this type is an interface. " + "`fields` and `possibleTypes` are valid fields.", + ), + "UNION": GraphQLEnumValue( TypeKind.UNION, - description='Indicates this type is a union. ' - '`possibleTypes` is a valid field.'), - 'ENUM': GraphQLEnumValue( + description="Indicates this type is a union. " + "`possibleTypes` is a valid field.", + ), + "ENUM": GraphQLEnumValue( TypeKind.ENUM, - description='Indicates this type is an enum. ' - '`enumValues` is a valid field.'), - 'INPUT_OBJECT': GraphQLEnumValue( + description="Indicates this type is an enum. " + "`enumValues` is a valid field.", + ), + "INPUT_OBJECT": GraphQLEnumValue( TypeKind.INPUT_OBJECT, - description='Indicates this type is an input object. ' - '`inputFields` is a valid field.'), - 'LIST': GraphQLEnumValue( + description="Indicates this type is an input object. " + "`inputFields` is a valid field.", + ), + "LIST": GraphQLEnumValue( TypeKind.LIST, - description='Indicates this type is a list. ' - '`ofType` is a valid field.'), - 'NON_NULL': GraphQLEnumValue( + description="Indicates this type is a list. " "`ofType` is a valid field.", + ), + "NON_NULL": GraphQLEnumValue( TypeKind.NON_NULL, - description='Indicates this type is a non-null. ' - '`ofType` is a valid field.')}) + description="Indicates this type is a non-null. " + "`ofType` is a valid field.", + ), + }, +) SchemaMetaFieldDef = GraphQLField( GraphQLNonNull(__Schema), # name = '__schema' - description='Access the current type schema of this server.', + description="Access the current type schema of this server.", args={}, - resolve=lambda source, info: info.schema) + resolve=lambda source, info: info.schema, +) TypeMetaFieldDef = GraphQLField( __Type, # name = '__type' - description='Request the type information of a single type.', - args={'name': GraphQLArgument(GraphQLNonNull(GraphQLString))}, - resolve=lambda source, info, **args: info.schema.get_type(args['name'])) + description="Request the type information of a single type.", + args={"name": GraphQLArgument(GraphQLNonNull(GraphQLString))}, + resolve=lambda source, info, **args: info.schema.get_type(args["name"]), +) TypeNameMetaFieldDef = GraphQLField( GraphQLNonNull(GraphQLString), # name='__typename' - description='The name of the current Object type at runtime.', + description="The name of the current Object type at runtime.", args={}, - resolve=lambda source, info, **args: info.parent_type.name) + resolve=lambda source, info, **args: info.parent_type.name, +) # Since double underscore names are subject to name mangling in Python, # the introspection classes are best imported via this dictionary: introspection_types = { - '__Schema': __Schema, - '__Directive': __Directive, - '__DirectiveLocation': __DirectiveLocation, - '__Type': __Type, - '__Field': __Field, - '__InputValue': __InputValue, - '__EnumValue': __EnumValue, - '__TypeKind': __TypeKind} + "__Schema": __Schema, + "__Directive": __Directive, + "__DirectiveLocation": __DirectiveLocation, + "__Type": __Type, + "__Field": __Field, + "__InputValue": __InputValue, + "__EnumValue": __EnumValue, + "__TypeKind": __TypeKind, +} def is_introspection_type(type_: Any) -> bool: diff --git a/graphql/type/scalars.py b/graphql/type/scalars.py index 4fad4c4e..372f0907 100644 --- a/graphql/type/scalars.py +++ b/graphql/type/scalars.py @@ -4,13 +4,22 @@ from ..error import INVALID from ..pyutils import is_finite, is_integer from ..language.ast import ( - BooleanValueNode, FloatValueNode, IntValueNode, StringValueNode) + BooleanValueNode, + FloatValueNode, + IntValueNode, + StringValueNode, +) from .definition import GraphQLScalarType, is_named_type __all__ = [ - 'is_specified_scalar_type', 'specified_scalar_types', - 'GraphQLInt', 'GraphQLFloat', 'GraphQLString', - 'GraphQLBoolean', 'GraphQLID'] + "is_specified_scalar_type", + "specified_scalar_types", + "GraphQLInt", + "GraphQLFloat", + "GraphQLString", + "GraphQLBoolean", + "GraphQLID", +] # As per the GraphQL Spec, Integers are only treated as valid when a valid @@ -34,7 +43,7 @@ def serialize_int(value: Any) -> int: if num != value: raise ValueError elif not value and isinstance(value, str): - value = '' + value = "" raise ValueError else: num = int(value) @@ -42,19 +51,21 @@ def serialize_int(value: Any) -> int: if num != float_value: raise ValueError except (OverflowError, ValueError, TypeError): - raise TypeError(f'Int cannot represent non-integer value: {value!r}') + raise TypeError(f"Int cannot represent non-integer value: {value!r}") if not MIN_INT <= num <= MAX_INT: raise TypeError( - f'Int cannot represent non 32-bit signed integer value: {value!r}') + f"Int cannot represent non 32-bit signed integer value: {value!r}" + ) return num def coerce_int(value: Any) -> int: if not is_integer(value): - raise TypeError(f'Int cannot represent non-integer value: {value!r}') + raise TypeError(f"Int cannot represent non-integer value: {value!r}") if not MIN_INT <= value <= MAX_INT: raise TypeError( - f'Int cannot represent non 32-bit signed integer value: {value!r}') + f"Int cannot represent non 32-bit signed integer value: {value!r}" + ) return int(value) @@ -68,13 +79,14 @@ def parse_int_literal(ast, _variables=None): GraphQLInt = GraphQLScalarType( - name='Int', - description='The `Int` scalar type represents' - ' non-fractional signed whole numeric values.' - ' Int can represent values between -(2^31) and 2^31 - 1. ', + name="Int", + description="The `Int` scalar type represents" + " non-fractional signed whole numeric values." + " Int can represent values between -(2^31) and 2^31 - 1. ", serialize=serialize_int, parse_value=coerce_int, - parse_literal=parse_int_literal) + parse_literal=parse_int_literal, +) def serialize_float(value: Any) -> float: @@ -82,19 +94,19 @@ def serialize_float(value: Any) -> float: return 1 if value else 0 try: if not value and isinstance(value, str): - value = '' + value = "" raise ValueError num = value if isinstance(value, float) else float(value) if not isfinite(num): raise ValueError except (ValueError, TypeError): - raise TypeError(f'Float cannot represent non numeric value: {value!r}') + raise TypeError(f"Float cannot represent non numeric value: {value!r}") return num def coerce_float(value: Any) -> float: if not is_finite(value): - raise TypeError(f'Float cannot represent non numeric value: {value!r}') + raise TypeError(f"Float cannot represent non numeric value: {value!r}") return float(value) @@ -106,34 +118,34 @@ def parse_float_literal(ast, _variables=None): GraphQLFloat = GraphQLScalarType( - name='Float', - description='The `Float` scalar type represents' - ' signed double-precision fractional values' - ' as specified by [IEEE 754]' - '(http://en.wikipedia.org/wiki/IEEE_floating_point).', + name="Float", + description="The `Float` scalar type represents" + " signed double-precision fractional values" + " as specified by [IEEE 754]" + "(http://en.wikipedia.org/wiki/IEEE_floating_point).", serialize=serialize_float, parse_value=coerce_float, - parse_literal=parse_float_literal) + parse_literal=parse_float_literal, +) def serialize_string(value: Any) -> str: if isinstance(value, str): return value if isinstance(value, bool): - return 'true' if value else 'false' + return "true" if value else "false" if is_finite(value): return str(value) # do not serialize builtin types as strings, # but allow serialization of custom types via their __str__ method - if type(value).__module__ == 'builtins': - raise TypeError(f'String cannot represent value: {value!r}') + if type(value).__module__ == "builtins": + raise TypeError(f"String cannot represent value: {value!r}") return str(value) def coerce_string(value: Any) -> str: if not isinstance(value, str): - raise TypeError( - f'String cannot represent a non string value: {value!r}') + raise TypeError(f"String cannot represent a non string value: {value!r}") return value @@ -145,14 +157,15 @@ def parse_string_literal(ast, _variables=None): GraphQLString = GraphQLScalarType( - name='String', - description='The `String` scalar type represents textual data,' - ' represented as UTF-8 character sequences.' - ' The String type is most often used by GraphQL' - ' to represent free-form human-readable text.', + name="String", + description="The `String` scalar type represents textual data," + " represented as UTF-8 character sequences." + " The String type is most often used by GraphQL" + " to represent free-form human-readable text.", serialize=serialize_string, parse_value=coerce_string, - parse_literal=parse_string_literal) + parse_literal=parse_string_literal, +) def serialize_boolean(value: Any) -> bool: @@ -160,13 +173,12 @@ def serialize_boolean(value: Any) -> bool: return value if is_finite(value): return bool(value) - raise TypeError(f'Boolean cannot represent a non boolean value: {value!r}') + raise TypeError(f"Boolean cannot represent a non boolean value: {value!r}") def coerce_boolean(value: Any) -> bool: if not isinstance(value, bool): - raise TypeError( - f'Boolean cannot represent a non boolean value: {value!r}') + raise TypeError(f"Boolean cannot represent a non boolean value: {value!r}") return value @@ -178,11 +190,12 @@ def parse_boolean_literal(ast, _variables=None): GraphQLBoolean = GraphQLScalarType( - name='Boolean', - description='The `Boolean` scalar type represents `true` or `false`.', + name="Boolean", + description="The `Boolean` scalar type represents `true` or `false`.", serialize=serialize_boolean, parse_value=coerce_boolean, - parse_literal=parse_boolean_literal) + parse_literal=parse_boolean_literal, +) def serialize_id(value: Any) -> str: @@ -192,14 +205,14 @@ def serialize_id(value: Any) -> str: return str(int(value)) # do not serialize builtin types as IDs, # but allow serialization of custom types via their __str__ method - if type(value).__module__ == 'builtins': - raise TypeError(f'ID cannot represent value: {value!r}') + if type(value).__module__ == "builtins": + raise TypeError(f"ID cannot represent value: {value!r}") return str(value) def coerce_id(value: Any) -> str: if not isinstance(value, str) and not is_integer(value): - raise TypeError(f'ID cannot represent value: {value!r}') + raise TypeError(f"ID cannot represent value: {value!r}") if isinstance(value, float): value = int(value) return str(value) @@ -213,20 +226,23 @@ def parse_id_literal(ast, _variables=None): GraphQLID = GraphQLScalarType( - name='ID', - description='The `ID` scalar type represents a unique identifier,' - ' often used to refetch an object or as key for a cache.' - ' The ID type appears in a JSON response as a String; however,' - ' it is not intended to be human-readable. When expected as an' - ' input type, any string (such as `"4"`) or integer (such as' - ' `4`) input value will be accepted as an ID.', + name="ID", + description="The `ID` scalar type represents a unique identifier," + " often used to refetch an object or as key for a cache." + " The ID type appears in a JSON response as a String; however," + " it is not intended to be human-readable. When expected as an" + ' input type, any string (such as `"4"`) or integer (such as' + " `4`) input value will be accepted as an ID.", serialize=serialize_id, parse_value=coerce_id, - parse_literal=parse_id_literal) + parse_literal=parse_id_literal, +) -specified_scalar_types = {type_.name: type_ for type_ in ( - GraphQLString, GraphQLInt, GraphQLFloat, GraphQLBoolean, GraphQLID)} +specified_scalar_types = { + type_.name: type_ + for type_ in (GraphQLString, GraphQLInt, GraphQLFloat, GraphQLBoolean, GraphQLID) +} def is_specified_scalar_type(type_: Any) -> bool: diff --git a/graphql/type/schema.py b/graphql/type/schema.py index 02b1fb3d..ac2b293d 100644 --- a/graphql/type/schema.py +++ b/graphql/type/schema.py @@ -1,19 +1,27 @@ from functools import partial, reduce -from typing import ( - Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, cast) +from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, cast from ..error import GraphQLError from ..language import ast from .definition import ( - GraphQLAbstractType, GraphQLInterfaceType, GraphQLNamedType, - GraphQLObjectType, GraphQLUnionType, GraphQLInputObjectType, + GraphQLAbstractType, + GraphQLInterfaceType, + GraphQLNamedType, + GraphQLObjectType, + GraphQLUnionType, + GraphQLInputObjectType, GraphQLWrappingType, - is_abstract_type, is_input_object_type, is_interface_type, - is_object_type, is_union_type, is_wrapping_type) + is_abstract_type, + is_input_object_type, + is_interface_type, + is_object_type, + is_union_type, + is_wrapping_type, +) from .directives import GraphQLDirective, specified_directives, is_directive from .introspection import introspection_types -__all__ = ['GraphQLSchema', 'is_schema'] +__all__ = ["GraphQLSchema", "is_schema"] TypeMap = Dict[str, GraphQLNamedType] @@ -56,15 +64,17 @@ class GraphQLSchema: ast_node: Optional[ast.SchemaDefinitionNode] extension_ast_nodes: Optional[Tuple[ast.SchemaExtensionNode]] - def __init__(self, - query: GraphQLObjectType=None, - mutation: GraphQLObjectType=None, - subscription: GraphQLObjectType=None, - types: Sequence[GraphQLNamedType]=None, - directives: Sequence[GraphQLDirective]=None, - ast_node: ast.SchemaDefinitionNode=None, - extension_ast_nodes: Sequence[ast.SchemaExtensionNode]=None, - assume_valid: bool=False) -> None: + def __init__( + self, + query: GraphQLObjectType = None, + mutation: GraphQLObjectType = None, + subscription: GraphQLObjectType = None, + types: Sequence[GraphQLNamedType] = None, + directives: Sequence[GraphQLDirective] = None, + ast_node: ast.SchemaDefinitionNode = None, + extension_ast_nodes: Sequence[ast.SchemaExtensionNode] = None, + assume_valid: bool = False, + ) -> None: """Initialize GraphQL schema. If this schema was built from a source known to be valid, then it may @@ -85,11 +95,11 @@ def __init__(self, elif isinstance(types, tuple): types = list(types) if not isinstance(types, list): - raise TypeError('Schema types must be a list/tuple.') + raise TypeError("Schema types must be a list/tuple.") if isinstance(directives, tuple): directives = list(directives) if directives is not None and not isinstance(directives, list): - raise TypeError('Schema directives must be a list/tuple.') + raise TypeError("Schema directives must be a list/tuple.") self._validation_errors = None self.query_type = query @@ -98,13 +108,14 @@ def __init__(self, # Provide specified directives (e.g. @include and @skip) by default self.directives = list(directives or specified_directives) self.ast_node = ast_node - self.extension_ast_nodes = cast( - Tuple[ast.SchemaExtensionNode], tuple(extension_ast_nodes) - ) if extension_ast_nodes else None + self.extension_ast_nodes = ( + cast(Tuple[ast.SchemaExtensionNode], tuple(extension_ast_nodes)) + if extension_ast_nodes + else None + ) # Build type map now to detect any errors within this schema. - initial_types = [query, mutation, subscription, - introspection_types['__Schema']] + initial_types = [query, mutation, subscription, introspection_types["__Schema"]] if types: initial_types.extend(types) @@ -135,8 +146,8 @@ def get_type(self, name: str) -> Optional[GraphQLNamedType]: return self.type_map.get(name) def get_possible_types( - self, abstract_type: GraphQLAbstractType - ) -> Sequence[GraphQLObjectType]: + self, abstract_type: GraphQLAbstractType + ) -> Sequence[GraphQLObjectType]: """Get list of all possible concrete types for given abstract type.""" if is_union_type(abstract_type): abstract_type = cast(GraphQLUnionType, abstract_type) @@ -144,8 +155,8 @@ def get_possible_types( return self._implementations[abstract_type.name] def is_possible_type( - self, abstract_type: GraphQLAbstractType, - possible_type: GraphQLObjectType) -> bool: + self, abstract_type: GraphQLAbstractType, possible_type: GraphQLObjectType + ) -> bool: """Check whether a concrete type is possible for an abstract type.""" possible_type_map = self._possible_type_map try: @@ -167,19 +178,21 @@ def validation_errors(self): return self._validation_errors -def type_map_reducer(map_: TypeMap, type_: GraphQLNamedType=None) -> TypeMap: +def type_map_reducer(map_: TypeMap, type_: GraphQLNamedType = None) -> TypeMap: """Reducer function for creating the type map from given types.""" if not type_: return map_ if is_wrapping_type(type_): return type_map_reducer( - map_, cast(GraphQLWrappingType[GraphQLNamedType], type_).of_type) + map_, cast(GraphQLWrappingType[GraphQLNamedType], type_).of_type + ) name = type_.name if name in map_: if map_[name] is not type_: raise TypeError( - 'Schema must contain unique named types but contains multiple' - f' types named {name!r}.') + "Schema must contain unique named types but contains multiple" + f" types named {name!r}." + ) return map_ map_[name] = type_ @@ -207,20 +220,23 @@ def type_map_reducer(map_: TypeMap, type_: GraphQLNamedType=None) -> TypeMap: def type_map_directive_reducer( - map_: TypeMap, directive: GraphQLDirective=None) -> TypeMap: + map_: TypeMap, directive: GraphQLDirective = None +) -> TypeMap: """Reducer function for creating the type map from given directives.""" # Directives are not validated until validate_schema() is called. if not is_directive(directive): return map_ - return reduce(lambda prev_map, arg: - type_map_reducer(prev_map, arg.type), # type: ignore - directive.args.values(), map_) # type: ignore + return reduce( + lambda prev_map, arg: type_map_reducer(prev_map, arg.type), # type: ignore + directive.args.values(), + map_, + ) # type: ignore # Reduce functions for type maps: type_map_reduce: Callable[ # type: ignore - [Sequence[Optional[GraphQLNamedType]], TypeMap], TypeMap] = partial( - reduce, type_map_reducer) + [Sequence[Optional[GraphQLNamedType]], TypeMap], TypeMap +] = partial(reduce, type_map_reducer) type_map_directive_reduce: Callable[ # type: ignore - [Sequence[Optional[GraphQLDirective]], TypeMap], TypeMap] = partial( - reduce, type_map_directive_reducer) + [Sequence[Optional[GraphQLDirective]], TypeMap], TypeMap +] = partial(reduce, type_map_directive_reducer) diff --git a/graphql/type/validate.py b/graphql/type/validate.py index a4e90dc3..9ac64fc6 100644 --- a/graphql/type/validate.py +++ b/graphql/type/validate.py @@ -3,21 +3,38 @@ from ..error import GraphQLError from ..language import ( - EnumValueDefinitionNode, FieldDefinitionNode, InputValueDefinitionNode, - NamedTypeNode, Node, OperationType, OperationTypeDefinitionNode, TypeNode) + EnumValueDefinitionNode, + FieldDefinitionNode, + InputValueDefinitionNode, + NamedTypeNode, + Node, + OperationType, + OperationTypeDefinitionNode, + TypeNode, +) from .definition import ( - GraphQLEnumType, GraphQLInputObjectType, GraphQLInterfaceType, - GraphQLObjectType, GraphQLUnionType, - is_enum_type, is_input_object_type, is_input_type, is_interface_type, - is_named_type, is_object_type, is_output_type, is_union_type, - is_required_argument) + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLUnionType, + is_enum_type, + is_input_object_type, + is_input_type, + is_interface_type, + is_named_type, + is_object_type, + is_output_type, + is_union_type, + is_required_argument, +) from ..utilities.assert_valid_name import is_valid_name_error from ..utilities.type_comparators import is_equal_type, is_type_sub_type_of from .directives import GraphQLDirective, is_directive from .introspection import is_introspection_type from .schema import GraphQLSchema, is_schema -__all__ = ['validate_schema', 'assert_valid_schema'] +__all__ = ["validate_schema", "assert_valid_schema"] def validate_schema(schema: GraphQLSchema) -> List[GraphQLError]: @@ -31,7 +48,7 @@ def validate_schema(schema: GraphQLSchema) -> List[GraphQLError]: """ # First check to ensure the provided value is in fact a GraphQLSchema. if not is_schema(schema): - raise TypeError(f'Expected {schema!r} to be a GraphQL schema.') + raise TypeError(f"Expected {schema!r} to be a GraphQL schema.") # If this Schema has already been validated, return the previous results. # noinspection PyProtectedMember @@ -59,7 +76,7 @@ def assert_valid_schema(schema: GraphQLSchema): """ errors = validate_schema(schema) if errors: - raise TypeError('\n\n'.join(error.message for error in errors)) + raise TypeError("\n\n".join(error.message for error in errors)) class SchemaValidationContext: @@ -72,8 +89,11 @@ def __init__(self, schema: GraphQLSchema) -> None: self.errors = [] self.schema = schema - def report_error(self, message: str, nodes: Union[ - Optional[Node], Sequence[Optional[Node]]]=None): + def report_error( + self, + message: str, + nodes: Union[Optional[Node], Sequence[Optional[Node]]] = None, + ): if isinstance(nodes, Node): nodes = [nodes] if nodes: @@ -89,30 +109,30 @@ def validate_root_types(self): query_type = schema.query_type if not query_type: - self.report_error( - 'Query root type must be provided.', schema.ast_node) + self.report_error("Query root type must be provided.", schema.ast_node) elif not is_object_type(query_type): self.report_error( - 'Query root type must be Object type,' - f' it cannot be {query_type}.', - get_operation_type_node( - schema, query_type, OperationType.QUERY)) + "Query root type must be Object type," f" it cannot be {query_type}.", + get_operation_type_node(schema, query_type, OperationType.QUERY), + ) mutation_type = schema.mutation_type if mutation_type and not is_object_type(mutation_type): self.report_error( - 'Mutation root type must be Object type if provided,' - f' it cannot be {mutation_type}.', - get_operation_type_node( - schema, mutation_type, OperationType.MUTATION)) + "Mutation root type must be Object type if provided," + f" it cannot be {mutation_type}.", + get_operation_type_node(schema, mutation_type, OperationType.MUTATION), + ) subscription_type = schema.subscription_type if subscription_type and not is_object_type(subscription_type): self.report_error( - 'Subscription root type must be Object type if provided,' - f' it cannot be {subscription_type}.', + "Subscription root type must be Object type if provided," + f" it cannot be {subscription_type}.", get_operation_type_node( - schema, subscription_type, OperationType.SUBSCRIPTION)) + schema, subscription_type, OperationType.SUBSCRIPTION + ), + ) def validate_directives(self): directives = self.schema.directives @@ -120,8 +140,9 @@ def validate_directives(self): # Ensure all directives are in fact GraphQL directives. if not is_directive(directive): self.report_error( - f'Expected directive but got: {directive!r}.', - getattr(directive, 'ast_node', None)) + f"Expected directive but got: {directive!r}.", + getattr(directive, "ast_node", None), + ) continue # Ensure they are named correctly. @@ -136,20 +157,22 @@ def validate_directives(self): # Ensure they are unique per directive. if arg_name in arg_names: self.report_error( - f'Argument @{directive.name}({arg_name}:)' - ' can only be defined once.', - get_all_directive_arg_nodes(directive, arg_name)) + f"Argument @{directive.name}({arg_name}:)" + " can only be defined once.", + get_all_directive_arg_nodes(directive, arg_name), + ) continue arg_names.add(arg_name) # Ensure the type is an input type. if not is_input_type(arg.type): self.report_error( - f'The type of @{directive.name}({arg_name}:)' - f' must be Input Type but got: {arg.type!r}.', - get_directive_arg_type_node(directive, arg_name)) + f"The type of @{directive.name}({arg_name}:)" + f" must be Input Type but got: {arg.type!r}.", + get_directive_arg_type_node(directive, arg_name), + ) - def validate_name(self, node: Any, name: str=None): + def validate_name(self, node: Any, name: str = None): # Ensure names are valid, however introspection types opt out. try: if not name: @@ -169,8 +192,9 @@ def validate_types(self): # Ensure all provided types are in fact GraphQL type. if not is_named_type(type_): self.report_error( - f'Expected GraphQL named type but got: {type_!r}.', - type_.ast_node if type_ else None) + f"Expected GraphQL named type but got: {type_!r}.", + type_.ast_node if type_ else None, + ) continue # Ensure it is named correctly (excluding introspection types). @@ -201,15 +225,15 @@ def validate_types(self): # Ensure Input Object fields are valid. self.validate_input_fields(type_) - def validate_fields( - self, type_: Union[GraphQLObjectType, GraphQLInterfaceType]): + def validate_fields(self, type_: Union[GraphQLObjectType, GraphQLInterfaceType]): fields = type_.fields # Objects and Interfaces both must define one or more fields. if not fields: self.report_error( - f'Type {type_.name} must define one or more fields.', - get_all_nodes(type_)) + f"Type {type_.name} must define one or more fields.", + get_all_nodes(type_), + ) for field_name, field in fields.items(): @@ -220,16 +244,18 @@ def validate_fields( field_nodes = get_all_field_nodes(type_, field_name) if len(field_nodes) > 1: self.report_error( - f'Field {type_.name}.{field_name}' - ' can only be defined once.', field_nodes) + f"Field {type_.name}.{field_name}" " can only be defined once.", + field_nodes, + ) continue # Ensure the type is an output type if not is_output_type(field.type): self.report_error( - f'The type of {type_.name}.{field_name}' - ' must be Output Type but got: {field.type!r}.', - get_field_type_node(type_, field_name)) + f"The type of {type_.name}.{field_name}" + " must be Output Type but got: {field.type!r}.", + get_field_type_node(type_, field_name), + ) # Ensure the arguments are valid. arg_names: Set[str] = set() @@ -240,40 +266,45 @@ def validate_fields( # Ensure they are unique per field. if arg_name in arg_names: self.report_error( - 'Field argument' - f' {type_.name}.{field_name}({arg_name}:)' - ' can only be defined once.', - get_all_field_arg_nodes(type_, field_name, arg_name)) + "Field argument" + f" {type_.name}.{field_name}({arg_name}:)" + " can only be defined once.", + get_all_field_arg_nodes(type_, field_name, arg_name), + ) break arg_names.add(arg_name) # Ensure the type is an input type. if not is_input_type(arg.type): self.report_error( - 'Field argument' - f' {type_.name}.{field_name}({arg_name}:)' - f' must be Input Type but got: {arg.type!r}.', - get_field_arg_type_node(type_, field_name, arg_name)) + "Field argument" + f" {type_.name}.{field_name}({arg_name}:)" + f" must be Input Type but got: {arg.type!r}.", + get_field_arg_type_node(type_, field_name, arg_name), + ) def validate_object_interfaces(self, obj: GraphQLObjectType): implemented_type_names: Set[str] = set() for iface in obj.interfaces: if not is_interface_type(iface): self.report_error( - f'Type {obj.name} must only implement Interface' - f' types, it cannot implement {iface!r}.', - get_implements_interface_node(obj, iface)) + f"Type {obj.name} must only implement Interface" + f" types, it cannot implement {iface!r}.", + get_implements_interface_node(obj, iface), + ) continue if iface.name in implemented_type_names: self.report_error( - f'Type {obj.name} can only implement {iface.name} once.', - get_all_implements_interface_nodes(obj, iface)) + f"Type {obj.name} can only implement {iface.name} once.", + get_all_implements_interface_nodes(obj, iface), + ) continue implemented_type_names.add(iface.name) self.validate_object_implements_interface(obj, iface) def validate_object_implements_interface( - self, obj: GraphQLObjectType, iface: GraphQLInterfaceType): + self, obj: GraphQLObjectType, iface: GraphQLInterfaceType + ): obj_fields, iface_fields = obj.fields, iface.fields # Assert each interface field is implemented. @@ -283,24 +314,26 @@ def validate_object_implements_interface( # Assert interface field exists on object. if not obj_field: self.report_error( - f'Interface field {iface.name}.{field_name}' - f' expected but {obj.name} does not provide it.', - [get_field_node(iface, field_name)] + - cast(List[Optional[FieldDefinitionNode]], - get_all_nodes(obj))) + f"Interface field {iface.name}.{field_name}" + f" expected but {obj.name} does not provide it.", + [get_field_node(iface, field_name)] + + cast(List[Optional[FieldDefinitionNode]], get_all_nodes(obj)), + ) continue # Assert interface field type is satisfied by object field type, # by being a valid subtype. (covariant) - if not is_type_sub_type_of( - self.schema, obj_field.type, iface_field.type): + if not is_type_sub_type_of(self.schema, obj_field.type, iface_field.type): self.report_error( - f'Interface field {iface.name}.{field_name}' - f' expects type {iface_field.type}' - f' but {obj.name}.{field_name}' - f' is type {obj_field.type}.', - [get_field_type_node(iface, field_name), - get_field_type_node(obj, field_name)]) + f"Interface field {iface.name}.{field_name}" + f" expects type {iface_field.type}" + f" but {obj.name}.{field_name}" + f" is type {obj_field.type}.", + [ + get_field_type_node(iface, field_name), + get_field_type_node(obj, field_name), + ], + ) # Assert each interface field arg is implemented. for arg_name, iface_arg in iface_field.args.items(): @@ -309,52 +342,63 @@ def validate_object_implements_interface( # Assert interface field arg exists on object field. if not obj_arg: self.report_error( - 'Interface field argument' - f' {iface.name}.{field_name}({arg_name}:)' - f' expected but {obj.name}.{field_name}' - ' does not provide it.', - [get_field_arg_node(iface, field_name, arg_name), - get_field_node(obj, field_name)]) + "Interface field argument" + f" {iface.name}.{field_name}({arg_name}:)" + f" expected but {obj.name}.{field_name}" + " does not provide it.", + [ + get_field_arg_node(iface, field_name, arg_name), + get_field_node(obj, field_name), + ], + ) continue # Assert interface field arg type matches object field arg type # (invariant). if not is_equal_type(iface_arg.type, obj_arg.type): self.report_error( - 'Interface field argument' - f' {iface.name}.{field_name}({arg_name}:)' - f' expects type {iface_arg.type}' - f' but {obj.name}.{field_name}({arg_name}:)' - f' is type {obj_arg.type}.', - [get_field_arg_type_node(iface, field_name, arg_name), - get_field_arg_type_node(obj, field_name, arg_name)]) + "Interface field argument" + f" {iface.name}.{field_name}({arg_name}:)" + f" expects type {iface_arg.type}" + f" but {obj.name}.{field_name}({arg_name}:)" + f" is type {obj_arg.type}.", + [ + get_field_arg_type_node(iface, field_name, arg_name), + get_field_arg_type_node(obj, field_name, arg_name), + ], + ) # Assert additional arguments must not be required. for arg_name, obj_arg in obj_field.args.items(): iface_arg = iface_field.args.get(arg_name) if not iface_arg and is_required_argument(obj_arg): self.report_error( - f'Object field {obj.name}.{field_name} includes' - f' required argument {arg_name} that is missing from' - f' the Interface field {iface.name}.{field_name}.', - [get_field_arg_node(obj, field_name, arg_name), - get_field_node(iface, field_name)]) + f"Object field {obj.name}.{field_name} includes" + f" required argument {arg_name} that is missing from" + f" the Interface field {iface.name}.{field_name}.", + [ + get_field_arg_node(obj, field_name, arg_name), + get_field_node(iface, field_name), + ], + ) def validate_union_members(self, union: GraphQLUnionType): member_types = union.types if not member_types: self.report_error( - f'Union type {union.name}' - ' must define one or more member types.', get_all_nodes(union)) + f"Union type {union.name}" " must define one or more member types.", + get_all_nodes(union), + ) included_type_names: Set[str] = set() for member_type in member_types: if member_type.name in included_type_names: self.report_error( - f'Union type {union.name} can only include type' - f' {member_type.name} once.', - get_union_member_type_nodes(union, member_type.name)) + f"Union type {union.name} can only include type" + f" {member_type.name} once.", + get_union_member_type_nodes(union, member_type.name), + ) continue included_type_names.add(member_type.name) @@ -363,31 +407,38 @@ def validate_enum_values(self, enum_type: GraphQLEnumType): if not enum_values: self.report_error( - f'Enum type {enum_type.name} must define one or more values.', - get_all_nodes(enum_type)) + f"Enum type {enum_type.name} must define one or more values.", + get_all_nodes(enum_type), + ) for value_name, enum_value in enum_values.items(): # Ensure no duplicates. all_nodes = get_enum_value_nodes(enum_type, value_name) if all_nodes and len(all_nodes) > 1: self.report_error( - f'Enum type {enum_type.name}' - f' can include value {value_name} only once.', all_nodes) + f"Enum type {enum_type.name}" + f" can include value {value_name} only once.", + all_nodes, + ) # Ensure valid name. self.validate_name(enum_value, value_name) - if value_name in ('true', 'false', 'null'): + if value_name in ("true", "false", "null"): self.report_error( - f'Enum type {enum_type.name} cannot include value:' - f' {value_name}.', enum_value.ast_node) + f"Enum type {enum_type.name} cannot include value:" + f" {value_name}.", + enum_value.ast_node, + ) def validate_input_fields(self, input_obj: GraphQLInputObjectType): fields = input_obj.fields if not fields: self.report_error( - f'Input Object type {input_obj.name}' - ' must define one or more fields.', get_all_nodes(input_obj)) + f"Input Object type {input_obj.name}" + " must define one or more fields.", + get_all_nodes(input_obj), + ) # Ensure the arguments are valid for field_name, field in fields.items(): @@ -398,16 +449,19 @@ def validate_input_fields(self, input_obj: GraphQLInputObjectType): # Ensure the type is an input type. if not is_input_type(field.type): self.report_error( - f'The type of {input_obj.name}.{field_name}' - f' must be Input Type but got: {field.type!r}.', - field.ast_node.type if field.ast_node else None) + f"The type of {input_obj.name}.{field_name}" + f" must be Input Type but got: {field.type!r}.", + field.ast_node.type if field.ast_node else None, + ) -def get_operation_type_node(schema: GraphQLSchema, type_: GraphQLObjectType, - operation: OperationType) -> Optional[Node]: +def get_operation_type_node( + schema: GraphQLSchema, type_: GraphQLObjectType, operation: OperationType +) -> Optional[Node]: operation_nodes = cast( List[OperationTypeDefinitionNode], - get_all_sub_nodes(schema, attrgetter('operation_types'))) + get_all_sub_nodes(schema, attrgetter("operation_types")), + ) for node in operation_nodes: if node.operation == operation: return node.type @@ -415,22 +469,28 @@ def get_operation_type_node(schema: GraphQLSchema, type_: GraphQLObjectType, SDLDefinedObject = Union[ - GraphQLSchema, GraphQLDirective, GraphQLInterfaceType, GraphQLObjectType, - GraphQLInputObjectType, GraphQLUnionType, GraphQLEnumType] + GraphQLSchema, + GraphQLDirective, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLInputObjectType, + GraphQLUnionType, + GraphQLEnumType, +] def get_all_nodes(obj: SDLDefinedObject) -> List[Node]: node = obj.ast_node nodes: List[Node] = [node] if node else [] - extension_nodes = getattr(obj, 'extension_ast_nodes', None) + extension_nodes = getattr(obj, "extension_ast_nodes", None) if extension_nodes: nodes.extend(extension_nodes) return nodes def get_all_sub_nodes( - obj: SDLDefinedObject, - getter: Callable[[Node], List[Node]]) -> List[Node]: + obj: SDLDefinedObject, getter: Callable[[Node], List[Node]] +) -> List[Node]: result: List[Node] = [] for ast_node in get_all_nodes(obj): if ast_node: @@ -441,56 +501,64 @@ def get_all_sub_nodes( def get_implements_interface_node( - type_: GraphQLObjectType, iface: GraphQLInterfaceType - ) -> Optional[NamedTypeNode]: + type_: GraphQLObjectType, iface: GraphQLInterfaceType +) -> Optional[NamedTypeNode]: nodes = get_all_implements_interface_nodes(type_, iface) return nodes[0] if nodes else None def get_all_implements_interface_nodes( - type_: GraphQLObjectType, iface: GraphQLInterfaceType - ) -> List[NamedTypeNode]: + type_: GraphQLObjectType, iface: GraphQLInterfaceType +) -> List[NamedTypeNode]: implements_nodes = cast( - List[NamedTypeNode], - get_all_sub_nodes(type_, attrgetter('interfaces'))) - return [iface_node for iface_node in implements_nodes - if iface_node.name.value == iface.name] + List[NamedTypeNode], get_all_sub_nodes(type_, attrgetter("interfaces")) + ) + return [ + iface_node + for iface_node in implements_nodes + if iface_node.name.value == iface.name + ] def get_field_node( - type_: Union[GraphQLObjectType, GraphQLInterfaceType], - field_name: str) -> Optional[FieldDefinitionNode]: + type_: Union[GraphQLObjectType, GraphQLInterfaceType], field_name: str +) -> Optional[FieldDefinitionNode]: nodes = get_all_field_nodes(type_, field_name) return nodes[0] if nodes else None def get_all_field_nodes( - type_: Union[GraphQLObjectType, GraphQLInterfaceType], - field_name: str) -> List[FieldDefinitionNode]: + type_: Union[GraphQLObjectType, GraphQLInterfaceType], field_name: str +) -> List[FieldDefinitionNode]: field_nodes = cast( - List[FieldDefinitionNode], - get_all_sub_nodes(type_, attrgetter('fields'))) - return [field_node for field_node in field_nodes - if field_node.name.value == field_name] + List[FieldDefinitionNode], get_all_sub_nodes(type_, attrgetter("fields")) + ) + return [ + field_node for field_node in field_nodes if field_node.name.value == field_name + ] def get_field_type_node( - type_: Union[GraphQLObjectType, GraphQLInterfaceType], - field_name: str) -> Optional[TypeNode]: + type_: Union[GraphQLObjectType, GraphQLInterfaceType], field_name: str +) -> Optional[TypeNode]: field_node = get_field_node(type_, field_name) return field_node.type if field_node else None def get_field_arg_node( - type_: Union[GraphQLObjectType, GraphQLInterfaceType], - field_name: str, arg_name: str) -> Optional[InputValueDefinitionNode]: + type_: Union[GraphQLObjectType, GraphQLInterfaceType], + field_name: str, + arg_name: str, +) -> Optional[InputValueDefinitionNode]: nodes = get_all_field_arg_nodes(type_, field_name, arg_name) return nodes[0] if nodes else None def get_all_field_arg_nodes( - type_: Union[GraphQLObjectType, GraphQLInterfaceType], - field_name: str, arg_name: str) -> List[InputValueDefinitionNode]: + type_: Union[GraphQLObjectType, GraphQLInterfaceType], + field_name: str, + arg_name: str, +) -> List[InputValueDefinitionNode]: arg_nodes = [] field_node = get_field_node(type_, field_name) if field_node and field_node.arguments: @@ -501,44 +569,48 @@ def get_all_field_arg_nodes( def get_field_arg_type_node( - type_: Union[GraphQLObjectType, GraphQLInterfaceType], - field_name: str, arg_name: str) -> Optional[TypeNode]: + type_: Union[GraphQLObjectType, GraphQLInterfaceType], + field_name: str, + arg_name: str, +) -> Optional[TypeNode]: field_arg_node = get_field_arg_node(type_, field_name, arg_name) return field_arg_node.type if field_arg_node else None def get_all_directive_arg_nodes( - directive: GraphQLDirective, arg_name: str - ) -> List[InputValueDefinitionNode]: + directive: GraphQLDirective, arg_name: str +) -> List[InputValueDefinitionNode]: arg_nodes = cast( List[InputValueDefinitionNode], - get_all_sub_nodes(directive, attrgetter('arguments'))) - return [arg_node for arg_node in arg_nodes - if arg_node.name.value == arg_name] + get_all_sub_nodes(directive, attrgetter("arguments")), + ) + return [arg_node for arg_node in arg_nodes if arg_node.name.value == arg_name] def get_directive_arg_type_node( - directive: GraphQLDirective, arg_name: str) -> Optional[TypeNode]: + directive: GraphQLDirective, arg_name: str +) -> Optional[TypeNode]: arg_nodes = get_all_directive_arg_nodes(directive, arg_name) arg_node = arg_nodes[0] if arg_nodes else None return arg_node.type if arg_node else None def get_union_member_type_nodes( - union: GraphQLUnionType, type_name: str - ) -> Optional[List[NamedTypeNode]]: + union: GraphQLUnionType, type_name: str +) -> Optional[List[NamedTypeNode]]: union_nodes = cast( - List[NamedTypeNode], - get_all_sub_nodes(union, attrgetter('types'))) - return [union_node for union_node in union_nodes - if union_node.name.value == type_name] + List[NamedTypeNode], get_all_sub_nodes(union, attrgetter("types")) + ) + return [ + union_node for union_node in union_nodes if union_node.name.value == type_name + ] def get_enum_value_nodes( - enum_type: GraphQLEnumType, value_name: str - ) -> Optional[List[EnumValueDefinitionNode]]: + enum_type: GraphQLEnumType, value_name: str +) -> Optional[List[EnumValueDefinitionNode]]: enum_nodes = cast( List[EnumValueDefinitionNode], - get_all_sub_nodes(enum_type, attrgetter('values'))) - return [enum_node for enum_node in enum_nodes - if enum_node.name.value == value_name] + get_all_sub_nodes(enum_type, attrgetter("values")), + ) + return [enum_node for enum_node in enum_nodes if enum_node.name.value == value_name] diff --git a/graphql/utilities/__init__.py b/graphql/utilities/__init__.py index ccd59f2b..9931ec7b 100644 --- a/graphql/utilities/__init__.py +++ b/graphql/utilities/__init__.py @@ -30,7 +30,11 @@ # Print a GraphQLSchema to GraphQL Schema language. from .schema_printer import ( - print_introspection_schema, print_schema, print_type, print_value) + print_introspection_schema, + print_schema, + print_type, + print_value, +) # Create a GraphQLType from a GraphQL language AST. from .type_from_ast import type_from_ast @@ -58,34 +62,57 @@ from .separate_operations import separate_operations # Comparators for types -from .type_comparators import ( - is_equal_type, is_type_sub_type_of, do_types_overlap) +from .type_comparators import is_equal_type, is_type_sub_type_of, do_types_overlap # Asserts that a string is a valid GraphQL name from .assert_valid_name import assert_valid_name, is_valid_name_error # Compares two GraphQLSchemas and detects breaking changes. from .find_breaking_changes import ( - BreakingChange, BreakingChangeType, DangerousChange, DangerousChangeType, - find_breaking_changes, find_dangerous_changes) + BreakingChange, + BreakingChangeType, + DangerousChange, + DangerousChangeType, + find_breaking_changes, + find_dangerous_changes, +) # Report all deprecated usage within a GraphQL document. from .find_deprecated_usages import find_deprecated_usages __all__ = [ - 'BreakingChange', 'BreakingChangeType', - 'DangerousChange', 'DangerousChangeType', 'TypeInfo', - 'assert_valid_name', 'ast_from_value', - 'build_ast_schema', 'build_client_schema', 'build_schema', - 'coerce_value', 'concat_ast', - 'do_types_overlap', 'extend_schema', - 'find_breaking_changes', 'find_dangerous_changes', - 'find_deprecated_usages', - 'get_description', 'get_introspection_query', - 'get_operation_ast', 'get_operation_root_type', - 'is_equal_type', 'is_type_sub_type_of', 'is_valid_name_error', - 'introspection_from_schema', - 'lexicographic_sort_schema', - 'print_introspection_schema', 'print_schema', 'print_type', 'print_value', - 'separate_operations', - 'type_from_ast', 'value_from_ast', 'value_from_ast_untyped'] + "BreakingChange", + "BreakingChangeType", + "DangerousChange", + "DangerousChangeType", + "TypeInfo", + "assert_valid_name", + "ast_from_value", + "build_ast_schema", + "build_client_schema", + "build_schema", + "coerce_value", + "concat_ast", + "do_types_overlap", + "extend_schema", + "find_breaking_changes", + "find_dangerous_changes", + "find_deprecated_usages", + "get_description", + "get_introspection_query", + "get_operation_ast", + "get_operation_root_type", + "is_equal_type", + "is_type_sub_type_of", + "is_valid_name_error", + "introspection_from_schema", + "lexicographic_sort_schema", + "print_introspection_schema", + "print_schema", + "print_type", + "print_value", + "separate_operations", + "type_from_ast", + "value_from_ast", + "value_from_ast_untyped", +] diff --git a/graphql/utilities/assert_valid_name.py b/graphql/utilities/assert_valid_name.py index dcc196d6..02d2ce94 100644 --- a/graphql/utilities/assert_valid_name.py +++ b/graphql/utilities/assert_valid_name.py @@ -4,10 +4,10 @@ from ..language import Node from ..error import GraphQLError -__all__ = ['assert_valid_name', 'is_valid_name_error'] +__all__ = ["assert_valid_name", "is_valid_name_error"] -re_name = re.compile('^[_a-zA-Z][_a-zA-Z0-9]*$') +re_name = re.compile("^[_a-zA-Z][_a-zA-Z0-9]*$") def assert_valid_name(name: str) -> str: @@ -18,17 +18,19 @@ def assert_valid_name(name: str) -> str: return name -def is_valid_name_error( - name: str, node: Node=None) -> Optional[GraphQLError]: +def is_valid_name_error(name: str, node: Node = None) -> Optional[GraphQLError]: """Return an Error if a name is invalid.""" if not isinstance(name, str): - raise TypeError('Expected string') - if name.startswith('__'): + raise TypeError("Expected string") + if name.startswith("__"): return GraphQLError( f"Name {name!r} must not begin with '__'," - ' which is reserved by GraphQL introspection.', node) + " which is reserved by GraphQL introspection.", + node, + ) if not re_name.match(name): return GraphQLError( - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/' - f' but {name!r} does not.', node) + "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/" f" but {name!r} does not.", + node, + ) return None diff --git a/graphql/utilities/ast_from_value.py b/graphql/utilities/ast_from_value.py index 962ab12f..ab6d7509 100644 --- a/graphql/utilities/ast_from_value.py +++ b/graphql/utilities/ast_from_value.py @@ -2,19 +2,35 @@ from typing import Any, Iterable, List, Mapping, Optional, cast from ..language import ( - BooleanValueNode, EnumValueNode, FloatValueNode, IntValueNode, - ListValueNode, NameNode, NullValueNode, ObjectFieldNode, - ObjectValueNode, StringValueNode, ValueNode) + BooleanValueNode, + EnumValueNode, + FloatValueNode, + IntValueNode, + ListValueNode, + NameNode, + NullValueNode, + ObjectFieldNode, + ObjectValueNode, + StringValueNode, + ValueNode, +) from ..pyutils import is_nullish, is_invalid from ..type import ( - GraphQLID, GraphQLInputType, GraphQLInputObjectType, - GraphQLList, GraphQLNonNull, - is_enum_type, is_input_object_type, is_list_type, - is_non_null_type, is_scalar_type) + GraphQLID, + GraphQLInputType, + GraphQLInputObjectType, + GraphQLList, + GraphQLNonNull, + is_enum_type, + is_input_object_type, + is_list_type, + is_non_null_type, + is_scalar_type, +) -__all__ = ['ast_from_value'] +__all__ = ["ast_from_value"] -_re_integer_string = re.compile('^-?(0|[1-9][0-9]*)$') +_re_integer_string = re.compile("^-?(0|[1-9][0-9]*)$") def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]: @@ -56,8 +72,8 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]: item_type = type_.of_type if isinstance(value, Iterable) and not isinstance(value, str): value_nodes = [ - ast_from_value(item, item_type) # type: ignore - for item in value] + ast_from_value(item, item_type) for item in value # type: ignore + ] return ListValueNode(values=value_nodes) return ast_from_value(value, item_type) # type: ignore @@ -73,8 +89,11 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]: if field_name in value: field_value = ast_from_value(value[field_name], field.type) if field_value: - append_node(ObjectFieldNode( - name=NameNode(value=field_name), value=field_value)) + append_node( + ObjectFieldNode( + name=NameNode(value=field_name), value=field_value + ) + ) return ObjectValueNode(fields=field_nodes) if is_scalar_type(type_) or is_enum_type(type_): @@ -90,9 +109,9 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]: # Python ints and floats correspond nicely to Int and Float values. if isinstance(serialized, int): - return IntValueNode(value=f'{serialized:d}') + return IntValueNode(value=f"{serialized:d}") if isinstance(serialized, float): - return FloatValueNode(value=f'{serialized:g}') + return FloatValueNode(value=f"{serialized:g}") if isinstance(serialized, str): # Enum types use Enum literals. @@ -105,6 +124,6 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]: return StringValueNode(value=serialized) - raise TypeError(f'Cannot convert value to AST: {serialized!r}') + raise TypeError(f"Cannot convert value to AST: {serialized!r}") - raise TypeError(f'Unknown type: {type_!r}.') + raise TypeError(f"Unknown type: {type_!r}.") diff --git a/graphql/utilities/build_ast_schema.py b/graphql/utilities/build_ast_schema.py index b65a99b1..15539e9b 100644 --- a/graphql/utilities/build_ast_schema.py +++ b/graphql/utilities/build_ast_schema.py @@ -1,35 +1,73 @@ -from typing import ( - Any, Callable, Dict, List, NoReturn, Optional, Union, cast) +from typing import Any, Callable, Dict, List, NoReturn, Optional, Union, cast from ..language import ( - DirectiveDefinitionNode, DirectiveLocation, DocumentNode, - EnumTypeDefinitionNode, EnumValueDefinitionNode, FieldDefinitionNode, - InputObjectTypeDefinitionNode, InputValueDefinitionNode, - InterfaceTypeDefinitionNode, ListTypeNode, NamedTypeNode, NonNullTypeNode, - ObjectTypeDefinitionNode, OperationType, ScalarTypeDefinitionNode, - SchemaDefinitionNode, Source, TypeDefinitionNode, TypeNode, - UnionTypeDefinitionNode, parse, Node) + DirectiveDefinitionNode, + DirectiveLocation, + DocumentNode, + EnumTypeDefinitionNode, + EnumValueDefinitionNode, + FieldDefinitionNode, + InputObjectTypeDefinitionNode, + InputValueDefinitionNode, + InterfaceTypeDefinitionNode, + ListTypeNode, + NamedTypeNode, + NonNullTypeNode, + ObjectTypeDefinitionNode, + OperationType, + ScalarTypeDefinitionNode, + SchemaDefinitionNode, + Source, + TypeDefinitionNode, + TypeNode, + UnionTypeDefinitionNode, + parse, + Node, +) from ..type import ( - GraphQLArgument, GraphQLDeprecatedDirective, GraphQLDirective, - GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLIncludeDirective, - GraphQLInputType, GraphQLInputField, GraphQLInputObjectType, - GraphQLInterfaceType, GraphQLList, GraphQLNamedType, GraphQLNonNull, - GraphQLNullableType, GraphQLObjectType, GraphQLOutputType, - GraphQLScalarType, GraphQLSchema, GraphQLSkipDirective, GraphQLType, - GraphQLUnionType, introspection_types, specified_scalar_types) + GraphQLArgument, + GraphQLDeprecatedDirective, + GraphQLDirective, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLIncludeDirective, + GraphQLInputType, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLList, + GraphQLNamedType, + GraphQLNonNull, + GraphQLNullableType, + GraphQLObjectType, + GraphQLOutputType, + GraphQLScalarType, + GraphQLSchema, + GraphQLSkipDirective, + GraphQLType, + GraphQLUnionType, + introspection_types, + specified_scalar_types, +) from .value_from_ast import value_from_ast TypeDefinitionsMap = Dict[str, TypeDefinitionNode] TypeResolver = Callable[[NamedTypeNode], GraphQLNamedType] __all__ = [ - 'build_ast_schema', 'build_schema', 'get_description', - 'ASTDefinitionBuilder'] + "build_ast_schema", + "build_schema", + "get_description", + "ASTDefinitionBuilder", +] def build_ast_schema( - document_ast: DocumentNode, assume_valid: bool=False, - assume_valid_sdl: bool=False) -> GraphQLSchema: + document_ast: DocumentNode, + assume_valid: bool = False, + assume_valid_sdl: bool = False, +) -> GraphQLSchema: """Build a GraphQL Schema from a given AST. This takes the ast of a schema document produced by the parse function in @@ -47,10 +85,11 @@ def build_ast_schema( assume it is already a valid SDL document. """ if not isinstance(document_ast, DocumentNode): - raise TypeError('Must provide a Document AST.') + raise TypeError("Must provide a Document AST.") if not (assume_valid or assume_valid_sdl): from ..validation.validate import assert_valid_sdl + assert_valid_sdl(document_ast) schema_def: Optional[SchemaDefinitionNode] = None @@ -66,8 +105,7 @@ def build_ast_schema( def_ = cast(TypeDefinitionNode, def_) type_name = def_.name.value if type_name in node_map: - raise TypeError( - f"Type '{type_name}' was defined more than once.") + raise TypeError(f"Type '{type_name}' was defined more than once.") append_type_def(def_) node_map[type_name] = def_ elif isinstance(def_, DirectiveDefinitionNode): @@ -75,29 +113,33 @@ def build_ast_schema( if schema_def: operation_types: Dict[OperationType, Any] = get_operation_types( - schema_def, node_map) + schema_def, node_map + ) else: operation_types = { - OperationType.QUERY: node_map.get('Query'), - OperationType.MUTATION: node_map.get('Mutation'), - OperationType.SUBSCRIPTION: node_map.get('Subscription')} + OperationType.QUERY: node_map.get("Query"), + OperationType.MUTATION: node_map.get("Mutation"), + OperationType.SUBSCRIPTION: node_map.get("Subscription"), + } def resolve_type(type_ref: NamedTypeNode): - raise TypeError( - f"Type {type_ref.name.value!r} not found in document.") + raise TypeError(f"Type {type_ref.name.value!r} not found in document.") definition_builder = ASTDefinitionBuilder( - node_map, assume_valid=assume_valid, resolve_type=resolve_type) + node_map, assume_valid=assume_valid, resolve_type=resolve_type + ) - directives = [definition_builder.build_directive(directive_def) - for directive_def in directive_defs] + directives = [ + definition_builder.build_directive(directive_def) + for directive_def in directive_defs + ] # If specified directives were not explicitly declared, add them. - if not any(directive.name == 'skip' for directive in directives): + if not any(directive.name == "skip" for directive in directives): directives.append(GraphQLSkipDirective) - if not any(directive.name == 'include' for directive in directives): + if not any(directive.name == "include" for directive in directives): directives.append(GraphQLIncludeDirective) - if not any(directive.name == 'deprecated' for directive in directives): + if not any(directive.name == "deprecated" for directive in directives): directives.append(GraphQLDeprecatedDirective) # Note: While this could make early assertions to get the correctly @@ -107,34 +149,38 @@ def resolve_type(type_ref: NamedTypeNode): mutation_type = operation_types.get(OperationType.MUTATION) subscription_type = operation_types.get(OperationType.SUBSCRIPTION) return GraphQLSchema( - query=cast(GraphQLObjectType, - definition_builder.build_type(query_type), - ) if query_type else None, - mutation=cast(GraphQLObjectType, - definition_builder.build_type(mutation_type) - ) if mutation_type else None, - subscription=cast(GraphQLObjectType, - definition_builder.build_type(subscription_type) - ) if subscription_type else None, + query=cast(GraphQLObjectType, definition_builder.build_type(query_type)) + if query_type + else None, + mutation=cast(GraphQLObjectType, definition_builder.build_type(mutation_type)) + if mutation_type + else None, + subscription=cast( + GraphQLObjectType, definition_builder.build_type(subscription_type) + ) + if subscription_type + else None, types=[definition_builder.build_type(node) for node in type_defs], directives=directives, - ast_node=schema_def, assume_valid=assume_valid) + ast_node=schema_def, + assume_valid=assume_valid, + ) def get_operation_types( - schema: SchemaDefinitionNode, - node_map: TypeDefinitionsMap) -> Dict[OperationType, NamedTypeNode]: + schema: SchemaDefinitionNode, node_map: TypeDefinitionsMap +) -> Dict[OperationType, NamedTypeNode]: op_types: Dict[OperationType, NamedTypeNode] = {} for operation_type in schema.operation_types: type_name = operation_type.type.name.value operation = operation_type.operation if operation in op_types: - raise TypeError( - f'Must provide only one {operation.value} type in schema.') + raise TypeError(f"Must provide only one {operation.value} type in schema.") if type_name not in node_map: raise TypeError( f"Specified {operation.value} type '{type_name}'" - ' not found in document.') + " not found in document." + ) op_types[operation] = operation_type.type return op_types @@ -145,26 +191,34 @@ def default_type_resolver(type_ref: NamedTypeNode) -> NoReturn: class ASTDefinitionBuilder: - - def __init__(self, type_definitions_map: TypeDefinitionsMap, - assume_valid: bool=False, - resolve_type: TypeResolver=default_type_resolver) -> None: + def __init__( + self, + type_definitions_map: TypeDefinitionsMap, + assume_valid: bool = False, + resolve_type: TypeResolver = default_type_resolver, + ) -> None: self._type_definitions_map = type_definitions_map self._assume_valid = assume_valid self._resolve_type = resolve_type # Initialize to the GraphQL built in scalars and introspection types. self._cache: Dict[str, GraphQLNamedType] = { - **specified_scalar_types, **introspection_types} + **specified_scalar_types, + **introspection_types, + } - def build_type(self, node: Union[NamedTypeNode, TypeDefinitionNode] - ) -> GraphQLNamedType: + def build_type( + self, node: Union[NamedTypeNode, TypeDefinitionNode] + ) -> GraphQLNamedType: type_name = node.name.value cache = self._cache if type_name not in cache: if isinstance(node, NamedTypeNode): def_node = self._type_definitions_map.get(type_name) - cache[type_name] = self._make_schema_def( - def_node) if def_node else self._resolve_type(node) + cache[type_name] = ( + self._make_schema_def(def_node) + if def_node + else self._resolve_type(node) + ) else: cache[type_name] = self._make_schema_def(node) return cache[type_name] @@ -175,21 +229,26 @@ def _build_wrapped_type(self, type_node: TypeNode) -> GraphQLType: if isinstance(type_node, NonNullTypeNode): return GraphQLNonNull( # Note: GraphQLNonNull constructor validates this type - cast(GraphQLNullableType, - self._build_wrapped_type(type_node.type))) + cast(GraphQLNullableType, self._build_wrapped_type(type_node.type)) + ) return self.build_type(cast(NamedTypeNode, type_node)) def build_directive( - self, directive_node: DirectiveDefinitionNode) -> GraphQLDirective: + self, directive_node: DirectiveDefinitionNode + ) -> GraphQLDirective: return GraphQLDirective( name=directive_node.name.value, description=directive_node.description.value - if directive_node.description else None, - locations=[DirectiveLocation[node.value] - for node in directive_node.locations], + if directive_node.description + else None, + locations=[ + DirectiveLocation[node.value] for node in directive_node.locations + ], args=self._make_args(directive_node.arguments) - if directive_node.arguments else None, - ast_node=directive_node) + if directive_node.arguments + else None, + ast_node=directive_node, + ) def build_field(self, field: FieldDefinitionNode) -> GraphQLField: # Note: While this could make assertions to get the correctly typed @@ -200,13 +259,12 @@ def build_field(self, field: FieldDefinitionNode) -> GraphQLField: return GraphQLField( type_=type_, description=field.description.value if field.description else None, - args=self._make_args(field.arguments) - if field.arguments else None, + args=self._make_args(field.arguments) if field.arguments else None, deprecation_reason=get_deprecation_reason(field), - ast_node=field) + ast_node=field, + ) - def build_input_field( - self, value: InputValueDefinitionNode) -> GraphQLInputField: + def build_input_field(self, value: InputValueDefinitionNode) -> GraphQLInputField: # Note: While this could make assertions to get the correctly typed # value, that would throw immediately while type system validation # with validate_schema() will produce more actionable results. @@ -216,54 +274,58 @@ def build_input_field( type_=type_, description=value.description.value if value.description else None, default_value=value_from_ast(value.default_value, type_), - ast_node=value) + ast_node=value, + ) @staticmethod def build_enum_value(value: EnumValueDefinitionNode) -> GraphQLEnumValue: return GraphQLEnumValue( description=value.description.value if value.description else None, deprecation_reason=get_deprecation_reason(value), - ast_node=value) + ast_node=value, + ) - def _make_schema_def( - self, type_def: TypeDefinitionNode) -> GraphQLNamedType: + def _make_schema_def(self, type_def: TypeDefinitionNode) -> GraphQLNamedType: method = { - 'object_type_definition': self._make_type_def, - 'interface_type_definition': self._make_interface_def, - 'enum_type_definition': self._make_enum_def, - 'union_type_definition': self._make_union_def, - 'scalar_type_definition': self._make_scalar_def, - 'input_object_type_definition': self._make_input_object_def + "object_type_definition": self._make_type_def, + "interface_type_definition": self._make_interface_def, + "enum_type_definition": self._make_enum_def, + "union_type_definition": self._make_union_def, + "scalar_type_definition": self._make_scalar_def, + "input_object_type_definition": self._make_input_object_def, }.get(type_def.kind) if not method: raise TypeError(f"Type kind '{type_def.kind}' not supported.") return method(type_def) # type: ignore - def _make_type_def( - self, type_def: ObjectTypeDefinitionNode) -> GraphQLObjectType: + def _make_type_def(self, type_def: ObjectTypeDefinitionNode) -> GraphQLObjectType: interfaces = type_def.interfaces return GraphQLObjectType( name=type_def.name.value, - description=type_def.description.value - if type_def.description else None, + description=type_def.description.value if type_def.description else None, fields=lambda: self._make_field_def_map(type_def), # While this could make early assertions to get the correctly typed # values, that would throw immediately while type system validation # with validate_schema will produce more actionable results. - interfaces=(lambda: [ - self.build_type(ref) for ref in interfaces]) # type: ignore - if interfaces else [], - ast_node=type_def) - - def _make_field_def_map(self, type_def: Union[ - ObjectTypeDefinitionNode, InterfaceTypeDefinitionNode] - ) -> Dict[str, GraphQLField]: + interfaces=( + lambda: [self.build_type(ref) for ref in interfaces] # type: ignore + ) + if interfaces + else [], + ast_node=type_def, + ) + + def _make_field_def_map( + self, type_def: Union[ObjectTypeDefinitionNode, InterfaceTypeDefinitionNode] + ) -> Dict[str, GraphQLField]: fields = type_def.fields - return {field.name.value: self.build_field(field) - for field in fields} if fields else {} + return ( + {field.name.value: self.build_field(field) for field in fields} + if fields + else {} + ) - def _make_arg( - self, value_node: InputValueDefinitionNode) -> GraphQLArgument: + def _make_arg(self, value_node: InputValueDefinitionNode) -> GraphQLArgument: # Note: While this could make assertions to get the correctly typed # value, that would throw immediately while type system validation # with validate_schema will produce more actionable results. @@ -272,92 +334,100 @@ def _make_arg( return GraphQLArgument( type_=type_, description=value_node.description.value - if value_node.description else None, + if value_node.description + else None, default_value=value_from_ast(value_node.default_value, type_), - ast_node=value_node) + ast_node=value_node, + ) def _make_args( - self, values: List[InputValueDefinitionNode] - ) -> Dict[str, GraphQLArgument]: - return {value.name.value: self._make_arg(value) - for value in values} + self, values: List[InputValueDefinitionNode] + ) -> Dict[str, GraphQLArgument]: + return {value.name.value: self._make_arg(value) for value in values} def _make_input_fields( - self, values: List[InputValueDefinitionNode] - ) -> Dict[str, GraphQLInputField]: - return {value.name.value: self.build_input_field(value) - for value in values} + self, values: List[InputValueDefinitionNode] + ) -> Dict[str, GraphQLInputField]: + return {value.name.value: self.build_input_field(value) for value in values} def _make_interface_def( - self, type_def: InterfaceTypeDefinitionNode - ) -> GraphQLInterfaceType: + self, type_def: InterfaceTypeDefinitionNode + ) -> GraphQLInterfaceType: return GraphQLInterfaceType( name=type_def.name.value, - description=type_def.description.value - if type_def.description else None, + description=type_def.description.value if type_def.description else None, fields=lambda: self._make_field_def_map(type_def), - ast_node=type_def) + ast_node=type_def, + ) - def _make_enum_def( - self, type_def: EnumTypeDefinitionNode) -> GraphQLEnumType: + def _make_enum_def(self, type_def: EnumTypeDefinitionNode) -> GraphQLEnumType: return GraphQLEnumType( name=type_def.name.value, - description=type_def.description.value - if type_def.description else None, + description=type_def.description.value if type_def.description else None, values=self._make_value_def_map(type_def), - ast_node=type_def) + ast_node=type_def, + ) def _make_value_def_map( - self, type_def: EnumTypeDefinitionNode - ) -> Dict[str, GraphQLEnumValue]: - return {value.name.value: self.build_enum_value(value) - for value in type_def.values} if type_def.values else {} - - def _make_union_def( - self, type_def: UnionTypeDefinitionNode - ) -> GraphQLUnionType: + self, type_def: EnumTypeDefinitionNode + ) -> Dict[str, GraphQLEnumValue]: + return ( + { + value.name.value: self.build_enum_value(value) + for value in type_def.values + } + if type_def.values + else {} + ) + + def _make_union_def(self, type_def: UnionTypeDefinitionNode) -> GraphQLUnionType: types = type_def.types return GraphQLUnionType( name=type_def.name.value, - description=type_def.description.value - if type_def.description else None, + description=type_def.description.value if type_def.description else None, # Note: While this could make assertions to get the correctly typed # values below, that would throw immediately while type system # validation with validate_schema will get more actionable results. - types=(lambda: [ - self.build_type(ref) for ref in types]) # type: ignore - if types else [], - ast_node=type_def) + types=(lambda: [self.build_type(ref) for ref in types]) # type: ignore + if types + else [], + ast_node=type_def, + ) @staticmethod - def _make_scalar_def( - type_def: ScalarTypeDefinitionNode) -> GraphQLScalarType: + def _make_scalar_def(type_def: ScalarTypeDefinitionNode) -> GraphQLScalarType: return GraphQLScalarType( name=type_def.name.value, - description=type_def.description.value - if type_def.description else None, + description=type_def.description.value if type_def.description else None, ast_node=type_def, - serialize=lambda value: value) + serialize=lambda value: value, + ) def _make_input_object_def( - self, type_def: InputObjectTypeDefinitionNode - ) -> GraphQLInputObjectType: + self, type_def: InputObjectTypeDefinitionNode + ) -> GraphQLInputObjectType: return GraphQLInputObjectType( name=type_def.name.value, - description=type_def.description.value - if type_def.description else None, - fields=(lambda: self._make_input_fields( - cast(List[InputValueDefinitionNode], type_def.fields))) - if type_def.fields else cast(Dict[str, GraphQLInputField], {}), - ast_node=type_def) + description=type_def.description.value if type_def.description else None, + fields=( + lambda: self._make_input_fields( + cast(List[InputValueDefinitionNode], type_def.fields) + ) + ) + if type_def.fields + else cast(Dict[str, GraphQLInputField], {}), + ast_node=type_def, + ) -def get_deprecation_reason(node: Union[ - EnumValueDefinitionNode, FieldDefinitionNode]) -> Optional[str]: +def get_deprecation_reason( + node: Union[EnumValueDefinitionNode, FieldDefinitionNode] +) -> Optional[str]: """Given a field or enum value node, get deprecation reason as string.""" from ..execution import get_directive_values + deprecated = get_directive_values(GraphQLDeprecatedDirective, node) - return deprecated['reason'] if deprecated else None + return deprecated["reason"] if deprecated else None def get_description(node: Node) -> Optional[str]: @@ -369,11 +439,20 @@ def get_description(node: Node) -> Optional[str]: return None -def build_schema(source: Union[str, Source], - assume_valid=False, assume_valid_sdl=False, no_location=False, - experimental_fragment_variables=False) -> GraphQLSchema: +def build_schema( + source: Union[str, Source], + assume_valid=False, + assume_valid_sdl=False, + no_location=False, + experimental_fragment_variables=False, +) -> GraphQLSchema: """Build a GraphQLSchema directly from a source document.""" - return build_ast_schema(parse( - source, no_location=no_location, - experimental_fragment_variables=experimental_fragment_variables), - assume_valid=assume_valid, assume_valid_sdl=assume_valid_sdl) + return build_ast_schema( + parse( + source, + no_location=no_location, + experimental_fragment_variables=experimental_fragment_variables, + ), + assume_valid=assume_valid, + assume_valid_sdl=assume_valid_sdl, + ) diff --git a/graphql/utilities/build_client_schema.py b/graphql/utilities/build_client_schema.py index cbcc245b..c60c2681 100644 --- a/graphql/utilities/build_client_schema.py +++ b/graphql/utilities/build_client_schema.py @@ -3,20 +3,41 @@ from ..error import INVALID from ..language import DirectiveLocation, parse_value from ..type import ( - GraphQLArgument, GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, - GraphQLField, GraphQLInputField, GraphQLInputObjectType, GraphQLInputType, - GraphQLInterfaceType, GraphQLList, GraphQLNamedType, GraphQLNonNull, - GraphQLObjectType, GraphQLOutputType, GraphQLScalarType, GraphQLSchema, - GraphQLType, GraphQLUnionType, TypeKind, assert_interface_type, - assert_nullable_type, assert_object_type, introspection_types, - is_input_type, is_output_type, specified_scalar_types) + GraphQLArgument, + GraphQLDirective, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInputType, + GraphQLInterfaceType, + GraphQLList, + GraphQLNamedType, + GraphQLNonNull, + GraphQLObjectType, + GraphQLOutputType, + GraphQLScalarType, + GraphQLSchema, + GraphQLType, + GraphQLUnionType, + TypeKind, + assert_interface_type, + assert_nullable_type, + assert_object_type, + introspection_types, + is_input_type, + is_output_type, + specified_scalar_types, +) from .value_from_ast import value_from_ast -__all__ = ['build_client_schema'] +__all__ = ["build_client_schema"] def build_client_schema( - introspection: Dict, assume_valid: bool=False) -> GraphQLSchema: + introspection: Dict, assume_valid: bool = False +) -> GraphQLSchema: """Build a GraphQLSchema for use by client tools. Given the result of a client running the introspection query, creates and @@ -29,38 +50,39 @@ def build_client_schema( check the "errors" field of a server response before calling this function. """ # Get the schema from the introspection result. - schema_introspection = introspection['__schema'] + schema_introspection = introspection["__schema"] # Converts the list of types into a dict based on the type names. type_introspection_map: Dict[str, Dict] = { - type_['name']: type_ for type_ in schema_introspection['types']} + type_["name"]: type_ for type_ in schema_introspection["types"] + } # A cache to use to store the actual GraphQLType definition objects by # name. Initialize to the GraphQL built in scalars. All functions below are # inline so that this type def cache is within the scope of the closure. type_def_cache: Dict[str, GraphQLNamedType] = { - **specified_scalar_types, **introspection_types} + **specified_scalar_types, + **introspection_types, + } # Given a type reference in introspection, return the GraphQLType instance. # preferring cached instances before building new instances. def get_type(type_ref: Dict) -> GraphQLType: - kind = type_ref.get('kind') + kind = type_ref.get("kind") if kind == TypeKind.LIST.name: - item_ref = type_ref.get('ofType') + item_ref = type_ref.get("ofType") if not item_ref: - raise TypeError( - 'Decorated type deeper than introspection query.') + raise TypeError("Decorated type deeper than introspection query.") return GraphQLList(get_type(item_ref)) elif kind == TypeKind.NON_NULL.name: - nullable_ref = type_ref.get('ofType') + nullable_ref = type_ref.get("ofType") if not nullable_ref: - raise TypeError( - 'Decorated type deeper than introspection query.') + raise TypeError("Decorated type deeper than introspection query.") nullable_type = get_type(nullable_ref) return GraphQLNonNull(assert_nullable_type(nullable_type)) - name = type_ref.get('name') + name = type_ref.get("name") if not name: - raise TypeError(f'Unknown type reference: {type_ref!r}') + raise TypeError(f"Unknown type reference: {type_ref!r}") return get_named_type(name) def get_named_type(type_name: str) -> GraphQLNamedType: @@ -70,9 +92,10 @@ def get_named_type(type_name: str) -> GraphQLNamedType: type_introspection = type_introspection_map.get(type_name) if not type_introspection: raise TypeError( - f'Invalid or incomplete schema, unknown type: {type_name}.' - ' Ensure that a full introspection query is used in order' - ' to build a client schema.') + f"Invalid or incomplete schema, unknown type: {type_name}." + " Ensure that a full introspection query is used in order" + " to build a client schema." + ) type_def = build_type(type_introspection) type_def_cache[type_name] = type_def return type_def @@ -80,15 +103,13 @@ def get_named_type(type_name: str) -> GraphQLNamedType: def get_input_type(type_ref: Dict) -> GraphQLInputType: input_type = get_type(type_ref) if not is_input_type(input_type): - raise TypeError( - 'Introspection must provide input type for arguments.') + raise TypeError("Introspection must provide input type for arguments.") return cast(GraphQLInputType, input_type) def get_output_type(type_ref: Dict) -> GraphQLOutputType: output_type = get_type(type_ref) if not is_output_type(output_type): - raise TypeError( - 'Introspection must provide output type for fields.') + raise TypeError("Introspection must provide output type for fields.") return cast(GraphQLOutputType, output_type) def get_object_type(type_ref: Dict) -> GraphQLObjectType: @@ -102,78 +123,93 @@ def get_interface_type(type_ref: Dict) -> GraphQLInterfaceType: # Given a type's introspection result, construct the correct # GraphQLType instance. def build_type(type_: Dict) -> GraphQLNamedType: - if type_ and 'name' in type_ and 'kind' in type_: - builder = type_builders.get(cast(str, type_['kind'])) + if type_ and "name" in type_ and "kind" in type_: + builder = type_builders.get(cast(str, type_["kind"])) if builder: return cast(GraphQLNamedType, builder(type_)) raise TypeError( - 'Invalid or incomplete introspection result.' - ' Ensure that a full introspection query is used in order' - f' to build a client schema: {type_!r}') + "Invalid or incomplete introspection result." + " Ensure that a full introspection query is used in order" + f" to build a client schema: {type_!r}" + ) def build_scalar_def(scalar_introspection: Dict) -> GraphQLScalarType: return GraphQLScalarType( - name=scalar_introspection['name'], - description=scalar_introspection.get('description'), - serialize=lambda value: value) + name=scalar_introspection["name"], + description=scalar_introspection.get("description"), + serialize=lambda value: value, + ) def build_object_def(object_introspection: Dict) -> GraphQLObjectType: - interfaces = object_introspection.get('interfaces') + interfaces = object_introspection.get("interfaces") if interfaces is None: raise TypeError( - 'Introspection result missing interfaces:' - f' {object_introspection!r}') + "Introspection result missing interfaces:" f" {object_introspection!r}" + ) return GraphQLObjectType( - name=object_introspection['name'], - description=object_introspection.get('description'), + name=object_introspection["name"], + description=object_introspection.get("description"), interfaces=lambda: [ get_interface_type(interface) - for interface in cast(List[Dict], interfaces)], - fields=lambda: build_field_def_map(object_introspection)) + for interface in cast(List[Dict], interfaces) + ], + fields=lambda: build_field_def_map(object_introspection), + ) - def build_interface_def( - interface_introspection: Dict) -> GraphQLInterfaceType: + def build_interface_def(interface_introspection: Dict) -> GraphQLInterfaceType: return GraphQLInterfaceType( - name=interface_introspection['name'], - description=interface_introspection.get('description'), - fields=lambda: build_field_def_map(interface_introspection)) + name=interface_introspection["name"], + description=interface_introspection.get("description"), + fields=lambda: build_field_def_map(interface_introspection), + ) def build_union_def(union_introspection: Dict) -> GraphQLUnionType: - possible_types = union_introspection.get('possibleTypes') + possible_types = union_introspection.get("possibleTypes") if possible_types is None: raise TypeError( - 'Introspection result missing possibleTypes:' - f' {union_introspection!r}') + "Introspection result missing possibleTypes:" + f" {union_introspection!r}" + ) return GraphQLUnionType( - name=union_introspection['name'], - description=union_introspection.get('description'), - types=lambda: [get_object_type(type_) - for type_ in cast(List[Dict], possible_types)]) + name=union_introspection["name"], + description=union_introspection.get("description"), + types=lambda: [ + get_object_type(type_) for type_ in cast(List[Dict], possible_types) + ], + ) def build_enum_def(enum_introspection: Dict) -> GraphQLEnumType: - if enum_introspection.get('enumValues') is None: + if enum_introspection.get("enumValues") is None: raise TypeError( - 'Introspection result missing enumValues:' - f' {enum_introspection!r}') + "Introspection result missing enumValues:" f" {enum_introspection!r}" + ) return GraphQLEnumType( - name=enum_introspection['name'], - description=enum_introspection.get('description'), - values={value_introspect['name']: GraphQLEnumValue( - description=value_introspect.get('description'), - deprecation_reason=value_introspect.get('deprecationReason')) - for value_introspect in enum_introspection['enumValues']}) + name=enum_introspection["name"], + description=enum_introspection.get("description"), + values={ + value_introspect["name"]: GraphQLEnumValue( + description=value_introspect.get("description"), + deprecation_reason=value_introspect.get("deprecationReason"), + ) + for value_introspect in enum_introspection["enumValues"] + }, + ) def build_input_object_def( - input_object_introspection: Dict) -> GraphQLInputObjectType: - if input_object_introspection.get('inputFields') is None: + input_object_introspection: Dict + ) -> GraphQLInputObjectType: + if input_object_introspection.get("inputFields") is None: raise TypeError( - 'Introspection result missing inputFields:' - f' {input_object_introspection!r}') + "Introspection result missing inputFields:" + f" {input_object_introspection!r}" + ) return GraphQLInputObjectType( - name=input_object_introspection['name'], - description=input_object_introspection.get('description'), + name=input_object_introspection["name"], + description=input_object_introspection.get("description"), fields=lambda: build_input_value_def_map( - input_object_introspection['inputFields'])) + input_object_introspection["inputFields"] + ), + ) type_builders: Dict[str, Callable[[Dict], GraphQLType]] = { TypeKind.SCALAR.name: build_scalar_def, @@ -181,75 +217,99 @@ def build_input_object_def( TypeKind.INTERFACE.name: build_interface_def, TypeKind.UNION.name: build_union_def, TypeKind.ENUM.name: build_enum_def, - TypeKind.INPUT_OBJECT.name: build_input_object_def} + TypeKind.INPUT_OBJECT.name: build_input_object_def, + } def build_field(field_introspection: Dict) -> GraphQLField: - if field_introspection.get('args') is None: + if field_introspection.get("args") is None: raise TypeError( - 'Introspection result missing field args:' - f' {field_introspection!r}') + "Introspection result missing field args:" f" {field_introspection!r}" + ) return GraphQLField( - get_output_type(field_introspection['type']), - args=build_arg_value_def_map(field_introspection['args']), - description=field_introspection.get('description'), - deprecation_reason=field_introspection.get('deprecationReason')) - - def build_field_def_map( - type_introspection: Dict) -> Dict[str, GraphQLField]: - if type_introspection.get('fields') is None: + get_output_type(field_introspection["type"]), + args=build_arg_value_def_map(field_introspection["args"]), + description=field_introspection.get("description"), + deprecation_reason=field_introspection.get("deprecationReason"), + ) + + def build_field_def_map(type_introspection: Dict) -> Dict[str, GraphQLField]: + if type_introspection.get("fields") is None: raise TypeError( - 'Introspection result missing fields:' - f' {type_introspection!r}') - return {field_introspection['name']: build_field(field_introspection) - for field_introspection in type_introspection['fields']} - - def build_arg_value( - arg_introspection: Dict) -> GraphQLArgument: - type_ = get_input_type(arg_introspection['type']) - default_value = arg_introspection.get('defaultValue') - default_value = INVALID if default_value is None else value_from_ast( - parse_value(default_value), type_) + "Introspection result missing fields:" f" {type_introspection!r}" + ) + return { + field_introspection["name"]: build_field(field_introspection) + for field_introspection in type_introspection["fields"] + } + + def build_arg_value(arg_introspection: Dict) -> GraphQLArgument: + type_ = get_input_type(arg_introspection["type"]) + default_value = arg_introspection.get("defaultValue") + default_value = ( + INVALID + if default_value is None + else value_from_ast(parse_value(default_value), type_) + ) return GraphQLArgument( - type_, default_value=default_value, - description=arg_introspection.get('description')) - - def build_arg_value_def_map( - arg_introspections: Dict) -> Dict[str, GraphQLArgument]: - return {input_value_introspection['name']: - build_arg_value(input_value_introspection) - for input_value_introspection in arg_introspections} - - def build_input_value( - input_value_introspection: Dict) -> GraphQLInputField: - type_ = get_input_type(input_value_introspection['type']) - default_value = input_value_introspection.get('defaultValue') - default_value = INVALID if default_value is None else value_from_ast( - parse_value(default_value), type_) + type_, + default_value=default_value, + description=arg_introspection.get("description"), + ) + + def build_arg_value_def_map(arg_introspections: Dict) -> Dict[str, GraphQLArgument]: + return { + input_value_introspection["name"]: build_arg_value( + input_value_introspection + ) + for input_value_introspection in arg_introspections + } + + def build_input_value(input_value_introspection: Dict) -> GraphQLInputField: + type_ = get_input_type(input_value_introspection["type"]) + default_value = input_value_introspection.get("defaultValue") + default_value = ( + INVALID + if default_value is None + else value_from_ast(parse_value(default_value), type_) + ) return GraphQLInputField( - type_, default_value=default_value, - description=input_value_introspection.get('description')) + type_, + default_value=default_value, + description=input_value_introspection.get("description"), + ) def build_input_value_def_map( - input_value_introspections: Dict) -> Dict[str, GraphQLInputField]: - return {input_value_introspection['name']: - build_input_value(input_value_introspection) - for input_value_introspection in input_value_introspections} + input_value_introspections: Dict + ) -> Dict[str, GraphQLInputField]: + return { + input_value_introspection["name"]: build_input_value( + input_value_introspection + ) + for input_value_introspection in input_value_introspections + } def build_directive(directive_introspection: Dict) -> GraphQLDirective: - if directive_introspection.get('args') is None: + if directive_introspection.get("args") is None: raise TypeError( - 'Introspection result missing directive args:' - f' {directive_introspection!r}') - if directive_introspection.get('locations') is None: + "Introspection result missing directive args:" + f" {directive_introspection!r}" + ) + if directive_introspection.get("locations") is None: raise TypeError( - 'Introspection result missing directive locations:' - f' {directive_introspection!r}') + "Introspection result missing directive locations:" + f" {directive_introspection!r}" + ) return GraphQLDirective( - name=directive_introspection['name'], - description=directive_introspection.get('description'), - locations=list(cast(Sequence[DirectiveLocation], - directive_introspection.get('locations'))), - args=build_arg_value_def_map(directive_introspection['args'])) + name=directive_introspection["name"], + description=directive_introspection.get("description"), + locations=list( + cast( + Sequence[DirectiveLocation], + directive_introspection.get("locations"), + ) + ), + args=build_arg_value_def_map(directive_introspection["args"]), + ) # Iterate through all types, getting the type definition for each, ensuring # that any type not directly referenced by a field will get created. @@ -257,24 +317,32 @@ def build_directive(directive_introspection: Dict) -> GraphQLDirective: # Get the root Query, Mutation, and Subscription types. - query_type_ref = schema_introspection.get('queryType') + query_type_ref = schema_introspection.get("queryType") query_type = get_object_type(query_type_ref) if query_type_ref else None - mutation_type_ref = schema_introspection.get('mutationType') - mutation_type = get_object_type( - mutation_type_ref) if mutation_type_ref else None - subscription_type_ref = schema_introspection.get('subscriptionType') - subscription_type = get_object_type( - subscription_type_ref) if subscription_type_ref else None + mutation_type_ref = schema_introspection.get("mutationType") + mutation_type = get_object_type(mutation_type_ref) if mutation_type_ref else None + subscription_type_ref = schema_introspection.get("subscriptionType") + subscription_type = ( + get_object_type(subscription_type_ref) if subscription_type_ref else None + ) # Get the directives supported by Introspection, assuming empty-set if # directives were not queried for. - directive_introspections = schema_introspection.get('directives') - directives = [build_directive(directive_introspection) - for directive_introspection in directive_introspections - ] if directive_introspections else [] + directive_introspections = schema_introspection.get("directives") + directives = ( + [ + build_directive(directive_introspection) + for directive_introspection in directive_introspections + ] + if directive_introspections + else [] + ) return GraphQLSchema( - query=query_type, mutation=mutation_type, + query=query_type, + mutation=mutation_type, subscription=subscription_type, - types=types, directives=directives, - assume_valid=assume_valid) + types=types, + directives=directives, + assume_valid=assume_valid, + ) diff --git a/graphql/utilities/coerce_value.py b/graphql/utilities/coerce_value.py index fe3e6b88..bdac06a5 100644 --- a/graphql/utilities/coerce_value.py +++ b/graphql/utilities/coerce_value.py @@ -4,11 +4,20 @@ from ..language import Node from ..pyutils import is_invalid, or_list, suggestion_list from ..type import ( - GraphQLEnumType, GraphQLInputObjectType, GraphQLInputType, - GraphQLList, GraphQLScalarType, is_enum_type, is_input_object_type, - is_list_type, is_non_null_type, is_scalar_type, GraphQLNonNull) - -__all__ = ['coerce_value', 'CoercedValue'] + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInputType, + GraphQLList, + GraphQLScalarType, + is_enum_type, + is_input_object_type, + is_list_type, + is_non_null_type, + is_scalar_type, + GraphQLNonNull, +) + +__all__ = ["coerce_value", "CoercedValue"] class CoercedValue(NamedTuple): @@ -21,8 +30,9 @@ class Path(NamedTuple): key: Union[str, int] -def coerce_value(value: Any, type_: GraphQLInputType, blame_node: Node=None, - path: Path=None) -> CoercedValue: +def coerce_value( + value: Any, type_: GraphQLInputType, blame_node: Node = None, path: Path = None +) -> CoercedValue: """Coerce a Python value given a GraphQL Type. Returns either a value which is valid for the provided type or a list of @@ -31,9 +41,15 @@ def coerce_value(value: Any, type_: GraphQLInputType, blame_node: Node=None, # A value must be provided if the type is non-null. if is_non_null_type(type_): if value is None or value is INVALID: - return of_errors([coercion_error( - f'Expected non-nullable type {type_} not to be null', - blame_node, path)]) + return of_errors( + [ + coercion_error( + f"Expected non-nullable type {type_} not to be null", + blame_node, + path, + ) + ] + ) type_ = cast(GraphQLNonNull, type_) return coerce_value(value, type_.of_type, blame_node, path) @@ -49,14 +65,22 @@ def coerce_value(value: Any, type_: GraphQLInputType, blame_node: Node=None, try: parse_result = type_.parse_value(value) if is_invalid(parse_result): - return of_errors([ - coercion_error( - f'Expected type {type_.name}', blame_node, path)]) + return of_errors( + [coercion_error(f"Expected type {type_.name}", blame_node, path)] + ) return of_value(parse_result) except (TypeError, ValueError) as error: - return of_errors([ - coercion_error(f'Expected type {type_.name}', blame_node, - path, str(error), error)]) + return of_errors( + [ + coercion_error( + f"Expected type {type_.name}", + blame_node, + path, + str(error), + error, + ) + ] + ) if is_enum_type(type_): type_ = cast(GraphQLEnumType, type_) @@ -64,13 +88,16 @@ def coerce_value(value: Any, type_: GraphQLInputType, blame_node: Node=None, if isinstance(value, str): enum_value = values.get(value) if enum_value: - return of_value( - value if enum_value.value is None else enum_value.value) + return of_value(value if enum_value.value is None else enum_value.value) suggestions = suggestion_list(str(value), values) - did_you_mean = (f'did you mean {or_list(suggestions)}?' - if suggestions else None) - return of_errors([coercion_error( - f'Expected type {type_.name}', blame_node, path, did_you_mean)]) + did_you_mean = f"did you mean {or_list(suggestions)}?" if suggestions else None + return of_errors( + [ + coercion_error( + f"Expected type {type_.name}", blame_node, path, did_you_mean + ) + ] + ) if is_list_type(type_): type_ = cast(GraphQLList, type_) @@ -81,23 +108,27 @@ def coerce_value(value: Any, type_: GraphQLInputType, blame_node: Node=None, append_item = coerced_value_list.append for index, item_value in enumerate(value): coerced_item = coerce_value( - item_value, item_type, blame_node, at_path(path, index)) + item_value, item_type, blame_node, at_path(path, index) + ) if coerced_item.errors: errors = add(errors, *coerced_item.errors) elif not errors: append_item(coerced_item.value) - return of_errors(errors) if errors else of_value( - coerced_value_list) + return of_errors(errors) if errors else of_value(coerced_value_list) # Lists accept a non-list value as a list of one. coerced_item = coerce_value(value, item_type, blame_node) - return coerced_item if coerced_item.errors else of_value( - [coerced_item.value]) + return coerced_item if coerced_item.errors else of_value([coerced_item.value]) if is_input_object_type(type_): type_ = cast(GraphQLInputObjectType, type_) if not isinstance(value, dict): - return of_errors([coercion_error( - f'Expected type {type_.name} to be a dict', blame_node, path)]) + return of_errors( + [ + coercion_error( + f"Expected type {type_.name} to be a dict", blame_node, path + ) + ] + ) errors = None coerced_value_dict: Dict[str, Any] = {} fields = type_.fields @@ -109,14 +140,18 @@ def coerce_value(value: Any, type_: GraphQLInputType, blame_node: Node=None, if not is_invalid(field.default_value): coerced_value_dict[field_name] = field.default_value elif is_non_null_type(field.type): - errors = add(errors, coercion_error( - f'Field {print_path(at_path(path, field_name))}' - f' of required type {field.type} was not provided', - blame_node)) + errors = add( + errors, + coercion_error( + f"Field {print_path(at_path(path, field_name))}" + f" of required type {field.type} was not provided", + blame_node, + ), + ) else: coerced_field = coerce_value( - field_value, field.type, blame_node, - at_path(path, field_name)) + field_value, field.type, blame_node, at_path(path, field_name) + ) if coerced_field.errors: errors = add(errors, *coerced_field.errors) else: @@ -126,16 +161,22 @@ def coerce_value(value: Any, type_: GraphQLInputType, blame_node: Node=None, for field_name in value: if field_name not in fields: suggestions = suggestion_list(field_name, fields) - did_you_mean = (f'did you mean {or_list(suggestions)}?' - if suggestions else None) - errors = add(errors, coercion_error( - f"Field '{field_name}'" - f" is not defined by type {type_.name}", - blame_node, path, did_you_mean)) + did_you_mean = ( + f"did you mean {or_list(suggestions)}?" if suggestions else None + ) + errors = add( + errors, + coercion_error( + f"Field '{field_name}'" f" is not defined by type {type_.name}", + blame_node, + path, + did_you_mean, + ), + ) return of_errors(errors) if errors else of_value(coerced_value_dict) - raise TypeError('Unexpected type: {type_}.') + raise TypeError("Unexpected type: {type_}.") def of_value(value: Any) -> CoercedValue: @@ -146,8 +187,9 @@ def of_errors(errors: List[GraphQLError]) -> CoercedValue: return CoercedValue(errors, INVALID) -def add(errors: Optional[List[GraphQLError]], - *more_errors: GraphQLError) -> List[GraphQLError]: +def add( + errors: Optional[List[GraphQLError]], *more_errors: GraphQLError +) -> List[GraphQLError]: return (errors or []) + list(more_errors) @@ -155,24 +197,31 @@ def at_path(prev: Optional[Path], key: Union[str, int]) -> Path: return Path(prev, key) -def coercion_error(message: str, blame_node: Node=None, - path: Path=None, sub_message: str=None, - original_error: Exception=None) -> GraphQLError: +def coercion_error( + message: str, + blame_node: Node = None, + path: Path = None, + sub_message: str = None, + original_error: Exception = None, +) -> GraphQLError: """Return a GraphQLError instance""" if path: path_str = print_path(path) - message += f' at {path_str}' - message += f'; {sub_message}' if sub_message else '.' + message += f" at {path_str}" + message += f"; {sub_message}" if sub_message else "." # noinspection PyArgumentEqualDefault return GraphQLError(message, blame_node, None, None, None, original_error) def print_path(path: Path) -> str: """Build string describing the path into the value where error was found""" - path_str = '' + path_str = "" current_path: Optional[Path] = path while current_path: - path_str = (f'.{current_path.key}' if isinstance(current_path.key, str) - else f'[{current_path.key}]') + path_str + path_str = ( + f".{current_path.key}" + if isinstance(current_path.key, str) + else f"[{current_path.key}]" + ) + path_str current_path = current_path.prev - return f'value{path_str}' if path_str else '' + return f"value{path_str}" if path_str else "" diff --git a/graphql/utilities/concat_ast.py b/graphql/utilities/concat_ast.py index 8400f068..ffe4329f 100644 --- a/graphql/utilities/concat_ast.py +++ b/graphql/utilities/concat_ast.py @@ -3,7 +3,7 @@ from ..language.ast import DocumentNode -__all__ = ['concat_ast'] +__all__ = ["concat_ast"] def concat_ast(asts: Sequence[DocumentNode]) -> DocumentNode: @@ -13,5 +13,6 @@ def concat_ast(asts: Sequence[DocumentNode]) -> DocumentNode: concatenate the ASTs together into batched AST, useful for validating many GraphQL source files which together represent one conceptual application. """ - return DocumentNode(definitions=list(chain.from_iterable( - document.definitions for document in asts))) + return DocumentNode( + definitions=list(chain.from_iterable(document.definitions for document in asts)) + ) diff --git a/graphql/utilities/extend_schema.py b/graphql/utilities/extend_schema.py index 360bd64a..36da1668 100644 --- a/graphql/utilities/extend_schema.py +++ b/graphql/utilities/extend_schema.py @@ -1,34 +1,69 @@ from collections import defaultdict from functools import partial from itertools import chain -from typing import ( - Any, Callable, Dict, List, Optional, Union, Tuple, cast) +from typing import Any, Callable, Dict, List, Optional, Union, Tuple, cast from ..error import GraphQLError from ..language import ( - DirectiveDefinitionNode, DocumentNode, EnumTypeExtensionNode, - InputObjectTypeExtensionNode, InterfaceTypeExtensionNode, - ObjectTypeExtensionNode, OperationType, SchemaExtensionNode, - SchemaDefinitionNode, TypeDefinitionNode, UnionTypeExtensionNode, - NamedTypeNode, TypeExtensionNode) + DirectiveDefinitionNode, + DocumentNode, + EnumTypeExtensionNode, + InputObjectTypeExtensionNode, + InterfaceTypeExtensionNode, + ObjectTypeExtensionNode, + OperationType, + SchemaExtensionNode, + SchemaDefinitionNode, + TypeDefinitionNode, + UnionTypeExtensionNode, + NamedTypeNode, + TypeExtensionNode, +) from ..type import ( - GraphQLArgument, GraphQLArgumentMap, GraphQLDirective, - GraphQLEnumType, GraphQLEnumValue, GraphQLEnumValueMap, - GraphQLField, GraphQLFieldMap, GraphQLInputField, GraphQLInputFieldMap, - GraphQLInputObjectType, GraphQLInputType, GraphQLInterfaceType, - GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLObjectType, - GraphQLScalarType, GraphQLSchema, GraphQLType, GraphQLUnionType, - is_enum_type, is_input_object_type, is_interface_type, is_list_type, - is_non_null_type, is_object_type, is_scalar_type, is_schema, is_union_type, - is_introspection_type, is_specified_scalar_type) + GraphQLArgument, + GraphQLArgumentMap, + GraphQLDirective, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLEnumValueMap, + GraphQLField, + GraphQLFieldMap, + GraphQLInputField, + GraphQLInputFieldMap, + GraphQLInputObjectType, + GraphQLInputType, + GraphQLInterfaceType, + GraphQLList, + GraphQLNamedType, + GraphQLNonNull, + GraphQLObjectType, + GraphQLScalarType, + GraphQLSchema, + GraphQLType, + GraphQLUnionType, + is_enum_type, + is_input_object_type, + is_interface_type, + is_list_type, + is_non_null_type, + is_object_type, + is_scalar_type, + is_schema, + is_union_type, + is_introspection_type, + is_specified_scalar_type, +) from .build_ast_schema import ASTDefinitionBuilder -__all__ = ['extend_schema'] +__all__ = ["extend_schema"] def extend_schema( - schema: GraphQLSchema, document_ast: DocumentNode, - assume_valid=False, assume_valid_sdl=False) -> GraphQLSchema: + schema: GraphQLSchema, + document_ast: DocumentNode, + assume_valid=False, + assume_valid_sdl=False, +) -> GraphQLSchema: """Extend the schema with extensions from a given document. Produces a new schema given an existing schema and a document which may @@ -49,13 +84,14 @@ def extend_schema( """ if not is_schema(schema): - raise TypeError('Must provide valid GraphQLSchema') + raise TypeError("Must provide valid GraphQLSchema") if not isinstance(document_ast, DocumentNode): - 'Must provide valid Document AST' + "Must provide valid Document AST" if not (assume_valid or assume_valid_sdl): from ..validation.validate import assert_valid_sdl_extension + assert_valid_sdl_extension(document_ast, schema) # Collect the type definitions and extensions found in the document. @@ -82,8 +118,9 @@ def extend_schema( if schema.get_type(type_name): raise GraphQLError( f"Type '{type_name}' already exists in the schema." - ' It cannot also be defined in this type definition.', - [def_]) + " It cannot also be defined in this type definition.", + [def_], + ) type_definition_map[type_name] = def_ elif isinstance(def_, TypeExtensionNode): # Sanity check that this type extension exists within the @@ -93,8 +130,9 @@ def extend_schema( if not existing_type: raise GraphQLError( f"Cannot extend type '{extended_type_name}'" - ' because it does not exist in the existing schema.', - [def_]) + " because it does not exist in the existing schema.", + [def_], + ) check_extension_node(existing_type, def_) type_extensions_map[extended_type_name].append(def_) elif isinstance(def_, DirectiveDefinitionNode): @@ -103,14 +141,20 @@ def extend_schema( if existing_directive: raise GraphQLError( f"Directive '{directive_name}' already exists" - ' in the schema. It cannot be redefined.', [def_]) + " in the schema. It cannot be redefined.", + [def_], + ) directive_definitions.append(def_) # If this document contains no new types, extensions, or directives then # return the same unmodified GraphQLSchema instance. - if (not type_extensions_map and not type_definition_map - and not directive_definitions and not schema_extensions - and not schema_def): + if ( + not type_extensions_map + and not type_definition_map + and not directive_definitions + and not schema_extensions + and not schema_def + ): return schema # Below are functions used for producing this schema that have closed over @@ -118,14 +162,18 @@ def extend_schema( def get_merged_directives() -> List[GraphQLDirective]: if not schema.directives: - raise TypeError('schema must have default directives') + raise TypeError("schema must have default directives") - return list(chain( - map(extend_directive, schema.directives), - map(ast_builder.build_directive, directive_definitions))) + return list( + chain( + map(extend_directive, schema.directives), + map(ast_builder.build_directive, directive_definitions), + ) + ) def extend_maybe_named_type( - type_: Optional[GraphQLNamedType]) -> Optional[GraphQLNamedType]: + type_: Optional[GraphQLNamedType] + ) -> Optional[GraphQLNamedType]: return extend_named_type(type_) if type_ else None def extend_named_type(type_: GraphQLNamedType) -> GraphQLNamedType: @@ -162,31 +210,41 @@ def extend_directive(directive: GraphQLDirective) -> GraphQLDirective: description=directive.description, locations=directive.locations, args=extend_args(directive.args), - ast_node=directive.ast_node) + ast_node=directive.ast_node, + ) def extend_input_object_type( - type_: GraphQLInputObjectType) -> GraphQLInputObjectType: + type_: GraphQLInputObjectType + ) -> GraphQLInputObjectType: name = type_.name extension_ast_nodes = ( + ( list(type_.extension_ast_nodes) + type_extensions_map[name] - if type_.extension_ast_nodes else type_extensions_map[name] - ) if name in type_extensions_map else type_.extension_ast_nodes + if type_.extension_ast_nodes + else type_extensions_map[name] + ) + if name in type_extensions_map + else type_.extension_ast_nodes + ) return GraphQLInputObjectType( name, description=type_.description, fields=lambda: extend_input_field_map(type_), ast_node=type_.ast_node, - extension_ast_nodes=extension_ast_nodes) + extension_ast_nodes=extension_ast_nodes, + ) - def extend_input_field_map( - type_: GraphQLInputObjectType) -> GraphQLInputFieldMap: + def extend_input_field_map(type_: GraphQLInputObjectType) -> GraphQLInputFieldMap: old_field_map = type_.fields - new_field_map = {field_name: GraphQLInputField( - cast(GraphQLInputType, extend_type(field.type)), - description=field.description, - default_value=field.default_value, - ast_node=field.ast_node) - for field_name, field in old_field_map.items()} + new_field_map = { + field_name: GraphQLInputField( + cast(GraphQLInputType, extend_type(field.type)), + description=field.description, + default_value=field.default_value, + ast_node=field.ast_node, + ) + for field_name, field in old_field_map.items() + } # If there are any extensions to the fields, apply those here. extensions = type_extensions_map.get(type_.name) @@ -197,34 +255,44 @@ def extend_input_field_map( if field_name in old_field_map: raise GraphQLError( f"Field '{type_.name}.{field_name}' already" - ' exists in the schema. It cannot also be defined' - ' in this type extension.', [field]) - new_field_map[field_name] = ast_builder.build_input_field( - field) + " exists in the schema. It cannot also be defined" + " in this type extension.", + [field], + ) + new_field_map[field_name] = ast_builder.build_input_field(field) return new_field_map def extend_enum_type(type_: GraphQLEnumType) -> GraphQLEnumType: name = type_.name extension_ast_nodes = ( + ( list(type_.extension_ast_nodes) + type_extensions_map[name] - if type_.extension_ast_nodes else type_extensions_map[name] - ) if name in type_extensions_map else type_.extension_ast_nodes + if type_.extension_ast_nodes + else type_extensions_map[name] + ) + if name in type_extensions_map + else type_.extension_ast_nodes + ) return GraphQLEnumType( name, description=type_.description, values=extend_value_map(type_), ast_node=type_.ast_node, - extension_ast_nodes=extension_ast_nodes) + extension_ast_nodes=extension_ast_nodes, + ) def extend_value_map(type_: GraphQLEnumType) -> GraphQLEnumValueMap: old_value_map = type_.values - new_value_map = {value_name: GraphQLEnumValue( - value.value, - description=value.description, - deprecation_reason=value.deprecation_reason, - ast_node=value.ast_node) - for value_name, value in old_value_map.items()} + new_value_map = { + value_name: GraphQLEnumValue( + value.value, + description=value.description, + deprecation_reason=value.deprecation_reason, + ast_node=value.ast_node, + ) + for value_name, value in old_value_map.items() + } # If there are any extensions to the values, apply those here. extensions = type_extensions_map.get(type_.name) @@ -235,19 +303,25 @@ def extend_value_map(type_: GraphQLEnumType) -> GraphQLEnumValueMap: if value_name in old_value_map: raise GraphQLError( f"Enum value '{type_.name}.{value_name}' already" - ' exists in the schema. It cannot also be defined' - ' in this type extension.', [value]) - new_value_map[value_name] = ast_builder.build_enum_value( - value) + " exists in the schema. It cannot also be defined" + " in this type extension.", + [value], + ) + new_value_map[value_name] = ast_builder.build_enum_value(value) return new_value_map def extend_scalar_type(type_: GraphQLScalarType) -> GraphQLScalarType: name = type_.name extension_ast_nodes = ( + ( list(type_.extension_ast_nodes) + type_extensions_map[name] - if type_.extension_ast_nodes else type_extensions_map[name] - ) if name in type_extensions_map else type_.extension_ast_nodes + if type_.extension_ast_nodes + else type_extensions_map[name] + ) + if name in type_extensions_map + else type_.extension_ast_nodes + ) return GraphQLScalarType( name, serialize=type_.serialize, @@ -255,7 +329,8 @@ def extend_scalar_type(type_: GraphQLScalarType) -> GraphQLScalarType: parse_value=type_.parse_value, parse_literal=type_.parse_literal, ast_node=type_.ast_node, - extension_ast_nodes=extension_ast_nodes) + extension_ast_nodes=extension_ast_nodes, + ) def extend_object_type(type_: GraphQLObjectType) -> GraphQLObjectType: name = type_.name @@ -266,8 +341,7 @@ def extend_object_type(type_: GraphQLObjectType) -> GraphQLObjectType: pass else: if extension_ast_nodes: - extension_ast_nodes = list( - extension_ast_nodes) + extensions + extension_ast_nodes = list(extension_ast_nodes) + extensions else: extension_ast_nodes = extensions return GraphQLObjectType( @@ -277,18 +351,21 @@ def extend_object_type(type_: GraphQLObjectType) -> GraphQLObjectType: fields=partial(extend_field_map, type_), ast_node=type_.ast_node, extension_ast_nodes=extension_ast_nodes, - is_type_of=type_.is_type_of) + is_type_of=type_.is_type_of, + ) def extend_args(args: GraphQLArgumentMap) -> GraphQLArgumentMap: - return {arg_name: GraphQLArgument( - cast(GraphQLInputType, extend_type(arg.type)), - default_value=arg.default_value, - description=arg.description, - ast_node=arg.ast_node) - for arg_name, arg in args.items()} - - def extend_interface_type( - type_: GraphQLInterfaceType) -> GraphQLInterfaceType: + return { + arg_name: GraphQLArgument( + cast(GraphQLInputType, extend_type(arg.type)), + default_value=arg.default_value, + description=arg.description, + ast_node=arg.ast_node, + ) + for arg_name, arg in args.items() + } + + def extend_interface_type(type_: GraphQLInterfaceType) -> GraphQLInterfaceType: name = type_.name extension_ast_nodes = type_.extension_ast_nodes try: @@ -297,8 +374,7 @@ def extend_interface_type( pass else: if extension_ast_nodes: - extension_ast_nodes = list( - extension_ast_nodes) + extensions + extension_ast_nodes = list(extension_ast_nodes) + extensions else: extension_ast_nodes = extensions return GraphQLInterfaceType( @@ -307,24 +383,30 @@ def extend_interface_type( fields=partial(extend_field_map, type_), ast_node=type_.ast_node, extension_ast_nodes=extension_ast_nodes, - resolve_type=type_.resolve_type) + resolve_type=type_.resolve_type, + ) def extend_union_type(type_: GraphQLUnionType) -> GraphQLUnionType: name = type_.name extension_ast_nodes = ( + ( list(type_.extension_ast_nodes) + type_extensions_map[name] - if type_.extension_ast_nodes else type_extensions_map[name] - ) if name in type_extensions_map else type_.extension_ast_nodes + if type_.extension_ast_nodes + else type_extensions_map[name] + ) + if name in type_extensions_map + else type_.extension_ast_nodes + ) return GraphQLUnionType( name, description=type_.description, types=lambda: extend_possible_types(type_), ast_node=type_.ast_node, resolve_type=type_.resolve_type, - extension_ast_nodes=extension_ast_nodes) + extension_ast_nodes=extension_ast_nodes, + ) - def extend_possible_types( - type_: GraphQLUnionType) -> List[GraphQLObjectType]: + def extend_possible_types(type_: GraphQLUnionType) -> List[GraphQLObjectType]: possible_types = list(map(extend_named_type, type_.types)) # If there are any extensions to the union, apply those here. @@ -341,10 +423,17 @@ def extend_possible_types( return cast(List[GraphQLObjectType], possible_types) def extend_implemented_interfaces( - type_: GraphQLObjectType) -> List[GraphQLInterfaceType]: + type_: GraphQLObjectType + ) -> List[GraphQLInterfaceType]: interfaces: List[GraphQLInterfaceType] = list( - map(cast(Callable[[GraphQLNamedType], GraphQLInterfaceType], - extend_named_type), type_.interfaces)) + map( + cast( + Callable[[GraphQLNamedType], GraphQLInterfaceType], + extend_named_type, + ), + type_.interfaces, + ) + ) # If there are any extensions to the interfaces, apply those here. for extension in type_extensions_map[type_.name]: @@ -353,23 +442,25 @@ def extend_implemented_interfaces( # correctly typed values, that would throw immediately while # type system validation with validate_schema() will produce # more actionable results. - interfaces.append( - cast(GraphQLInterfaceType, build_type(named_type))) + interfaces.append(cast(GraphQLInterfaceType, build_type(named_type))) return interfaces def extend_field_map( - type_: Union[GraphQLObjectType, GraphQLInterfaceType] - ) -> GraphQLFieldMap: + type_: Union[GraphQLObjectType, GraphQLInterfaceType] + ) -> GraphQLFieldMap: old_field_map = type_.fields - new_field_map = {field_name: GraphQLField( - cast(GraphQLObjectType, extend_type(field.type)), - description=field.description, - deprecation_reason=field.deprecation_reason, - args=extend_args(field.args), - ast_node=field.ast_node, - resolve=field.resolve) - for field_name, field in old_field_map.items()} + new_field_map = { + field_name: GraphQLField( + cast(GraphQLObjectType, extend_type(field.type)), + description=field.description, + deprecation_reason=field.deprecation_reason, + args=extend_args(field.args), + ast_node=field.ast_node, + resolve=field.resolve, + ) + for field_name, field in old_field_map.items() + } # If there are any extensions to the fields, apply those here. for extension in type_extensions_map[type_.name]: @@ -378,9 +469,10 @@ def extend_field_map( if field_name in old_field_map: raise GraphQLError( f"Field '{type_.name}.{field_name}'" - ' already exists in the schema.' - ' It cannot also be defined in this type extension.', - [field]) + " already exists in the schema." + " It cannot also be defined in this type extension.", + [field], + ) new_field_map[field_name] = build_field(field) return new_field_map @@ -390,8 +482,7 @@ def extend_type(type_def: GraphQLType) -> GraphQLType: if is_list_type(type_def): return GraphQLList(extend_type(type_def.of_type)) # type: ignore if is_non_null_type(type_def): - return GraphQLNonNull( # type: ignore - extend_type(type_def.of_type)) # type: ignore + return GraphQLNonNull(extend_type(type_def.of_type)) # type: ignore return extend_named_type(type_def) # type: ignore # noinspection PyShadowingNames @@ -402,12 +493,14 @@ def resolve_type(type_ref: NamedTypeNode) -> GraphQLNamedType: return extend_named_type(existing_type) raise GraphQLError( f"Unknown type: '{type_name}'." - ' Ensure that this type exists either in the original schema,' - ' or is added in a type definition.', [type_ref]) + " Ensure that this type exists either in the original schema," + " or is added in a type definition.", + [type_ref], + ) ast_builder = ASTDefinitionBuilder( - type_definition_map, - assume_valid=assume_valid, resolve_type=resolve_type) + type_definition_map, assume_valid=assume_valid, resolve_type=resolve_type + ) build_field = ast_builder.build_field build_type = ast_builder.build_type @@ -417,21 +510,21 @@ def resolve_type(type_ref: NamedTypeNode) -> GraphQLNamedType: operation_types = { OperationType.QUERY: extend_maybe_named_type(schema.query_type), OperationType.MUTATION: extend_maybe_named_type(schema.mutation_type), - OperationType.SUBSCRIPTION: - extend_maybe_named_type(schema.subscription_type)} + OperationType.SUBSCRIPTION: extend_maybe_named_type(schema.subscription_type), + } if schema_def: for operation_type in schema_def.operation_types: operation = operation_type.operation if operation_types[operation]: raise TypeError( - f'Must provide only one {operation.value} type in schema.') + f"Must provide only one {operation.value} type in schema." + ) # Note: While this could make early assertions to get the # correctly typed values, that would throw immediately while # type system validation with validate_schema() will produce # more actionable results. - operation_types[operation] = ast_builder.build_type( - operation_type.type) + operation_types[operation] = ast_builder.build_type(operation_type.type) # Then, incorporate schema definition and all schema extensions. for schema_extension in schema_extensions: @@ -439,18 +532,18 @@ def resolve_type(type_ref: NamedTypeNode) -> GraphQLNamedType: for operation_type in schema_extension.operation_types: operation = operation_type.operation if operation_types[operation]: - raise TypeError(f'Must provide only one {operation.value}' - ' type in schema.') + raise TypeError( + f"Must provide only one {operation.value}" " type in schema." + ) # Note: While this could make early assertions to get the # correctly typed values, that would throw immediately while # type system validation with validate_schema() will produce # more actionable results. - operation_types[operation] = ast_builder.build_type( - operation_type.type) + operation_types[operation] = ast_builder.build_type(operation_type.type) schema_extension_ast_nodes = ( schema.extension_ast_nodes or cast(Tuple[SchemaExtensionNode], ()) - ) + tuple(schema_extensions) + ) + tuple(schema_extensions) # Iterate through all types, getting the type definition for each, ensuring # that any type not directly referenced by a value will get created. @@ -466,27 +559,27 @@ def resolve_type(type_ref: NamedTypeNode) -> GraphQLNamedType: types=types, directives=get_merged_directives(), ast_node=schema.ast_node, - extension_ast_nodes=schema_extension_ast_nodes) + extension_ast_nodes=schema_extension_ast_nodes, + ) def check_extension_node(type_: GraphQLNamedType, node: TypeExtensionNode): if isinstance(node, ObjectTypeExtensionNode): if not is_object_type(type_): - raise GraphQLError( - f"Cannot extend non-object type '{type_.name}'.", [node]) + raise GraphQLError(f"Cannot extend non-object type '{type_.name}'.", [node]) elif isinstance(node, InterfaceTypeExtensionNode): if not is_interface_type(type_): raise GraphQLError( - f"Cannot extend non-interface type '{type_.name}'.", [node]) + f"Cannot extend non-interface type '{type_.name}'.", [node] + ) elif isinstance(node, EnumTypeExtensionNode): if not is_enum_type(type_): - raise GraphQLError( - f"Cannot extend non-enum type '{type_.name}'.", [node]) + raise GraphQLError(f"Cannot extend non-enum type '{type_.name}'.", [node]) elif isinstance(node, UnionTypeExtensionNode): if not is_union_type(type_): - raise GraphQLError( - f"Cannot extend non-union type '{type_.name}'.", [node]) + raise GraphQLError(f"Cannot extend non-union type '{type_.name}'.", [node]) elif isinstance(node, InputObjectTypeExtensionNode): if not is_input_object_type(type_): raise GraphQLError( - f"Cannot extend non-input object type '{type_.name}'.", [node]) + f"Cannot extend non-input object type '{type_.name}'.", [node] + ) diff --git a/graphql/utilities/find_breaking_changes.py b/graphql/utilities/find_breaking_changes.py index 96ade444..831049b6 100644 --- a/graphql/utilities/find_breaking_changes.py +++ b/graphql/utilities/find_breaking_changes.py @@ -4,27 +4,55 @@ from ..error import INVALID from ..language import DirectiveLocation from ..type import ( - GraphQLArgument, GraphQLDirective, GraphQLEnumType, GraphQLInputObjectType, - GraphQLInterfaceType, GraphQLList, GraphQLNamedType, GraphQLNonNull, - GraphQLObjectType, GraphQLSchema, GraphQLType, GraphQLUnionType, - is_enum_type, is_input_object_type, is_interface_type, is_list_type, - is_named_type, is_required_argument, is_required_input_field, - is_non_null_type, is_object_type, is_scalar_type, is_union_type) + GraphQLArgument, + GraphQLDirective, + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLList, + GraphQLNamedType, + GraphQLNonNull, + GraphQLObjectType, + GraphQLSchema, + GraphQLType, + GraphQLUnionType, + is_enum_type, + is_input_object_type, + is_interface_type, + is_list_type, + is_named_type, + is_required_argument, + is_required_input_field, + is_non_null_type, + is_object_type, + is_scalar_type, + is_union_type, +) __all__ = [ - 'BreakingChange', 'BreakingChangeType', - 'DangerousChange', 'DangerousChangeType', - 'find_breaking_changes', 'find_dangerous_changes', - 'find_removed_types', 'find_types_that_changed_kind', - 'find_fields_that_changed_type_on_object_or_interface_types', - 'find_fields_that_changed_type_on_input_object_types', - 'find_types_removed_from_unions', 'find_values_removed_from_enums', - 'find_arg_changes', 'find_interfaces_removed_from_object_types', - 'find_removed_directives', 'find_removed_directive_args', - 'find_added_non_null_directive_args', - 'find_removed_locations_for_directive', - 'find_removed_directive_locations', 'find_values_added_to_enums', - 'find_interfaces_added_to_object_types', 'find_types_added_to_unions'] + "BreakingChange", + "BreakingChangeType", + "DangerousChange", + "DangerousChangeType", + "find_breaking_changes", + "find_dangerous_changes", + "find_removed_types", + "find_types_that_changed_kind", + "find_fields_that_changed_type_on_object_or_interface_types", + "find_fields_that_changed_type_on_input_object_types", + "find_types_removed_from_unions", + "find_values_removed_from_enums", + "find_arg_changes", + "find_interfaces_removed_from_object_types", + "find_removed_directives", + "find_removed_directive_args", + "find_added_non_null_directive_args", + "find_removed_locations_for_directive", + "find_removed_directive_locations", + "find_values_added_to_enums", + "find_interfaces_added_to_object_types", + "find_types_added_to_unions", +] class BreakingChangeType(Enum): @@ -70,50 +98,55 @@ class BreakingAndDangerousChanges(NamedTuple): def find_breaking_changes( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: """Find breaking changes. Given two schemas, returns a list containing descriptions of all the types of breaking changes covered by the other functions down below. """ return ( - find_removed_types(old_schema, new_schema) + - find_types_that_changed_kind(old_schema, new_schema) + - find_fields_that_changed_type_on_object_or_interface_types( - old_schema, new_schema) + - find_fields_that_changed_type_on_input_object_types( - old_schema, new_schema).breaking_changes + - find_types_removed_from_unions(old_schema, new_schema) + - find_values_removed_from_enums(old_schema, new_schema) + - find_arg_changes(old_schema, new_schema).breaking_changes + - find_interfaces_removed_from_object_types(old_schema, new_schema) + - find_removed_directives(old_schema, new_schema) + - find_removed_directive_args(old_schema, new_schema) + - find_added_non_null_directive_args(old_schema, new_schema) + - find_removed_directive_locations(old_schema, new_schema)) + find_removed_types(old_schema, new_schema) + + find_types_that_changed_kind(old_schema, new_schema) + + find_fields_that_changed_type_on_object_or_interface_types( + old_schema, new_schema + ) + + find_fields_that_changed_type_on_input_object_types( + old_schema, new_schema + ).breaking_changes + + find_types_removed_from_unions(old_schema, new_schema) + + find_values_removed_from_enums(old_schema, new_schema) + + find_arg_changes(old_schema, new_schema).breaking_changes + + find_interfaces_removed_from_object_types(old_schema, new_schema) + + find_removed_directives(old_schema, new_schema) + + find_removed_directive_args(old_schema, new_schema) + + find_added_non_null_directive_args(old_schema, new_schema) + + find_removed_directive_locations(old_schema, new_schema) + ) def find_dangerous_changes( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[DangerousChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[DangerousChange]: """Find dangerous changes. Given two schemas, returns a list containing descriptions of all the types of potentially dangerous changes covered by the other functions down below. """ return ( - find_arg_changes(old_schema, new_schema).dangerous_changes + - find_values_added_to_enums(old_schema, new_schema) + - find_interfaces_added_to_object_types(old_schema, new_schema) + - find_types_added_to_unions(old_schema, new_schema) + - find_fields_that_changed_type_on_input_object_types( - old_schema, new_schema).dangerous_changes) + find_arg_changes(old_schema, new_schema).dangerous_changes + + find_values_added_to_enums(old_schema, new_schema) + + find_interfaces_added_to_object_types(old_schema, new_schema) + + find_types_added_to_unions(old_schema, new_schema) + + find_fields_that_changed_type_on_input_object_types( + old_schema, new_schema + ).dangerous_changes + ) def find_removed_types( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: """Find removed types. Given two schemas, returns a list containing descriptions of any breaking @@ -125,14 +158,17 @@ def find_removed_types( breaking_changes = [] for type_name in old_type_map: if type_name not in new_type_map: - breaking_changes.append(BreakingChange( - BreakingChangeType.TYPE_REMOVED, f'{type_name} was removed.')) + breaking_changes.append( + BreakingChange( + BreakingChangeType.TYPE_REMOVED, f"{type_name} was removed." + ) + ) return breaking_changes def find_types_that_changed_kind( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: """Find types that changed kind Given two schemas, returns a list containing descriptions of any breaking @@ -148,16 +184,19 @@ def find_types_that_changed_kind( old_type = old_type_map[type_name] new_type = new_type_map[type_name] if old_type.__class__ is not new_type.__class__: - breaking_changes.append(BreakingChange( - BreakingChangeType.TYPE_CHANGED_KIND, - f'{type_name} changed from {type_kind_name(old_type)}' - f' to {type_kind_name(new_type)}.')) + breaking_changes.append( + BreakingChange( + BreakingChangeType.TYPE_CHANGED_KIND, + f"{type_name} changed from {type_kind_name(old_type)}" + f" to {type_kind_name(new_type)}.", + ) + ) return breaking_changes def find_arg_changes( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> BreakingAndDangerousChanges: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> BreakingAndDangerousChanges: """Find argument changes. Given two schemas, returns a list containing descriptions of any @@ -173,14 +212,14 @@ def find_arg_changes( for type_name, old_type in old_type_map.items(): new_type = new_type_map.get(type_name) - if (not (is_object_type(old_type) or is_interface_type(old_type)) or - not (is_object_type(new_type) or is_interface_type(new_type)) or - new_type.__class__ is not old_type.__class__): + if ( + not (is_object_type(old_type) or is_interface_type(old_type)) + or not (is_object_type(new_type) or is_interface_type(new_type)) + or new_type.__class__ is not old_type.__class__ + ): continue - old_type = cast( - Union[GraphQLObjectType, GraphQLInterfaceType], old_type) - new_type = cast( - Union[GraphQLObjectType, GraphQLInterfaceType], new_type) + old_type = cast(Union[GraphQLObjectType, GraphQLInterfaceType], old_type) + new_type = cast(Union[GraphQLObjectType, GraphQLInterfaceType], new_type) old_type_fields = old_type.fields new_type_fields = new_type.fields @@ -194,110 +233,139 @@ def find_arg_changes( new_arg = new_args.get(arg_name) if not new_arg: # Arg not present - breaking_changes.append(BreakingChange( - BreakingChangeType.ARG_REMOVED, - f'{old_type.name}.{field_name} arg' - f' {arg_name} was removed')) + breaking_changes.append( + BreakingChange( + BreakingChangeType.ARG_REMOVED, + f"{old_type.name}.{field_name} arg" + f" {arg_name} was removed", + ) + ) continue is_safe = is_change_safe_for_input_object_field_or_field_arg( - old_arg.type, new_arg.type) + old_arg.type, new_arg.type + ) if not is_safe: - breaking_changes.append(BreakingChange( - BreakingChangeType.ARG_CHANGED_KIND, - f'{old_type.name}.{field_name} arg' - f' {arg_name} has changed type from' - f' {old_arg.type} to {new_arg.type}')) - elif (old_arg.default_value is not INVALID and - old_arg.default_value != new_arg.default_value): - dangerous_changes.append(DangerousChange( - DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, - f'{old_type.name}.{field_name} arg' - f' {arg_name} has changed defaultValue')) + breaking_changes.append( + BreakingChange( + BreakingChangeType.ARG_CHANGED_KIND, + f"{old_type.name}.{field_name} arg" + f" {arg_name} has changed type from" + f" {old_arg.type} to {new_arg.type}", + ) + ) + elif ( + old_arg.default_value is not INVALID + and old_arg.default_value != new_arg.default_value + ): + dangerous_changes.append( + DangerousChange( + DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, + f"{old_type.name}.{field_name} arg" + f" {arg_name} has changed defaultValue", + ) + ) # Check if arg was added to the field for arg_name in new_args: if arg_name not in old_args: new_arg_def = new_args[arg_name] if is_required_argument(new_arg_def): - breaking_changes.append(BreakingChange( - BreakingChangeType.REQUIRED_ARG_ADDED, - f'A required arg {arg_name} on' - f' {type_name}.{field_name} was added')) + breaking_changes.append( + BreakingChange( + BreakingChangeType.REQUIRED_ARG_ADDED, + f"A required arg {arg_name} on" + f" {type_name}.{field_name} was added", + ) + ) else: - dangerous_changes.append(DangerousChange( - DangerousChangeType.OPTIONAL_ARG_ADDED, - f'An optional arg {arg_name} on' - f' {type_name}.{field_name} was added')) + dangerous_changes.append( + DangerousChange( + DangerousChangeType.OPTIONAL_ARG_ADDED, + f"An optional arg {arg_name} on" + f" {type_name}.{field_name} was added", + ) + ) return BreakingAndDangerousChanges(breaking_changes, dangerous_changes) def type_kind_name(type_: GraphQLNamedType) -> str: if is_scalar_type(type_): - return 'a Scalar type' + return "a Scalar type" if is_object_type(type_): - return 'an Object type' + return "an Object type" if is_interface_type(type_): - return 'an Interface type' + return "an Interface type" if is_union_type(type_): - return 'a Union type' + return "a Union type" if is_enum_type(type_): - return 'an Enum type' + return "an Enum type" if is_input_object_type(type_): - return 'an Input type' - raise TypeError(f'Unknown type {type_.__class__.__name__}') + return "an Input type" + raise TypeError(f"Unknown type {type_.__class__.__name__}") def find_fields_that_changed_type_on_object_or_interface_types( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: old_type_map = old_schema.type_map new_type_map = new_schema.type_map breaking_changes = [] for type_name, old_type in old_type_map.items(): new_type = new_type_map.get(type_name) - if (not (is_object_type(old_type) or is_interface_type(old_type)) or - not (is_object_type(new_type) or is_interface_type(new_type)) or - new_type.__class__ is not old_type.__class__): + if ( + not (is_object_type(old_type) or is_interface_type(old_type)) + or not (is_object_type(new_type) or is_interface_type(new_type)) + or new_type.__class__ is not old_type.__class__ + ): continue - old_type = cast( - Union[GraphQLObjectType, GraphQLInterfaceType], old_type) - new_type = cast( - Union[GraphQLObjectType, GraphQLInterfaceType], new_type) + old_type = cast(Union[GraphQLObjectType, GraphQLInterfaceType], old_type) + new_type = cast(Union[GraphQLObjectType, GraphQLInterfaceType], new_type) old_type_fields_def = old_type.fields new_type_fields_def = new_type.fields for field_name in old_type_fields_def: # Check if the field is missing on the type in the new schema. if field_name not in new_type_fields_def: - breaking_changes.append(BreakingChange( - BreakingChangeType.FIELD_REMOVED, - f'{type_name}.{field_name} was removed.')) + breaking_changes.append( + BreakingChange( + BreakingChangeType.FIELD_REMOVED, + f"{type_name}.{field_name} was removed.", + ) + ) else: old_field_type = old_type_fields_def[field_name].type new_field_type = new_type_fields_def[field_name].type is_safe = is_change_safe_for_object_or_interface_field( - old_field_type, new_field_type) + old_field_type, new_field_type + ) if not is_safe: old_field_type_string = ( - old_field_type.name if is_named_type(old_field_type) - else str(old_field_type)) + old_field_type.name + if is_named_type(old_field_type) + else str(old_field_type) + ) new_field_type_string = ( - new_field_type.name if is_named_type(new_field_type) - else str(new_field_type)) - breaking_changes.append(BreakingChange( - BreakingChangeType.FIELD_CHANGED_KIND, - f'{type_name}.{field_name} changed type' - f' from {old_field_type_string}' - f' to {new_field_type_string}.')) + new_field_type.name + if is_named_type(new_field_type) + else str(new_field_type) + ) + breaking_changes.append( + BreakingChange( + BreakingChangeType.FIELD_CHANGED_KIND, + f"{type_name}.{field_name} changed type" + f" from {old_field_type_string}" + f" to {new_field_type_string}.", + ) + ) return breaking_changes def find_fields_that_changed_type_on_input_object_types( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> BreakingAndDangerousChanges: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> BreakingAndDangerousChanges: old_type_map = old_schema.type_map new_type_map = new_schema.type_map @@ -305,8 +373,7 @@ def find_fields_that_changed_type_on_input_object_types( dangerous_changes = [] for type_name, old_type in old_type_map.items(): new_type = new_type_map.get(type_name) - if not (is_input_object_type(old_type) and - is_input_object_type(new_type)): + if not (is_input_object_type(old_type) and is_input_object_type(new_type)): continue old_type = cast(GraphQLInputObjectType, old_type) new_type = cast(GraphQLInputObjectType, new_type) @@ -316,115 +383,157 @@ def find_fields_that_changed_type_on_input_object_types( for field_name in old_type_fields_def: # Check if the field is missing on the type in the new schema. if field_name not in new_type_fields_def: - breaking_changes.append(BreakingChange( - BreakingChangeType.FIELD_REMOVED, - f'{type_name}.{field_name} was removed.')) + breaking_changes.append( + BreakingChange( + BreakingChangeType.FIELD_REMOVED, + f"{type_name}.{field_name} was removed.", + ) + ) else: old_field_type = old_type_fields_def[field_name].type new_field_type = new_type_fields_def[field_name].type is_safe = is_change_safe_for_input_object_field_or_field_arg( - old_field_type, new_field_type) + old_field_type, new_field_type + ) if not is_safe: old_field_type_string = ( cast(GraphQLNamedType, old_field_type).name if is_named_type(old_field_type) - else str(old_field_type)) + else str(old_field_type) + ) new_field_type_string = ( cast(GraphQLNamedType, new_field_type).name if is_named_type(new_field_type) - else str(new_field_type)) - breaking_changes.append(BreakingChange( - BreakingChangeType.FIELD_CHANGED_KIND, - f'{type_name}.{field_name} changed type' - f' from {old_field_type_string}' - f' to {new_field_type_string}.')) + else str(new_field_type) + ) + breaking_changes.append( + BreakingChange( + BreakingChangeType.FIELD_CHANGED_KIND, + f"{type_name}.{field_name} changed type" + f" from {old_field_type_string}" + f" to {new_field_type_string}.", + ) + ) # Check if a field was added to the input object type for field_name in new_type_fields_def: if field_name not in old_type_fields_def: if is_required_input_field(new_type_fields_def[field_name]): - breaking_changes.append(BreakingChange( - BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED, - f'A required field {field_name} on' - f' input type {type_name} was added.')) + breaking_changes.append( + BreakingChange( + BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED, + f"A required field {field_name} on" + f" input type {type_name} was added.", + ) + ) else: - dangerous_changes.append(DangerousChange( - DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED, - f'An optional field {field_name} on' - f' input type {type_name} was added.')) + dangerous_changes.append( + DangerousChange( + DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED, + f"An optional field {field_name} on" + f" input type {type_name} was added.", + ) + ) return BreakingAndDangerousChanges(breaking_changes, dangerous_changes) def is_change_safe_for_object_or_interface_field( - old_type: GraphQLType, new_type: GraphQLType) -> bool: + old_type: GraphQLType, new_type: GraphQLType +) -> bool: if is_named_type(old_type): return ( # if they're both named types, see if their names are equivalent - (is_named_type(new_type) and - cast(GraphQLNamedType, old_type).name == - cast(GraphQLNamedType, new_type).name) or + ( + is_named_type(new_type) + and cast(GraphQLNamedType, old_type).name + == cast(GraphQLNamedType, new_type).name + ) + or # moving from nullable to non-null of same underlying type is safe - (is_non_null_type(new_type) and - is_change_safe_for_object_or_interface_field( - old_type, cast(GraphQLNonNull, new_type).of_type))) + ( + is_non_null_type(new_type) + and is_change_safe_for_object_or_interface_field( + old_type, cast(GraphQLNonNull, new_type).of_type + ) + ) + ) elif is_list_type(old_type): return ( # if they're both lists, make sure underlying types are compatible - (is_list_type(new_type) and - is_change_safe_for_object_or_interface_field( - cast(GraphQLList, old_type).of_type, - cast(GraphQLList, new_type).of_type)) or + ( + is_list_type(new_type) + and is_change_safe_for_object_or_interface_field( + cast(GraphQLList, old_type).of_type, + cast(GraphQLList, new_type).of_type, + ) + ) + or # moving from nullable to non-null of same underlying type is safe - (is_non_null_type(new_type) and - is_change_safe_for_object_or_interface_field( - old_type, cast(GraphQLNonNull, new_type).of_type))) + ( + is_non_null_type(new_type) + and is_change_safe_for_object_or_interface_field( + old_type, cast(GraphQLNonNull, new_type).of_type + ) + ) + ) elif is_non_null_type(old_type): # if they're both non-null, make sure underlying types are compatible - return ( - is_non_null_type(new_type) and - is_change_safe_for_object_or_interface_field( - cast(GraphQLNonNull, old_type).of_type, - cast(GraphQLNonNull, new_type).of_type)) + return is_non_null_type( + new_type + ) and is_change_safe_for_object_or_interface_field( + cast(GraphQLNonNull, old_type).of_type, + cast(GraphQLNonNull, new_type).of_type, + ) else: return False def is_change_safe_for_input_object_field_or_field_arg( - old_type: GraphQLType, new_type: GraphQLType) -> bool: + old_type: GraphQLType, new_type: GraphQLType +) -> bool: if is_named_type(old_type): # if they're both named types, see if their names are equivalent return ( - is_named_type(new_type) and - cast(GraphQLNamedType, old_type).name == - cast(GraphQLNamedType, new_type).name) + is_named_type(new_type) + and cast(GraphQLNamedType, old_type).name + == cast(GraphQLNamedType, new_type).name + ) elif is_list_type(old_type): # if they're both lists, make sure underlying types are compatible - return ( - is_list_type(new_type) and - is_change_safe_for_input_object_field_or_field_arg( - cast(GraphQLList, old_type).of_type, - cast(GraphQLList, new_type).of_type)) + return is_list_type( + new_type + ) and is_change_safe_for_input_object_field_or_field_arg( + cast(GraphQLList, old_type).of_type, cast(GraphQLList, new_type).of_type + ) elif is_non_null_type(old_type): return ( # if they're both non-null, # make sure the underlying types are compatible - (is_non_null_type(new_type) and - is_change_safe_for_input_object_field_or_field_arg( - cast(GraphQLNonNull, old_type).of_type, - cast(GraphQLNonNull, new_type).of_type)) or + ( + is_non_null_type(new_type) + and is_change_safe_for_input_object_field_or_field_arg( + cast(GraphQLNonNull, old_type).of_type, + cast(GraphQLNonNull, new_type).of_type, + ) + ) + or # moving from non-null to nullable of same underlying type is safe - (not is_non_null_type(new_type) and - is_change_safe_for_input_object_field_or_field_arg( - cast(GraphQLNonNull, old_type).of_type, new_type))) + ( + not is_non_null_type(new_type) + and is_change_safe_for_input_object_field_or_field_arg( + cast(GraphQLNonNull, old_type).of_type, new_type + ) + ) + ) else: return False def find_types_removed_from_unions( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: """Find types removed from unions. Given two schemas, returns a list containing descriptions of any breaking @@ -444,16 +553,18 @@ def find_types_removed_from_unions( for type_ in old_type.types: type_name = type_.name if type_name not in type_names_in_new_union: - types_removed_from_union.append(BreakingChange( - BreakingChangeType.TYPE_REMOVED_FROM_UNION, - f'{type_name} was removed' - f' from union type {old_type_name}.')) + types_removed_from_union.append( + BreakingChange( + BreakingChangeType.TYPE_REMOVED_FROM_UNION, + f"{type_name} was removed" f" from union type {old_type_name}.", + ) + ) return types_removed_from_union def find_types_added_to_unions( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[DangerousChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[DangerousChange]: """Find types added to union. Given two schemas, returns a list containing descriptions of any dangerous @@ -473,15 +584,18 @@ def find_types_added_to_unions( for type_ in new_type.types: type_name = type_.name if type_name not in type_names_in_old_union: - types_added_to_union.append(DangerousChange( - DangerousChangeType.TYPE_ADDED_TO_UNION, - f'{type_name} was added to union type {new_type_name}.')) + types_added_to_union.append( + DangerousChange( + DangerousChangeType.TYPE_ADDED_TO_UNION, + f"{type_name} was added to union type {new_type_name}.", + ) + ) return types_added_to_union def find_values_removed_from_enums( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: """Find values removed from enums. Given two schemas, returns a list containing descriptions of any breaking @@ -500,15 +614,18 @@ def find_values_removed_from_enums( values_in_new_enum = new_type.values for value_name in old_type.values: if value_name not in values_in_new_enum: - values_removed_from_enums.append(BreakingChange( - BreakingChangeType.VALUE_REMOVED_FROM_ENUM, - f'{value_name} was removed from enum type {type_name}.')) + values_removed_from_enums.append( + BreakingChange( + BreakingChangeType.VALUE_REMOVED_FROM_ENUM, + f"{value_name} was removed from enum type {type_name}.", + ) + ) return values_removed_from_enums def find_values_added_to_enums( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[DangerousChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[DangerousChange]: """Find values added to enums. Given two schemas, returns a list containing descriptions of any dangerous @@ -527,15 +644,18 @@ def find_values_added_to_enums( values_in_old_enum = old_type.values for value_name in new_type.values: if value_name not in values_in_old_enum: - values_added_to_enums.append(DangerousChange( - DangerousChangeType.VALUE_ADDED_TO_ENUM, - f'{value_name} was added to enum type {type_name}.')) + values_added_to_enums.append( + DangerousChange( + DangerousChangeType.VALUE_ADDED_TO_ENUM, + f"{value_name} was added to enum type {type_name}.", + ) + ) return values_added_to_enums def find_interfaces_removed_from_object_types( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: old_type_map = old_schema.type_map new_type_map = new_schema.type_map breaking_changes = [] @@ -550,18 +670,22 @@ def find_interfaces_removed_from_object_types( old_interfaces = old_type.interfaces new_interfaces = new_type.interfaces for old_interface in old_interfaces: - if not any(interface.name == old_interface.name - for interface in new_interfaces): - breaking_changes.append(BreakingChange( - BreakingChangeType.INTERFACE_REMOVED_FROM_OBJECT, - f'{type_name} no longer implements interface' - f' {old_interface.name}.')) + if not any( + interface.name == old_interface.name for interface in new_interfaces + ): + breaking_changes.append( + BreakingChange( + BreakingChangeType.INTERFACE_REMOVED_FROM_OBJECT, + f"{type_name} no longer implements interface" + f" {old_interface.name}.", + ) + ) return breaking_changes def find_interfaces_added_to_object_types( - old_schema: GraphQLSchema, new_schema: GraphQLSchema + old_schema: GraphQLSchema, new_schema: GraphQLSchema ) -> List[DangerousChange]: old_type_map = old_schema.type_map new_type_map = new_schema.type_map @@ -577,42 +701,48 @@ def find_interfaces_added_to_object_types( old_interfaces = old_type.interfaces new_interfaces = new_type.interfaces for new_interface in new_interfaces: - if not any(interface.name == new_interface.name - for interface in old_interfaces): - interfaces_added_to_object_types.append(DangerousChange( - DangerousChangeType.INTERFACE_ADDED_TO_OBJECT, - f'{new_interface.name} added to interfaces implemented' - f' by {type_name}.')) + if not any( + interface.name == new_interface.name for interface in old_interfaces + ): + interfaces_added_to_object_types.append( + DangerousChange( + DangerousChangeType.INTERFACE_ADDED_TO_OBJECT, + f"{new_interface.name} added to interfaces implemented" + f" by {type_name}.", + ) + ) return interfaces_added_to_object_types def find_removed_directives( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: removed_directives = [] new_schema_directive_map = get_directive_map_for_schema(new_schema) for directive in old_schema.directives: if directive.name not in new_schema_directive_map: - removed_directives.append(BreakingChange( - BreakingChangeType.DIRECTIVE_REMOVED, - f'{directive.name} was removed')) + removed_directives.append( + BreakingChange( + BreakingChangeType.DIRECTIVE_REMOVED, + f"{directive.name} was removed", + ) + ) return removed_directives def find_removed_args_for_directive( - old_directive: GraphQLDirective, new_directive: GraphQLDirective - ) -> List[str]: + old_directive: GraphQLDirective, new_directive: GraphQLDirective +) -> List[str]: new_arg_map = new_directive.args - return [arg_name for arg_name in old_directive.args - if arg_name not in new_arg_map] + return [arg_name for arg_name in old_directive.args if arg_name not in new_arg_map] def find_removed_directive_args( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: removed_directive_args = [] old_schema_directive_map = get_directive_map_for_schema(old_schema) @@ -621,26 +751,31 @@ def find_removed_directive_args( if not old_directive: continue - for arg_name in find_removed_args_for_directive( - old_directive, new_directive): - removed_directive_args.append(BreakingChange( - BreakingChangeType.DIRECTIVE_ARG_REMOVED, - f'{arg_name} was removed from {new_directive.name}')) + for arg_name in find_removed_args_for_directive(old_directive, new_directive): + removed_directive_args.append( + BreakingChange( + BreakingChangeType.DIRECTIVE_ARG_REMOVED, + f"{arg_name} was removed from {new_directive.name}", + ) + ) return removed_directive_args def find_added_args_for_directive( - old_directive: GraphQLDirective, new_directive: GraphQLDirective - ) -> Dict[str, GraphQLArgument]: + old_directive: GraphQLDirective, new_directive: GraphQLDirective +) -> Dict[str, GraphQLArgument]: old_arg_map = old_directive.args - return {arg_name: arg for arg_name, arg in new_directive.args.items() - if arg_name not in old_arg_map} + return { + arg_name: arg + for arg_name, arg in new_directive.args.items() + if arg_name not in old_arg_map + } def find_added_non_null_directive_args( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: added_non_nullable_args = [] old_schema_directive_map = get_directive_map_for_schema(old_schema) @@ -650,27 +785,34 @@ def find_added_non_null_directive_args( continue for arg_name, arg in find_added_args_for_directive( - old_directive, new_directive).items(): + old_directive, new_directive + ).items(): if is_required_argument(arg): - added_non_nullable_args.append(BreakingChange( - BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, - f'A required arg {arg_name} on directive' - f' {new_directive.name} was added')) + added_non_nullable_args.append( + BreakingChange( + BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, + f"A required arg {arg_name} on directive" + f" {new_directive.name} was added", + ) + ) return added_non_nullable_args def find_removed_locations_for_directive( - old_directive: GraphQLDirective, new_directive: GraphQLDirective - ) -> List[DirectiveLocation]: + old_directive: GraphQLDirective, new_directive: GraphQLDirective +) -> List[DirectiveLocation]: new_location_set = set(new_directive.locations) - return [old_location for old_location in old_directive.locations - if old_location not in new_location_set] + return [ + old_location + for old_location in old_directive.locations + if old_location not in new_location_set + ] def find_removed_directive_locations( - old_schema: GraphQLSchema, new_schema: GraphQLSchema - ) -> List[BreakingChange]: + old_schema: GraphQLSchema, new_schema: GraphQLSchema +) -> List[BreakingChange]: removed_locations = [] old_schema_directive_map = get_directive_map_for_schema(old_schema) @@ -680,14 +822,17 @@ def find_removed_directive_locations( continue for location in find_removed_locations_for_directive( - old_directive, new_directive): - removed_locations.append(BreakingChange( - BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, - f'{location.name} was removed from {new_directive.name}')) + old_directive, new_directive + ): + removed_locations.append( + BreakingChange( + BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, + f"{location.name} was removed from {new_directive.name}", + ) + ) return removed_locations -def get_directive_map_for_schema( - schema: GraphQLSchema) -> Dict[str, GraphQLDirective]: +def get_directive_map_for_schema(schema: GraphQLSchema) -> Dict[str, GraphQLDirective]: return {directive.name: directive for directive in schema.directives} diff --git a/graphql/utilities/find_deprecated_usages.py b/graphql/utilities/find_deprecated_usages.py index 3ac08f85..1571e4ae 100644 --- a/graphql/utilities/find_deprecated_usages.py +++ b/graphql/utilities/find_deprecated_usages.py @@ -6,11 +6,12 @@ from .type_info import TypeInfo -__all__ = ['find_deprecated_usages'] +__all__ = ["find_deprecated_usages"] def find_deprecated_usages( - schema: GraphQLSchema, ast: DocumentNode) -> List[GraphQLError]: + schema: GraphQLSchema, ast: DocumentNode +) -> List[GraphQLError]: """Get a list of GraphQLError instances describing each deprecated use.""" type_info = TypeInfo(schema) @@ -37,10 +38,13 @@ def enter_field(self, node, *_args): if parent_type: field_name = node.name.value reason = field_def.deprecation_reason - self.errors.append(GraphQLError( - f'The field {parent_type.name}.{field_name}' - ' is deprecated.' + (f' {reason}' if reason else ''), - [node])) + self.errors.append( + GraphQLError( + f"The field {parent_type.name}.{field_name}" + " is deprecated." + (f" {reason}" if reason else ""), + [node], + ) + ) def enter_enum_value(self, node, *_args): enum_val = self.type_info.get_enum_value() @@ -49,7 +53,10 @@ def enter_enum_value(self, node, *_args): if type_: enum_val_name = node.value reason = enum_val.deprecation_reason - self.errors.append(GraphQLError( - f'The enum value {type_.name}.{enum_val_name}' - ' is deprecated.' + (f' {reason}' if reason else ''), - [node])) + self.errors.append( + GraphQLError( + f"The enum value {type_.name}.{enum_val_name}" + " is deprecated." + (f" {reason}" if reason else ""), + [node], + ) + ) diff --git a/graphql/utilities/get_operation_ast.py b/graphql/utilities/get_operation_ast.py index 09d1f29a..0a54ce70 100644 --- a/graphql/utilities/get_operation_ast.py +++ b/graphql/utilities/get_operation_ast.py @@ -2,12 +2,12 @@ from ..language import DocumentNode, OperationDefinitionNode -__all__ = ['get_operation_ast'] +__all__ = ["get_operation_ast"] def get_operation_ast( - document_ast: DocumentNode, operation_name: Optional[str]=None - ) -> Optional[OperationDefinitionNode]: + document_ast: DocumentNode, operation_name: Optional[str] = None +) -> Optional[OperationDefinitionNode]: """Get operation AST node. Returns an operation AST given a document AST and optionally an operation diff --git a/graphql/utilities/get_operation_root_type.py b/graphql/utilities/get_operation_root_type.py index 7cb8de39..33c0a982 100644 --- a/graphql/utilities/get_operation_root_type.py +++ b/graphql/utilities/get_operation_root_type.py @@ -2,38 +2,41 @@ from ..error import GraphQLError from ..language import ( - OperationType, OperationDefinitionNode, OperationTypeDefinitionNode) + OperationType, + OperationDefinitionNode, + OperationTypeDefinitionNode, +) from ..type import GraphQLObjectType, GraphQLSchema -__all__ = ['get_operation_root_type'] +__all__ = ["get_operation_root_type"] def get_operation_root_type( - schema: GraphQLSchema, - operation: Union[OperationDefinitionNode, OperationTypeDefinitionNode] - ) -> GraphQLObjectType: + schema: GraphQLSchema, + operation: Union[OperationDefinitionNode, OperationTypeDefinitionNode], +) -> GraphQLObjectType: """Extract the root type of the operation from the schema.""" operation_type = operation.operation if operation_type == OperationType.QUERY: query_type = schema.query_type if not query_type: raise GraphQLError( - 'Schema does not define the required query root type.', - [operation]) + "Schema does not define the required query root type.", [operation] + ) return query_type elif operation_type == OperationType.MUTATION: mutation_type = schema.mutation_type if not mutation_type: - raise GraphQLError( - 'Schema is not configured for mutations.', [operation]) + raise GraphQLError("Schema is not configured for mutations.", [operation]) return mutation_type elif operation_type == OperationType.SUBSCRIPTION: subscription_type = schema.subscription_type if not subscription_type: raise GraphQLError( - 'Schema is not configured for subscriptions.', [operation]) + "Schema is not configured for subscriptions.", [operation] + ) return subscription_type else: raise GraphQLError( - 'Can only have query, mutation and subscription operations.', - [operation]) + "Can only have query, mutation and subscription operations.", [operation] + ) diff --git a/graphql/utilities/introspection_from_schema.py b/graphql/utilities/introspection_from_schema.py index fbc5736b..79b24d74 100644 --- a/graphql/utilities/introspection_from_schema.py +++ b/graphql/utilities/introspection_from_schema.py @@ -5,15 +5,15 @@ from ..type import GraphQLSchema from ..utilities.introspection_query import get_introspection_query -__all__ = ['introspection_from_schema'] +__all__ = ["introspection_from_schema"] IntrospectionSchema = Dict[str, Any] def introspection_from_schema( - schema: GraphQLSchema, - descriptions: bool=True) -> IntrospectionSchema: + schema: GraphQLSchema, descriptions: bool = True +) -> IntrospectionSchema: """Build an IntrospectionQuery from a GraphQLSchema IntrospectionQuery is useful for utilities that care about type and field @@ -25,10 +25,12 @@ def introspection_from_schema( query_ast = parse(get_introspection_query(descriptions)) from ..execution.execute import execute, ExecutionResult + result = execute(schema, query_ast) if not isinstance(result, ExecutionResult): - raise RuntimeError('Introspection cannot be executed') + raise RuntimeError("Introspection cannot be executed") if result.errors or not result.data: raise result.errors[0] if result.errors else GraphQLError( - 'Introspection did not return a result') + "Introspection did not return a result" + ) return result.data diff --git a/graphql/utilities/introspection_query.py b/graphql/utilities/introspection_query.py index 9c170223..47b0a0d1 100644 --- a/graphql/utilities/introspection_query.py +++ b/graphql/utilities/introspection_query.py @@ -1,11 +1,12 @@ from textwrap import dedent -__all__ = ['get_introspection_query'] +__all__ = ["get_introspection_query"] def get_introspection_query(descriptions=True) -> str: """Get a query for introspection, optionally without descriptions.""" - return dedent(f""" + return dedent( + f""" query IntrospectionQuery {{ __schema {{ queryType {{ name }} @@ -97,4 +98,5 @@ def get_introspection_query(descriptions=True) -> str: }} }} }} - """) + """ + ) diff --git a/graphql/utilities/lexicographic_sort_schema.py b/graphql/utilities/lexicographic_sort_schema.py index 0accba34..4a9c64ce 100644 --- a/graphql/utilities/lexicographic_sort_schema.py +++ b/graphql/utilities/lexicographic_sort_schema.py @@ -2,15 +2,33 @@ from typing import Collection, Dict, List, cast from ..type import ( - GraphQLArgument, GraphQLDirective, GraphQLEnumType, - GraphQLEnumValue, GraphQLField, GraphQLInputField, GraphQLInputObjectType, - GraphQLInterfaceType, GraphQLList, GraphQLNamedType, GraphQLNonNull, - GraphQLObjectType, GraphQLSchema, GraphQLUnionType, - is_enum_type, is_input_object_type, is_interface_type, - is_introspection_type, is_list_type, is_non_null_type, is_object_type, - is_scalar_type, is_specified_scalar_type, is_union_type) - -__all__ = ['lexicographic_sort_schema'] + GraphQLArgument, + GraphQLDirective, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLList, + GraphQLNamedType, + GraphQLNonNull, + GraphQLObjectType, + GraphQLSchema, + GraphQLUnionType, + is_enum_type, + is_input_object_type, + is_interface_type, + is_introspection_type, + is_list_type, + is_non_null_type, + is_object_type, + is_scalar_type, + is_specified_scalar_type, + is_union_type, +) + +__all__ = ["lexicographic_sort_schema"] def lexicographic_sort_schema(schema: GraphQLSchema) -> GraphQLSchema: @@ -25,36 +43,46 @@ def sort_directive(directive): return GraphQLDirective( name=directive.name, description=directive.description, - locations=sorted(directive.locations, key=attrgetter('name')), + locations=sorted(directive.locations, key=attrgetter("name")), args=sort_args(directive.args), - ast_node=directive.ast_node) + ast_node=directive.ast_node, + ) def sort_args(args): - return {name: GraphQLArgument( - sort_type(arg.type), - default_value=arg.default_value, - description=arg.description, - ast_node=arg.ast_node) - for name, arg in sorted(args.items())} + return { + name: GraphQLArgument( + sort_type(arg.type), + default_value=arg.default_value, + description=arg.description, + ast_node=arg.ast_node, + ) + for name, arg in sorted(args.items()) + } def sort_fields(fields_map): - return {name: GraphQLField( - sort_type(field.type), - args=sort_args(field.args), - resolve=field.resolve, - subscribe=field.subscribe, - description=field.description, - deprecation_reason=field.deprecation_reason, - ast_node=field.ast_node) - for name, field in sorted(fields_map.items())} + return { + name: GraphQLField( + sort_type(field.type), + args=sort_args(field.args), + resolve=field.resolve, + subscribe=field.subscribe, + description=field.description, + deprecation_reason=field.deprecation_reason, + ast_node=field.ast_node, + ) + for name, field in sorted(fields_map.items()) + } def sort_input_fields(fields_map): - return {name: GraphQLInputField( - sort_type(field.type), - description=field.description, - default_value=field.default_value, - ast_node=field.ast_node) - for name, field in sorted(fields_map.items())} + return { + name: GraphQLInputField( + sort_type(field.type), + description=field.description, + default_value=field.default_value, + ast_node=field.ast_node, + ) + for name, field in sorted(fields_map.items()) + } def sort_type(type_): if is_list_type(type_): @@ -74,10 +102,8 @@ def sort_named_type(type_: GraphQLNamedType) -> GraphQLNamedType: cache[type_.name] = sorted_type return sorted_type - def sort_types( - arr: Collection[GraphQLNamedType]) -> List[GraphQLNamedType]: - return [sort_named_type(type_) - for type_ in sorted(arr, key=attrgetter('name'))] + def sort_types(arr: Collection[GraphQLNamedType]) -> List[GraphQLNamedType]: + return [sort_named_type(type_) for type_ in sorted(arr, key=attrgetter("name"))] def sort_named_type_impl(type_: GraphQLNamedType) -> GraphQLNamedType: if is_scalar_type(type_): @@ -87,12 +113,14 @@ def sort_named_type_impl(type_: GraphQLNamedType) -> GraphQLNamedType: return GraphQLObjectType( type_.name, interfaces=lambda: cast( - List[GraphQLInterfaceType], sort_types(type1.interfaces)), + List[GraphQLInterfaceType], sort_types(type1.interfaces) + ), fields=lambda: sort_fields(type1.fields), is_type_of=type1.is_type_of, description=type_.description, ast_node=type1.ast_node, - extension_ast_nodes=type1.extension_ast_nodes) + extension_ast_nodes=type1.extension_ast_nodes, + ) elif is_interface_type(type_): type2 = cast(GraphQLInterfaceType, type_) return GraphQLInterfaceType( @@ -101,42 +129,51 @@ def sort_named_type_impl(type_: GraphQLNamedType) -> GraphQLNamedType: resolve_type=type2.resolve_type, description=type_.description, ast_node=type2.ast_node, - extension_ast_nodes=type2.extension_ast_nodes) + extension_ast_nodes=type2.extension_ast_nodes, + ) elif is_union_type(type_): type3 = cast(GraphQLUnionType, type_) return GraphQLUnionType( type_.name, - types=lambda: cast( - List[GraphQLObjectType], sort_types(type3.types)), + types=lambda: cast(List[GraphQLObjectType], sort_types(type3.types)), resolve_type=type3.resolve_type, description=type_.description, - ast_node=type3.ast_node) + ast_node=type3.ast_node, + ) elif is_enum_type(type_): type4 = cast(GraphQLEnumType, type_) return GraphQLEnumType( type_.name, - values={name: GraphQLEnumValue( - val.value, - description=val.description, - deprecation_reason=val.deprecation_reason, - ast_node=val.ast_node) - for name, val in sorted(type4.values.items())}, + values={ + name: GraphQLEnumValue( + val.value, + description=val.description, + deprecation_reason=val.deprecation_reason, + ast_node=val.ast_node, + ) + for name, val in sorted(type4.values.items()) + }, description=type_.description, - ast_node=type4.ast_node) + ast_node=type4.ast_node, + ) elif is_input_object_type(type_): type5 = cast(GraphQLInputObjectType, type_) return GraphQLInputObjectType( type_.name, sort_input_fields(type5.fields), description=type_.description, - ast_node=type5.ast_node) + ast_node=type5.ast_node, + ) raise TypeError(f"Unknown type: '{type_}'") return GraphQLSchema( types=sort_types(schema.type_map.values()), - directives=[sort_directive(directive) for directive in sorted( - schema.directives, key=attrgetter('name'))], + directives=[ + sort_directive(directive) + for directive in sorted(schema.directives, key=attrgetter("name")) + ], query=sort_maybe_type(schema.query_type), mutation=sort_maybe_type(schema.mutation_type), subscription=sort_maybe_type(schema.subscription_type), - ast_node=schema.ast_node) + ast_node=schema.ast_node, + ) diff --git a/graphql/utilities/schema_printer.py b/graphql/utilities/schema_printer.py index fcd5e39a..a8da1ae5 100644 --- a/graphql/utilities/schema_printer.py +++ b/graphql/utilities/schema_printer.py @@ -5,47 +5,69 @@ from ..language import print_ast from ..pyutils import is_invalid, is_nullish from ..type import ( - DEFAULT_DEPRECATION_REASON, GraphQLArgument, - GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, GraphQLField, - GraphQLInputObjectType, GraphQLInputType, GraphQLInterfaceType, - GraphQLNamedType, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, - GraphQLString, GraphQLUnionType, is_enum_type, is_input_object_type, - is_interface_type, is_introspection_type, is_object_type, is_scalar_type, - is_specified_directive, is_specified_scalar_type, is_union_type) + DEFAULT_DEPRECATION_REASON, + GraphQLArgument, + GraphQLDirective, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLInputObjectType, + GraphQLInputType, + GraphQLInterfaceType, + GraphQLNamedType, + GraphQLObjectType, + GraphQLScalarType, + GraphQLSchema, + GraphQLString, + GraphQLUnionType, + is_enum_type, + is_input_object_type, + is_interface_type, + is_introspection_type, + is_object_type, + is_scalar_type, + is_specified_directive, + is_specified_scalar_type, + is_union_type, +) from .ast_from_value import ast_from_value -__all__ = [ - 'print_schema', 'print_introspection_schema', 'print_type', 'print_value'] +__all__ = ["print_schema", "print_introspection_schema", "print_type", "print_value"] def print_schema(schema: GraphQLSchema) -> str: return print_filtered_schema( - schema, lambda n: not is_specified_directive(n), is_defined_type) + schema, lambda n: not is_specified_directive(n), is_defined_type + ) def print_introspection_schema(schema: GraphQLSchema) -> str: - return print_filtered_schema( - schema, is_specified_directive, is_introspection_type) + return print_filtered_schema(schema, is_specified_directive, is_introspection_type) def is_defined_type(type_: GraphQLNamedType) -> bool: - return (not is_specified_scalar_type(type_) and - not is_introspection_type(type_)) + return not is_specified_scalar_type(type_) and not is_introspection_type(type_) def print_filtered_schema( - schema: GraphQLSchema, - directive_filter: Callable[[GraphQLDirective], bool], - type_filter: Callable[[GraphQLNamedType], bool]) -> str: + schema: GraphQLSchema, + directive_filter: Callable[[GraphQLDirective], bool], + type_filter: Callable[[GraphQLNamedType], bool], +) -> str: directives = filter(directive_filter, schema.directives) type_map = schema.type_map - types = filter( # type: ignore - type_filter, map(type_map.get, sorted(type_map))) + types = filter(type_filter, map(type_map.get, sorted(type_map))) # type: ignore - return '\n\n'.join(chain(filter(None, [ - print_schema_definition(schema)]), - (print_directive(directive) for directive in directives), - (print_type(type_) for type_ in types))) + '\n' # type: ignore + return ( + "\n\n".join( + chain( + filter(None, [print_schema_definition(schema)]), + (print_directive(directive) for directive in directives), + (print_type(type_) for type_ in types), # type: ignore + ) + ) + + "\n" + ) def print_schema_definition(schema: GraphQLSchema) -> Optional[str]: @@ -56,17 +78,17 @@ def print_schema_definition(schema: GraphQLSchema) -> Optional[str]: query_type = schema.query_type if query_type: - operation_types.append(f' query: {query_type.name}') + operation_types.append(f" query: {query_type.name}") mutation_type = schema.mutation_type if mutation_type: - operation_types.append(f' mutation: {mutation_type.name}') + operation_types.append(f" mutation: {mutation_type.name}") subscription_type = schema.subscription_type if subscription_type: - operation_types.append(f' subscription: {subscription_type.name}') + operation_types.append(f" subscription: {subscription_type.name}") - return 'schema {\n' + '\n'.join(operation_types) + '\n}' + return "schema {\n" + "\n".join(operation_types) + "\n}" def is_schema_of_common_names(schema: GraphQLSchema) -> bool: @@ -84,15 +106,15 @@ def is_schema_of_common_names(schema: GraphQLSchema) -> bool: When using this naming convention, the schema description can be omitted. """ query_type = schema.query_type - if query_type and query_type.name != 'Query': + if query_type and query_type.name != "Query": return False mutation_type = schema.mutation_type - if mutation_type and mutation_type.name != 'Mutation': + if mutation_type and mutation_type.name != "Mutation": return False subscription_type = schema.subscription_type - if subscription_type and subscription_type.name != 'Subscription': + if subscription_type and subscription_type.name != "Subscription": return False return True @@ -117,120 +139,153 @@ def print_type(type_: GraphQLNamedType) -> str: if is_input_object_type(type_): type_ = cast(GraphQLInputObjectType, type_) return print_input_object(type_) - raise TypeError(f'Unknown type: {type_!r}') + raise TypeError(f"Unknown type: {type_!r}") def print_scalar(type_: GraphQLScalarType) -> str: - return print_description(type_) + f'scalar {type_.name}' + return print_description(type_) + f"scalar {type_.name}" def print_object(type_: GraphQLObjectType) -> str: interfaces = type_.interfaces implemented_interfaces = ( - ' implements ' + ' & '.join(i.name for i in interfaces) - ) if interfaces else '' - return (print_description(type_) + - f'type {type_.name}{implemented_interfaces} ' + - '{\n' + print_fields(type_) + '\n}') + (" implements " + " & ".join(i.name for i in interfaces)) if interfaces else "" + ) + return ( + print_description(type_) + + f"type {type_.name}{implemented_interfaces} " + + "{\n" + + print_fields(type_) + + "\n}" + ) def print_interface(type_: GraphQLInterfaceType) -> str: - return (print_description(type_) + - f'interface {type_.name} ' + - '{\n' + print_fields(type_) + '\n}') + return ( + print_description(type_) + + f"interface {type_.name} " + + "{\n" + + print_fields(type_) + + "\n}" + ) def print_union(type_: GraphQLUnionType) -> str: - return (print_description(type_) + - f'union {type_.name} = ' + ' | '.join( - t.name for t in type_.types)) + return ( + print_description(type_) + + f"union {type_.name} = " + + " | ".join(t.name for t in type_.types) + ) def print_enum(type_: GraphQLEnumType) -> str: - return (print_description(type_) + - f'enum {type_.name} ' + - '{\n' + print_enum_values(type_.values) + '\n}') + return ( + print_description(type_) + + f"enum {type_.name} " + + "{\n" + + print_enum_values(type_.values) + + "\n}" + ) def print_enum_values(values: Dict[str, GraphQLEnumValue]) -> str: - return '\n'.join( - print_description(value, ' ', not i) + - f' {name}' + print_deprecated(value) - for i, (name, value) in enumerate(values.items())) + return "\n".join( + print_description(value, " ", not i) + f" {name}" + print_deprecated(value) + for i, (name, value) in enumerate(values.items()) + ) def print_input_object(type_: GraphQLInputObjectType) -> str: fields = type_.fields.items() - return (print_description(type_) + - f'input {type_.name} ' + '{\n' + - '\n'.join( - print_description(field, ' ', not i) + ' ' + - print_input_value(name, field) - for i, (name, field) in enumerate(fields)) + '\n}') + return ( + print_description(type_) + + f"input {type_.name} " + + "{\n" + + "\n".join( + print_description(field, " ", not i) + + " " + + print_input_value(name, field) + for i, (name, field) in enumerate(fields) + ) + + "\n}" + ) def print_fields(type_: Union[GraphQLObjectType, GraphQLInterfaceType]) -> str: fields = type_.fields.items() - return '\n'.join( - print_description(field, ' ', not i) + f' {name}' + - print_args(field.args, ' ') + f': {field.type}' + - print_deprecated(field) - for i, (name, field) in enumerate(fields)) + return "\n".join( + print_description(field, " ", not i) + + f" {name}" + + print_args(field.args, " ") + + f": {field.type}" + + print_deprecated(field) + for i, (name, field) in enumerate(fields) + ) -def print_args(args: Dict[str, GraphQLArgument], indentation='') -> str: +def print_args(args: Dict[str, GraphQLArgument], indentation="") -> str: if not args: - return '' + return "" # If every arg does not have a description, print them on one line. if not any(arg.description for arg in args.values()): - return '(' + ', '.join( - print_input_value(name, arg) for name, arg in args.items()) + ')' - - return ('(\n' + '\n'.join( - print_description(arg, f' {indentation}', not i) + - f' {indentation}' + print_input_value(name, arg) - for i, (name, arg) in enumerate(args.items())) + f'\n{indentation})') + return ( + "(" + + ", ".join(print_input_value(name, arg) for name, arg in args.items()) + + ")" + ) + + return ( + "(\n" + + "\n".join( + print_description(arg, f" {indentation}", not i) + + f" {indentation}" + + print_input_value(name, arg) + for i, (name, arg) in enumerate(args.items()) + ) + + f"\n{indentation})" + ) def print_input_value(name: str, arg: GraphQLArgument) -> str: - arg_decl = f'{name}: {arg.type}' + arg_decl = f"{name}: {arg.type}" if not is_invalid(arg.default_value): - arg_decl += f' = {print_value(arg.default_value, arg.type)}' + arg_decl += f" = {print_value(arg.default_value, arg.type)}" return arg_decl def print_directive(directive: GraphQLDirective) -> str: - return (print_description(directive) + - f'directive @{directive.name}' + - print_args(directive.args) + - ' on ' + ' | '.join( - location.name for location in directive.locations)) + return ( + print_description(directive) + + f"directive @{directive.name}" + + print_args(directive.args) + + " on " + + " | ".join(location.name for location in directive.locations) + ) -def print_deprecated( - field_or_enum_value: Union[GraphQLField, GraphQLEnumValue]) -> str: +def print_deprecated(field_or_enum_value: Union[GraphQLField, GraphQLEnumValue]) -> str: if not field_or_enum_value.is_deprecated: - return '' + return "" reason = field_or_enum_value.deprecation_reason - if (is_nullish(reason) or reason == '' or - reason == DEFAULT_DEPRECATION_REASON): - return ' @deprecated' + if is_nullish(reason) or reason == "" or reason == DEFAULT_DEPRECATION_REASON: + return " @deprecated" else: - return f' @deprecated(reason: {print_value(reason, GraphQLString)})' + return f" @deprecated(reason: {print_value(reason, GraphQLString)})" def print_description( - type_: Union[GraphQLArgument, GraphQLDirective, - GraphQLEnumValue, GraphQLNamedType], - indentation='', first_in_block=True) -> str: + type_: Union[GraphQLArgument, GraphQLDirective, GraphQLEnumValue, GraphQLNamedType], + indentation="", + first_in_block=True, +) -> str: if not type_.description: - return '' + return "" lines = description_lines(type_.description, 120 - len(indentation)) description = [] if indentation and not first_in_block: - description.append('\n') + description.append("\n") description.extend([indentation, '"""']) if len(lines) == 1 and len(lines[0]) < 70 and not lines[0].endswith('"'): @@ -238,16 +293,16 @@ def print_description( description.extend([escape_quote(lines[0]), '"""\n']) else: # Format a multi-line block quote to account for leading space. - has_leading_space = lines and lines[0].startswith((' ', '\t')) + has_leading_space = lines and lines[0].startswith((" ", "\t")) if not has_leading_space: - description.append('\n') + description.append("\n") for i, line in enumerate(lines): if i or not has_leading_space: description.append(indentation) - description.extend([escape_quote(line), '\n']) + description.extend([escape_quote(line), "\n"]) description.extend([indentation, '"""\n']) - return ''.join(description) + return "".join(description) def escape_quote(line: str) -> str: @@ -271,7 +326,7 @@ def description_lines(description: str, max_len: int) -> List[str]: def break_line(line: str, max_len: int) -> List[str]: if len(line) < max_len + 5: return [line] - parts = re.split(f'((?: |^).{{15,{max_len - 40}}}(?= |$))', line) + parts = re.split(f"((?: |^).{{15,{max_len - 40}}}(?= |$))", line) if len(parts) < 4: return [line] sublines = [parts[0] + parts[1] + parts[2]] diff --git a/graphql/utilities/separate_operations.py b/graphql/utilities/separate_operations.py index b06e40fd..6b995b78 100644 --- a/graphql/utilities/separate_operations.py +++ b/graphql/utilities/separate_operations.py @@ -2,10 +2,15 @@ from typing import Dict, List, Set from ..language import ( - DocumentNode, ExecutableDefinitionNode, FragmentDefinitionNode, - OperationDefinitionNode, Visitor, visit) + DocumentNode, + ExecutableDefinitionNode, + FragmentDefinitionNode, + OperationDefinitionNode, + Visitor, + visit, +) -__all__ = ['separate_operations'] +__all__ = ["separate_operations"] DepGraph = Dict[str, Set[str]] @@ -34,8 +39,7 @@ def separate_operations(document_ast: DocumentNode) -> Dict[str, DocumentNode]: for operation in operations: operation_name = op_name(operation) dependencies: Set[str] = set() - collect_transitive_dependencies( - dependencies, dep_graph, operation_name) + collect_transitive_dependencies(dependencies, dep_graph, operation_name) # The list of definition nodes to be included for this operation, # sorted to retain the same order as the original document. @@ -44,14 +48,12 @@ def separate_operations(document_ast: DocumentNode) -> Dict[str, DocumentNode]: definitions.append(fragments[name]) definitions.sort(key=lambda n: positions.get(n, 0)) - separated_document_asts[operation_name] = DocumentNode( - definitions=definitions) + separated_document_asts[operation_name] = DocumentNode(definitions=definitions) return separated_document_asts class SeparateOperations(Visitor): - def __init__(self): super().__init__() self.operations: List[OperationDefinitionNode] = [] @@ -80,12 +82,12 @@ def enter_fragment_spread(self, node, *_args): def op_name(operation: OperationDefinitionNode) -> str: """Provide the empty string for anonymous operations.""" - return operation.name.value if operation.name else '' + return operation.name.value if operation.name else "" def collect_transitive_dependencies( - collected: Set[str], dep_graph: DepGraph, - from_name: str) -> None: + collected: Set[str], dep_graph: DepGraph, from_name: str +) -> None: """Collect transitive dependencies. From a dependency graph, collects a list of transitive dependencies by diff --git a/graphql/utilities/type_comparators.py b/graphql/utilities/type_comparators.py index e4d626d3..72b1e223 100644 --- a/graphql/utilities/type_comparators.py +++ b/graphql/utilities/type_comparators.py @@ -1,11 +1,19 @@ from typing import cast from ..type import ( - GraphQLAbstractType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLSchema, GraphQLType, - is_abstract_type, is_list_type, is_non_null_type, is_object_type) + GraphQLAbstractType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLSchema, + GraphQLType, + is_abstract_type, + is_list_type, + is_non_null_type, + is_object_type, +) -__all__ = ['is_equal_type', 'is_type_sub_type_of', 'do_types_overlap'] +__all__ = ["is_equal_type", "is_type_sub_type_of", "do_types_overlap"] def is_equal_type(type_a: GraphQLType, type_b: GraphQLType): @@ -32,8 +40,8 @@ def is_equal_type(type_a: GraphQLType, type_b: GraphQLType): # noinspection PyUnresolvedReferences def is_type_sub_type_of( - schema: GraphQLSchema, - maybe_subtype: GraphQLType, super_type: GraphQLType) -> bool: + schema: GraphQLSchema, maybe_subtype: GraphQLType, super_type: GraphQLType +) -> bool: """Check whether a type is subtype of another type in a given schema. Provided a type and a super type, return true if the first type is either @@ -47,20 +55,25 @@ def is_type_sub_type_of( if is_non_null_type(super_type): if is_non_null_type(maybe_subtype): return is_type_sub_type_of( - schema, cast(GraphQLNonNull, maybe_subtype).of_type, - cast(GraphQLNonNull, super_type).of_type) + schema, + cast(GraphQLNonNull, maybe_subtype).of_type, + cast(GraphQLNonNull, super_type).of_type, + ) return False elif is_non_null_type(maybe_subtype): # If super_type is nullable, maybe_subtype may be non-null or nullable. return is_type_sub_type_of( - schema, cast(GraphQLNonNull, maybe_subtype).of_type, super_type) + schema, cast(GraphQLNonNull, maybe_subtype).of_type, super_type + ) # If superType type is a list, maybeSubType type must also be a list. if is_list_type(super_type): if is_list_type(maybe_subtype): return is_type_sub_type_of( - schema, cast(GraphQLList, maybe_subtype).of_type, - cast(GraphQLList, super_type).of_type) + schema, + cast(GraphQLList, maybe_subtype).of_type, + cast(GraphQLList, super_type).of_type, + ) return False elif is_list_type(maybe_subtype): # If super_type is not a list, maybe_subtype must also be not a list. @@ -69,11 +82,14 @@ def is_type_sub_type_of( # If super_type type is an abstract type, maybe_subtype type may be a # currently possible object type. # noinspection PyTypeChecker - if (is_abstract_type(super_type) and - is_object_type(maybe_subtype) and - schema.is_possible_type( - cast(GraphQLAbstractType, super_type), - cast(GraphQLObjectType, maybe_subtype))): + if ( + is_abstract_type(super_type) + and is_object_type(maybe_subtype) + and schema.is_possible_type( + cast(GraphQLAbstractType, super_type), + cast(GraphQLObjectType, maybe_subtype), + ) + ): return True # Otherwise, the child type is not a valid subtype of the parent type. @@ -99,8 +115,10 @@ def do_types_overlap(schema, type_a, type_b): if is_abstract_type(type_b): # If both types are abstract, then determine if there is any # intersection between possible concrete types of each. - return any(schema.is_possible_type(type_b, type_) - for type_ in schema.get_possible_types(type_a)) + return any( + schema.is_possible_type(type_b, type_) + for type_ in schema.get_possible_types(type_a) + ) # Determine if latter type is a possible concrete type of the former. return schema.is_possible_type(type_a, type_b) diff --git a/graphql/utilities/type_from_ast.py b/graphql/utilities/type_from_ast.py index 6be29c4e..6e09ec23 100644 --- a/graphql/utilities/type_from_ast.py +++ b/graphql/utilities/type_from_ast.py @@ -1,34 +1,40 @@ from typing import Optional, overload -from ..language import ( - TypeNode, NamedTypeNode, ListTypeNode, NonNullTypeNode) +from ..language import TypeNode, NamedTypeNode, ListTypeNode, NonNullTypeNode from ..type import ( - GraphQLType, GraphQLSchema, GraphQLNamedType, GraphQLList, GraphQLNonNull) + GraphQLType, + GraphQLSchema, + GraphQLNamedType, + GraphQLList, + GraphQLNonNull, +) -__all__ = ['type_from_ast'] +__all__ = ["type_from_ast"] @overload -def type_from_ast(schema: GraphQLSchema, - type_node: NamedTypeNode) -> Optional[GraphQLNamedType]: +def type_from_ast( + schema: GraphQLSchema, type_node: NamedTypeNode +) -> Optional[GraphQLNamedType]: ... @overload # noqa: F811 (pycqa/flake8#423) -def type_from_ast(schema: GraphQLSchema, - type_node: ListTypeNode) -> Optional[GraphQLList]: +def type_from_ast( + schema: GraphQLSchema, type_node: ListTypeNode +) -> Optional[GraphQLList]: ... @overload # noqa: F811 -def type_from_ast(schema: GraphQLSchema, - type_node: NonNullTypeNode) -> Optional[GraphQLNonNull]: +def type_from_ast( + schema: GraphQLSchema, type_node: NonNullTypeNode +) -> Optional[GraphQLNonNull]: ... @overload # noqa: F811 -def type_from_ast(schema: GraphQLSchema, - type_node: TypeNode) -> Optional[GraphQLType]: +def type_from_ast(schema: GraphQLSchema, type_node: TypeNode) -> Optional[GraphQLType]: ... @@ -49,4 +55,4 @@ def type_from_ast(schema, type_node): # noqa: F811 return GraphQLNonNull(inner_type) if inner_type else None if isinstance(type_node, NamedTypeNode): return schema.get_type(type_node.name.value) - raise TypeError(f'Unexpected type kind: {type_node.kind}') + raise TypeError(f"Unexpected type kind: {type_node.kind}") diff --git a/graphql/utilities/type_info.py b/graphql/utilities/type_info.py index 964398e5..75fba845 100644 --- a/graphql/utilities/type_info.py +++ b/graphql/utilities/type_info.py @@ -2,24 +2,53 @@ from ..error import INVALID from ..language import ( - ArgumentNode, DirectiveNode, EnumValueNode, FieldNode, InlineFragmentNode, - ListValueNode, Node, ObjectFieldNode, OperationDefinitionNode, - OperationType, SelectionSetNode, VariableDefinitionNode) + ArgumentNode, + DirectiveNode, + EnumValueNode, + FieldNode, + InlineFragmentNode, + ListValueNode, + Node, + ObjectFieldNode, + OperationDefinitionNode, + OperationType, + SelectionSetNode, + VariableDefinitionNode, +) from ..type import ( - GraphQLArgument, GraphQLCompositeType, GraphQLDirective, - GraphQLEnumValue, GraphQLField, GraphQLInputType, GraphQLInterfaceType, - GraphQLObjectType, GraphQLOutputType, GraphQLSchema, GraphQLType, - is_composite_type, is_input_type, is_output_type, get_named_type, - SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, is_object_type, - is_interface_type, get_nullable_type, is_list_type, is_input_object_type, - is_enum_type) + GraphQLArgument, + GraphQLCompositeType, + GraphQLDirective, + GraphQLEnumValue, + GraphQLField, + GraphQLInputType, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLOutputType, + GraphQLSchema, + GraphQLType, + is_composite_type, + is_input_type, + is_output_type, + get_named_type, + SchemaMetaFieldDef, + TypeMetaFieldDef, + TypeNameMetaFieldDef, + is_object_type, + is_interface_type, + get_nullable_type, + is_list_type, + is_input_object_type, + is_enum_type, +) from ..utilities import type_from_ast -__all__ = ['TypeInfo'] +__all__ = ["TypeInfo"] GetFieldDefType = Callable[ - [GraphQLSchema, GraphQLType, FieldNode], Optional[GraphQLField]] + [GraphQLSchema, GraphQLType, FieldNode], Optional[GraphQLField] +] class TypeInfo: @@ -31,9 +60,12 @@ class TypeInfo: `enter(node)` and `leave(node)`. """ - def __init__(self, schema: GraphQLSchema, - get_field_def_fn: GetFieldDefType=None, - initial_type: GraphQLType=None) -> None: + def __init__( + self, + schema: GraphQLSchema, + get_field_def_fn: GetFieldDefType = None, + initial_type: GraphQLType = None, + ) -> None: """Initialize the TypeInfo for the given GraphQL schema. The experimental optional second parameter is only needed in order to @@ -55,11 +87,9 @@ def __init__(self, schema: GraphQLSchema, self._get_field_def = get_field_def_fn or get_field_def if initial_type: if is_input_type(initial_type): - self._input_type_stack.append( - cast(GraphQLInputType, initial_type)) + self._input_type_stack.append(cast(GraphQLInputType, initial_type)) if is_composite_type(initial_type): - self._parent_type_stack.append( - cast(GraphQLCompositeType, initial_type)) + self._parent_type_stack.append(cast(GraphQLCompositeType, initial_type)) if is_output_type(initial_type): self._type_stack.append(cast(GraphQLOutputType, initial_type)) @@ -97,12 +127,12 @@ def get_enum_value(self): return self._enum_value def enter(self, node: Node): - method = getattr(self, 'enter_' + node.kind, None) + method = getattr(self, "enter_" + node.kind, None) if method: return method(node) def leave(self, node: Node): - method = getattr(self, 'leave_' + node.kind, None) + method = getattr(self, "leave_" + node.kind, None) if method: return method() @@ -110,7 +140,8 @@ def leave(self, node: Node): def enter_selection_set(self, node: SelectionSetNode): named_type = get_named_type(self.get_type()) self._parent_type_stack.append( - named_type if is_composite_type(named_type) else None) + named_type if is_composite_type(named_type) else None + ) def enter_field(self, node: FieldNode): parent_type = self.get_parent_type() @@ -120,8 +151,7 @@ def enter_field(self, node: FieldNode): else: field_def = field_type = None self._field_def_stack.append(field_def) - self._type_stack.append( - field_type if is_output_type(field_type) else None) + self._type_stack.append(field_type if is_output_type(field_type) else None) def enter_directive(self, node: DirectiveNode): self._directive = self._schema.get_directive(node.name.value) @@ -139,20 +169,24 @@ def enter_operation_definition(self, node: OperationDefinitionNode): def enter_inline_fragment(self, node: InlineFragmentNode): type_condition_ast = node.type_condition - output_type = type_from_ast( - self._schema, type_condition_ast - ) if type_condition_ast else get_named_type(self.get_type()) + output_type = ( + type_from_ast(self._schema, type_condition_ast) + if type_condition_ast + else get_named_type(self.get_type()) + ) self._type_stack.append( - cast(GraphQLOutputType, output_type) if is_output_type(output_type) - else None) + cast(GraphQLOutputType, output_type) + if is_output_type(output_type) + else None + ) enter_fragment_definition = enter_inline_fragment def enter_variable_definition(self, node: VariableDefinitionNode): input_type = type_from_ast(self._schema, node.type) self._input_type_stack.append( - cast(GraphQLInputType, input_type) if is_input_type(input_type) - else None) + cast(GraphQLInputType, input_type) if is_input_type(input_type) else None + ) def enter_argument(self, node: ArgumentNode): field_or_directive = self.get_directive() or self.get_field_def() @@ -162,10 +196,8 @@ def enter_argument(self, node: ArgumentNode): else: arg_def = arg_type = None self._argument = arg_def - self._default_value_stack.append( - arg_def.default_value if arg_def else INVALID) - self._input_type_stack.append( - arg_type if is_input_type(arg_type) else None) + self._default_value_stack.append(arg_def.default_value if arg_def else INVALID) + self._input_type_stack.append(arg_type if is_input_type(arg_type) else None) # noinspection PyUnusedLocal def enter_list_value(self, node: ListValueNode): @@ -173,8 +205,7 @@ def enter_list_value(self, node: ListValueNode): item_type = list_type.of_type if is_list_type(list_type) else list_type # List positions never have a default value. self._default_value_stack.append(INVALID) - self._input_type_stack.append( - item_type if is_input_type(item_type) else None) + self._input_type_stack.append(item_type if is_input_type(item_type) else None) def enter_object_field(self, node: ObjectFieldNode): object_type = get_named_type(self.get_input_type()) @@ -184,9 +215,11 @@ def enter_object_field(self, node: ObjectFieldNode): else: input_field = input_field_type = None self._default_value_stack.append( - input_field.default_value if input_field else INVALID) + input_field.default_value if input_field else INVALID + ) self._input_type_stack.append( - input_field_type if is_input_type(input_field_type) else None) + input_field_type if is_input_type(input_field_type) else None + ) def enter_enum_value(self, node: EnumValueNode): enum_type = get_named_type(self.get_input_type()) @@ -230,8 +263,9 @@ def leave_enum(self): self._enum_value = None -def get_field_def(schema: GraphQLSchema, parent_type: GraphQLType, - field_node: FieldNode) -> Optional[GraphQLField]: +def get_field_def( + schema: GraphQLSchema, parent_type: GraphQLType, field_node: FieldNode +) -> Optional[GraphQLField]: """Get field definition. Not exactly the same as the executor's definition of getFieldDef, in this @@ -239,14 +273,13 @@ def get_field_def(schema: GraphQLSchema, parent_type: GraphQLType, and need to handle Interface and Union types. """ name = field_node.name.value - if name == '__schema' and schema.query_type is parent_type: + if name == "__schema" and schema.query_type is parent_type: return SchemaMetaFieldDef - if name == '__type' and schema.query_type is parent_type: + if name == "__type" and schema.query_type is parent_type: return TypeMetaFieldDef - if name == '__typename' and is_composite_type(parent_type): + if name == "__typename" and is_composite_type(parent_type): return TypeNameMetaFieldDef if is_object_type(parent_type) or is_interface_type(parent_type): - parent_type = cast( - Union[GraphQLObjectType, GraphQLInterfaceType], parent_type) + parent_type = cast(Union[GraphQLObjectType, GraphQLInterfaceType], parent_type) return parent_type.fields.get(name) return None diff --git a/graphql/utilities/value_from_ast.py b/graphql/utilities/value_from_ast.py index df74b824..bf76f671 100644 --- a/graphql/utilities/value_from_ast.py +++ b/graphql/utilities/value_from_ast.py @@ -2,20 +2,36 @@ from ..error import INVALID from ..language import ( - EnumValueNode, ListValueNode, NullValueNode, - ObjectValueNode, ValueNode, VariableNode) + EnumValueNode, + ListValueNode, + NullValueNode, + ObjectValueNode, + ValueNode, + VariableNode, +) from ..pyutils import is_invalid from ..type import ( - GraphQLEnumType, GraphQLInputObjectType, GraphQLInputType, GraphQLList, - GraphQLNonNull, GraphQLScalarType, is_enum_type, is_input_object_type, - is_list_type, is_non_null_type, is_scalar_type) - -__all__ = ['value_from_ast'] + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInputType, + GraphQLList, + GraphQLNonNull, + GraphQLScalarType, + is_enum_type, + is_input_object_type, + is_list_type, + is_non_null_type, + is_scalar_type, +) + +__all__ = ["value_from_ast"] def value_from_ast( - value_node: Optional[ValueNode], type_: GraphQLInputType, - variables: Dict[str, Any]=None) -> Any: + value_node: Optional[ValueNode], + type_: GraphQLInputType, + variables: Dict[str, Any] = None, +) -> Any: """Produce a Python value given a GraphQL Value AST. A GraphQL type must be provided, which will be used to interpret different @@ -78,8 +94,7 @@ def value_from_ast( return INVALID append_value(None) else: - item_value = value_from_ast( - item_node, item_type, variables) + item_value = value_from_ast(item_node, item_type, variables) if is_invalid(item_value): return INVALID append_value(item_value) @@ -98,15 +113,13 @@ def value_from_ast( field_nodes = {field.name.value: field for field in value_node.fields} for field_name, field in fields.items(): field_node = field_nodes.get(field_name) - if not field_node or is_missing_variable( - field_node.value, variables): + if not field_node or is_missing_variable(field_node.value, variables): if field.default_value is not INVALID: coerced_obj[field_name] = field.default_value elif is_non_null_type(field.type): return INVALID continue - field_value = value_from_ast( - field_node.value, field.type, variables) + field_value = value_from_ast(field_node.value, field.type, variables) if is_invalid(field_value): return INVALID coerced_obj[field_name] = field_value @@ -139,8 +152,9 @@ def value_from_ast( def is_missing_variable( - value_node: ValueNode, variables: Dict[str, Any]=None) -> bool: + value_node: ValueNode, variables: Dict[str, Any] = None +) -> bool: """Check if value_node is a variable not defined in the variables dict.""" return isinstance(value_node, VariableNode) and ( - not variables or - is_invalid(variables.get(value_node.name.value, INVALID))) + not variables or is_invalid(variables.get(value_node.name.value, INVALID)) + ) diff --git a/graphql/utilities/value_from_ast_untyped.py b/graphql/utilities/value_from_ast_untyped.py index e7cfd911..8049671c 100644 --- a/graphql/utilities/value_from_ast_untyped.py +++ b/graphql/utilities/value_from_ast_untyped.py @@ -4,11 +4,12 @@ from ..language import ValueNode from ..pyutils import is_invalid -__all__ = ['value_from_ast_untyped'] +__all__ = ["value_from_ast_untyped"] def value_from_ast_untyped( - value_node: ValueNode, variables: Dict[str, Any]=None) -> Any: + value_node: ValueNode, variables: Dict[str, Any] = None +) -> Any: """Produce a Python value given a GraphQL Value AST. Unlike `value_from_ast()`, no type is provided. The resulting Python @@ -27,7 +28,7 @@ def value_from_ast_untyped( func = _value_from_kind_functions.get(value_node.kind) if func: return func(value_node, variables) - raise TypeError(f'Unexpected value kind: {value_node.kind}') + raise TypeError(f"Unexpected value kind: {value_node.kind}") def value_from_null(_value_node, _variables): @@ -53,13 +54,14 @@ def value_from_string(value_node, _variables): def value_from_list(value_node, variables): - return [value_from_ast_untyped(node, variables) - for node in value_node.values] + return [value_from_ast_untyped(node, variables) for node in value_node.values] def value_from_object(value_node, variables): - return {field.name.value: value_from_ast_untyped(field.value, variables) - for field in value_node.fields} + return { + field.name.value: value_from_ast_untyped(field.value, variables) + for field in value_node.fields + } def value_from_variable(value_node, variables): @@ -73,12 +75,13 @@ def value_from_variable(value_node, variables): _value_from_kind_functions = { - 'null_value': value_from_null, - 'int_value': value_from_int, - 'float_value': value_from_float, - 'string_value': value_from_string, - 'enum_value': value_from_string, - 'boolean_value': value_from_string, - 'list_value': value_from_list, - 'object_value': value_from_object, - 'variable': value_from_variable} + "null_value": value_from_null, + "int_value": value_from_int, + "float_value": value_from_float, + "string_value": value_from_string, + "enum_value": value_from_string, + "boolean_value": value_from_string, + "list_value": value_from_list, + "object_value": value_from_object, + "variable": value_from_variable, +} diff --git a/graphql/validation/__init__.py b/graphql/validation/__init__.py index a5616143..d6acbd4a 100644 --- a/graphql/validation/__init__.py +++ b/graphql/validation/__init__.py @@ -49,8 +49,7 @@ from .rules.no_unused_variables import NoUnusedVariablesRule # Spec Section: "Field Selection Merging" -from .rules.overlapping_fields_can_be_merged import ( - OverlappingFieldsCanBeMergedRule) +from .rules.overlapping_fields_can_be_merged import OverlappingFieldsCanBeMergedRule # Spec Section: "Fragment spread is possible" from .rules.possible_fragment_spreads import PossibleFragmentSpreadsRule @@ -68,8 +67,7 @@ from .rules.unique_argument_names import UniqueArgumentNamesRule # Spec Section: "Directives Are Unique Per Location" -from .rules.unique_directives_per_location import ( - UniqueDirectivesPerLocationRule) +from .rules.unique_directives_per_location import UniqueDirectivesPerLocationRule # Spec Section: "Fragment Name Uniqueness" from .rules.unique_fragment_names import UniqueFragmentNamesRule @@ -93,19 +91,36 @@ from .rules.variables_in_allowed_position import VariablesInAllowedPositionRule __all__ = [ - 'validate', 'ValidationContext', - 'ValidationRule', 'ASTValidationRule', 'SDLValidationRule', - 'specified_rules', - 'ExecutableDefinitionsRule', 'FieldsOnCorrectTypeRule', - 'FragmentsOnCompositeTypesRule', 'KnownArgumentNamesRule', - 'KnownDirectivesRule', 'KnownFragmentNamesRule', 'KnownTypeNamesRule', - 'LoneAnonymousOperationRule', 'NoFragmentCyclesRule', - 'NoUndefinedVariablesRule', 'NoUnusedFragmentsRule', - 'NoUnusedVariablesRule', 'OverlappingFieldsCanBeMergedRule', - 'PossibleFragmentSpreadsRule', 'ProvidedRequiredArgumentsRule', - 'ScalarLeafsRule', 'SingleFieldSubscriptionsRule', - 'UniqueArgumentNamesRule', 'UniqueDirectivesPerLocationRule', - 'UniqueFragmentNamesRule', 'UniqueInputFieldNamesRule', - 'UniqueOperationNamesRule', 'UniqueVariableNamesRule', - 'ValuesOfCorrectTypeRule', 'VariablesAreInputTypesRule', - 'VariablesInAllowedPositionRule'] + "validate", + "ValidationContext", + "ValidationRule", + "ASTValidationRule", + "SDLValidationRule", + "specified_rules", + "ExecutableDefinitionsRule", + "FieldsOnCorrectTypeRule", + "FragmentsOnCompositeTypesRule", + "KnownArgumentNamesRule", + "KnownDirectivesRule", + "KnownFragmentNamesRule", + "KnownTypeNamesRule", + "LoneAnonymousOperationRule", + "NoFragmentCyclesRule", + "NoUndefinedVariablesRule", + "NoUnusedFragmentsRule", + "NoUnusedVariablesRule", + "OverlappingFieldsCanBeMergedRule", + "PossibleFragmentSpreadsRule", + "ProvidedRequiredArgumentsRule", + "ScalarLeafsRule", + "SingleFieldSubscriptionsRule", + "UniqueArgumentNamesRule", + "UniqueDirectivesPerLocationRule", + "UniqueFragmentNamesRule", + "UniqueInputFieldNamesRule", + "UniqueOperationNamesRule", + "UniqueVariableNamesRule", + "ValuesOfCorrectTypeRule", + "VariablesAreInputTypesRule", + "VariablesInAllowedPositionRule", +] diff --git a/graphql/validation/rules/__init__.py b/graphql/validation/rules/__init__.py index 26efe0a9..8b78c381 100644 --- a/graphql/validation/rules/__init__.py +++ b/graphql/validation/rules/__init__.py @@ -5,10 +5,12 @@ from ...error import GraphQLError from ...language.visitor import Visitor from ..validation_context import ( - ASTValidationContext, SDLValidationContext, ValidationContext) + ASTValidationContext, + SDLValidationContext, + ValidationContext, +) -__all__ = [ - 'ASTValidationRule', 'SDLValidationRule', 'ValidationRule', 'RuleType'] +__all__ = ["ASTValidationRule", "SDLValidationRule", "ValidationRule", "RuleType"] class ASTValidationRule(Visitor): diff --git a/graphql/validation/rules/executable_definitions.py b/graphql/validation/rules/executable_definitions.py index 80840bf7..218485e1 100644 --- a/graphql/validation/rules/executable_definitions.py +++ b/graphql/validation/rules/executable_definitions.py @@ -2,15 +2,20 @@ from ...error import GraphQLError from ...language import ( - DirectiveDefinitionNode, DocumentNode, ExecutableDefinitionNode, - SchemaDefinitionNode, SchemaExtensionNode, TypeDefinitionNode) + DirectiveDefinitionNode, + DocumentNode, + ExecutableDefinitionNode, + SchemaDefinitionNode, + SchemaExtensionNode, + TypeDefinitionNode, +) from . import ASTValidationRule -__all__ = ['ExecutableDefinitionsRule', 'non_executable_definitions_message'] +__all__ = ["ExecutableDefinitionsRule", "non_executable_definitions_message"] def non_executable_definitions_message(def_name: str) -> str: - return f'The {def_name} definition is not executable.' + return f"The {def_name} definition is not executable." class ExecutableDefinitionsRule(ASTValidationRule): @@ -23,11 +28,19 @@ class ExecutableDefinitionsRule(ASTValidationRule): def enter_document(self, node: DocumentNode, *_args): for definition in node.definitions: if not isinstance(definition, ExecutableDefinitionNode): - self.report_error(GraphQLError( - non_executable_definitions_message( - 'schema' if isinstance(definition, ( - SchemaDefinitionNode, SchemaExtensionNode)) - else cast(Union[ - DirectiveDefinitionNode, TypeDefinitionNode], - definition).name.value), [definition])) + self.report_error( + GraphQLError( + non_executable_definitions_message( + "schema" + if isinstance( + definition, (SchemaDefinitionNode, SchemaExtensionNode) + ) + else cast( + Union[DirectiveDefinitionNode, TypeDefinitionNode], + definition, + ).name.value + ), + [definition], + ) + ) return self.SKIP diff --git a/graphql/validation/rules/fields_on_correct_type.py b/graphql/validation/rules/fields_on_correct_type.py index 13e50fcb..8514c474 100644 --- a/graphql/validation/rules/fields_on_correct_type.py +++ b/graphql/validation/rules/fields_on_correct_type.py @@ -2,27 +2,34 @@ from typing import Dict, List, cast from ...type import ( - GraphQLAbstractType, GraphQLSchema, GraphQLOutputType, - is_abstract_type, is_interface_type, is_object_type) + GraphQLAbstractType, + GraphQLSchema, + GraphQLOutputType, + is_abstract_type, + is_interface_type, + is_object_type, +) from ...error import GraphQLError from ...language import FieldNode from ...pyutils import quoted_or_list, suggestion_list from . import ValidationRule -__all__ = ['FieldsOnCorrectTypeRule', 'undefined_field_message'] +__all__ = ["FieldsOnCorrectTypeRule", "undefined_field_message"] def undefined_field_message( - field_name: str, type_: str, - suggested_type_names: List[str], - suggested_field_names: List[str]) -> str: + field_name: str, + type_: str, + suggested_type_names: List[str], + suggested_field_names: List[str], +) -> str: message = f"Cannot query field '{field_name}' on type '{type_}'." if suggested_type_names: suggestions = quoted_or_list(suggested_type_names) - message += f' Did you mean to use an inline fragment on {suggestions}?' + message += f" Did you mean to use an inline fragment on {suggestions}?" elif suggested_field_names: suggestions = quoted_or_list(suggested_field_names) - message += f' Did you mean {suggestions}?' + message += f" Did you mean {suggestions}?" return message @@ -44,22 +51,26 @@ def enter_field(self, node: FieldNode, *_args): schema = self.context.schema field_name = node.name.value # First determine if there are any suggested types to condition on. - suggested_type_names = get_suggested_type_names( - schema, type_, field_name) + suggested_type_names = get_suggested_type_names(schema, type_, field_name) # If there are no suggested types, then perhaps this was a typo? suggested_field_names = ( - [] if suggested_type_names - else get_suggested_field_names(type_, field_name)) + [] if suggested_type_names else get_suggested_field_names(type_, field_name) + ) # Report an error, including helpful suggestions. - self.report_error(GraphQLError(undefined_field_message( - field_name, type_.name, - suggested_type_names, suggested_field_names), [node])) + self.report_error( + GraphQLError( + undefined_field_message( + field_name, type_.name, suggested_type_names, suggested_field_names + ), + [node], + ) + ) def get_suggested_type_names( - schema: GraphQLSchema, type_: GraphQLOutputType, - field_name: str) -> List[str]: + schema: GraphQLSchema, type_: GraphQLOutputType, field_name: str +) -> List[str]: """ Get a list of suggested type names. @@ -85,7 +96,8 @@ def get_suggested_type_names( # Suggest interface types based on how common they are. suggested_interface_types = sorted( - interface_usage_count, key=lambda k: -interface_usage_count[k]) + interface_usage_count, key=lambda k: -interface_usage_count[k] + ) # Suggest both interface and object types. return suggested_interface_types + suggested_object_types @@ -94,8 +106,7 @@ def get_suggested_type_names( return [] -def get_suggested_field_names( - type_: GraphQLOutputType, field_name: str) -> List[str]: +def get_suggested_field_names(type_: GraphQLOutputType, field_name: str) -> List[str]: """Get a list of suggested field names. For the field name provided, determine if there are any similar field names diff --git a/graphql/validation/rules/fragments_on_composite_types.py b/graphql/validation/rules/fragments_on_composite_types.py index 788cd02b..93f8fbe9 100644 --- a/graphql/validation/rules/fragments_on_composite_types.py +++ b/graphql/validation/rules/fragments_on_composite_types.py @@ -5,20 +5,20 @@ from . import ValidationRule __all__ = [ - 'FragmentsOnCompositeTypesRule', - 'inline_fragment_on_non_composite_error_message', - 'fragment_on_non_composite_error_message'] + "FragmentsOnCompositeTypesRule", + "inline_fragment_on_non_composite_error_message", + "fragment_on_non_composite_error_message", +] -def inline_fragment_on_non_composite_error_message( - type_: str) -> str: +def inline_fragment_on_non_composite_error_message(type_: str) -> str: return f"Fragment cannot condition on non composite type '{type_}'." -def fragment_on_non_composite_error_message( - frag_name: str, type_: str) -> str: - return (f"Fragment '{frag_name}'" - f" cannot condition on non composite type '{type_}'.") +def fragment_on_non_composite_error_message(frag_name: str, type_: str) -> str: + return ( + f"Fragment '{frag_name}'" f" cannot condition on non composite type '{type_}'." + ) class FragmentsOnCompositeTypesRule(ValidationRule): @@ -34,15 +34,24 @@ def enter_inline_fragment(self, node: InlineFragmentNode, *_args): if type_condition: type_ = type_from_ast(self.context.schema, type_condition) if type_ and not is_composite_type(type_): - self.report_error(GraphQLError( - inline_fragment_on_non_composite_error_message( - print_ast(type_condition)), [type_condition])) + self.report_error( + GraphQLError( + inline_fragment_on_non_composite_error_message( + print_ast(type_condition) + ), + [type_condition], + ) + ) def enter_fragment_definition(self, node: FragmentDefinitionNode, *_args): type_condition = node.type_condition type_ = type_from_ast(self.context.schema, type_condition) if type_ and not is_composite_type(type_): - self.report_error(GraphQLError( - fragment_on_non_composite_error_message( - node.name.value, print_ast(type_condition)), - [type_condition])) + self.report_error( + GraphQLError( + fragment_on_non_composite_error_message( + node.name.value, print_ast(type_condition) + ), + [type_condition], + ) + ) diff --git a/graphql/validation/rules/known_argument_names.py b/graphql/validation/rules/known_argument_names.py index 580a07a3..f20374ea 100644 --- a/graphql/validation/rules/known_argument_names.py +++ b/graphql/validation/rules/known_argument_names.py @@ -1,34 +1,37 @@ from typing import cast, Dict, List, Union from ...error import GraphQLError -from ...language import ( - ArgumentNode, DirectiveDefinitionNode, DirectiveNode, SKIP) +from ...language import ArgumentNode, DirectiveDefinitionNode, DirectiveNode, SKIP from ...pyutils import quoted_or_list, suggestion_list from ...type import specified_directives from . import ASTValidationRule, SDLValidationContext, ValidationContext __all__ = [ - 'KnownArgumentNamesRule', 'KnownArgumentNamesOnDirectivesRule', - 'unknown_arg_message', 'unknown_directive_arg_message'] + "KnownArgumentNamesRule", + "KnownArgumentNamesOnDirectivesRule", + "unknown_arg_message", + "unknown_directive_arg_message", +] def unknown_arg_message( - arg_name: str, field_name: str, type_name: str, - suggested_args: List[str]) -> str: - message = (f"Unknown argument '{arg_name}' on field '{field_name}'" - f" of type '{type_name}'.") + arg_name: str, field_name: str, type_name: str, suggested_args: List[str] +) -> str: + message = ( + f"Unknown argument '{arg_name}' on field '{field_name}'" + f" of type '{type_name}'." + ) if suggested_args: - message += f' Did you mean {quoted_or_list(suggested_args)}?' + message += f" Did you mean {quoted_or_list(suggested_args)}?" return message def unknown_directive_arg_message( - arg_name: str, directive_name: str, - suggested_args: List[str]) -> str: - message = (f"Unknown argument '{arg_name}'" - f" on directive '@{directive_name}'.") + arg_name: str, directive_name: str, suggested_args: List[str] +) -> str: + message = f"Unknown argument '{arg_name}'" f" on directive '@{directive_name}'." if suggested_args: - message += f' Did you mean {quoted_or_list(suggested_args)}?' + message += f" Did you mean {quoted_or_list(suggested_args)}?" return message @@ -40,23 +43,21 @@ class KnownArgumentNamesOnDirectivesRule(ASTValidationRule): context: Union[ValidationContext, SDLValidationContext] - def __init__(self, context: Union[ - ValidationContext, SDLValidationContext]) -> None: + def __init__(self, context: Union[ValidationContext, SDLValidationContext]) -> None: super().__init__(context) directive_args: Dict[str, List[str]] = {} schema = context.schema - defined_directives = ( - schema.directives if schema else specified_directives) + defined_directives = schema.directives if schema else specified_directives for directive in cast(List, defined_directives): directive_args[directive.name] = list(directive.args) ast_definitions = context.document.definitions for def_ in ast_definitions: if isinstance(def_, DirectiveDefinitionNode): - directive_args[def_.name.value] = [ - arg.name.value for arg in def_.arguments - ] if def_.arguments else [] + directive_args[def_.name.value] = ( + [arg.name.value for arg in def_.arguments] if def_.arguments else [] + ) self.directive_args = directive_args @@ -68,9 +69,14 @@ def enter_directive(self, directive_node: DirectiveNode, *_args): arg_name = arg_node.name.value if arg_name not in known_args: suggestions = suggestion_list(arg_name, known_args) - self.report_error(GraphQLError( - unknown_directive_arg_message( - arg_name, directive_name, suggestions), arg_node)) + self.report_error( + GraphQLError( + unknown_directive_arg_message( + arg_name, directive_name, suggestions + ), + arg_node, + ) + ) return SKIP @@ -86,8 +92,7 @@ class KnownArgumentNamesRule(KnownArgumentNamesOnDirectivesRule): def __init__(self, context: ValidationContext) -> None: super().__init__(context) - def enter_argument( - self, arg_node: ArgumentNode, *args): + def enter_argument(self, arg_node: ArgumentNode, *args): context = self.context arg_def = context.get_argument() field_def = context.get_field_def() @@ -96,7 +101,14 @@ def enter_argument( arg_name = arg_node.name.value field_name = args[3][-1].name.value known_args_names = list(field_def.args) - context.report_error(GraphQLError( - unknown_arg_message( - arg_name, field_name, parent_type.name, - suggestion_list(arg_name, known_args_names)), arg_node)) + context.report_error( + GraphQLError( + unknown_arg_message( + arg_name, + field_name, + parent_type.name, + suggestion_list(arg_name, known_args_names), + ), + arg_node, + ) + ) diff --git a/graphql/validation/rules/known_directives.py b/graphql/validation/rules/known_directives.py index bc2cd727..0b2ffc39 100644 --- a/graphql/validation/rules/known_directives.py +++ b/graphql/validation/rules/known_directives.py @@ -2,14 +2,20 @@ from ...error import GraphQLError from ...language import ( - DirectiveLocation, DirectiveDefinitionNode, DirectiveNode, Node, - OperationDefinitionNode) + DirectiveLocation, + DirectiveDefinitionNode, + DirectiveNode, + Node, + OperationDefinitionNode, +) from ...type import specified_directives from . import ASTValidationRule, SDLValidationContext, ValidationContext __all__ = [ - 'KnownDirectivesRule', - 'unknown_directive_message', 'misplaced_directive_message'] + "KnownDirectivesRule", + "unknown_directive_message", + "misplaced_directive_message", +] def unknown_directive_message(directive_name: str) -> str: @@ -29,79 +35,88 @@ class KnownDirectivesRule(ASTValidationRule): context: Union[ValidationContext, SDLValidationContext] - def __init__(self, context: Union[ - ValidationContext, SDLValidationContext]) -> None: + def __init__(self, context: Union[ValidationContext, SDLValidationContext]) -> None: super().__init__(context) locations_map: Dict[str, List[DirectiveLocation]] = {} schema = context.schema defined_directives = ( - schema.directives if schema else cast(List, specified_directives)) + schema.directives if schema else cast(List, specified_directives) + ) for directive in defined_directives: locations_map[directive.name] = directive.locations ast_definitions = context.document.definitions for def_ in ast_definitions: if isinstance(def_, DirectiveDefinitionNode): locations_map[def_.name.value] = [ - DirectiveLocation[name.value] for name in def_.locations] + DirectiveLocation[name.value] for name in def_.locations + ] self.locations_map = locations_map - def enter_directive( - self, node: DirectiveNode, _key, _parent, _path, ancestors): + def enter_directive(self, node: DirectiveNode, _key, _parent, _path, ancestors): name = node.name.value locations = self.locations_map.get(name) if locations: - candidate_location = get_directive_location_for_ast_path( - ancestors) + candidate_location = get_directive_location_for_ast_path(ancestors) if candidate_location and candidate_location not in locations: - self.report_error(GraphQLError( - misplaced_directive_message( - node.name.value, candidate_location.value), [node])) + self.report_error( + GraphQLError( + misplaced_directive_message( + node.name.value, candidate_location.value + ), + [node], + ) + ) else: - self.report_error(GraphQLError( - unknown_directive_message(node.name.value), [node])) + self.report_error( + GraphQLError(unknown_directive_message(node.name.value), [node]) + ) _operation_location = { - 'query': DirectiveLocation.QUERY, - 'mutation': DirectiveLocation.MUTATION, - 'subscription': DirectiveLocation.SUBSCRIPTION} + "query": DirectiveLocation.QUERY, + "mutation": DirectiveLocation.MUTATION, + "subscription": DirectiveLocation.SUBSCRIPTION, +} _directive_location = { - 'field': DirectiveLocation.FIELD, - 'fragment_spread': DirectiveLocation.FRAGMENT_SPREAD, - 'inline_fragment': DirectiveLocation.INLINE_FRAGMENT, - 'fragment_definition': DirectiveLocation.FRAGMENT_DEFINITION, - 'variable_definition': DirectiveLocation.VARIABLE_DEFINITION, - 'schema_definition': DirectiveLocation.SCHEMA, - 'schema_extension': DirectiveLocation.SCHEMA, - 'scalar_type_definition': DirectiveLocation.SCALAR, - 'scalar_type_extension': DirectiveLocation.SCALAR, - 'object_type_definition': DirectiveLocation.OBJECT, - 'object_type_extension': DirectiveLocation.OBJECT, - 'field_definition': DirectiveLocation.FIELD_DEFINITION, - 'interface_type_definition': DirectiveLocation.INTERFACE, - 'interface_type_extension': DirectiveLocation.INTERFACE, - 'union_type_definition': DirectiveLocation.UNION, - 'union_type_extension': DirectiveLocation.UNION, - 'enum_type_definition': DirectiveLocation.ENUM, - 'enum_type_extension': DirectiveLocation.ENUM, - 'enum_value_definition': DirectiveLocation.ENUM_VALUE, - 'input_object_type_definition': DirectiveLocation.INPUT_OBJECT, - 'input_object_type_extension': DirectiveLocation.INPUT_OBJECT} + "field": DirectiveLocation.FIELD, + "fragment_spread": DirectiveLocation.FRAGMENT_SPREAD, + "inline_fragment": DirectiveLocation.INLINE_FRAGMENT, + "fragment_definition": DirectiveLocation.FRAGMENT_DEFINITION, + "variable_definition": DirectiveLocation.VARIABLE_DEFINITION, + "schema_definition": DirectiveLocation.SCHEMA, + "schema_extension": DirectiveLocation.SCHEMA, + "scalar_type_definition": DirectiveLocation.SCALAR, + "scalar_type_extension": DirectiveLocation.SCALAR, + "object_type_definition": DirectiveLocation.OBJECT, + "object_type_extension": DirectiveLocation.OBJECT, + "field_definition": DirectiveLocation.FIELD_DEFINITION, + "interface_type_definition": DirectiveLocation.INTERFACE, + "interface_type_extension": DirectiveLocation.INTERFACE, + "union_type_definition": DirectiveLocation.UNION, + "union_type_extension": DirectiveLocation.UNION, + "enum_type_definition": DirectiveLocation.ENUM, + "enum_type_extension": DirectiveLocation.ENUM, + "enum_value_definition": DirectiveLocation.ENUM_VALUE, + "input_object_type_definition": DirectiveLocation.INPUT_OBJECT, + "input_object_type_extension": DirectiveLocation.INPUT_OBJECT, +} def get_directive_location_for_ast_path(ancestors): applied_to = ancestors[-1] if isinstance(applied_to, Node): kind = applied_to.kind - if kind == 'operation_definition': + if kind == "operation_definition": applied_to = cast(OperationDefinitionNode, applied_to) return _operation_location.get(applied_to.operation.value) - elif kind == 'input_value_definition': + elif kind == "input_value_definition": parent_node = ancestors[-3] - return (DirectiveLocation.INPUT_FIELD_DEFINITION - if parent_node.kind == 'input_object_type_definition' - else DirectiveLocation.ARGUMENT_DEFINITION) + return ( + DirectiveLocation.INPUT_FIELD_DEFINITION + if parent_node.kind == "input_object_type_definition" + else DirectiveLocation.ARGUMENT_DEFINITION + ) else: return _directive_location.get(kind) diff --git a/graphql/validation/rules/known_fragment_names.py b/graphql/validation/rules/known_fragment_names.py index 55bc40c9..d1b2c725 100644 --- a/graphql/validation/rules/known_fragment_names.py +++ b/graphql/validation/rules/known_fragment_names.py @@ -2,7 +2,7 @@ from ...language import FragmentSpreadNode from . import ValidationRule -__all__ = ['KnownFragmentNamesRule', 'unknown_fragment_message'] +__all__ = ["KnownFragmentNamesRule", "unknown_fragment_message"] def unknown_fragment_message(fragment_name: str) -> str: @@ -20,5 +20,6 @@ def enter_fragment_spread(self, node: FragmentSpreadNode, *_args): fragment_name = node.name.value fragment = self.context.get_fragment(fragment_name) if not fragment: - self.report_error(GraphQLError( - unknown_fragment_message(fragment_name), [node.name])) + self.report_error( + GraphQLError(unknown_fragment_message(fragment_name), [node.name]) + ) diff --git a/graphql/validation/rules/known_type_names.py b/graphql/validation/rules/known_type_names.py index c925b05a..a0a11aa7 100644 --- a/graphql/validation/rules/known_type_names.py +++ b/graphql/validation/rules/known_type_names.py @@ -5,13 +5,13 @@ from ...pyutils import suggestion_list from . import ValidationRule -__all__ = ['KnownTypeNamesRule', 'unknown_type_message'] +__all__ = ["KnownTypeNamesRule", "unknown_type_message"] def unknown_type_message(type_name: str, suggested_types: List[str]) -> str: message = f"Unknown type '{type_name}'." if suggested_types: - message += ' Perhaps you meant {quoted_or_list(suggested_types)}?' + message += " Perhaps you meant {quoted_or_list(suggested_types)}?" return message @@ -38,7 +38,11 @@ def enter_named_type(self, node: NamedTypeNode, *_args): schema = self.context.schema type_name = node.name.value if not schema.get_type(type_name): - self.report_error(GraphQLError( - unknown_type_message( - type_name, suggestion_list( - type_name, list(schema.type_map))), [node])) + self.report_error( + GraphQLError( + unknown_type_message( + type_name, suggestion_list(type_name, list(schema.type_map)) + ), + [node], + ) + ) diff --git a/graphql/validation/rules/lone_anonymous_operation.py b/graphql/validation/rules/lone_anonymous_operation.py index 8c198c15..401916a4 100644 --- a/graphql/validation/rules/lone_anonymous_operation.py +++ b/graphql/validation/rules/lone_anonymous_operation.py @@ -2,12 +2,11 @@ from ...language import DocumentNode, OperationDefinitionNode from . import ASTValidationContext, ASTValidationRule -__all__ = [ - 'LoneAnonymousOperationRule', 'anonymous_operation_not_alone_message'] +__all__ = ["LoneAnonymousOperationRule", "anonymous_operation_not_alone_message"] def anonymous_operation_not_alone_message() -> str: - return 'This anonymous operation must be the only defined operation.' + return "This anonymous operation must be the only defined operation." class LoneAnonymousOperationRule(ASTValidationRule): @@ -24,11 +23,13 @@ def __init__(self, context: ASTValidationContext) -> None: def enter_document(self, node: DocumentNode, *_args): self.operation_count = sum( - 1 for definition in node.definitions - if isinstance(definition, OperationDefinitionNode)) + 1 + for definition in node.definitions + if isinstance(definition, OperationDefinitionNode) + ) - def enter_operation_definition( - self, node: OperationDefinitionNode, *_args): + def enter_operation_definition(self, node: OperationDefinitionNode, *_args): if not node.name and self.operation_count > 1: - self.report_error(GraphQLError( - anonymous_operation_not_alone_message(), [node])) + self.report_error( + GraphQLError(anonymous_operation_not_alone_message(), [node]) + ) diff --git a/graphql/validation/rules/lone_schema_definition.py b/graphql/validation/rules/lone_schema_definition.py index 92f3b452..05ca4567 100644 --- a/graphql/validation/rules/lone_schema_definition.py +++ b/graphql/validation/rules/lone_schema_definition.py @@ -3,17 +3,18 @@ from . import SDLValidationRule, SDLValidationContext __all__ = [ - 'LoneSchemaDefinitionRule', - 'schema_definition_not_alone_message', - 'cannot_define_schema_within_extension_message'] + "LoneSchemaDefinitionRule", + "schema_definition_not_alone_message", + "cannot_define_schema_within_extension_message", +] def schema_definition_not_alone_message(): - return 'Must provide only one schema definition.' + return "Must provide only one schema definition." def cannot_define_schema_within_extension_message(): - return 'Cannot define a new schema within a schema extension.' + return "Cannot define a new schema within a schema extension." class LoneSchemaDefinitionRule(SDLValidationRule): @@ -26,16 +27,21 @@ def __init__(self, context: SDLValidationContext) -> None: super().__init__(context) old_schema = context.schema self.already_defined = old_schema and ( - old_schema.ast_node or old_schema.query_type or - old_schema.mutation_type or old_schema.subscription_type) + old_schema.ast_node + or old_schema.query_type + or old_schema.mutation_type + or old_schema.subscription_type + ) self.schema_definitions_count = 0 def enter_schema_definition(self, node: SchemaDefinitionNode, *_args): if self.already_defined: - self.report_error(GraphQLError( - cannot_define_schema_within_extension_message(), node)) + self.report_error( + GraphQLError(cannot_define_schema_within_extension_message(), node) + ) else: if self.schema_definitions_count: - self.report_error(GraphQLError( - schema_definition_not_alone_message(), node)) + self.report_error( + GraphQLError(schema_definition_not_alone_message(), node) + ) self.schema_definitions_count += 1 diff --git a/graphql/validation/rules/no_fragment_cycles.py b/graphql/validation/rules/no_fragment_cycles.py index 08b2bf29..448dc0f8 100644 --- a/graphql/validation/rules/no_fragment_cycles.py +++ b/graphql/validation/rules/no_fragment_cycles.py @@ -4,11 +4,11 @@ from ...language import FragmentDefinitionNode, FragmentSpreadNode from . import ValidationContext, ValidationRule -__all__ = ['NoFragmentCyclesRule', 'cycle_error_message'] +__all__ = ["NoFragmentCyclesRule", "cycle_error_message"] def cycle_error_message(frag_name: str, spread_names: List[str]) -> str: - via = f" via {', '.join(spread_names)}" if spread_names else '' + via = f" via {', '.join(spread_names)}" if spread_names else "" return f"Cannot spread fragment '{frag_name}' within itself{via}." @@ -43,8 +43,7 @@ def detect_cycle_recursive(self, fragment: FragmentDefinitionNode): visited_frags = self.visited_frags visited_frags.add(fragment_name) - spread_nodes = self.context.get_fragment_spreads( - fragment.selection_set) + spread_nodes = self.context.get_fragment_spreads(fragment.selection_set) if not spread_nodes: return @@ -65,9 +64,11 @@ def detect_cycle_recursive(self, fragment: FragmentDefinitionNode): else: cycle_path = spread_path[cycle_index:] fragment_names = [s.name.value for s in cycle_path[:-1]] - self.report_error(GraphQLError( - cycle_error_message(spread_name, fragment_names), - cycle_path)) + self.report_error( + GraphQLError( + cycle_error_message(spread_name, fragment_names), cycle_path + ) + ) spread_path.pop() del spread_path_index[fragment_name] diff --git a/graphql/validation/rules/no_undefined_variables.py b/graphql/validation/rules/no_undefined_variables.py index 0af2a554..e2ed1a8f 100644 --- a/graphql/validation/rules/no_undefined_variables.py +++ b/graphql/validation/rules/no_undefined_variables.py @@ -4,12 +4,15 @@ from ...language import OperationDefinitionNode, VariableDefinitionNode from . import ValidationContext, ValidationRule -__all__ = ['NoUndefinedVariablesRule', 'undefined_var_message'] +__all__ = ["NoUndefinedVariablesRule", "undefined_var_message"] -def undefined_var_message(var_name: str, op_name: str=None) -> str: - return (f"Variable '${var_name}' is not defined by operation '{op_name}'." - if op_name else f"Variable '${var_name}' is not defined.") +def undefined_var_message(var_name: str, op_name: str = None) -> str: + return ( + f"Variable '${var_name}' is not defined by operation '{op_name}'." + if op_name + else f"Variable '${var_name}' is not defined." + ) class NoUndefinedVariablesRule(ValidationRule): @@ -26,8 +29,7 @@ def __init__(self, context: ValidationContext) -> None: def enter_operation_definition(self, *_args): self.defined_variable_names.clear() - def leave_operation_definition( - self, operation: OperationDefinitionNode, *_args): + def leave_operation_definition(self, operation: OperationDefinitionNode, *_args): usages = self.context.get_recursive_variable_usages(operation) defined_variables = self.defined_variable_names for usage in usages: @@ -35,8 +37,11 @@ def leave_operation_definition( var_name = node.name.value if var_name not in defined_variables: op_name = operation.name.value if operation.name else None - self.report_error(GraphQLError(undefined_var_message( - var_name, op_name), [node, operation])) + self.report_error( + GraphQLError( + undefined_var_message(var_name, op_name), [node, operation] + ) + ) def enter_variable_definition(self, node: VariableDefinitionNode, *_args): self.defined_variable_names.add(node.variable.name.value) diff --git a/graphql/validation/rules/no_unused_fragments.py b/graphql/validation/rules/no_unused_fragments.py index 9befd15b..08ef94ee 100644 --- a/graphql/validation/rules/no_unused_fragments.py +++ b/graphql/validation/rules/no_unused_fragments.py @@ -4,7 +4,7 @@ from ...language import FragmentDefinitionNode, OperationDefinitionNode from . import ValidationContext, ValidationRule -__all__ = ['NoUnusedFragmentsRule', 'unused_fragment_message'] +__all__ = ["NoUnusedFragmentsRule", "unused_fragment_message"] def unused_fragment_message(frag_name: str) -> str: @@ -24,8 +24,7 @@ def __init__(self, context: ValidationContext) -> None: self.operation_defs: List[OperationDefinitionNode] = [] self.fragment_defs: List[FragmentDefinitionNode] = [] - def enter_operation_definition( - self, node: OperationDefinitionNode, *_args): + def enter_operation_definition(self, node: OperationDefinitionNode, *_args): self.operation_defs.append(node) return False @@ -43,5 +42,6 @@ def leave_document(self, *_args): for fragment_def in self.fragment_defs: frag_name = fragment_def.name.value if frag_name not in fragment_names_used: - self.report_error(GraphQLError( - unused_fragment_message(frag_name), [fragment_def])) + self.report_error( + GraphQLError(unused_fragment_message(frag_name), [fragment_def]) + ) diff --git a/graphql/validation/rules/no_unused_variables.py b/graphql/validation/rules/no_unused_variables.py index 34895380..3193a9ba 100644 --- a/graphql/validation/rules/no_unused_variables.py +++ b/graphql/validation/rules/no_unused_variables.py @@ -4,12 +4,15 @@ from ...language import OperationDefinitionNode, VariableDefinitionNode from . import ValidationContext, ValidationRule -__all__ = ['NoUnusedVariablesRule', 'unused_variable_message'] +__all__ = ["NoUnusedVariablesRule", "unused_variable_message"] -def unused_variable_message(var_name: str, op_name: str=None) -> str: - return (f"Variable '${var_name}' is never used in operation '{op_name}'." - if op_name else f"Variable '${var_name}' is never used.") +def unused_variable_message(var_name: str, op_name: str = None) -> str: + return ( + f"Variable '${var_name}' is never used in operation '{op_name}'." + if op_name + else f"Variable '${var_name}' is never used." + ) class NoUnusedVariablesRule(ValidationRule): @@ -26,8 +29,7 @@ def __init__(self, context: ValidationContext) -> None: def enter_operation_definition(self, *_args): self.variable_defs.clear() - def leave_operation_definition( - self, operation: OperationDefinitionNode, *_args): + def leave_operation_definition(self, operation: OperationDefinitionNode, *_args): variable_name_used: Set[str] = set() usages = self.context.get_recursive_variable_usages(operation) op_name = operation.name.value if operation.name else None @@ -38,9 +40,11 @@ def leave_operation_definition( for variable_def in self.variable_defs: variable_name = variable_def.variable.name.value if variable_name not in variable_name_used: - self.report_error(GraphQLError(unused_variable_message( - variable_name, op_name), [variable_def])) + self.report_error( + GraphQLError( + unused_variable_message(variable_name, op_name), [variable_def] + ) + ) - def enter_variable_definition( - self, definition: VariableDefinitionNode, *_args): + def enter_variable_definition(self, definition: VariableDefinitionNode, *_args): self.variable_defs.append(definition) diff --git a/graphql/validation/rules/overlapping_fields_can_be_merged.py b/graphql/validation/rules/overlapping_fields_can_be_merged.py index 720dc04b..1c7b5e46 100644 --- a/graphql/validation/rules/overlapping_fields_can_be_merged.py +++ b/graphql/validation/rules/overlapping_fields_can_be_merged.py @@ -3,37 +3,55 @@ from ...error import GraphQLError from ...language import ( - ArgumentNode, FieldNode, FragmentDefinitionNode, FragmentSpreadNode, - InlineFragmentNode, SelectionSetNode, print_ast) + ArgumentNode, + FieldNode, + FragmentDefinitionNode, + FragmentSpreadNode, + InlineFragmentNode, + SelectionSetNode, + print_ast, +) from ...type import ( - GraphQLCompositeType, GraphQLField, GraphQLList, GraphQLNamedType, - GraphQLNonNull, GraphQLOutputType, - get_named_type, is_interface_type, is_leaf_type, - is_list_type, is_non_null_type, is_object_type) + GraphQLCompositeType, + GraphQLField, + GraphQLList, + GraphQLNamedType, + GraphQLNonNull, + GraphQLOutputType, + get_named_type, + is_interface_type, + is_leaf_type, + is_list_type, + is_non_null_type, + is_object_type, +) from ...utilities import type_from_ast from . import ValidationContext, ValidationRule MYPY = False __all__ = [ - 'OverlappingFieldsCanBeMergedRule', - 'fields_conflict_message', 'reason_message'] + "OverlappingFieldsCanBeMergedRule", + "fields_conflict_message", + "reason_message", +] -def fields_conflict_message( - response_name: str, reason: 'ConflictReasonMessage') -> str: +def fields_conflict_message(response_name: str, reason: "ConflictReasonMessage") -> str: return ( f"Fields '{response_name}' conflict because {reason_message(reason)}." - ' Use different aliases on the fields to fetch both if this was' - ' intentional.') + " Use different aliases on the fields to fetch both if this was" + " intentional." + ) -def reason_message(reason: 'ConflictReasonMessage') -> str: +def reason_message(reason: "ConflictReasonMessage") -> str: if isinstance(reason, list): - return ' and '.join( + return " and ".join( f"subfields '{response_name}' conflict" - f' because {reason_message(subreason)}' - for response_name, subreason in reason) + f" because {reason_message(subreason)}" + for response_name, subreason in reason + ) return reason @@ -65,16 +83,19 @@ def enter_selection_set(self, selection_set: SelectionSetNode, *_args): self.cached_fields_and_fragment_names, self.compared_fragment_pairs, self.context.get_parent_type(), - selection_set) + selection_set, + ) for (reason_name, reason), fields1, fields2 in conflicts: - self.report_error(GraphQLError( - fields_conflict_message(reason_name, reason), - fields1 + fields2)) + self.report_error( + GraphQLError( + fields_conflict_message(reason_name, reason), fields1 + fields2 + ) + ) -Conflict = Tuple['ConflictReason', List[FieldNode], List[FieldNode]] +Conflict = Tuple["ConflictReason", List[FieldNode], List[FieldNode]] # Field name and reason. -ConflictReason = Tuple[str, 'ConflictReasonMessage'] +ConflictReason = Tuple[str, "ConflictReasonMessage"] # Reason is a string, or a nested list of conflicts. if MYPY: # recursive types not fully supported yet (/python/mypy/issues/731) ConflictReasonMessage = Union[str, List] @@ -140,11 +161,12 @@ def enter_selection_set(self, selection_set: SelectionSetNode, *_args): def find_conflicts_within_selection_set( - context: ValidationContext, - cached_fields_and_fragment_names: Dict, - compared_fragment_pairs: 'PairSet', - parent_type: Optional[GraphQLNamedType], - selection_set: SelectionSetNode) -> List[Conflict]: + context: ValidationContext, + cached_fields_and_fragment_names: Dict, + compared_fragment_pairs: "PairSet", + parent_type: Optional[GraphQLNamedType], + selection_set: SelectionSetNode, +) -> List[Conflict]: """Find conflicts within selection set. Find all conflicts found "within" a selection set, including those found @@ -155,10 +177,8 @@ def find_conflicts_within_selection_set( conflicts: List[Conflict] = [] field_map, fragment_names = get_fields_and_fragment_names( - context, - cached_fields_and_fragment_names, - parent_type, - selection_set) + context, cached_fields_and_fragment_names, parent_type, selection_set + ) # (A) Find all conflicts "within" the fields of this selection set. # Note: this is the *only place* `collect_conflicts_within` is called. @@ -167,7 +187,8 @@ def find_conflicts_within_selection_set( conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, - field_map) + field_map, + ) if fragment_names: compared_fragments: Set[str] = set() @@ -182,12 +203,13 @@ def find_conflicts_within_selection_set( compared_fragment_pairs, False, field_map, - fragment_name) + fragment_name, + ) # (C) Then compare this fragment with all other fragments found in # this selection set to collect conflicts within fragments spread # together. This compares each item in the list of fragment names # to every other item in that same list (except for itself). - for other_fragment_name in fragment_names[i + 1:]: + for other_fragment_name in fragment_names[i + 1 :]: collect_conflicts_between_fragments( context, conflicts, @@ -195,20 +217,22 @@ def find_conflicts_within_selection_set( compared_fragment_pairs, False, fragment_name, - other_fragment_name) + other_fragment_name, + ) return conflicts def collect_conflicts_between_fields_and_fragment( - context: ValidationContext, - conflicts: List[Conflict], - cached_fields_and_fragment_names: Dict, - compared_fragments: Set[str], - compared_fragment_pairs: 'PairSet', - are_mutually_exclusive: bool, - field_map: NodeAndDefCollection, - fragment_name: str) -> None: + context: ValidationContext, + conflicts: List[Conflict], + cached_fields_and_fragment_names: Dict, + compared_fragments: Set[str], + compared_fragment_pairs: "PairSet", + are_mutually_exclusive: bool, + field_map: NodeAndDefCollection, + fragment_name: str, +) -> None: """Collect conflicts between fields and fragment. Collect all conflicts found between a set of fields and a fragment @@ -224,9 +248,8 @@ def collect_conflicts_between_fields_and_fragment( return None field_map2, fragment_names2 = get_referenced_fields_and_fragment_names( - context, - cached_fields_and_fragment_names, - fragment) + context, cached_fields_and_fragment_names, fragment + ) # Do not compare a fragment's fieldMap to itself. if field_map is field_map2: @@ -241,7 +264,8 @@ def collect_conflicts_between_fields_and_fragment( compared_fragment_pairs, are_mutually_exclusive, field_map, - field_map2) + field_map2, + ) # (E) Then collect any conflicts between the provided collection of fields # and any fragment names found in the given fragment. @@ -254,17 +278,19 @@ def collect_conflicts_between_fields_and_fragment( compared_fragment_pairs, are_mutually_exclusive, field_map, - fragment_name2) + fragment_name2, + ) def collect_conflicts_between_fragments( - context: ValidationContext, - conflicts: List[Conflict], - cached_fields_and_fragment_names: Dict, - compared_fragment_pairs: 'PairSet', - are_mutually_exclusive: bool, - fragment_name1: str, - fragment_name2: str) -> None: + context: ValidationContext, + conflicts: List[Conflict], + cached_fields_and_fragment_names: Dict, + compared_fragment_pairs: "PairSet", + are_mutually_exclusive: bool, + fragment_name1: str, + fragment_name2: str, +) -> None: """Collect conflicts between fragments. Collect all conflicts found between two fragments, including via spreading @@ -276,10 +302,10 @@ def collect_conflicts_between_fragments( # Memoize so two fragments are not compared for conflicts more than once. if compared_fragment_pairs.has( - fragment_name1, fragment_name2, are_mutually_exclusive): + fragment_name1, fragment_name2, are_mutually_exclusive + ): return - compared_fragment_pairs.add( - fragment_name1, fragment_name2, are_mutually_exclusive) + compared_fragment_pairs.add(fragment_name1, fragment_name2, are_mutually_exclusive) fragment1 = context.get_fragment(fragment_name1) fragment2 = context.get_fragment(fragment_name2) @@ -287,14 +313,12 @@ def collect_conflicts_between_fragments( return None field_map1, fragment_names1 = get_referenced_fields_and_fragment_names( - context, - cached_fields_and_fragment_names, - fragment1) + context, cached_fields_and_fragment_names, fragment1 + ) field_map2, fragment_names2 = get_referenced_fields_and_fragment_names( - context, - cached_fields_and_fragment_names, - fragment2) + context, cached_fields_and_fragment_names, fragment2 + ) # (F) First, collect all conflicts between these two collections of fields # (not including any nested fragments) @@ -305,7 +329,8 @@ def collect_conflicts_between_fragments( compared_fragment_pairs, are_mutually_exclusive, field_map1, - field_map2) + field_map2, + ) # (G) Then collect conflicts between the first fragment and any nested # fragments spread in the second fragment. @@ -317,7 +342,8 @@ def collect_conflicts_between_fragments( compared_fragment_pairs, are_mutually_exclusive, fragment_name1, - nested_fragment_name2) + nested_fragment_name2, + ) # (G) Then collect conflicts between the second fragment and any nested # fragments spread in the first fragment. @@ -329,18 +355,20 @@ def collect_conflicts_between_fragments( compared_fragment_pairs, are_mutually_exclusive, nested_fragment_name1, - fragment_name2) + fragment_name2, + ) def find_conflicts_between_sub_selection_sets( - context: ValidationContext, - cached_fields_and_fragment_names: Dict, - compared_fragment_pairs: 'PairSet', - are_mutually_exclusive: bool, - parent_type1: Optional[GraphQLNamedType], - selection_set1: SelectionSetNode, - parent_type2: Optional[GraphQLNamedType], - selection_set2: SelectionSetNode) -> List[Conflict]: + context: ValidationContext, + cached_fields_and_fragment_names: Dict, + compared_fragment_pairs: "PairSet", + are_mutually_exclusive: bool, + parent_type1: Optional[GraphQLNamedType], + selection_set1: SelectionSetNode, + parent_type2: Optional[GraphQLNamedType], + selection_set2: SelectionSetNode, +) -> List[Conflict]: """Find conflicts between sub selection sets. Find all conflicts found between two selection sets, including those found @@ -350,15 +378,11 @@ def find_conflicts_between_sub_selection_sets( conflicts: List[Conflict] = [] field_map1, fragment_names1 = get_fields_and_fragment_names( - context, - cached_fields_and_fragment_names, - parent_type1, - selection_set1) + context, cached_fields_and_fragment_names, parent_type1, selection_set1 + ) field_map2, fragment_names2 = get_fields_and_fragment_names( - context, - cached_fields_and_fragment_names, - parent_type2, - selection_set2) + context, cached_fields_and_fragment_names, parent_type2, selection_set2 + ) # (H) First, collect all conflicts between these two collections of field. collect_conflicts_between( @@ -368,7 +392,8 @@ def find_conflicts_between_sub_selection_sets( compared_fragment_pairs, are_mutually_exclusive, field_map1, - field_map2) + field_map2, + ) # (I) Then collect conflicts between the first collection of fields and # those referenced by each fragment name associated with the second. @@ -383,7 +408,8 @@ def find_conflicts_between_sub_selection_sets( compared_fragment_pairs, are_mutually_exclusive, field_map1, - fragment_name2) + fragment_name2, + ) # (I) Then collect conflicts between the second collection of fields and # those referenced by each fragment name associated with the first. @@ -398,7 +424,8 @@ def find_conflicts_between_sub_selection_sets( compared_fragment_pairs, are_mutually_exclusive, field_map2, - fragment_name1) + fragment_name1, + ) # (J) Also collect conflicts between any fragment names by the first and # fragment names by the second. This compares each item in the first set of @@ -412,17 +439,19 @@ def find_conflicts_between_sub_selection_sets( compared_fragment_pairs, are_mutually_exclusive, fragment_name1, - fragment_name2) + fragment_name2, + ) return conflicts def collect_conflicts_within( - context: ValidationContext, - conflicts: List[Conflict], - cached_fields_and_fragment_names: Dict, - compared_fragment_pairs: 'PairSet', - field_map: NodeAndDefCollection) -> None: + context: ValidationContext, + conflicts: List[Conflict], + cached_fields_and_fragment_names: Dict, + compared_fragment_pairs: "PairSet", + field_map: NodeAndDefCollection, +) -> None: """Collect all Conflicts "within" one collection of fields.""" # A field map is a keyed collection, where each key represents a response # name and the value at that key is a list of all fields which provide that @@ -434,7 +463,7 @@ def collect_conflicts_within( # to be compared. if len(fields) > 1: for i, field in enumerate(fields): - for other_field in fields[i + 1:]: + for other_field in fields[i + 1 :]: conflict = find_conflict( context, cached_fields_and_fragment_names, @@ -443,19 +472,21 @@ def collect_conflicts_within( False, response_name, field, - other_field) + other_field, + ) if conflict: conflicts.append(conflict) def collect_conflicts_between( - context: ValidationContext, - conflicts: List[Conflict], - cached_fields_and_fragment_names: Dict, - compared_fragment_pairs: 'PairSet', - parent_fields_are_mutually_exclusive: bool, - field_map1: NodeAndDefCollection, - field_map2: NodeAndDefCollection) -> None: + context: ValidationContext, + conflicts: List[Conflict], + cached_fields_and_fragment_names: Dict, + compared_fragment_pairs: "PairSet", + parent_fields_are_mutually_exclusive: bool, + field_map1: NodeAndDefCollection, + field_map2: NodeAndDefCollection, +) -> None: """Collect all Conflicts between two collections of fields. This is similar to, but different from the `collectConflictsWithin` @@ -480,19 +511,21 @@ def collect_conflicts_between( parent_fields_are_mutually_exclusive, response_name, field1, - field2) + field2, + ) if conflict: conflicts.append(conflict) def find_conflict( - context: ValidationContext, - cached_fields_and_fragment_names: Dict, - compared_fragment_pairs: 'PairSet', - parent_fields_are_mutually_exclusive: bool, - response_name: str, - field1: NodeAndDef, - field2: NodeAndDef) -> Optional[Conflict]: + context: ValidationContext, + cached_fields_and_fragment_names: Dict, + compared_fragment_pairs: "PairSet", + parent_fields_are_mutually_exclusive: bool, + response_name: str, + field1: NodeAndDef, + field2: NodeAndDef, +) -> Optional[Conflict]: """Find conflict. Determines if there is a conflict between two particular fields, including @@ -509,11 +542,11 @@ def find_conflict( # different Object types. Interface or Union types might overlap - if not # in the current state of the schema, then perhaps in some future version, # thus may not safely diverge. - are_mutually_exclusive = ( - parent_fields_are_mutually_exclusive or ( - parent_type1 != parent_type2 and - is_object_type(parent_type1) and - is_object_type(parent_type2))) + are_mutually_exclusive = parent_fields_are_mutually_exclusive or ( + parent_type1 != parent_type2 + and is_object_type(parent_type1) + and is_object_type(parent_type2) + ) # The return type for each field. type1 = cast(Optional[GraphQLOutputType], def1 and def1.type) @@ -525,23 +558,21 @@ def find_conflict( name2 = node2.name.value if name1 != name2: return ( - (response_name, f'{name1} and {name2} are different fields'), + (response_name, f"{name1} and {name2} are different fields"), [node1], - [node2]) + [node2], + ) # Two field calls must have the same arguments. if not same_arguments(node1.arguments or [], node2.arguments or []): - return ( - (response_name, 'they have differing arguments'), - [node1], - [node2]) + return ((response_name, "they have differing arguments"), [node1], [node2]) if type1 and type2 and do_types_conflict(type1, type2): return ( - (response_name, 'they return conflicting types' - f' {type1} and {type2}'), + (response_name, "they return conflicting types" f" {type1} and {type2}"), [node1], - [node2]) + [node2], + ) # Collect and compare sub-fields. Use the same "visited fragment names" # list for both collections so fields in a fragment reference are never @@ -557,15 +588,16 @@ def find_conflict( get_named_type(type1), selection_set1, get_named_type(type2), - selection_set2) + selection_set2, + ) return subfield_conflicts(conflicts, response_name, node1, node2) return None # no conflict def same_arguments( - arguments1: Sequence[ArgumentNode], - arguments2: Sequence[ArgumentNode]) -> bool: + arguments1: Sequence[ArgumentNode], arguments2: Sequence[ArgumentNode] +) -> bool: if len(arguments1) != len(arguments2): return False for argument1 in arguments1: @@ -580,13 +612,10 @@ def same_arguments( def same_value(value1, value2): - return (not value1 and not value2) or ( - print_ast(value1) == print_ast(value2)) + return (not value1 and not value2) or (print_ast(value1) == print_ast(value2)) -def do_types_conflict( - type1: GraphQLOutputType, - type2: GraphQLOutputType) -> bool: +def do_types_conflict(type1: GraphQLOutputType, type2: GraphQLOutputType) -> bool: """Check whether two types conflict Two types conflict if both types could not apply to a value simultaneously. @@ -594,17 +623,23 @@ def do_types_conflict( compared later recursively. However List and Non-Null types must match. """ if is_list_type(type1): - return do_types_conflict( - cast(GraphQLList, type1).of_type, - cast(GraphQLList, type2).of_type - ) if is_list_type(type2) else True + return ( + do_types_conflict( + cast(GraphQLList, type1).of_type, cast(GraphQLList, type2).of_type + ) + if is_list_type(type2) + else True + ) if is_list_type(type2): return True if is_non_null_type(type1): - return do_types_conflict( - cast(GraphQLNonNull, type1).of_type, - cast(GraphQLNonNull, type2).of_type - ) if is_non_null_type(type2) else True + return ( + do_types_conflict( + cast(GraphQLNonNull, type1).of_type, cast(GraphQLNonNull, type2).of_type + ) + if is_non_null_type(type2) + else True + ) if is_non_null_type(type2): return True if is_leaf_type(type1) or is_leaf_type(type2): @@ -613,11 +648,11 @@ def do_types_conflict( def get_fields_and_fragment_names( - context: ValidationContext, - cached_fields_and_fragment_names: Dict, - parent_type: Optional[GraphQLNamedType], - selection_set: SelectionSetNode - ) -> Tuple[NodeAndDefCollection, List[str]]: + context: ValidationContext, + cached_fields_and_fragment_names: Dict, + parent_type: Optional[GraphQLNamedType], + selection_set: SelectionSetNode, +) -> Tuple[NodeAndDefCollection, List[str]]: """Get fields and referenced fragment names Given a selection set, return the collection of fields (a mapping of @@ -629,21 +664,18 @@ def get_fields_and_fragment_names( node_and_defs: NodeAndDefCollection = {} fragment_names: Dict[str, bool] = {} collect_fields_and_fragment_names( - context, - parent_type, - selection_set, - node_and_defs, - fragment_names) + context, parent_type, selection_set, node_and_defs, fragment_names + ) cached = (node_and_defs, list(fragment_names)) cached_fields_and_fragment_names[selection_set] = cached return cached def get_referenced_fields_and_fragment_names( - context: ValidationContext, - cached_fields_and_fragment_names: Dict, - fragment: FragmentDefinitionNode - ) -> Tuple[NodeAndDefCollection, List[str]]: + context: ValidationContext, + cached_fields_and_fragment_names: Dict, + fragment: FragmentDefinitionNode, +) -> Tuple[NodeAndDefCollection, List[str]]: """Get referenced fields and nested fragment names Given a reference to a fragment, return the represented collection of @@ -657,50 +689,52 @@ def get_referenced_fields_and_fragment_names( fragment_type = type_from_ast(context.schema, fragment.type_condition) return get_fields_and_fragment_names( - context, - cached_fields_and_fragment_names, - fragment_type, - fragment.selection_set) + context, cached_fields_and_fragment_names, fragment_type, fragment.selection_set + ) def collect_fields_and_fragment_names( - context: ValidationContext, - parent_type: Optional[GraphQLNamedType], - selection_set: SelectionSetNode, - node_and_defs: NodeAndDefCollection, - fragment_names: Dict[str, bool]) -> None: + context: ValidationContext, + parent_type: Optional[GraphQLNamedType], + selection_set: SelectionSetNode, + node_and_defs: NodeAndDefCollection, + fragment_names: Dict[str, bool], +) -> None: for selection in selection_set.selections: if isinstance(selection, FieldNode): field_name = selection.name.value - field_def = (parent_type.fields.get(field_name) # type: ignore - if is_object_type(parent_type) or - is_interface_type(parent_type) else None) - response_name = (selection.alias.value - if selection.alias else field_name) + field_def = ( + parent_type.fields.get(field_name) # type: ignore + if is_object_type(parent_type) or is_interface_type(parent_type) + else None + ) + response_name = selection.alias.value if selection.alias else field_name if not node_and_defs.get(response_name): node_and_defs[response_name] = [] node_and_defs[response_name].append( - cast(NodeAndDef, (parent_type, selection, field_def))) + cast(NodeAndDef, (parent_type, selection, field_def)) + ) elif isinstance(selection, FragmentSpreadNode): fragment_names[selection.name.value] = True elif isinstance(selection, InlineFragmentNode): type_condition = selection.type_condition inline_fragment_type = ( type_from_ast(context.schema, type_condition) - if type_condition else parent_type) + if type_condition + else parent_type + ) collect_fields_and_fragment_names( context, inline_fragment_type, selection.selection_set, node_and_defs, - fragment_names) + fragment_names, + ) def subfield_conflicts( - conflicts: List[Conflict], - response_name: str, - node1: FieldNode, - node2: FieldNode) -> Optional[Conflict]: + conflicts: List[Conflict], response_name: str, node1: FieldNode, node2: FieldNode +) -> Optional[Conflict]: """Check whether there are conflicts between sub-fields. Given a series of Conflicts which occurred between two sub-fields, @@ -710,7 +744,8 @@ def subfield_conflicts( return ( (response_name, [conflict[0] for conflict in conflicts]), list(chain([node1], *[conflict[1] for conflict in conflicts])), - list(chain([node2], *[conflict[2] for conflict in conflicts]))) + list(chain([node2], *[conflict[2] for conflict in conflicts])), + ) return None # no conflict @@ -721,7 +756,7 @@ class PairSet: not matter. We do this by maintaining a sort of double adjacency sets. """ - __slots__ = '_data', + __slots__ = ("_data",) def __init__(self): self._data: Dict[str, Dict[str, bool]] = {} diff --git a/graphql/validation/rules/possible_fragment_spreads.py b/graphql/validation/rules/possible_fragment_spreads.py index 356fca75..eeb921b2 100644 --- a/graphql/validation/rules/possible_fragment_spreads.py +++ b/graphql/validation/rules/possible_fragment_spreads.py @@ -5,21 +5,26 @@ from . import ValidationRule __all__ = [ - 'PossibleFragmentSpreadsRule', - 'type_incompatible_spread_message', - 'type_incompatible_anon_spread_message'] + "PossibleFragmentSpreadsRule", + "type_incompatible_spread_message", + "type_incompatible_anon_spread_message", +] def type_incompatible_spread_message( - frag_name: str, parent_type: str, frag_type: str) -> str: - return (f"Fragment '{frag_name}' cannot be spread here as objects" - f" of type '{parent_type}' can never be of type '{frag_type}'.") + frag_name: str, parent_type: str, frag_type: str +) -> str: + return ( + f"Fragment '{frag_name}' cannot be spread here as objects" + f" of type '{parent_type}' can never be of type '{frag_type}'." + ) -def type_incompatible_anon_spread_message( - parent_type: str, frag_type: str) -> str: - return (f'Fragment cannot be spread here as objects' - f" of type '{parent_type}' can never be of type '{frag_type}'.") +def type_incompatible_anon_spread_message(parent_type: str, frag_type: str) -> str: + return ( + f"Fragment cannot be spread here as objects" + f" of type '{parent_type}' can never be of type '{frag_type}'." + ) class PossibleFragmentSpreadsRule(ValidationRule): @@ -34,23 +39,38 @@ def enter_inline_fragment(self, node: InlineFragmentNode, *_args): context = self.context frag_type = context.get_type() parent_type = context.get_parent_type() - if (is_composite_type(frag_type) and is_composite_type(parent_type) and - not do_types_overlap(context.schema, frag_type, parent_type)): - context.report_error(GraphQLError( - type_incompatible_anon_spread_message( - str(parent_type), str(frag_type)), - [node])) + if ( + is_composite_type(frag_type) + and is_composite_type(parent_type) + and not do_types_overlap(context.schema, frag_type, parent_type) + ): + context.report_error( + GraphQLError( + type_incompatible_anon_spread_message( + str(parent_type), str(frag_type) + ), + [node], + ) + ) def enter_fragment_spread(self, node: FragmentSpreadNode, *_args): context = self.context frag_name = node.name.value frag_type = self.get_fragment_type(frag_name) parent_type = context.get_parent_type() - if frag_type and parent_type and not do_types_overlap( - context.schema, frag_type, parent_type): - context.report_error(GraphQLError( - type_incompatible_spread_message( - frag_name, str(parent_type), str(frag_type)), [node])) + if ( + frag_type + and parent_type + and not do_types_overlap(context.schema, frag_type, parent_type) + ): + context.report_error( + GraphQLError( + type_incompatible_spread_message( + frag_name, str(parent_type), str(frag_type) + ), + [node], + ) + ) def get_fragment_type(self, name: str): context = self.context diff --git a/graphql/validation/rules/provided_required_arguments.py b/graphql/validation/rules/provided_required_arguments.py index 0621a279..44927e9a 100644 --- a/graphql/validation/rules/provided_required_arguments.py +++ b/graphql/validation/rules/provided_required_arguments.py @@ -2,28 +2,39 @@ from ...error import GraphQLError from ...language import ( - DirectiveDefinitionNode, DirectiveNode, FieldNode, - InputValueDefinitionNode, NonNullTypeNode, TypeNode, print_ast) -from ...type import ( - GraphQLArgument, is_required_argument, is_type, specified_directives) + DirectiveDefinitionNode, + DirectiveNode, + FieldNode, + InputValueDefinitionNode, + NonNullTypeNode, + TypeNode, + print_ast, +) +from ...type import GraphQLArgument, is_required_argument, is_type, specified_directives from . import ASTValidationRule, SDLValidationContext, ValidationContext __all__ = [ - 'ProvidedRequiredArgumentsRule', - 'ProvidedRequiredArgumentsOnDirectivesRule', - 'missing_field_arg_message', 'missing_directive_arg_message'] + "ProvidedRequiredArgumentsRule", + "ProvidedRequiredArgumentsOnDirectivesRule", + "missing_field_arg_message", + "missing_directive_arg_message", +] -def missing_field_arg_message( - field_name: str, arg_name: str, type_: str) -> str: - return (f"Field '{field_name}' argument '{arg_name}'" - f" of type '{type_}' is required but not provided.") +def missing_field_arg_message(field_name: str, arg_name: str, type_: str) -> str: + return ( + f"Field '{field_name}' argument '{arg_name}'" + f" of type '{type_}' is required but not provided." + ) def missing_directive_arg_message( - directive_name: str, arg_name: str, type_: str) -> str: - return (f"Directive '@{directive_name}' argument '{arg_name}'" - f" of type '{type_}' is required but not provided.") + directive_name: str, arg_name: str, type_: str +) -> str: + return ( + f"Directive '@{directive_name}' argument '{arg_name}'" + f" of type '{type_}' is required but not provided." + ) class ProvidedRequiredArgumentsOnDirectivesRule(ASTValidationRule): @@ -35,27 +46,32 @@ class ProvidedRequiredArgumentsOnDirectivesRule(ASTValidationRule): context: Union[ValidationContext, SDLValidationContext] - def __init__(self, context: Union[ - ValidationContext, SDLValidationContext]) -> None: + def __init__(self, context: Union[ValidationContext, SDLValidationContext]) -> None: super().__init__(context) - required_args_map: Dict[str, Dict[str, Union[ - GraphQLArgument, InputValueDefinitionNode]]] = {} + required_args_map: Dict[ + str, Dict[str, Union[GraphQLArgument, InputValueDefinitionNode]] + ] = {} schema = context.schema - defined_directives = ( - schema.directives if schema else specified_directives) + defined_directives = schema.directives if schema else specified_directives for directive in cast(List, defined_directives): required_args_map[directive.name] = { - name: arg for name, arg in directive.args.items() - if is_required_argument(arg)} + name: arg + for name, arg in directive.args.items() + if is_required_argument(arg) + } ast_definitions = context.document.definitions for def_ in ast_definitions: if isinstance(def_, DirectiveDefinitionNode): - required_args_map[def_.name.value] = { - arg.name.value: arg for arg in filter( - is_required_argument_node, def_.arguments) - } if def_.arguments else {} + required_args_map[def_.name.value] = ( + { + arg.name.value: arg + for arg in filter(is_required_argument_node, def_.arguments) + } + if def_.arguments + else {} + ) self.required_args_map = required_args_map @@ -70,12 +86,18 @@ def leave_directive(self, directive_node: DirectiveNode, *_args): for arg_name in required_args: if arg_name not in arg_node_set: arg_type = required_args[arg_name].type - self.report_error(GraphQLError( - missing_directive_arg_message( - directive_name, arg_name, str(arg_type) - if is_type(arg_type) - else print_ast(cast(TypeNode, arg_type))), - [directive_node])) + self.report_error( + GraphQLError( + missing_directive_arg_message( + directive_name, + arg_name, + str(arg_type) + if is_type(arg_type) + else print_ast(cast(TypeNode, arg_type)), + ), + [directive_node], + ) + ) class ProvidedRequiredArgumentsRule(ProvidedRequiredArgumentsOnDirectivesRule): @@ -101,9 +123,14 @@ def leave_field(self, field_node: FieldNode, *_args): for arg_name, arg_def in field_def.args.items(): arg_node = arg_node_map.get(arg_name) if not arg_node and is_required_argument(arg_def): - self.report_error(GraphQLError(missing_field_arg_message( - field_node.name.value, arg_name, str(arg_def.type)), - [field_node])) + self.report_error( + GraphQLError( + missing_field_arg_message( + field_node.name.value, arg_name, str(arg_def.type) + ), + [field_node], + ) + ) def is_required_argument_node(arg: InputValueDefinitionNode) -> bool: diff --git a/graphql/validation/rules/scalar_leafs.py b/graphql/validation/rules/scalar_leafs.py index fafb6533..e27645bd 100644 --- a/graphql/validation/rules/scalar_leafs.py +++ b/graphql/validation/rules/scalar_leafs.py @@ -4,21 +4,25 @@ from . import ValidationRule __all__ = [ - 'ScalarLeafsRule', - 'no_subselection_allowed_message', 'required_subselection_message'] + "ScalarLeafsRule", + "no_subselection_allowed_message", + "required_subselection_message", +] -def no_subselection_allowed_message( - field_name: str, type_: str) -> str: - return (f"Field '{field_name}' must not have a sub selection" - f" since type '{type_}' has no subfields.") +def no_subselection_allowed_message(field_name: str, type_: str) -> str: + return ( + f"Field '{field_name}' must not have a sub selection" + f" since type '{type_}' has no subfields." + ) -def required_subselection_message( - field_name: str, type_: str) -> str: - return (f"Field '{field_name}' of type '{type_}' must have a" - ' sub selection of subfields.' - f" Did you mean '{field_name} {{ ... }}'?") +def required_subselection_message(field_name: str, type_: str) -> str: + return ( + f"Field '{field_name}' of type '{type_}' must have a" + " sub selection of subfields." + f" Did you mean '{field_name} {{ ... }}'?" + ) class ScalarLeafsRule(ValidationRule): @@ -34,11 +38,18 @@ def enter_field(self, node: FieldNode, *_args): selection_set = node.selection_set if is_leaf_type(get_named_type(type_)): if selection_set: - self.report_error(GraphQLError( - no_subselection_allowed_message( - node.name.value, str(type_)), - [selection_set])) + self.report_error( + GraphQLError( + no_subselection_allowed_message( + node.name.value, str(type_) + ), + [selection_set], + ) + ) elif not selection_set: - self.report_error(GraphQLError( - required_subselection_message(node.name.value, str(type_)), - [node])) + self.report_error( + GraphQLError( + required_subselection_message(node.name.value, str(type_)), + [node], + ) + ) diff --git a/graphql/validation/rules/single_field_subscriptions.py b/graphql/validation/rules/single_field_subscriptions.py index ede95235..77259509 100644 --- a/graphql/validation/rules/single_field_subscriptions.py +++ b/graphql/validation/rules/single_field_subscriptions.py @@ -4,12 +4,13 @@ from ...language import OperationDefinitionNode, OperationType from . import ASTValidationRule -__all__ = ['SingleFieldSubscriptionsRule', 'single_field_only_message'] +__all__ = ["SingleFieldSubscriptionsRule", "single_field_only_message"] def single_field_only_message(name: Optional[str]) -> str: - return ((f"Subscription '{name}'" if name else 'Anonymous Subscription') + - ' must select only one top level field.') + return ( + f"Subscription '{name}'" if name else "Anonymous Subscription" + ) + " must select only one top level field." class SingleFieldSubscriptionsRule(ASTValidationRule): @@ -18,10 +19,14 @@ class SingleFieldSubscriptionsRule(ASTValidationRule): A GraphQL subscription is valid only if it contains a single root """ - def enter_operation_definition( - self, node: OperationDefinitionNode, *_args): + def enter_operation_definition(self, node: OperationDefinitionNode, *_args): if node.operation == OperationType.SUBSCRIPTION: if len(node.selection_set.selections) != 1: - self.report_error(GraphQLError(single_field_only_message( - node.name.value if node.name else None), - node.selection_set.selections[1:])) + self.report_error( + GraphQLError( + single_field_only_message( + node.name.value if node.name else None + ), + node.selection_set.selections[1:], + ) + ) diff --git a/graphql/validation/rules/unique_argument_names.py b/graphql/validation/rules/unique_argument_names.py index 5c15449c..d3907d9b 100644 --- a/graphql/validation/rules/unique_argument_names.py +++ b/graphql/validation/rules/unique_argument_names.py @@ -4,7 +4,7 @@ from ...language import NameNode, ArgumentNode from . import ASTValidationContext, ASTValidationRule -__all__ = ['UniqueArgumentNamesRule', 'duplicate_arg_message'] +__all__ = ["UniqueArgumentNamesRule", "duplicate_arg_message"] def duplicate_arg_message(arg_name: str) -> str: @@ -32,9 +32,12 @@ def enter_argument(self, node: ArgumentNode, *_args): known_arg_names = self.known_arg_names arg_name = node.name.value if arg_name in known_arg_names: - self.report_error(GraphQLError( - duplicate_arg_message(arg_name), - [known_arg_names[arg_name], node.name])) + self.report_error( + GraphQLError( + duplicate_arg_message(arg_name), + [known_arg_names[arg_name], node.name], + ) + ) else: known_arg_names[arg_name] = node.name return self.SKIP diff --git a/graphql/validation/rules/unique_directives_per_location.py b/graphql/validation/rules/unique_directives_per_location.py index b2bf0fa3..93d7e4e7 100644 --- a/graphql/validation/rules/unique_directives_per_location.py +++ b/graphql/validation/rules/unique_directives_per_location.py @@ -4,12 +4,13 @@ from ...language import DirectiveNode, Node from . import ASTValidationRule -__all__ = ['UniqueDirectivesPerLocationRule', 'duplicate_directive_message'] +__all__ = ["UniqueDirectivesPerLocationRule", "duplicate_directive_message"] def duplicate_directive_message(directive_name: str) -> str: - return (f"The directive '{directive_name}'" - ' can only be used once at this location.') + return ( + f"The directive '{directive_name}'" " can only be used once at this location." + ) class UniqueDirectivesPerLocationRule(ASTValidationRule): @@ -23,14 +24,17 @@ class UniqueDirectivesPerLocationRule(ASTValidationRule): # them all, just listen for entering any node, and check to see if it # defines any directives. def enter(self, node: Node, *_args): - directives: List[DirectiveNode] = getattr(node, 'directives', None) + directives: List[DirectiveNode] = getattr(node, "directives", None) if directives: known_directives: Dict[str, DirectiveNode] = {} for directive in directives: directive_name = directive.name.value if directive_name in known_directives: - self.report_error(GraphQLError( - duplicate_directive_message(directive_name), - [known_directives[directive_name], directive])) + self.report_error( + GraphQLError( + duplicate_directive_message(directive_name), + [known_directives[directive_name], directive], + ) + ) else: known_directives[directive_name] = directive diff --git a/graphql/validation/rules/unique_fragment_names.py b/graphql/validation/rules/unique_fragment_names.py index 41d1826e..2ee1131f 100644 --- a/graphql/validation/rules/unique_fragment_names.py +++ b/graphql/validation/rules/unique_fragment_names.py @@ -4,7 +4,7 @@ from ...language import NameNode, FragmentDefinitionNode from . import ASTValidationContext, ASTValidationRule -__all__ = ['UniqueFragmentNamesRule', 'duplicate_fragment_name_message'] +__all__ = ["UniqueFragmentNamesRule", "duplicate_fragment_name_message"] def duplicate_fragment_name_message(frag_name: str) -> str: @@ -29,9 +29,12 @@ def enter_fragment_definition(self, node: FragmentDefinitionNode, *_args): known_fragment_names = self.known_fragment_names fragment_name = node.name.value if fragment_name in known_fragment_names: - self.report_error(GraphQLError( - duplicate_fragment_name_message(fragment_name), - [known_fragment_names[fragment_name], node.name])) + self.report_error( + GraphQLError( + duplicate_fragment_name_message(fragment_name), + [known_fragment_names[fragment_name], node.name], + ) + ) else: known_fragment_names[fragment_name] = node.name return self.SKIP diff --git a/graphql/validation/rules/unique_input_field_names.py b/graphql/validation/rules/unique_input_field_names.py index f6c401d8..c76ba245 100644 --- a/graphql/validation/rules/unique_input_field_names.py +++ b/graphql/validation/rules/unique_input_field_names.py @@ -4,7 +4,7 @@ from ...language import NameNode, ObjectFieldNode from . import ASTValidationContext, ASTValidationRule -__all__ = ['UniqueInputFieldNamesRule', 'duplicate_input_field_message'] +__all__ = ["UniqueInputFieldNamesRule", "duplicate_input_field_message"] def duplicate_input_field_message(field_name: str) -> str: @@ -34,8 +34,12 @@ def enter_object_field(self, node: ObjectFieldNode, *_args): known_names = self.known_names field_name = node.name.value if field_name in known_names: - self.report_error(GraphQLError(duplicate_input_field_message( - field_name), [known_names[field_name], node.name])) + self.report_error( + GraphQLError( + duplicate_input_field_message(field_name), + [known_names[field_name], node.name], + ) + ) else: known_names[field_name] = node.name return False diff --git a/graphql/validation/rules/unique_operation_names.py b/graphql/validation/rules/unique_operation_names.py index 685799c3..d7dc8df9 100644 --- a/graphql/validation/rules/unique_operation_names.py +++ b/graphql/validation/rules/unique_operation_names.py @@ -4,7 +4,7 @@ from ...language import NameNode, OperationDefinitionNode from . import ASTValidationContext, ASTValidationRule -__all__ = ['UniqueOperationNamesRule', 'duplicate_operation_name_message'] +__all__ = ["UniqueOperationNamesRule", "duplicate_operation_name_message"] def duplicate_operation_name_message(operation_name: str) -> str: @@ -22,16 +22,17 @@ def __init__(self, context: ASTValidationContext) -> None: super().__init__(context) self.known_operation_names: Dict[str, NameNode] = {} - def enter_operation_definition( - self, node: OperationDefinitionNode, *_args): + def enter_operation_definition(self, node: OperationDefinitionNode, *_args): operation_name = node.name if operation_name: known_operation_names = self.known_operation_names if operation_name.value in known_operation_names: - self.report_error(GraphQLError( - duplicate_operation_name_message(operation_name.value), - [known_operation_names[operation_name.value], - operation_name])) + self.report_error( + GraphQLError( + duplicate_operation_name_message(operation_name.value), + [known_operation_names[operation_name.value], operation_name], + ) + ) else: known_operation_names[operation_name.value] = operation_name return self.SKIP diff --git a/graphql/validation/rules/unique_variable_names.py b/graphql/validation/rules/unique_variable_names.py index b4397187..89042b25 100644 --- a/graphql/validation/rules/unique_variable_names.py +++ b/graphql/validation/rules/unique_variable_names.py @@ -4,7 +4,7 @@ from ...language import NameNode, VariableDefinitionNode from . import ASTValidationContext, ASTValidationRule -__all__ = ['UniqueVariableNamesRule', 'duplicate_variable_message'] +__all__ = ["UniqueVariableNamesRule", "duplicate_variable_message"] def duplicate_variable_message(variable_name: str) -> str: @@ -28,8 +28,11 @@ def enter_variable_definition(self, node: VariableDefinitionNode, *_args): known_variable_names = self.known_variable_names variable_name = node.variable.name.value if variable_name in known_variable_names: - self.report_error(GraphQLError( - duplicate_variable_message(variable_name), - [known_variable_names[variable_name], node.variable.name])) + self.report_error( + GraphQLError( + duplicate_variable_message(variable_name), + [known_variable_names[variable_name], node.variable.name], + ) + ) else: known_variable_names[variable_name] = node.variable.name diff --git a/graphql/validation/rules/values_of_correct_type.py b/graphql/validation/rules/values_of_correct_type.py index 5c56ffa0..0c6850eb 100644 --- a/graphql/validation/rules/values_of_correct_type.py +++ b/graphql/validation/rules/values_of_correct_type.py @@ -2,37 +2,61 @@ from ...error import GraphQLError from ...language import ( - BooleanValueNode, EnumValueNode, FloatValueNode, IntValueNode, - NullValueNode, ListValueNode, ObjectFieldNode, ObjectValueNode, - StringValueNode, ValueNode, print_ast) + BooleanValueNode, + EnumValueNode, + FloatValueNode, + IntValueNode, + NullValueNode, + ListValueNode, + ObjectFieldNode, + ObjectValueNode, + StringValueNode, + ValueNode, + print_ast, +) from ...pyutils import is_invalid, or_list, suggestion_list from ...type import ( - GraphQLEnumType, GraphQLScalarType, GraphQLType, - get_named_type, get_nullable_type, is_enum_type, is_input_object_type, - is_list_type, is_non_null_type, is_required_input_field, is_scalar_type) + GraphQLEnumType, + GraphQLScalarType, + GraphQLType, + get_named_type, + get_nullable_type, + is_enum_type, + is_input_object_type, + is_list_type, + is_non_null_type, + is_required_input_field, + is_scalar_type, +) from . import ValidationRule __all__ = [ - 'ValuesOfCorrectTypeRule', - 'bad_value_message', 'required_field_message', 'unknown_field_message'] + "ValuesOfCorrectTypeRule", + "bad_value_message", + "required_field_message", + "unknown_field_message", +] -def bad_value_message( - type_name: str, value_name: str, message: str=None) -> str: - return f'Expected type {type_name}, found {value_name}' + ( - f'; {message}' if message else '.') +def bad_value_message(type_name: str, value_name: str, message: str = None) -> str: + return f"Expected type {type_name}, found {value_name}" + ( + f"; {message}" if message else "." + ) def required_field_message( - type_name: str, field_name: str, field_type_name: str) -> str: - return (f'Field {type_name}.{field_name} of required type' - f' {field_type_name} was not provided.') + type_name: str, field_name: str, field_type_name: str +) -> str: + return ( + f"Field {type_name}.{field_name} of required type" + f" {field_type_name} was not provided." + ) -def unknown_field_message( - type_name: str, field_name: str, message: str=None) -> str: - return f'Field {field_name} is not defined by type {type_name}' + ( - f'; {message}' if message else '.') +def unknown_field_message(type_name: str, field_name: str, message: str = None) -> str: + return f"Field {field_name} is not defined by type {type_name}" + ( + f"; {message}" if message else "." + ) class ValuesOfCorrectTypeRule(ValidationRule): @@ -45,8 +69,9 @@ class ValuesOfCorrectTypeRule(ValidationRule): def enter_null_value(self, node: NullValueNode, *_args): type_ = self.context.get_input_type() if is_non_null_type(type_): - self.report_error(GraphQLError( - bad_value_message(type_, print_ast(node)), node)) + self.report_error( + GraphQLError(bad_value_message(type_, print_ast(node)), node) + ) def enter_list_value(self, node: ListValueNode, *_args): # Note: TypeInfo will traverse into a list's item type, so look to the @@ -68,28 +93,43 @@ def enter_object_value(self, node: ObjectValueNode, *_args): field_node = field_node_map.get(field_name) if not field_node and is_required_input_field(field_def): field_type = field_def.type - self.report_error(GraphQLError(required_field_message( - type_.name, field_name, str(field_type)), node)) + self.report_error( + GraphQLError( + required_field_message(type_.name, field_name, str(field_type)), + node, + ) + ) def enter_object_field(self, node: ObjectFieldNode, *_args): parent_type = get_named_type(self.context.get_parent_input_type()) field_type = self.context.get_input_type() if not field_type and is_input_object_type(parent_type): - suggestions = suggestion_list( - node.name.value, list(parent_type.fields)) - did_you_mean = (f'Did you mean {or_list(suggestions)}?' - if suggestions else None) - self.report_error(GraphQLError(unknown_field_message( - parent_type.name, node.name.value, did_you_mean), node)) + suggestions = suggestion_list(node.name.value, list(parent_type.fields)) + did_you_mean = ( + f"Did you mean {or_list(suggestions)}?" if suggestions else None + ) + self.report_error( + GraphQLError( + unknown_field_message( + parent_type.name, node.name.value, did_you_mean + ), + node, + ) + ) def enter_enum_value(self, node: EnumValueNode, *_args): type_ = get_named_type(self.context.get_input_type()) if not is_enum_type(type_): self.is_valid_scalar(node) elif node.value not in type_.values: - self.report_error(GraphQLError(bad_value_message( - type_.name, print_ast(node), - enum_type_suggestion(type_, node)), node)) + self.report_error( + GraphQLError( + bad_value_message( + type_.name, print_ast(node), enum_type_suggestion(type_, node) + ), + node, + ) + ) def enter_int_value(self, node: IntValueNode, *_args): self.is_valid_scalar(node) @@ -117,9 +157,16 @@ def is_valid_scalar(self, node: ValueNode) -> None: type_ = get_named_type(location_type) if not is_scalar_type(type_): - self.report_error(GraphQLError(bad_value_message( - location_type, print_ast(node), - enum_type_suggestion(type_, node)), node)) + self.report_error( + GraphQLError( + bad_value_message( + location_type, + print_ast(node), + enum_type_suggestion(type_, node), + ), + node, + ) + ) return # Scalars determine if a literal value is valid via parse_literal() @@ -128,20 +175,26 @@ def is_valid_scalar(self, node: ValueNode) -> None: try: parse_result = type_.parse_literal(node) if is_invalid(parse_result): - self.report_error(GraphQLError(bad_value_message( - location_type, print_ast(node)), node)) + self.report_error( + GraphQLError( + bad_value_message(location_type, print_ast(node)), node + ) + ) except Exception as error: # Ensure a reference to the original error is maintained. - self.report_error(GraphQLError(bad_value_message( - location_type, print_ast(node), str(error)), - node, original_error=error)) + self.report_error( + GraphQLError( + bad_value_message(location_type, print_ast(node), str(error)), + node, + original_error=error, + ) + ) def enum_type_suggestion(type_: GraphQLType, node: ValueNode) -> Optional[str]: if is_enum_type(type_): type_ = cast(GraphQLEnumType, type_) - suggestions = suggestion_list( - print_ast(node), list(type_.values)) + suggestions = suggestion_list(print_ast(node), list(type_.values)) if suggestions: - return f'Did you mean the enum value {or_list(suggestions)}?' + return f"Did you mean the enum value {or_list(suggestions)}?" return None diff --git a/graphql/validation/rules/variables_are_input_types.py b/graphql/validation/rules/variables_are_input_types.py index 6f4a5d59..83381e6d 100644 --- a/graphql/validation/rules/variables_are_input_types.py +++ b/graphql/validation/rules/variables_are_input_types.py @@ -4,13 +4,11 @@ from ...utilities import type_from_ast from . import ValidationRule -__all__ = ['VariablesAreInputTypesRule', 'non_input_type_on_var_message'] +__all__ = ["VariablesAreInputTypesRule", "non_input_type_on_var_message"] -def non_input_type_on_var_message( - variable_name: str, type_name: str) -> str: - return (f"Variable '${variable_name}'" - f" cannot be non-input type '{type_name}'.") +def non_input_type_on_var_message(variable_name: str, type_name: str) -> str: + return f"Variable '${variable_name}'" f" cannot be non-input type '{type_name}'." class VariablesAreInputTypesRule(ValidationRule): @@ -26,5 +24,9 @@ def enter_variable_definition(self, node: VariableDefinitionNode, *_args): # If the variable type is not an input type, return an error. if type_ and not is_input_type(type_): variable_name = node.variable.name.value - self.report_error(GraphQLError(non_input_type_on_var_message( - variable_name, print_ast(node.type)), [node.type])) + self.report_error( + GraphQLError( + non_input_type_on_var_message(variable_name, print_ast(node.type)), + [node.type], + ) + ) diff --git a/graphql/validation/rules/variables_in_allowed_position.py b/graphql/validation/rules/variables_in_allowed_position.py index 4a3f1a92..65fdb8ba 100644 --- a/graphql/validation/rules/variables_in_allowed_position.py +++ b/graphql/validation/rules/variables_in_allowed_position.py @@ -2,19 +2,23 @@ from ...error import GraphQLError, INVALID from ...language import ( - NullValueNode, OperationDefinitionNode, ValueNode, VariableDefinitionNode) -from ...type import ( - GraphQLNonNull, GraphQLSchema, GraphQLType, is_non_null_type) + NullValueNode, + OperationDefinitionNode, + ValueNode, + VariableDefinitionNode, +) +from ...type import GraphQLNonNull, GraphQLSchema, GraphQLType, is_non_null_type from ...utilities import type_from_ast, is_type_sub_type_of from . import ValidationContext, ValidationRule -__all__ = ['VariablesInAllowedPositionRule', 'bad_var_pos_message'] +__all__ = ["VariablesInAllowedPositionRule", "bad_var_pos_message"] -def bad_var_pos_message( - var_name: str, var_type: str, expected_type: str) -> str: - return (f"Variable '${var_name}' of type '{var_type}' used" - f" in position expecting type '{expected_type}'.") +def bad_var_pos_message(var_name: str, var_type: str, expected_type: str) -> str: + return ( + f"Variable '${var_name}' of type '{var_type}' used" + f" in position expecting type '{expected_type}'." + ) class VariablesInAllowedPositionRule(ValidationRule): @@ -27,8 +31,7 @@ def __init__(self, context: ValidationContext) -> None: def enter_operation_definition(self, *_args): self.var_def_map.clear() - def leave_operation_definition( - self, operation: OperationDefinitionNode, *_args): + def leave_operation_definition(self, operation: OperationDefinitionNode, *_args): var_def_map = self.var_def_map usages = self.context.get_recursive_variable_usages(operation) @@ -47,21 +50,26 @@ def leave_operation_definition( schema = self.context.schema var_type = type_from_ast(schema, var_def.type) if var_type and not allowed_variable_usage( - schema, var_type, var_def.default_value, - type_, default_value): - self.report_error(GraphQLError( - bad_var_pos_message( - var_name, str(var_type), str(type_)), - [var_def, node])) + schema, var_type, var_def.default_value, type_, default_value + ): + self.report_error( + GraphQLError( + bad_var_pos_message(var_name, str(var_type), str(type_)), + [var_def, node], + ) + ) def enter_variable_definition(self, node: VariableDefinitionNode, *_args): self.var_def_map[node.variable.name.value] = node def allowed_variable_usage( - schema: GraphQLSchema, var_type: GraphQLType, - var_default_value: Optional[ValueNode], - location_type: GraphQLType, location_default_value: Any) -> bool: + schema: GraphQLSchema, + var_type: GraphQLType, + var_default_value: Optional[ValueNode], + location_type: GraphQLType, + location_default_value: Any, +) -> bool: """Check for allowed variable usage. Returns True if the variable is allowed in the location it was found, @@ -69,12 +77,11 @@ def allowed_variable_usage( or the location at which it is located. """ if is_non_null_type(location_type) and not is_non_null_type(var_type): - has_non_null_variable_default_value = ( - var_default_value and not isinstance( - var_default_value, NullValueNode)) + has_non_null_variable_default_value = var_default_value and not isinstance( + var_default_value, NullValueNode + ) has_location_default_value = location_default_value is not INVALID - if (not has_non_null_variable_default_value - and not has_location_default_value): + if not has_non_null_variable_default_value and not has_location_default_value: return False location_type = cast(GraphQLNonNull, location_type) nullable_location_type = location_type.of_type diff --git a/graphql/validation/specified_rules.py b/graphql/validation/specified_rules.py index c097b225..521b015e 100644 --- a/graphql/validation/specified_rules.py +++ b/graphql/validation/specified_rules.py @@ -57,8 +57,7 @@ from .rules.known_directives import KnownDirectivesRule # Spec Section: "Directives Are Unique Per Location" -from .rules.unique_directives_per_location import ( - UniqueDirectivesPerLocationRule) +from .rules.unique_directives_per_location import UniqueDirectivesPerLocationRule # Spec Section: "Argument Names" from .rules.known_argument_names import KnownArgumentNamesRule @@ -76,8 +75,7 @@ from .rules.variables_in_allowed_position import VariablesInAllowedPositionRule # Spec Section: "Field Selection Merging" -from .rules.overlapping_fields_can_be_merged import ( - OverlappingFieldsCanBeMergedRule) +from .rules.overlapping_fields_can_be_merged import OverlappingFieldsCanBeMergedRule # Spec Section: "Input Object Field Uniqueness" from .rules.unique_input_field_names import UniqueInputFieldNamesRule @@ -85,10 +83,9 @@ # Schema definition language: from .rules.lone_schema_definition import LoneSchemaDefinitionRule from .rules.known_argument_names import KnownArgumentNamesOnDirectivesRule -from .rules.provided_required_arguments import ( - ProvidedRequiredArgumentsOnDirectivesRule) +from .rules.provided_required_arguments import ProvidedRequiredArgumentsOnDirectivesRule -__all__ = ['specified_rules', 'specified_sdl_rules'] +__all__ = ["specified_rules", "specified_sdl_rules"] # This list includes all validation rules defined by the GraphQL spec. @@ -122,7 +119,8 @@ ProvidedRequiredArgumentsRule, VariablesInAllowedPositionRule, OverlappingFieldsCanBeMergedRule, - UniqueInputFieldNamesRule] + UniqueInputFieldNamesRule, +] specified_sdl_rules: List[RuleType] = [ LoneSchemaDefinitionRule, @@ -131,4 +129,5 @@ KnownArgumentNamesOnDirectivesRule, UniqueArgumentNamesRule, UniqueInputFieldNamesRule, - ProvidedRequiredArgumentsOnDirectivesRule] + ProvidedRequiredArgumentsOnDirectivesRule, +] diff --git a/graphql/validation/validate.py b/graphql/validation/validate.py index 7dbd5eb6..e493180a 100644 --- a/graphql/validation/validate.py +++ b/graphql/validation/validate.py @@ -8,14 +8,15 @@ from .specified_rules import specified_rules, specified_sdl_rules from .validation_context import SDLValidationContext, ValidationContext -__all__ = [ - 'assert_valid_sdl', 'assert_valid_sdl_extension', - 'validate', 'validate_sdl'] +__all__ = ["assert_valid_sdl", "assert_valid_sdl_extension", "validate", "validate_sdl"] -def validate(schema: GraphQLSchema, document_ast: DocumentNode, - rules: Sequence[RuleType]=None, - type_info: TypeInfo=None) -> List[GraphQLError]: +def validate( + schema: GraphQLSchema, + document_ast: DocumentNode, + rules: Sequence[RuleType] = None, + type_info: TypeInfo = None, +) -> List[GraphQLError]: """Implements the "Validation" section of the spec. Validation runs synchronously, returning a list of encountered errors, or @@ -33,17 +34,17 @@ def validate(schema: GraphQLSchema, document_ast: DocumentNode, will be created from the provided schema. """ if not document_ast or not isinstance(document_ast, DocumentNode): - raise TypeError('You must provide a document node.') + raise TypeError("You must provide a document node.") # If the schema used for validation is invalid, throw an error. assert_valid_schema(schema) if type_info is None: type_info = TypeInfo(schema) elif not isinstance(type_info, TypeInfo): - raise TypeError(f'Not a TypeInfo object: {type_info!r}') + raise TypeError(f"Not a TypeInfo object: {type_info!r}") if rules is None: rules = specified_rules elif not isinstance(rules, (list, tuple)): - raise TypeError('Rules must be passed as a list/tuple.') + raise TypeError("Rules must be passed as a list/tuple.") context = ValidationContext(schema, document_ast, type_info) # This uses a specialized visitor which runs multiple visitors in parallel, # while maintaining the visitor skip and break API. @@ -53,9 +54,11 @@ def validate(schema: GraphQLSchema, document_ast: DocumentNode, return context.errors -def validate_sdl(document_ast: DocumentNode, - schema_to_extend: GraphQLSchema=None, - rules: Sequence[RuleType]=None) -> List[GraphQLError]: +def validate_sdl( + document_ast: DocumentNode, + schema_to_extend: GraphQLSchema = None, + rules: Sequence[RuleType] = None, +) -> List[GraphQLError]: """Validate an SDL document.""" context = SDLValidationContext(document_ast, schema_to_extend) if rules is None: @@ -74,11 +77,12 @@ def assert_valid_sdl(document_ast: DocumentNode) -> None: errors = validate_sdl(document_ast) if errors: - raise TypeError('\n\n'.join(error.message for error in errors)) + raise TypeError("\n\n".join(error.message for error in errors)) def assert_valid_sdl_extension( - document_ast: DocumentNode, schema: GraphQLSchema) -> None: + document_ast: DocumentNode, schema: GraphQLSchema +) -> None: """Assert document is a valid SDL extension. Utility function which asserts a SDL document is valid by throwing an error @@ -87,4 +91,4 @@ def assert_valid_sdl_extension( errors = validate_sdl(document_ast, schema) if errors: - raise TypeError('\n\n'.join(error.message for error in errors)) + raise TypeError("\n\n".join(error.message for error in errors)) diff --git a/graphql/validation/validation_context.py b/graphql/validation/validation_context.py index 4c3296a8..0cc95221 100644 --- a/graphql/validation/validation_context.py +++ b/graphql/validation/validation_context.py @@ -2,15 +2,26 @@ from ..error import GraphQLError from ..language import ( - DocumentNode, FragmentDefinitionNode, FragmentSpreadNode, - OperationDefinitionNode, SelectionSetNode, TypeInfoVisitor, - VariableNode, Visitor, visit) + DocumentNode, + FragmentDefinitionNode, + FragmentSpreadNode, + OperationDefinitionNode, + SelectionSetNode, + TypeInfoVisitor, + VariableNode, + Visitor, + visit, +) from ..type import GraphQLSchema, GraphQLInputType from ..utilities import TypeInfo __all__ = [ - 'ASTValidationContext', 'SDLValidationContext', 'ValidationContext', - 'VariableUsage', 'VariableUsageVisitor'] + "ASTValidationContext", + "SDLValidationContext", + "ValidationContext", + "VariableUsage", + "VariableUsageVisitor", +] NodeWithSelectionSet = Union[OperationDefinitionNode, FragmentDefinitionNode] @@ -37,7 +48,8 @@ def enter_variable_definition(self, *_args): def enter_variable(self, node, *_args): type_info = self._type_info usage = VariableUsage( - node, type_info.get_input_type(), type_info.get_default_value()) + node, type_info.get_input_type(), type_info.get_default_value() + ) self._append_usage(usage) @@ -70,7 +82,7 @@ class SDLValidationContext(ASTValidationContext): schema: Optional[GraphQLSchema] - def __init__(self, ast: DocumentNode, schema: GraphQLSchema=None) -> None: + def __init__(self, ast: DocumentNode, schema: GraphQLSchema = None) -> None: super().__init__(ast) self.schema = schema @@ -85,20 +97,21 @@ class ValidationContext(ASTValidationContext): schema: GraphQLSchema - def __init__(self, schema: GraphQLSchema, - ast: DocumentNode, type_info: TypeInfo) -> None: + def __init__( + self, schema: GraphQLSchema, ast: DocumentNode, type_info: TypeInfo + ) -> None: super().__init__(ast) self.schema = schema self._type_info = type_info self._fragments: Optional[Dict[str, FragmentDefinitionNode]] = None - self._fragment_spreads: Dict[ - SelectionSetNode, List[FragmentSpreadNode]] = {} + self._fragment_spreads: Dict[SelectionSetNode, List[FragmentSpreadNode]] = {} self._recursively_referenced_fragments: Dict[ - OperationDefinitionNode, List[FragmentDefinitionNode]] = {} - self._variable_usages: Dict[ - NodeWithSelectionSet, List[VariableUsage]] = {} + OperationDefinitionNode, List[FragmentDefinitionNode] + ] = {} + self._variable_usages: Dict[NodeWithSelectionSet, List[VariableUsage]] = {} self._recursive_variable_usages: Dict[ - OperationDefinitionNode, List[VariableUsage]] = {} + OperationDefinitionNode, List[VariableUsage] + ] = {} def get_fragment(self, name: str) -> Optional[FragmentDefinitionNode]: fragments = self._fragments @@ -110,8 +123,7 @@ def get_fragment(self, name: str) -> Optional[FragmentDefinitionNode]: self._fragments = fragments return fragments.get(name) - def get_fragment_spreads( - self, node: SelectionSetNode) -> List[FragmentSpreadNode]: + def get_fragment_spreads(self, node: SelectionSetNode) -> List[FragmentSpreadNode]: spreads = self._fragment_spreads.get(node) if spreads is None: spreads = [] @@ -126,15 +138,16 @@ def get_fragment_spreads( append_spread(selection) else: set_to_visit = cast( - NodeWithSelectionSet, selection).selection_set + NodeWithSelectionSet, selection + ).selection_set if set_to_visit: append_set(set_to_visit) self._fragment_spreads[node] = spreads return spreads def get_recursively_referenced_fragments( - self, operation: OperationDefinitionNode - ) -> List[FragmentDefinitionNode]: + self, operation: OperationDefinitionNode + ) -> List[FragmentDefinitionNode]: fragments = self._recursively_referenced_fragments.get(operation) if fragments is None: fragments = [] @@ -159,8 +172,7 @@ def get_recursively_referenced_fragments( self._recursively_referenced_fragments[operation] = fragments return fragments - def get_variable_usages( - self, node: NodeWithSelectionSet) -> List[VariableUsage]: + def get_variable_usages(self, node: NodeWithSelectionSet) -> List[VariableUsage]: usages = self._variable_usages.get(node) if usages is None: usage_visitor = VariableUsageVisitor(self._type_info) @@ -170,7 +182,8 @@ def get_variable_usages( return usages def get_recursive_variable_usages( - self, operation: OperationDefinitionNode) -> List[VariableUsage]: + self, operation: OperationDefinitionNode + ) -> List[VariableUsage]: usages = self._recursive_variable_usages.get(operation) if usages is None: get_variable_usages = self.get_variable_usages diff --git a/setup.py b/setup.py index f38f7139..50f5d734 100644 --- a/setup.py +++ b/setup.py @@ -1,45 +1,49 @@ from re import search from setuptools import setup, find_packages -with open('graphql/__init__.py') as init_file: - version = search("__version__ = '(.*)'", init_file.read()).group(1) +with open("graphql/__init__.py") as init_file: + version = search('__version__ = "(.*)"', init_file.read()).group(1) -with open('README.md') as readme_file: +with open("README.md") as readme_file: readme = readme_file.read() setup( - name='GraphQL-core-next', + name="GraphQL-core-next", version=version, - - description='GraphQL-core-next is a Python port of GraphQL.js,' - ' the JavaScript reference implementation for GraphQL.', + description="GraphQL-core-next is a Python port of GraphQL.js," + " the JavaScript reference implementation for GraphQL.", long_description=readme, - long_description_content_type='text/markdown', - keywords='graphql', - - url='https://github.com/graphql-python/graphql-core-next', - - author='Christoph Zwerschke', - author_email='cito@online.de', - license='MIT license', - + long_description_content_type="text/markdown", + keywords="graphql", + url="https://github.com/graphql-python/graphql-core-next", + author="Christoph Zwerschke", + author_email="cito@online.de", + license="MIT license", # PEP-561: https://www.python.org/dev/peps/pep-0561/ - package_data={'graphql': ['py.typed']}, - + package_data={"graphql": ["py.typed"]}, classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7'], - + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + ], install_requires=[], - python_requires='>=3.6', - test_suite='tests', + python_requires=">=3.6", + test_suite="tests", tests_require=[ - 'pytest', 'pytest-asyncio', 'pytest-cov', 'pytest-describe', - 'flake8', 'mypy', 'tox', 'python-coveralls'], - packages=find_packages(include=['graphql']), + "pytest", + "pytest-asyncio", + "pytest-cov", + "pytest-describe", + "flake8", + "mypy", + "tox", + "python-coveralls", + ], + packages=find_packages(include=["graphql"]), include_package_data=True, - zip_safe=False) + zip_safe=False, +) + diff --git a/tests/error/test_format_error.py b/tests/error/test_format_error.py index d7a7c3bb..e234f0d4 100644 --- a/tests/error/test_format_error.py +++ b/tests/error/test_format_error.py @@ -5,25 +5,35 @@ def describe_format_error(): - def throw_if_not_an_error(): with raises(ValueError): format_error(None) def format_graphql_error(): - source = Source(""" + source = Source( + """ query { something - }""") - path = ['one', 2] - extensions = {'ext': None} + }""" + ) + path = ["one", 2] + extensions = {"ext": None} error = GraphQLError( - 'test message', Node(), source, [14, 40], path, - ValueError('original'), extensions=extensions) + "test message", + Node(), + source, + [14, 40], + path, + ValueError("original"), + extensions=extensions, + ) assert error == { - 'message': 'test message', 'locations': [(2, 14), (3, 20)], - 'path': path, 'extensions': extensions} + "message": "test message", + "locations": [(2, 14), (3, 20)], + "path": path, + "extensions": extensions, + } def add_default_message(): error = format_error(GraphQLError(None)) - assert error['message'] == 'An unknown error occurred.' + assert error["message"] == "An unknown error occurred." diff --git a/tests/error/test_graphql_error.py b/tests/error/test_graphql_error.py index 602646b3..cb305cd6 100644 --- a/tests/error/test_graphql_error.py +++ b/tests/error/test_graphql_error.py @@ -3,100 +3,101 @@ def describe_graphql_error(): - def is_a_class_and_is_a_subclass_of_exception(): assert issubclass(GraphQLError, Exception) - assert isinstance(GraphQLError('msg'), GraphQLError) + assert isinstance(GraphQLError("msg"), GraphQLError) def has_a_name_message_and_stack_trace(): - e = GraphQLError('msg') - assert e.__class__.__name__ == 'GraphQLError' - assert e.message == 'msg' + e = GraphQLError("msg") + assert e.__class__.__name__ == "GraphQLError" + assert e.message == "msg" def stores_the_original_error(): - original = Exception('original') - e = GraphQLError('msg', original_error=original) - assert e.__class__.__name__ == 'GraphQLError' - assert e.message == 'msg' + original = Exception("original") + e = GraphQLError("msg", original_error=original) + assert e.__class__.__name__ == "GraphQLError" + assert e.message == "msg" assert e.original_error == original def converts_nodes_to_positions_and_locations(): - source = Source('{\n field\n}') + source = Source("{\n field\n}") ast = parse(source) # noinspection PyUnresolvedReferences field_node = ast.definitions[0].selection_set.selections[0] - e = GraphQLError('msg', [field_node]) + e = GraphQLError("msg", [field_node]) assert e.nodes == [field_node] assert e.source is source assert e.positions == [8] assert e.locations == [(2, 7)] def converts_single_node_to_positions_and_locations(): - source = Source('{\n field\n}') + source = Source("{\n field\n}") ast = parse(source) # noinspection PyUnresolvedReferences field_node = ast.definitions[0].selection_set.selections[0] - e = GraphQLError('msg', field_node) # Non-array value. + e = GraphQLError("msg", field_node) # Non-array value. assert e.nodes == [field_node] assert e.source is source assert e.positions == [8] assert e.locations == [(2, 7)] def converts_node_with_loc_start_zero_to_positions_and_locations(): - source = Source('{\n field\n}') + source = Source("{\n field\n}") ast = parse(source) operations_node = ast.definitions[0] - e = GraphQLError('msg', [operations_node]) + e = GraphQLError("msg", [operations_node]) assert e.nodes == [operations_node] assert e.source is source assert e.positions == [0] assert e.locations == [(1, 1)] def converts_source_and_positions_to_locations(): - source = Source('{\n field\n}') + source = Source("{\n field\n}") # noinspection PyArgumentEqualDefault - e = GraphQLError('msg', None, source, [10]) + e = GraphQLError("msg", None, source, [10]) assert e.nodes is None assert e.source is source assert e.positions == [10] assert e.locations == [(2, 9)] def serializes_to_include_message(): - e = GraphQLError('msg') - assert str(e) == 'msg' + e = GraphQLError("msg") + assert str(e) == "msg" assert repr(e) == "GraphQLError('msg')" def serializes_to_include_message_and_locations(): # noinspection PyUnresolvedReferences - node = parse('{ field }').definitions[0].selection_set.selections[0] - e = GraphQLError('msg', [node]) - assert 'msg' in str(e) - assert '(1:3)' in str(e) - assert repr(e) == ("GraphQLError('msg'," - " locations=[SourceLocation(line=1, column=3)])") + node = parse("{ field }").definitions[0].selection_set.selections[0] + e = GraphQLError("msg", [node]) + assert "msg" in str(e) + assert "(1:3)" in str(e) + assert repr(e) == ( + "GraphQLError('msg'," " locations=[SourceLocation(line=1, column=3)])" + ) def serializes_to_include_path(): - path = ['path', 3, 'to', 'field'] + path = ["path", 3, "to", "field"] # noinspection PyArgumentEqualDefault - e = GraphQLError('msg', None, None, None, path) + e = GraphQLError("msg", None, None, None, path) assert e.path is path - assert repr(e) == ("GraphQLError('msg'," - " path=['path', 3, 'to', 'field'])") + assert repr(e) == ("GraphQLError('msg'," " path=['path', 3, 'to', 'field'])") def default_error_formatter_includes_path(): - path = ['path', 3, 'to', 'field'] + path = ["path", 3, "to", "field"] # noinspection PyArgumentEqualDefault - e = GraphQLError('msg', None, None, None, path) + e = GraphQLError("msg", None, None, None, path) formatted = format_error(e) assert formatted == e.formatted - assert formatted == { - 'message': 'msg', 'locations': None, 'path': path} + assert formatted == {"message": "msg", "locations": None, "path": path} def default_error_formatter_includes_extension_fields(): # noinspection PyArgumentEqualDefault - e = GraphQLError('msg', None, None, None, None, None, {'foo': 'bar'}) + e = GraphQLError("msg", None, None, None, None, None, {"foo": "bar"}) formatted = format_error(e) assert formatted == e.formatted assert formatted == { - 'message': 'msg', 'locations': None, 'path': None, - 'extensions': {'foo': 'bar'}} + "message": "msg", + "locations": None, + "path": None, + "extensions": {"foo": "bar"}, + } diff --git a/tests/error/test_invalid.py b/tests/error/test_invalid.py index e368ea8e..b3add9ef 100644 --- a/tests/error/test_invalid.py +++ b/tests/error/test_invalid.py @@ -2,12 +2,11 @@ def describe_invalid(): - def has_repr(): - assert repr(INVALID) == '' + assert repr(INVALID) == "" def has_str(): - assert str(INVALID) == 'INVALID' + assert str(INVALID) == "INVALID" def as_bool_is_false(): assert bool(INVALID) is False diff --git a/tests/error/test_located_error.py b/tests/error/test_located_error.py index 15bd0b75..1904be2f 100644 --- a/tests/error/test_located_error.py +++ b/tests/error/test_located_error.py @@ -2,15 +2,14 @@ def describe_located_error(): - def passes_graphql_error_through(): - path = ['path', 3, 'to', 'field'] + path = ["path", 3, "to", "field"] # noinspection PyArgumentEqualDefault - e = GraphQLError('msg', None, None, None, path) + e = GraphQLError("msg", None, None, None, path) assert located_error(e, [], []) == e def passes_graphql_error_ish_through(): - e = Exception('I am an ordinary exception') + e = Exception("I am an ordinary exception") e.locations = [] e.path = [] e.nodes = [] @@ -19,6 +18,6 @@ def passes_graphql_error_ish_through(): assert located_error(e, [], []) == e def does_not_pass_through_elasticsearch_like_errors(): - e = Exception('I am from elasticsearch') - e.path = '/something/feed/_search' + e = Exception("I am from elasticsearch") + e.path = "/something/feed/_search" assert located_error(e, [], []) != e diff --git a/tests/error/test_print_error.py b/tests/error/test_print_error.py index a4c876a5..6cc319b4 100644 --- a/tests/error/test_print_error.py +++ b/tests/error/test_print_error.py @@ -1,8 +1,7 @@ from typing import cast from graphql.error import GraphQLError, print_error -from graphql.language import ( - parse, ObjectTypeDefinitionNode, Source, SourceLocation) +from graphql.language import parse, ObjectTypeDefinitionNode, Source, SourceLocation from graphql.pyutils import dedent @@ -11,48 +10,76 @@ def describe_print_error(): # noinspection PyArgumentEqualDefault def prints_line_numbers_with_correct_padding(): single_digit = GraphQLError( - 'Single digit line number with no padding', None, - Source('*', 'Test', SourceLocation(9, 1)), [0]) - assert print_error(single_digit) == dedent(""" + "Single digit line number with no padding", + None, + Source("*", "Test", SourceLocation(9, 1)), + [0], + ) + assert print_error(single_digit) == dedent( + """ Single digit line number with no padding Test (9:1) 9: * ^ - """) + """ + ) double_digit = GraphQLError( - 'Left padded first line number', None, - Source('*\n', 'Test', SourceLocation(9, 1)), [0]) + "Left padded first line number", + None, + Source("*\n", "Test", SourceLocation(9, 1)), + [0], + ) - assert print_error(double_digit) == dedent(""" + assert print_error(double_digit) == dedent( + """ Left padded first line number Test (9:1) 9: * ^ 10:\x20 - """) + """ + ) def prints_an_error_with_nodes_from_different_sources(): - source_a = parse(Source(dedent(""" + source_a = parse( + Source( + dedent( + """ type Foo { field: String } - """), 'SourceA')) - field_type_a = cast( - ObjectTypeDefinitionNode, source_a.definitions[0]).fields[0].type - source_b = parse(Source(dedent(""" + """ + ), + "SourceA", + ) + ) + field_type_a = ( + cast(ObjectTypeDefinitionNode, source_a.definitions[0]).fields[0].type + ) + source_b = parse( + Source( + dedent( + """ type Foo { field: Int } - """), 'SourceB')) - field_type_b = cast( - ObjectTypeDefinitionNode, source_b.definitions[0]).fields[0].type - error = GraphQLError('Example error with two nodes', - [field_type_a, field_type_b]) + """ + ), + "SourceB", + ) + ) + field_type_b = ( + cast(ObjectTypeDefinitionNode, source_b.definitions[0]).fields[0].type + ) + error = GraphQLError( + "Example error with two nodes", [field_type_a, field_type_b] + ) printed_error = print_error(error) - assert printed_error == dedent(""" + assert printed_error == dedent( + """ Example error with two nodes SourceA (2:10) @@ -66,5 +93,6 @@ def prints_an_error_with_nodes_from_different_sources(): 2: field: Int ^ 3: } - """) + """ + ) assert str(error) == printed_error diff --git a/tests/execution/test_abstract.py b/tests/execution/test_abstract.py index 8c6e2478..b98f4fb3 100644 --- a/tests/execution/test_abstract.py +++ b/tests/execution/test_abstract.py @@ -3,24 +3,32 @@ from graphql import graphql_sync from graphql.error import format_error from graphql.type import ( - GraphQLBoolean, GraphQLField, GraphQLInterfaceType, - GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, - GraphQLUnionType) + GraphQLBoolean, + GraphQLField, + GraphQLInterfaceType, + GraphQLList, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, + GraphQLUnionType, +) -Dog = namedtuple('Dog', 'name woofs') -Cat = namedtuple('Cat', 'name meows') -Human = namedtuple('Human', 'name') +Dog = namedtuple("Dog", "name woofs") +Cat = namedtuple("Cat", "name meows") +Human = namedtuple("Human", "name") def get_is_type_of(type_): def is_type_of(obj, _info): return isinstance(obj, type_) + return is_type_of def get_type_resolver(types): def resolve(obj, _info): return resolve_thunk(types).get(obj.__class__) + return resolve @@ -29,27 +37,44 @@ def resolve_thunk(thunk): def describe_execute_handles_synchronous_execution_of_abstract_types(): - def is_type_of_used_to_resolve_runtime_type_for_interface(): - PetType = GraphQLInterfaceType('Pet', { - 'name': GraphQLField(GraphQLString)}) + PetType = GraphQLInterfaceType("Pet", {"name": GraphQLField(GraphQLString)}) - DogType = GraphQLObjectType('Dog', { - 'name': GraphQLField(GraphQLString), - 'woofs': GraphQLField(GraphQLBoolean)}, + DogType = GraphQLObjectType( + "Dog", + { + "name": GraphQLField(GraphQLString), + "woofs": GraphQLField(GraphQLBoolean), + }, interfaces=[PetType], - is_type_of=get_is_type_of(Dog)) + is_type_of=get_is_type_of(Dog), + ) - CatType = GraphQLObjectType('Cat', { - 'name': GraphQLField(GraphQLString), - 'meows': GraphQLField(GraphQLBoolean)}, + 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]) + 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 = """ { @@ -66,26 +91,51 @@ def is_type_of_used_to_resolve_runtime_type_for_interface(): """ result = graphql_sync(schema, query) - assert result == ({'pets': [ - {'name': 'Odie', 'woofs': True}, - {'name': 'Garfield', 'meows': False}]}, None) + assert result == ( + { + "pets": [ + {"name": "Odie", "woofs": True}, + {"name": "Garfield", "meows": False}, + ] + }, + None, + ) 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)])})) + 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 = """ { @@ -103,33 +153,61 @@ def is_type_of_used_to_resolve_runtime_type_for_union(): """ result = graphql_sync(schema, query) - assert result == ({'pets': [ - {'name': 'Odie', 'woofs': True}, - {'name': 'Garfield', 'meows': False}]}, None) + assert result == ( + { + "pets": [ + {"name": "Odie", "woofs": True}, + {"name": "Garfield", "meows": False}, + ] + }, + None, + ) def resolve_type_on_interface_yields_useful_error(): - PetType = GraphQLInterfaceType('Pet', { - 'name': GraphQLField(GraphQLString)}, - resolve_type=get_type_resolver(lambda: { - Dog: DogType, Cat: CatType, Human: HumanType})) - - HumanType = GraphQLObjectType('Human', { - 'name': GraphQLField(GraphQLString)}) - - DogType = GraphQLObjectType('Dog', { - 'name': GraphQLField(GraphQLString), - 'woofs': GraphQLField(GraphQLBoolean)}, - interfaces=[PetType]) - - CatType = GraphQLObjectType('Cat', { - 'name': GraphQLField(GraphQLString), - 'meows': GraphQLField(GraphQLBoolean)}, - interfaces=[PetType]) + PetType = GraphQLInterfaceType( + "Pet", + {"name": GraphQLField(GraphQLString)}, + resolve_type=get_type_resolver( + lambda: {Dog: DogType, Cat: CatType, Human: HumanType} + ), + ) + + HumanType = GraphQLObjectType("Human", {"name": GraphQLField(GraphQLString)}) + + DogType = GraphQLObjectType( + "Dog", + { + "name": GraphQLField(GraphQLString), + "woofs": GraphQLField(GraphQLBoolean), + }, + interfaces=[PetType], + ) - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'pets': GraphQLField(GraphQLList(PetType), resolve=lambda *_args: [ - Dog('Odie', True), Cat('Garfield', False), Human('Jon')])}), - types=[CatType, DogType]) + CatType = GraphQLObjectType( + "Cat", + { + "name": GraphQLField(GraphQLString), + "meows": GraphQLField(GraphQLBoolean), + }, + interfaces=[PetType], + ) + + schema = GraphQLSchema( + GraphQLObjectType( + "Query", + { + "pets": GraphQLField( + GraphQLList(PetType), + resolve=lambda *_args: [ + Dog("Odie", True), + Cat("Garfield", False), + Human("Jon"), + ], + ) + }, + ), + types=[CatType, DogType], + ) query = """ { @@ -146,36 +224,64 @@ def resolve_type_on_interface_yields_useful_error(): """ result = graphql_sync(schema, query) - assert result.data == {'pets': [ - {'name': 'Odie', 'woofs': True}, - {'name': 'Garfield', 'meows': False}, None]} + 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]} + "message": "Runtime Object type 'Human'" + " is not a possible type for 'Pet'.", + "locations": [(3, 15)], + "path": ["pets", 2], + } def resolve_type_on_union_yields_useful_error(): - HumanType = GraphQLObjectType('Human', { - 'name': GraphQLField(GraphQLString)}) + 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})) + DogType = GraphQLObjectType( + "Dog", + { + "name": GraphQLField(GraphQLString), + "woofs": GraphQLField(GraphQLBoolean), + }, + ) - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'pets': GraphQLField(GraphQLList(PetType), resolve=lambda *_: [ - Dog('Odie', True), Cat('Garfield', False), Human('Jon')])})) + 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 = """ { @@ -193,61 +299,95 @@ def resolve_type_on_union_yields_useful_error(): """ result = graphql_sync(schema, query) - assert result.data == {'pets': [ - {'name': 'Odie', 'woofs': True}, - {'name': 'Garfield', 'meows': False}, None]} + 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]} + "message": "Runtime Object type 'Human'" + " is not a possible type for 'Pet'.", + "locations": [(3, 15)], + "path": ["pets", 2], + } def returning_invalid_value_from_resolve_type_yields_useful_error(): - fooInterface = GraphQLInterfaceType('FooInterface', { - 'bar': GraphQLField(GraphQLString)}, - resolve_type=lambda *_args: []) - - fooObject = GraphQLObjectType('FooObject', { - 'bar': GraphQLField(GraphQLString)}, - interfaces=[fooInterface]) - - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'foo': GraphQLField( - fooInterface, resolve=lambda *_args: 'dummy')}), - types=[fooObject]) - - result = graphql_sync(schema, '{ foo { bar } }') - - assert result == ({'foo': None}, [{ - 'message': - 'Abstract type FooInterface must resolve to an Object type' - " at runtime for field Query.foo with value 'dummy'," - " received '[]'. Either the FooInterface type should provide" - ' a "resolve_type" function or each possible type' - ' should provide an "is_type_of" function.', - 'locations': [(1, 3)], 'path': ['foo']}]) + fooInterface = GraphQLInterfaceType( + "FooInterface", + {"bar": GraphQLField(GraphQLString)}, + resolve_type=lambda *_args: [], + ) + + fooObject = GraphQLObjectType( + "FooObject", {"bar": GraphQLField(GraphQLString)}, interfaces=[fooInterface] + ) + + schema = GraphQLSchema( + GraphQLObjectType( + "Query", + {"foo": GraphQLField(fooInterface, resolve=lambda *_args: "dummy")}, + ), + types=[fooObject], + ) + + result = graphql_sync(schema, "{ foo { bar } }") + + assert result == ( + {"foo": None}, + [ + { + "message": "Abstract type FooInterface must resolve to an" + " Object type at runtime for field Query.foo with value 'dummy'," + " received '[]'. Either the FooInterface type should provide" + ' a "resolve_type" function or each possible type' + ' should provide an "is_type_of" function.', + "locations": [(1, 3)], + "path": ["foo"], + } + ], + ) 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]) + 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 = """ { @@ -263,6 +403,12 @@ def resolve_type_allows_resolving_with_type_name(): }""" result = graphql_sync(schema, query) - assert result == ({'pets': [ - {'name': 'Odie', 'woofs': True}, - {'name': 'Garfield', 'meows': False}]}, None) + assert result == ( + { + "pets": [ + {"name": "Odie", "woofs": True}, + {"name": "Garfield", "meows": False}, + ] + }, + None, + ) diff --git a/tests/execution/test_abstract_async.py b/tests/execution/test_abstract_async.py index 0d59528d..1159cb4c 100644 --- a/tests/execution/test_abstract_async.py +++ b/tests/execution/test_abstract_async.py @@ -5,28 +5,36 @@ from graphql import graphql from graphql.error import format_error from graphql.type import ( - GraphQLBoolean, GraphQLField, GraphQLInterfaceType, - GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, - GraphQLUnionType) + GraphQLBoolean, + GraphQLField, + GraphQLInterfaceType, + GraphQLList, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, + GraphQLUnionType, +) -Dog = namedtuple('Dog', 'name woofs') -Cat = namedtuple('Cat', 'name meows') -Human = namedtuple('Human', 'name') +Dog = namedtuple("Dog", "name woofs") +Cat = namedtuple("Cat", "name meows") +Human = namedtuple("Human", "name") async def is_type_of_error(*_args): - raise RuntimeError('We are testing this error') + raise RuntimeError("We are testing this error") def get_is_type_of(type_): async def is_type_of(obj, _info): return isinstance(obj, type_) + return is_type_of def get_type_resolver(types): async def resolve(obj, _info): return resolve_thunk(types).get(obj.__class__) + return resolve @@ -35,28 +43,45 @@ def resolve_thunk(thunk): def describe_execute_handles_asynchronous_execution_of_abstract_types(): - @mark.asyncio async def is_type_of_used_to_resolve_runtime_type_for_interface(): - PetType = GraphQLInterfaceType('Pet', { - 'name': GraphQLField(GraphQLString)}) + PetType = GraphQLInterfaceType("Pet", {"name": GraphQLField(GraphQLString)}) - DogType = GraphQLObjectType('Dog', { - 'name': GraphQLField(GraphQLString), - 'woofs': GraphQLField(GraphQLBoolean)}, + DogType = GraphQLObjectType( + "Dog", + { + "name": GraphQLField(GraphQLString), + "woofs": GraphQLField(GraphQLBoolean), + }, interfaces=[PetType], - is_type_of=get_is_type_of(Dog)) + is_type_of=get_is_type_of(Dog), + ) - CatType = GraphQLObjectType('Cat', { - 'name': GraphQLField(GraphQLString), - 'meows': GraphQLField(GraphQLBoolean)}, + 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]) + 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 = """ { @@ -73,31 +98,55 @@ async def is_type_of_used_to_resolve_runtime_type_for_interface(): """ result = await graphql(schema, query) - assert result == ({'pets': [ - {'name': 'Odie', 'woofs': True}, - {'name': 'Garfield', 'meows': False}]}, None) + assert result == ( + { + "pets": [ + {"name": "Odie", "woofs": True}, + {"name": "Garfield", "meows": False}, + ] + }, + None, + ) @mark.asyncio async def is_type_of_with_async_error(): - PetType = GraphQLInterfaceType('Pet', { - 'name': GraphQLField(GraphQLString)}) + PetType = GraphQLInterfaceType("Pet", {"name": GraphQLField(GraphQLString)}) - DogType = GraphQLObjectType('Dog', { - 'name': GraphQLField(GraphQLString), - 'woofs': GraphQLField(GraphQLBoolean)}, + DogType = GraphQLObjectType( + "Dog", + { + "name": GraphQLField(GraphQLString), + "woofs": GraphQLField(GraphQLBoolean), + }, interfaces=[PetType], - is_type_of=is_type_of_error) + is_type_of=is_type_of_error, + ) - CatType = GraphQLObjectType('Cat', { - 'name': GraphQLField(GraphQLString), - 'meows': GraphQLField(GraphQLBoolean)}, + 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]) + 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 = """ { @@ -116,30 +165,56 @@ async def is_type_of_with_async_error(): 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]}] + 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], + }, + ] @mark.asyncio 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)])})) + 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 = """ { @@ -157,34 +232,62 @@ async def is_type_of_used_to_resolve_runtime_type_for_union(): """ result = await graphql(schema, query) - assert result == ({'pets': [ - {'name': 'Odie', 'woofs': True}, - {'name': 'Garfield', 'meows': False}]}, None) + assert result == ( + { + "pets": [ + {"name": "Odie", "woofs": True}, + {"name": "Garfield", "meows": False}, + ] + }, + None, + ) @mark.asyncio async def resolve_type_on_interface_yields_useful_error(): - PetType = GraphQLInterfaceType('Pet', { - 'name': GraphQLField(GraphQLString)}, - resolve_type=get_type_resolver(lambda: { - Dog: DogType, Cat: CatType, Human: HumanType})) - - HumanType = GraphQLObjectType('Human', { - 'name': GraphQLField(GraphQLString)}) - - DogType = GraphQLObjectType('Dog', { - 'name': GraphQLField(GraphQLString), - 'woofs': GraphQLField(GraphQLBoolean)}, - interfaces=[PetType]) - - CatType = GraphQLObjectType('Cat', { - 'name': GraphQLField(GraphQLString), - 'meows': GraphQLField(GraphQLBoolean)}, - interfaces=[PetType]) + PetType = GraphQLInterfaceType( + "Pet", + {"name": GraphQLField(GraphQLString)}, + resolve_type=get_type_resolver( + lambda: {Dog: DogType, Cat: CatType, Human: HumanType} + ), + ) + + HumanType = GraphQLObjectType("Human", {"name": GraphQLField(GraphQLString)}) + + DogType = GraphQLObjectType( + "Dog", + { + "name": GraphQLField(GraphQLString), + "woofs": GraphQLField(GraphQLBoolean), + }, + interfaces=[PetType], + ) - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'pets': GraphQLField(GraphQLList(PetType), resolve=lambda *_args: [ - Dog('Odie', True), Cat('Garfield', False), Human('Jon')])}), - types=[CatType, DogType]) + CatType = GraphQLObjectType( + "Cat", + { + "name": GraphQLField(GraphQLString), + "meows": GraphQLField(GraphQLBoolean), + }, + interfaces=[PetType], + ) + + schema = GraphQLSchema( + GraphQLObjectType( + "Query", + { + "pets": GraphQLField( + GraphQLList(PetType), + resolve=lambda *_args: [ + Dog("Odie", True), + Cat("Garfield", False), + Human("Jon"), + ], + ) + }, + ), + types=[CatType, DogType], + ) query = """ { @@ -201,37 +304,65 @@ async def resolve_type_on_interface_yields_useful_error(): """ result = await graphql(schema, query) - assert result.data == {'pets': [ - {'name': 'Odie', 'woofs': True}, - {'name': 'Garfield', 'meows': False}, None]} + 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]} + "message": "Runtime Object type 'Human'" + " is not a possible type for 'Pet'.", + "locations": [(3, 15)], + "path": ["pets", 2], + } @mark.asyncio 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)}) + HumanType = GraphQLObjectType("Human", {"name": GraphQLField(GraphQLString)}) - PetType = GraphQLUnionType('Pet', [ - DogType, CatType], - resolve_type=get_type_resolver({ - Dog: DogType, Cat: CatType, Human: HumanType})) + DogType = GraphQLObjectType( + "Dog", + { + "name": GraphQLField(GraphQLString), + "woofs": GraphQLField(GraphQLBoolean), + }, + ) - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'pets': GraphQLField(GraphQLList(PetType), resolve=lambda *_: [ - Dog('Odie', True), Cat('Garfield', False), Human('Jon')])})) + 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 = """ { @@ -249,37 +380,60 @@ async def resolve_type_on_union_yields_useful_error(): """ result = await graphql(schema, query) - assert result.data == {'pets': [ - {'name': 'Odie', 'woofs': True}, - {'name': 'Garfield', 'meows': False}, None]} + 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]} + "message": "Runtime Object type 'Human'" + " is not a possible type for 'Pet'.", + "locations": [(3, 15)], + "path": ["pets", 2], + } @mark.asyncio async def resolve_type_allows_resolving_with_type_name(): - PetType = GraphQLInterfaceType('Pet', { - 'name': GraphQLField(GraphQLString)}, - resolve_type=get_type_resolver({ - Dog: 'Dog', Cat: 'Cat'})) - - DogType = GraphQLObjectType('Dog', { - 'name': GraphQLField(GraphQLString), - 'woofs': GraphQLField(GraphQLBoolean)}, - interfaces=[PetType]) - - CatType = GraphQLObjectType('Cat', { - 'name': GraphQLField(GraphQLString), - 'meows': GraphQLField(GraphQLBoolean)}, - interfaces=[PetType]) - - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'pets': GraphQLField(GraphQLList(PetType), resolve=lambda *_: [ - Dog('Odie', True), Cat('Garfield', False)])}), - types=[CatType, DogType]) + 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 = """ { @@ -295,6 +449,12 @@ async def resolve_type_allows_resolving_with_type_name(): }""" result = await graphql(schema, query) - assert result == ({'pets': [ - {'name': 'Odie', 'woofs': True}, - {'name': 'Garfield', 'meows': False}]}, None) + assert result == ( + { + "pets": [ + {"name": "Odie", "woofs": True}, + {"name": "Garfield", "meows": False}, + ] + }, + None, + ) diff --git a/tests/execution/test_directives.py b/tests/execution/test_directives.py index 759e6b2a..2613e00b 100644 --- a/tests/execution/test_directives.py +++ b/tests/execution/test_directives.py @@ -3,19 +3,20 @@ from graphql.language import parse from graphql.type import GraphQLObjectType, GraphQLField, GraphQLString -schema = GraphQLSchema(GraphQLObjectType('TestType', { - 'a': GraphQLField(GraphQLString), - 'b': GraphQLField(GraphQLString)})) +schema = GraphQLSchema( + GraphQLObjectType( + "TestType", {"a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString)} + ) +) # noinspection PyMethodMayBeStatic class Data: - def a(self, *_args): - return 'a' + return "a" def b(self, *_args): - return 'b' + return "b" def execute_test_query(doc): @@ -23,35 +24,32 @@ def execute_test_query(doc): def describe_execute_handles_directives(): - def describe_works_without_directives(): - def basic_query_works(): - result = execute_test_query('{ a, b }') - assert result == ({'a': 'a', 'b': 'b'}, None) + result = execute_test_query("{ a, b }") + assert result == ({"a": "a", "b": "b"}, None) def describe_works_on_scalars(): - def if_true_includes_scalar(): - result = execute_test_query('{ a, b @include(if: true) }') - assert result == ({'a': 'a', 'b': 'b'}, None) + result = execute_test_query("{ a, b @include(if: true) }") + assert result == ({"a": "a", "b": "b"}, None) def if_false_omits_on_scalar(): - result = execute_test_query('{ a, b @include(if: false) }') - assert result == ({'a': 'a'}, None) + result = execute_test_query("{ a, b @include(if: false) }") + assert result == ({"a": "a"}, None) def unless_false_includes_scalar(): - result = execute_test_query('{ a, b @skip(if: false) }') - assert result == ({'a': 'a', 'b': 'b'}, None) + result = execute_test_query("{ a, b @skip(if: false) }") + assert result == ({"a": "a", "b": "b"}, None) def unless_true_omits_scalar(): - result = execute_test_query('{ a, b @skip(if: true) }') - assert result == ({'a': 'a'}, None) + result = execute_test_query("{ a, b @skip(if: true) }") + assert result == ({"a": "a"}, None) def describe_works_on_fragment_spreads(): - def if_false_omits_fragment_spread(): - result = execute_test_query(""" + result = execute_test_query( + """ query Q { a ...Frag @include(if: false) @@ -59,11 +57,13 @@ def if_false_omits_fragment_spread(): fragment Frag on TestType { b } - """) - assert result == ({'a': 'a'}, None) + """ + ) + assert result == ({"a": "a"}, None) def if_true_includes_fragment_spread(): - result = execute_test_query(""" + result = execute_test_query( + """ query Q { a ...Frag @include(if: true) @@ -71,11 +71,13 @@ def if_true_includes_fragment_spread(): fragment Frag on TestType { b } - """) - assert result == ({'a': 'a', 'b': 'b'}, None) + """ + ) + assert result == ({"a": "a", "b": "b"}, None) def unless_false_includes_fragment_spread(): - result = execute_test_query(""" + result = execute_test_query( + """ query Q { a ...Frag @skip(if: false) @@ -83,11 +85,13 @@ def unless_false_includes_fragment_spread(): fragment Frag on TestType { b } - """) - assert result == ({'a': 'a', 'b': 'b'}, None) + """ + ) + assert result == ({"a": "a", "b": "b"}, None) def unless_true_omits_fragment_spread(): - result = execute_test_query(""" + result = execute_test_query( + """ query Q { a ...Frag @skip(if: true) @@ -95,126 +99,146 @@ def unless_true_omits_fragment_spread(): fragment Frag on TestType { b } - """) - assert result == ({'a': 'a'}, None) + """ + ) + assert result == ({"a": "a"}, None) def describe_works_on_inline_fragment(): - def if_false_omits_inline_fragment(): - result = execute_test_query(""" + result = execute_test_query( + """ query Q { a ... on TestType @include(if: false) { b } } - """) - assert result == ({'a': 'a'}, None) + """ + ) + assert result == ({"a": "a"}, None) def if_true_includes_inline_fragment(): - result = execute_test_query(""" + result = execute_test_query( + """ query Q { a ... on TestType @include(if: true) { b } } - """) - assert result == ({'a': 'a', 'b': 'b'}, None) + """ + ) + assert result == ({"a": "a", "b": "b"}, None) def unless_false_includes_inline_fragment(): - result = execute_test_query(""" + result = execute_test_query( + """ query Q { a ... on TestType @skip(if: false) { b } } - """) - assert result == ({'a': 'a', 'b': 'b'}, None) + """ + ) + assert result == ({"a": "a", "b": "b"}, None) def unless_true_omits_inline_fragment(): - result = execute_test_query(""" + result = execute_test_query( + """ query Q { a ... on TestType @skip(if: true) { b } } - """) - assert result == ({'a': 'a'}, None) + """ + ) + assert result == ({"a": "a"}, None) def describe_works_on_anonymous_inline_fragment(): - def if_false_omits_anonymous_inline_fragment(): - result = execute_test_query(""" + result = execute_test_query( + """ query { a ... @include(if: false) { b } } - """) - assert result == ({'a': 'a'}, None) + """ + ) + assert result == ({"a": "a"}, None) def if_true_includes_anonymous_inline_fragment(): - result = execute_test_query(""" + result = execute_test_query( + """ query { a ... @include(if: true) { b } } - """) - assert result == ({'a': 'a', 'b': 'b'}, None) + """ + ) + assert result == ({"a": "a", "b": "b"}, None) def unless_false_includes_anonymous_inline_fragment(): - result = execute_test_query(""" + result = execute_test_query( + """ query { a ... @skip(if: false) { b } } - """) - assert result == ({'a': 'a', 'b': 'b'}, None) + """ + ) + assert result == ({"a": "a", "b": "b"}, None) def unless_true_omits_anonymous_inline_fragment(): - result = execute_test_query(""" + result = execute_test_query( + """ query { a ... @skip(if: true) { b } } - """) - assert result == ({'a': 'a'}, None) + """ + ) + assert result == ({"a": "a"}, None) def describe_works_with_skip_and_include_directives(): - def include_and_no_skip(): - result = execute_test_query(""" + result = execute_test_query( + """ { a b @include(if: true) @skip(if: false) } - """) - assert result == ({'a': 'a', 'b': 'b'}, None) + """ + ) + assert result == ({"a": "a", "b": "b"}, None) def include_and_skip(): - result = execute_test_query(""" + result = execute_test_query( + """ { a b @include(if: true) @skip(if: true) } - """) - assert result == ({'a': 'a'}, None) + """ + ) + assert result == ({"a": "a"}, None) def no_include_or_skip(): - result = execute_test_query(""" + result = execute_test_query( + """ { a b @include(if: false) @skip(if: false) } - """) - assert result == ({'a': 'a'}, None) + """ + ) + assert result == ({"a": "a"}, None) diff --git a/tests/execution/test_executor.py b/tests/execution/test_executor.py index 3246880a..4da2f6be 100644 --- a/tests/execution/test_executor.py +++ b/tests/execution/test_executor.py @@ -8,67 +8,85 @@ from graphql.execution import execute from graphql.language import parse, OperationDefinitionNode, FieldNode from graphql.type import ( - GraphQLSchema, GraphQLObjectType, GraphQLString, - GraphQLField, GraphQLArgument, GraphQLInt, GraphQLList, GraphQLNonNull, - GraphQLBoolean, GraphQLResolveInfo, ResponsePath) + GraphQLSchema, + GraphQLObjectType, + GraphQLString, + GraphQLField, + GraphQLArgument, + GraphQLInt, + GraphQLList, + GraphQLNonNull, + GraphQLBoolean, + GraphQLResolveInfo, + ResponsePath, +) def describe_execute_handles_basic_execution_tasks(): # noinspection PyTypeChecker def throws_if_no_document_is_provided(): - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString)})) + schema = GraphQLSchema( + GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) + ) with raises(TypeError) as exc_info: assert execute(schema, None) - assert str(exc_info.value) == 'Must provide document' + assert str(exc_info.value) == "Must provide document" # noinspection PyTypeChecker def throws_if_no_schema_is_provided(): with raises(TypeError) as exc_info: - assert execute(schema=None, document=parse('{ field }')) + assert execute(schema=None, document=parse("{ field }")) - assert str(exc_info.value) == 'Expected None to be a GraphQL schema.' + assert str(exc_info.value) == "Expected None to be a GraphQL schema." def accepts_an_object_with_named_properties_as_arguments(): - doc = 'query Example { a }' + doc = "query Example { a }" - data = 'rootValue' + data = "rootValue" - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString, - resolve=lambda root_value, *args: root_value)})) + schema = GraphQLSchema( + GraphQLObjectType( + "Type", + { + "a": GraphQLField( + GraphQLString, resolve=lambda root_value, *args: root_value + ) + }, + ) + ) assert execute(schema, document=parse(doc), root_value=data) == ( - {'a': 'rootValue'}, None) + {"a": "rootValue"}, + None, + ) @mark.asyncio async def executes_arbitrary_code(): # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class Data: - def a(self, _info): - return 'Apple' + return "Apple" def b(self, _info): - return 'Banana' + return "Banana" def c(self, _info): - return 'Cookie' + return "Cookie" def d(self, _info): - return 'Donut' + return "Donut" def e(self, _info): - return 'Egg' + return "Egg" - f = 'Fish' + f = "Fish" def pic(self, _info, size=50): - return f'Pic of size: {size}' + return f"Pic of size: {size}" def deep(self, _info): return DeepData() @@ -78,15 +96,14 @@ def promise(self, _info): # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class DeepData: - def a(self, _info): - return 'Already Been Done' + return "Already Been Done" def b(self, _info): - return 'Boring' + return "Boring" def c(self, _info): - return ['Contrived', None, 'Confusing'] + return ["Contrived", None, "Confusing"] def deeper(self, _info): return [Data(), None, Data()] @@ -126,52 +143,75 @@ async def promise_data(): """ 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)}) + 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 + assert ( + await execute( + schema, + ast, + Data(), + variable_values={"size": 100}, + operation_name="Example", + ) + == expected + ) def merges_parallel_fragments(): - ast = parse(""" + ast = parse( + """ { a, ...FragOne, ...FragTwo } fragment FragOne on Type { @@ -183,63 +223,90 @@ def merges_parallel_fragments(): c deep { c, deeper: deep { c } } } - """) - - Type = GraphQLObjectType('Type', lambda: { - 'a': GraphQLField(GraphQLString, resolve=lambda *_args: 'Apple'), - 'b': GraphQLField(GraphQLString, resolve=lambda *_args: 'Banana'), - 'c': GraphQLField(GraphQLString, resolve=lambda *_args: 'Cherry'), - 'deep': GraphQLField(Type, resolve=lambda *_args: {})}) + """ + ) + + Type = GraphQLObjectType( + "Type", + lambda: { + "a": GraphQLField(GraphQLString, resolve=lambda *_args: "Apple"), + "b": GraphQLField(GraphQLString, resolve=lambda *_args: "Banana"), + "c": GraphQLField(GraphQLString, resolve=lambda *_args: "Cherry"), + "deep": GraphQLField(Type, resolve=lambda *_args: {}), + }, + ) schema = GraphQLSchema(Type) - assert execute(schema, ast) == ({ - 'a': 'Apple', 'b': 'Banana', 'c': 'Cherry', 'deep': { - 'b': 'Banana', 'c': 'Cherry', 'deeper': { - 'b': 'Banana', 'c': 'Cherry'}}}, None) + assert execute(schema, ast) == ( + { + "a": "Apple", + "b": "Banana", + "c": "Cherry", + "deep": { + "b": "Banana", + "c": "Cherry", + "deeper": {"b": "Banana", "c": "Cherry"}, + }, + }, + None, + ) def provides_info_about_current_execution_state(): - ast = parse('query ($var: String) { result: test }') + ast = parse("query ($var: String) { result: test }") infos = [] def resolve(_obj, info): infos.append(info) - schema = GraphQLSchema(GraphQLObjectType('Test', { - 'test': GraphQLField(GraphQLString, resolve=resolve)})) + schema = GraphQLSchema( + GraphQLObjectType( + "Test", {"test": GraphQLField(GraphQLString, resolve=resolve)} + ) + ) - root_value = {'root': 'val'} + root_value = {"root": "val"} - execute(schema, ast, root_value, variable_values={'var': 'abc'}) + execute(schema, ast, root_value, variable_values={"var": "abc"}) assert len(infos) == 1 operation = cast(OperationDefinitionNode, ast.definitions[0]) field = cast(FieldNode, operation.selection_set.selections[0]) assert infos[0] == GraphQLResolveInfo( - field_name='test', field_nodes=[field], - return_type=GraphQLString, parent_type=schema.query_type, - path=ResponsePath(None, 'result'), schema=schema, - fragments={}, root_value=root_value, operation=operation, - variable_values={'var': 'abc'}, context=None) + field_name="test", + field_nodes=[field], + return_type=GraphQLString, + parent_type=schema.query_type, + path=ResponsePath(None, "result"), + schema=schema, + fragments={}, + root_value=root_value, + operation=operation, + variable_values={"var": "abc"}, + context=None, + ) def threads_root_value_context_correctly(): - doc = 'query Example { a }' + doc = "query Example { a }" class Data: - context_thing = 'thing' + context_thing = "thing" resolved_values = [] def resolve(obj, _info): resolved_values.append(obj) - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString, resolve=resolve)})) + schema = GraphQLSchema( + GraphQLObjectType( + "Type", {"a": GraphQLField(GraphQLString, resolve=resolve)} + ) + ) execute(schema, parse(doc), Data()) assert len(resolved_values) == 1 - assert resolved_values[0].context_thing == 'thing' + assert resolved_values[0].context_thing == "thing" def correctly_threads_arguments(): doc = """ @@ -253,16 +320,26 @@ def correctly_threads_arguments(): def resolve(_obj, _info, **args): resolved_args.append(args) - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'b': GraphQLField(GraphQLString, args={ - 'numArg': GraphQLArgument(GraphQLInt), - 'stringArg': GraphQLArgument(GraphQLString)}, - resolve=resolve)})) + schema = GraphQLSchema( + GraphQLObjectType( + "Type", + { + "b": GraphQLField( + GraphQLString, + args={ + "numArg": GraphQLArgument(GraphQLInt), + "stringArg": GraphQLArgument(GraphQLString), + }, + resolve=resolve, + ) + }, + ) + ) execute(schema, parse(doc)) assert len(resolved_args) == 1 - assert resolved_args[0] == {'numArg': 123, 'stringArg': 'foo'} + assert resolved_args[0] == {"numArg": 123, "stringArg": "foo"} @mark.asyncio async def nulls_out_error_subtrees(): @@ -281,106 +358,147 @@ async def nulls_out_error_subtrees(): # noinspection PyPep8Naming,PyMethodMayBeStatic class Data: - def syncOk(self, _info): - return 'sync ok' + return "sync ok" def syncError(self, _info): - raise GraphQLError('Error getting syncError') + raise GraphQLError("Error getting syncError") def syncRawError(self, _info): - raise Exception('Error getting syncRawError') + raise Exception("Error getting syncRawError") def syncReturnError(self, _info): - return Exception('Error getting syncReturnError') + return Exception("Error getting syncReturnError") def syncReturnErrorList(self, _info): return [ - 'sync0', - Exception('Error getting syncReturnErrorList1'), - 'sync2', - Exception('Error getting syncReturnErrorList3')] + "sync0", + Exception("Error getting syncReturnErrorList1"), + "sync2", + Exception("Error getting syncReturnErrorList3"), + ] async def asyncOk(self, _info): - return 'async ok' + return "async ok" async def asyncError(self, _info): - raise Exception('Error getting asyncError') + raise Exception("Error getting asyncError") async def asyncRawError(self, _info): - raise Exception('Error getting asyncRawError') + raise Exception("Error getting asyncRawError") async def asyncReturnError(self, _info): - return GraphQLError('Error getting asyncReturnError') + return GraphQLError("Error getting asyncReturnError") async def asyncReturnErrorWithExtensions(self, _info): return GraphQLError( - 'Error getting asyncReturnErrorWithExtensions', - extensions={'foo': 'bar'}) + "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'}}]) + 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 full_response_path_is_included_for_non_nullable_fields(): - def resolve_ok(*_args): return {} def resolve_error(*_args): - raise Exception('Catch me if you can') - - A = GraphQLObjectType('A', lambda: { - 'nullableA': GraphQLField(A, resolve=resolve_ok), - 'nonNullA': GraphQLField(GraphQLNonNull(A), resolve=resolve_ok), - 'throws': GraphQLField(GraphQLNonNull(A), resolve=resolve_error)}) - - query_type = GraphQLObjectType('query', lambda: { - 'nullableA': GraphQLField(A, resolve=resolve_ok)}) + raise Exception("Catch me if you can") + + A = GraphQLObjectType( + "A", + lambda: { + "nullableA": GraphQLField(A, resolve=resolve_ok), + "nonNullA": GraphQLField(GraphQLNonNull(A), resolve=resolve_ok), + "throws": GraphQLField(GraphQLNonNull(A), resolve=resolve_error), + }, + ) + + query_type = GraphQLObjectType( + "query", lambda: {"nullableA": GraphQLField(A, resolve=resolve_ok)} + ) schema = GraphQLSchema(query_type) query = """ @@ -397,171 +515,194 @@ def resolve_error(*_args): } """ - assert execute(schema, parse(query)) == ({ - 'nullableA': {'aliasedA': None} - }, [{ - 'message': 'Catch me if you can', - 'locations': [(7, 23)], 'path': [ - 'nullableA', 'aliasedA', 'nonNullA', 'anotherA', 'throws'] - }]) + assert execute(schema, parse(query)) == ( + {"nullableA": {"aliasedA": None}}, + [ + { + "message": "Catch me if you can", + "locations": [(7, 23)], + "path": ["nullableA", "aliasedA", "nonNullA", "anotherA", "throws"], + } + ], + ) def uses_the_inline_operation_if_no_operation_name_is_provided(): - doc = '{ a }' + doc = "{ a }" class Data: - a = 'b' + a = "b" ast = parse(doc) - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString)})) + schema = GraphQLSchema( + GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) + ) - assert execute(schema, ast, Data()) == ({'a': 'b'}, None) + assert execute(schema, ast, Data()) == ({"a": "b"}, None) def uses_the_only_operation_if_no_operation_name_is_provided(): - doc = 'query Example { a }' + doc = "query Example { a }" class Data: - a = 'b' + a = "b" ast = parse(doc) - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString)})) + schema = GraphQLSchema( + GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) + ) - assert execute(schema, ast, Data()) == ({'a': 'b'}, None) + assert execute(schema, ast, Data()) == ({"a": "b"}, None) def uses_the_named_operation_if_operation_name_is_provided(): - doc = 'query Example { first: a } query OtherExample { second: a }' + doc = "query Example { first: a } query OtherExample { second: a }" class Data: - a = 'b' + a = "b" ast = parse(doc) - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString)})) + schema = GraphQLSchema( + GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) + ) - assert execute(schema, ast, Data(), operation_name='OtherExample') == ( - {'second': 'b'}, None) + assert execute(schema, ast, Data(), operation_name="OtherExample") == ( + {"second": "b"}, + None, + ) def provides_error_if_no_operation_is_provided(): - doc = 'fragment Example on Type { a }' + doc = "fragment Example on Type { a }" class Data: - a = 'b' + a = "b" ast = parse(doc) - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString)})) + schema = GraphQLSchema( + GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) + ) - assert execute(schema, ast, Data()) == (None, [{ - 'message': 'Must provide an operation.'}]) + assert execute(schema, ast, Data()) == ( + None, + [{"message": "Must provide an operation."}], + ) def errors_if_no_operation_name_is_provided_with_multiple_operations(): - doc = 'query Example { a } query OtherExample { a }' + doc = "query Example { a } query OtherExample { a }" class Data: - a = 'b' + a = "b" ast = parse(doc) - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString)})) - - assert execute(schema, ast, Data()) == (None, [{ - 'message': 'Must provide operation name if query contains' - ' multiple operations.'}]) + schema = GraphQLSchema( + GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) + ) + + assert execute(schema, ast, Data()) == ( + None, + [ + { + "message": "Must provide operation name if query contains" + " multiple operations." + } + ], + ) def errors_if_unknown_operation_name_is_provided(): - doc = 'query Example { a } query OtherExample { a }' + doc = "query Example { a } query OtherExample { a }" ast = parse(doc) - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString)})) + schema = GraphQLSchema( + GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) + ) - assert execute(schema, ast, operation_name='UnknownExample') == ( - None, [{'message': "Unknown operation named 'UnknownExample'."}]) + assert execute(schema, ast, operation_name="UnknownExample") == ( + None, + [{"message": "Unknown operation named 'UnknownExample'."}], + ) def uses_the_query_schema_for_queries(): - doc = 'query Q { a } mutation M { c } subscription S { a }' + doc = "query Q { a } mutation M { c } subscription S { a }" class Data: - a = 'b' - c = 'd' + a = "b" + c = "d" ast = parse(doc) schema = GraphQLSchema( - GraphQLObjectType('Q', {'a': GraphQLField(GraphQLString)}), - GraphQLObjectType('M', {'c': GraphQLField(GraphQLString)}), - GraphQLObjectType('S', {'a': GraphQLField(GraphQLString)})) + GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}), + GraphQLObjectType("M", {"c": GraphQLField(GraphQLString)}), + GraphQLObjectType("S", {"a": GraphQLField(GraphQLString)}), + ) - assert execute(schema, ast, Data(), operation_name='Q') == ( - {'a': 'b'}, None) + assert execute(schema, ast, Data(), operation_name="Q") == ({"a": "b"}, None) def uses_the_mutation_schema_for_mutations(): - doc = 'query Q { a } mutation M { c }' + doc = "query Q { a } mutation M { c }" class Data: - a = 'b' - c = 'd' + a = "b" + c = "d" ast = parse(doc) schema = GraphQLSchema( - GraphQLObjectType('Q', {'a': GraphQLField(GraphQLString)}), - GraphQLObjectType('M', {'c': GraphQLField(GraphQLString)})) + GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}), + GraphQLObjectType("M", {"c": GraphQLField(GraphQLString)}), + ) - assert execute(schema, ast, Data(), operation_name='M') == ( - {'c': 'd'}, None) + assert execute(schema, ast, Data(), operation_name="M") == ({"c": "d"}, None) def uses_the_subscription_schema_for_subscriptions(): - doc = 'query Q { a } subscription S { a }' + doc = "query Q { a } subscription S { a }" class Data: - a = 'b' - c = 'd' + a = "b" + c = "d" ast = parse(doc) schema = GraphQLSchema( - query=GraphQLObjectType( - 'Q', {'a': GraphQLField(GraphQLString)}), - subscription=GraphQLObjectType( - 'S', {'a': GraphQLField(GraphQLString)})) + query=GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}), + subscription=GraphQLObjectType("S", {"a": GraphQLField(GraphQLString)}), + ) - assert execute(schema, ast, Data(), operation_name='S') == ( - {'a': 'b'}, None) + assert execute(schema, ast, Data(), operation_name="S") == ({"a": "b"}, None) @mark.asyncio async def correct_field_ordering_despite_execution_order(): - doc = '{ a, b, c, d, e}' + doc = "{ a, b, c, d, e}" # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class Data: - def a(self, _info): - return 'a' + return "a" async def b(self, _info): - return 'b' + return "b" def c(self, _info): - return 'c' + return "c" async def d(self, _info): - return 'd' + return "d" def e(self, _info): - return 'e' + return "e" ast = parse(doc) - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString), - 'b': GraphQLField(GraphQLString), - 'c': GraphQLField(GraphQLString), - 'd': GraphQLField(GraphQLString), - 'e': GraphQLField(GraphQLString)})) + schema = GraphQLSchema( + GraphQLObjectType( + "Type", + { + "a": GraphQLField(GraphQLString), + "b": GraphQLField(GraphQLString), + "c": GraphQLField(GraphQLString), + "d": GraphQLField(GraphQLString), + "e": GraphQLField(GraphQLString), + }, + ) + ) result = await execute(schema, ast, Data()) - assert result == ( - {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd', 'e': 'e'}, None) + assert result == ({"a": "a", "b": "b", "c": "c", "d": "d", "e": "e"}, None) - assert list(result.data) == ['a', 'b', 'c', 'd', 'e'] + assert list(result.data) == ["a", "b", "c", "d", "e"] def avoids_recursion(): doc = """ @@ -578,41 +719,55 @@ def avoids_recursion(): """ class Data: - a = 'b' + a = "b" ast = parse(doc) - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'a': GraphQLField(GraphQLString)})) + schema = GraphQLSchema( + GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) + ) - query_result = execute(schema, ast, Data(), operation_name='Q') + query_result = execute(schema, ast, Data(), operation_name="Q") - assert query_result == ({'a': 'b'}, None) + assert query_result == ({"a": "b"}, None) def does_not_include_illegal_fields_in_output(): - doc = 'mutation M { thisIsIllegalDoNotIncludeMe }' + doc = "mutation M { thisIsIllegalDoNotIncludeMe }" ast = parse(doc) schema = GraphQLSchema( - GraphQLObjectType('Q', {'a': GraphQLField(GraphQLString)}), - GraphQLObjectType('M', {'c': GraphQLField(GraphQLString)})) + GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}), + GraphQLObjectType("M", {"c": GraphQLField(GraphQLString)}), + ) mutation_result = execute(schema, ast) assert mutation_result == ({}, None) def does_not_include_arguments_that_were_not_set(): - schema = GraphQLSchema(GraphQLObjectType('Type', { - 'field': GraphQLField(GraphQLString, args={ - 'a': GraphQLArgument(GraphQLBoolean), - 'b': GraphQLArgument(GraphQLBoolean), - 'c': GraphQLArgument(GraphQLBoolean), - 'd': GraphQLArgument(GraphQLInt), - 'e': GraphQLArgument(GraphQLInt)}, - resolve=lambda _source, _info, **args: args and dumps(args))})) - - query = parse('{ field(a: true, c: false, e: 0) }') + schema = GraphQLSchema( + GraphQLObjectType( + "Type", + { + "field": GraphQLField( + GraphQLString, + args={ + "a": GraphQLArgument(GraphQLBoolean), + "b": GraphQLArgument(GraphQLBoolean), + "c": GraphQLArgument(GraphQLBoolean), + "d": GraphQLArgument(GraphQLInt), + "e": GraphQLArgument(GraphQLInt), + }, + resolve=lambda _source, _info, **args: args and dumps(args), + ) + }, + ) + ) + + query = parse("{ field(a: true, c: false, e: 0) }") assert execute(schema, query) == ( - {'field': '{"a": true, "c": false, "e": 0}'}, None) + {"field": '{"a": true, "c": false, "e": 0}'}, + None, + ) def fails_when_an_is_type_of_check_is_not_met(): class Special: @@ -626,50 +781,68 @@ def __init__(self, value): self.value = value def __repr__(self): - return f'{self.__class__.__name__}({self.value!r})' - - SpecialType = GraphQLObjectType('SpecialType', { - 'value': GraphQLField(GraphQLString)}, - is_type_of=lambda obj, _info: isinstance(obj, Special)) - - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'specials': GraphQLField( - GraphQLList(SpecialType), - resolve=lambda root_value, *_args: root_value['specials'])})) + return f"{self.__class__.__name__}({self.value!r})" - query = parse('{ specials { value } }') - value = {'specials': [Special('foo'), NotSpecial('bar')]} + SpecialType = GraphQLObjectType( + "SpecialType", + {"value": GraphQLField(GraphQLString)}, + is_type_of=lambda obj, _info: isinstance(obj, Special), + ) - assert execute(schema, query, value) == ({ - 'specials': [{'value': 'foo'}, None] - }, [{ - 'message': - "Expected value of type 'SpecialType' but got:" - " NotSpecial('bar').", - 'locations': [(1, 3)], 'path': ['specials', 1] - }]) + schema = GraphQLSchema( + GraphQLObjectType( + "Query", + { + "specials": GraphQLField( + GraphQLList(SpecialType), + resolve=lambda root_value, *_args: root_value["specials"], + ) + }, + ) + ) + + query = parse("{ specials { value } }") + value = {"specials": [Special("foo"), NotSpecial("bar")]} + + assert execute(schema, query, value) == ( + {"specials": [{"value": "foo"}, None]}, + [ + { + "message": "Expected value of type 'SpecialType' but got:" + " NotSpecial('bar').", + "locations": [(1, 3)], + "path": ["specials", 1], + } + ], + ) def executes_ignoring_invalid_non_executable_definitions(): - query = parse(""" + query = parse( + """ { foo } type Query { bar: String } - """) + """ + ) - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'foo': GraphQLField(GraphQLString)})) + schema = GraphQLSchema( + GraphQLObjectType("Query", {"foo": GraphQLField(GraphQLString)}) + ) - assert execute(schema, query) == ({'foo': None}, None) + assert execute(schema, query) == ({"foo": None}, None) def uses_a_custom_field_resolver(): - query = parse('{ foo }') + query = parse("{ foo }") - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'foo': GraphQLField(GraphQLString)})) + schema = GraphQLSchema( + GraphQLObjectType("Query", {"foo": GraphQLField(GraphQLString)}) + ) # For the purposes of test, just return the name of the field! def custom_resolver(_source, info, **_args): return info.field_name assert execute(schema, query, field_resolver=custom_resolver) == ( - {'foo': 'foo'}, None) + {"foo": "foo"}, + None, + ) diff --git a/tests/execution/test_lists.py b/tests/execution/test_lists.py index 0a8eb515..c5998f58 100644 --- a/tests/execution/test_lists.py +++ b/tests/execution/test_lists.py @@ -5,11 +5,17 @@ from graphql.language import parse from graphql.type import ( - GraphQLField, GraphQLInt, GraphQLList, - GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString) + GraphQLField, + GraphQLInt, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, +) from graphql.execution import execute -Data = namedtuple('Data', 'test') +Data = namedtuple("Data", "test") async def get_async(value): @@ -23,13 +29,17 @@ async def raise_async(msg): def get_response(test_type, test_data): data = Data(test=test_data) - data_type = GraphQLObjectType('DataType', lambda: { - 'test': GraphQLField(test_type), - 'nest': GraphQLField(data_type, resolve=lambda *_args: data)}) + data_type = GraphQLObjectType( + "DataType", + lambda: { + "test": GraphQLField(test_type), + "nest": GraphQLField(data_type, resolve=lambda *_args: data), + }, + ) schema = GraphQLSchema(data_type) - ast = parse('{ nest { test } }') + ast = parse("{ nest { test } }") return execute(schema, ast, data) @@ -56,312 +66,492 @@ async def check_async(test_type, test_data, expected): def describe_execute_accepts_any_iterable_as_list_value(): - def accepts_a_set_as_a_list_value(): # We need to use a dict instead of a set, # since sets are not ordered in Python. - check(GraphQLList(GraphQLString), dict.fromkeys( - ['apple', 'banana', 'coconut']), { - 'nest': {'test': ['apple', 'banana', 'coconut']}}) + check( + GraphQLList(GraphQLString), + dict.fromkeys(["apple", "banana", "coconut"]), + {"nest": {"test": ["apple", "banana", "coconut"]}}, + ) def accepts_a_generator_as_a_list_value(): - def yield_items(): - yield 'one' + yield "one" yield 2 yield True - check(GraphQLList(GraphQLString), yield_items(), { - 'nest': {'test': ['one', '2', 'true']}}) + check( + GraphQLList(GraphQLString), + yield_items(), + {"nest": {"test": ["one", "2", "true"]}}, + ) def accepts_function_arguments_as_a_list_value(): - def get_args(*args): return args # actually just a tuple, nothing special in Python - check(GraphQLList(GraphQLString), get_args( - 'one', 'two'), {'nest': {'test': ['one', 'two']}}) + check( + GraphQLList(GraphQLString), + get_args("one", "two"), + {"nest": {"test": ["one", "two"]}}, + ) def does_not_accept_iterable_string_literal_as_a_list_value(): - check(GraphQLList(GraphQLString), 'Singular', ( - {'nest': {'test': None}}, - [{'message': 'Expected Iterable,' - ' but did not find one for field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test']}])) + check( + GraphQLList(GraphQLString), + "Singular", + ( + {"nest": {"test": None}}, + [ + { + "message": "Expected Iterable," + " but did not find one for field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test"], + } + ], + ), + ) def describe_execute_handles_list_nullability(): - def describe_list(): type_ = GraphQLList(GraphQLInt) def describe_sync_list(): - def contains_values(): - check(type_, [1, 2], {'nest': {'test': [1, 2]}}) + check(type_, [1, 2], {"nest": {"test": [1, 2]}}) def contains_null(): - check(type_, [1, None, 2], {'nest': {'test': [1, None, 2]}}) + check(type_, [1, None, 2], {"nest": {"test": [1, None, 2]}}) def returns_null(): - check(type_, None, {'nest': {'test': None}}) + check(type_, None, {"nest": {"test": None}}) def describe_async_list(): - @mark.asyncio async def contains_values(): - await check_async(type_, get_async([1, 2]), { - 'nest': {'test': [1, 2]}}) + await check_async(type_, get_async([1, 2]), {"nest": {"test": [1, 2]}}) @mark.asyncio async def contains_null(): - await check_async(type_, get_async([1, None, 2]), { - 'nest': {'test': [1, None, 2]}}) + await check_async( + type_, get_async([1, None, 2]), {"nest": {"test": [1, None, 2]}} + ) @mark.asyncio async def returns_null(): - await check_async(type_, get_async(None), { - 'nest': {'test': None}}) + await check_async(type_, get_async(None), {"nest": {"test": None}}) @mark.asyncio async def async_error(): - await check_async(type_, raise_async('bad'), ( - {'nest': {'test': None}}, - [{'message': 'bad', - 'locations': [(1, 10)], 'path': ['nest', 'test']}])) + await check_async( + type_, + raise_async("bad"), + ( + {"nest": {"test": None}}, + [ + { + "message": "bad", + "locations": [(1, 10)], + "path": ["nest", "test"], + } + ], + ), + ) def describe_list_async(): - @mark.asyncio async def contains_values(): - await check_async(type_, [get_async(1), get_async(2)], { - 'nest': {'test': [1, 2]}}) + await check_async( + type_, [get_async(1), get_async(2)], {"nest": {"test": [1, 2]}} + ) @mark.asyncio async def contains_null(): - await check_async(type_, [ - get_async(1), get_async(None), get_async(2)], { - 'nest': {'test': [1, None, 2]}}) + await check_async( + type_, + [get_async(1), get_async(None), get_async(2)], + {"nest": {"test": [1, None, 2]}}, + ) @mark.asyncio async def contains_async_error(): - await check_async(type_, [ - get_async(1), raise_async('bad'), get_async(2)], ( - {'nest': {'test': [1, None, 2]}}, - [{'message': 'bad', - 'locations': [(1, 10)], 'path': ['nest', 'test', 1]}])) + await check_async( + type_, + [get_async(1), raise_async("bad"), get_async(2)], + ( + {"nest": {"test": [1, None, 2]}}, + [ + { + "message": "bad", + "locations": [(1, 10)], + "path": ["nest", "test", 1], + } + ], + ), + ) def describe_not_null_list(): type_ = GraphQLNonNull(GraphQLList(GraphQLInt)) def describe_sync_list(): - def contains_values(): - check(type_, [1, 2], {'nest': {'test': [1, 2]}}) + check(type_, [1, 2], {"nest": {"test": [1, 2]}}) def contains_null(): - check(type_, [1, None, 2], {'nest': {'test': [1, None, 2]}}) + check(type_, [1, None, 2], {"nest": {"test": [1, None, 2]}}) def returns_null(): - check(type_, None, ( - {'nest': None}, - [{'message': 'Cannot return null' - ' for non-nullable field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test']}])) + check( + type_, + None, + ( + {"nest": None}, + [ + { + "message": "Cannot return null" + " for non-nullable field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test"], + } + ], + ), + ) def describe_async_list(): - @mark.asyncio async def contains_values(): - await check_async(type_, get_async([1, 2]), { - 'nest': {'test': [1, 2]}}) + await check_async(type_, get_async([1, 2]), {"nest": {"test": [1, 2]}}) @mark.asyncio async def contains_null(): - await check_async(type_, get_async([1, None, 2]), { - 'nest': {'test': [1, None, 2]}}) + await check_async( + type_, get_async([1, None, 2]), {"nest": {"test": [1, None, 2]}} + ) @mark.asyncio async def returns_null(): - await check_async(type_, get_async(None), ( - {'nest': None}, - [{'message': 'Cannot return null' - ' for non-nullable field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test']}])) + await check_async( + type_, + get_async(None), + ( + {"nest": None}, + [ + { + "message": "Cannot return null" + " for non-nullable field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test"], + } + ], + ), + ) @mark.asyncio async def async_error(): - await check_async(type_, raise_async('bad'), ( - {'nest': None}, - [{'message': 'bad', - 'locations': [(1, 10)], 'path': ['nest', 'test']}])) + await check_async( + type_, + raise_async("bad"), + ( + {"nest": None}, + [ + { + "message": "bad", + "locations": [(1, 10)], + "path": ["nest", "test"], + } + ], + ), + ) def describe_list_async(): - @mark.asyncio async def contains_values(): - await check_async(type_, [get_async(1), get_async(2)], { - 'nest': {'test': [1, 2]}}) + await check_async( + type_, [get_async(1), get_async(2)], {"nest": {"test": [1, 2]}} + ) @mark.asyncio async def contains_null(): - await check_async(type_, [ - get_async(1), get_async(None), get_async(2)], { - 'nest': {'test': [1, None, 2]}}) + await check_async( + type_, + [get_async(1), get_async(None), get_async(2)], + {"nest": {"test": [1, None, 2]}}, + ) @mark.asyncio async def contains_async_error(): - await check_async(type_, [ - get_async(1), raise_async('bad'), get_async(2)], ( - {'nest': {'test': [1, None, 2]}}, - [{'message': 'bad', - 'locations': [(1, 10)], 'path': ['nest', 'test', 1]}])) + await check_async( + type_, + [get_async(1), raise_async("bad"), get_async(2)], + ( + {"nest": {"test": [1, None, 2]}}, + [ + { + "message": "bad", + "locations": [(1, 10)], + "path": ["nest", "test", 1], + } + ], + ), + ) def describe_list_not_null(): type_ = GraphQLList(GraphQLNonNull(GraphQLInt)) def describe_sync_list(): - def contains_values(): - check(type_, [1, 2], {'nest': {'test': [1, 2]}}) + check(type_, [1, 2], {"nest": {"test": [1, 2]}}) def contains_null(): - check(type_, [1, None, 2], ( - {'nest': {'test': None}}, - [{'message': 'Cannot return null' - ' for non-nullable field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test', 1]}])) + check( + type_, + [1, None, 2], + ( + {"nest": {"test": None}}, + [ + { + "message": "Cannot return null" + " for non-nullable field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test", 1], + } + ], + ), + ) def returns_null(): - check(type_, None, {'nest': {'test': None}}) + check(type_, None, {"nest": {"test": None}}) def describe_async_list(): - @mark.asyncio async def contains_values(): - await check_async(type_, get_async([1, 2]), { - 'nest': {'test': [1, 2]}}) + await check_async(type_, get_async([1, 2]), {"nest": {"test": [1, 2]}}) @mark.asyncio async def contains_null(): - await check_async(type_, get_async([1, None, 2]), ( - {'nest': {'test': None}}, - [{'message': 'Cannot return null' - ' for non-nullable field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test', 1]}])) + await check_async( + type_, + get_async([1, None, 2]), + ( + {"nest": {"test": None}}, + [ + { + "message": "Cannot return null" + " for non-nullable field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test", 1], + } + ], + ), + ) @mark.asyncio async def returns_null(): - await check_async(type_, get_async(None), { - 'nest': {'test': None}}) + await check_async(type_, get_async(None), {"nest": {"test": None}}) @mark.asyncio async def async_error(): - await check_async(type_, raise_async('bad'), ( - {'nest': {'test': None}}, - [{'message': 'bad', - 'locations': [(1, 10)], 'path': ['nest', 'test']}])) + await check_async( + type_, + raise_async("bad"), + ( + {"nest": {"test": None}}, + [ + { + "message": "bad", + "locations": [(1, 10)], + "path": ["nest", "test"], + } + ], + ), + ) def describe_list_async(): - @mark.asyncio async def contains_values(): - await check_async(type_, [get_async(1), get_async(2)], { - 'nest': {'test': [1, 2]}}) + await check_async( + type_, [get_async(1), get_async(2)], {"nest": {"test": [1, 2]}} + ) @mark.asyncio - @mark.filterwarnings('ignore::RuntimeWarning') + @mark.filterwarnings("ignore::RuntimeWarning") async def contains_null(): - await check_async(type_, [ - get_async(1), get_async(None), get_async(2)], ( - {'nest': {'test': None}}, - [{'message': 'Cannot return null' - ' for non-nullable field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test', 1]}])) + await check_async( + type_, + [get_async(1), get_async(None), get_async(2)], + ( + {"nest": {"test": None}}, + [ + { + "message": "Cannot return null" + " for non-nullable field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test", 1], + } + ], + ), + ) @mark.asyncio - @mark.filterwarnings('ignore::RuntimeWarning') + @mark.filterwarnings("ignore::RuntimeWarning") async def contains_async_error(): - await check_async(type_, [ - get_async(1), raise_async('bad'), get_async(2)], ( - {'nest': {'test': None}}, - [{'message': 'bad', - 'locations': [(1, 10)], 'path': ['nest', 'test', 1]}])) + await check_async( + type_, + [get_async(1), raise_async("bad"), get_async(2)], + ( + {"nest": {"test": None}}, + [ + { + "message": "bad", + "locations": [(1, 10)], + "path": ["nest", "test", 1], + } + ], + ), + ) def describe_not_null_list_not_null(): type_ = GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLInt))) def describe_sync_list(): - def contains_values(): - check(type_, [1, 2], {'nest': {'test': [1, 2]}}) + check(type_, [1, 2], {"nest": {"test": [1, 2]}}) def contains_null(): - check(type_, [1, None, 2], ( - {'nest': None}, - [{'message': 'Cannot return null' - ' for non-nullable field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test', 1]}])) + check( + type_, + [1, None, 2], + ( + {"nest": None}, + [ + { + "message": "Cannot return null" + " for non-nullable field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test", 1], + } + ], + ), + ) def returns_null(): - check(type_, None, ( - {'nest': None}, - [{'message': 'Cannot return null' - ' for non-nullable field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test']}])) + check( + type_, + None, + ( + {"nest": None}, + [ + { + "message": "Cannot return null" + " for non-nullable field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test"], + } + ], + ), + ) def describe_async_list(): - @mark.asyncio async def contains_values(): - await check_async(type_, get_async([1, 2]), { - 'nest': {'test': [1, 2]}}) + await check_async(type_, get_async([1, 2]), {"nest": {"test": [1, 2]}}) @mark.asyncio async def contains_null(): - await check_async(type_, get_async([1, None, 2]), ( - {'nest': None}, - [{'message': 'Cannot return null' - ' for non-nullable field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test', 1]}])) + await check_async( + type_, + get_async([1, None, 2]), + ( + {"nest": None}, + [ + { + "message": "Cannot return null" + " for non-nullable field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test", 1], + } + ], + ), + ) @mark.asyncio async def returns_null(): - await check_async(type_, get_async(None), ( - {'nest': None}, - [{'message': 'Cannot return null' - ' for non-nullable field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test']}])) + await check_async( + type_, + get_async(None), + ( + {"nest": None}, + [ + { + "message": "Cannot return null" + " for non-nullable field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test"], + } + ], + ), + ) @mark.asyncio async def async_error(): - await check_async(type_, raise_async('bad'), ( - {'nest': None}, - [{'message': 'bad', - 'locations': [(1, 10)], 'path': ['nest', 'test']}])) + await check_async( + type_, + raise_async("bad"), + ( + {"nest": None}, + [ + { + "message": "bad", + "locations": [(1, 10)], + "path": ["nest", "test"], + } + ], + ), + ) def describe_list_async(): - @mark.asyncio async def contains_values(): - await check_async(type_, [get_async(1), get_async(2)], { - 'nest': {'test': [1, 2]}}) + await check_async( + type_, [get_async(1), get_async(2)], {"nest": {"test": [1, 2]}} + ) @mark.asyncio - @mark.filterwarnings('ignore::RuntimeWarning') + @mark.filterwarnings("ignore::RuntimeWarning") async def contains_null(): - await check_async(type_, [ - get_async(1), get_async(None), get_async(2)], ( - {'nest': None}, - [{'message': 'Cannot return null' - ' for non-nullable field DataType.test.', - 'locations': [(1, 10)], 'path': ['nest', 'test', 1]}])) + await check_async( + type_, + [get_async(1), get_async(None), get_async(2)], + ( + {"nest": None}, + [ + { + "message": "Cannot return null" + " for non-nullable field DataType.test.", + "locations": [(1, 10)], + "path": ["nest", "test", 1], + } + ], + ), + ) @mark.asyncio - @mark.filterwarnings('ignore::RuntimeWarning') + @mark.filterwarnings("ignore::RuntimeWarning") async def contains_async_error(): - await check_async(type_, [ - get_async(1), raise_async('bad'), get_async(2)], ( - {'nest': None}, - [{'message': 'bad', - 'locations': [(1, 10)], 'path': ['nest', 'test', 1]}])) + await check_async( + type_, + [get_async(1), raise_async("bad"), get_async(2)], + ( + {"nest": None}, + [ + { + "message": "bad", + "locations": [(1, 10)], + "path": ["nest", "test", 1], + } + ], + ), + ) diff --git a/tests/execution/test_middleware.py b/tests/execution/test_middleware.py index 6e8ebb91..a9a6d0c4 100644 --- a/tests/execution/test_middleware.py +++ b/tests/execution/test_middleware.py @@ -2,30 +2,29 @@ from graphql.execution import MiddlewareManager, execute from graphql.language.parser import parse -from graphql.type import ( - GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString) +from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString def describe_middleware(): - def describe_with_manager(): - def default(): doc = parse("{ field }") # noinspection PyMethodMayBeStatic class Data: def field(self, _info): - return 'resolved' + return "resolved" - test_type = GraphQLObjectType('TestType', { - 'field': GraphQLField(GraphQLString)}) + test_type = GraphQLObjectType( + "TestType", {"field": GraphQLField(GraphQLString)} + ) middlewares = MiddlewareManager() result = execute( - GraphQLSchema(test_type), doc, Data(), middleware=middlewares) + GraphQLSchema(test_type), doc, Data(), middleware=middlewares + ) - assert result.data['field'] == 'resolved' + assert result.data["field"] == "resolved" def single_function(): doc = parse("{ first second }") @@ -33,23 +32,28 @@ def single_function(): # noinspection PyMethodMayBeStatic class Data: def first(self, _info): - return 'one' + return "one" def second(self, _info): - return 'two' + return "two" - test_type = GraphQLObjectType('TestType', { - 'first': GraphQLField(GraphQLString), - 'second': GraphQLField(GraphQLString)}) + test_type = GraphQLObjectType( + "TestType", + { + "first": GraphQLField(GraphQLString), + "second": GraphQLField(GraphQLString), + }, + ) def reverse_middleware(next_, *args, **kwargs): return next_(*args, **kwargs)[::-1] middlewares = MiddlewareManager(reverse_middleware) result = execute( - GraphQLSchema(test_type), doc, Data(), middleware=middlewares) + GraphQLSchema(test_type), doc, Data(), middleware=middlewares + ) - assert result.data == {'first': 'eno', 'second': 'owt'} + assert result.data == {"first": "eno", "second": "owt"} def single_object(): doc = parse("{ first second }") @@ -57,14 +61,18 @@ def single_object(): # noinspection PyMethodMayBeStatic class Data: def first(self, _info): - return 'one' + return "one" def second(self, _info): - return 'two' + return "two" - test_type = GraphQLObjectType('TestType', { - 'first': GraphQLField(GraphQLString), - 'second': GraphQLField(GraphQLString)}) + test_type = GraphQLObjectType( + "TestType", + { + "first": GraphQLField(GraphQLString), + "second": GraphQLField(GraphQLString), + }, + ) class ReverseMiddleware: @@ -74,9 +82,10 @@ def resolve(self, next_, *args, **kwargs): middlewares = MiddlewareManager(ReverseMiddleware()) result = execute( - GraphQLSchema(test_type), doc, Data(), middleware=middlewares) + GraphQLSchema(test_type), doc, Data(), middleware=middlewares + ) - assert result.data == {'first': 'eno', 'second': 'owt'} + assert result.data == {"first": "eno", "second": "owt"} def with_function_and_object(): doc = parse("{ field }") @@ -84,10 +93,11 @@ def with_function_and_object(): # noinspection PyMethodMayBeStatic class Data: def field(self, _info): - return 'resolved' + return "resolved" - test_type = GraphQLObjectType('TestType', { - 'field': GraphQLField(GraphQLString)}) + test_type = GraphQLObjectType( + "TestType", {"field": GraphQLField(GraphQLString)} + ) def reverse_middleware(next_, *args, **kwargs): return next_(*args, **kwargs)[::-1] @@ -98,29 +108,28 @@ class CaptitalizeMiddleware: def resolve(self, next_, *args, **kwargs): return next_(*args, **kwargs).capitalize() - middlewares = MiddlewareManager( - reverse_middleware, CaptitalizeMiddleware()) + middlewares = MiddlewareManager(reverse_middleware, CaptitalizeMiddleware()) result = execute( - GraphQLSchema(test_type), doc, Data(), middleware=middlewares) - assert result.data == {'field': 'Devloser'} + GraphQLSchema(test_type), doc, Data(), middleware=middlewares + ) + assert result.data == {"field": "Devloser"} def describe_without_manager(): - def no_middleware(): doc = parse("{ field }") # noinspection PyMethodMayBeStatic class Data: def field(self, _info): - return 'resolved' + return "resolved" - test_type = GraphQLObjectType('TestType', { - 'field': GraphQLField(GraphQLString)}) + test_type = GraphQLObjectType( + "TestType", {"field": GraphQLField(GraphQLString)} + ) - result = execute( - GraphQLSchema(test_type), doc, Data(), middleware=None) + result = execute(GraphQLSchema(test_type), doc, Data(), middleware=None) - assert result.data['field'] == 'resolved' + assert result.data["field"] == "resolved" def empty_middleware_list(): doc = parse("{ field }") @@ -128,30 +137,33 @@ def empty_middleware_list(): # noinspection PyMethodMayBeStatic class Data: def field(self, _info): - return 'resolved' + return "resolved" - test_type = GraphQLObjectType('TestType', { - 'field': GraphQLField(GraphQLString)}) + test_type = GraphQLObjectType( + "TestType", {"field": GraphQLField(GraphQLString)} + ) - result = execute( - GraphQLSchema(test_type), doc, Data(), middleware=[]) + result = execute(GraphQLSchema(test_type), doc, Data(), middleware=[]) - assert result.data['field'] == 'resolved' + assert result.data["field"] == "resolved" def bad_middleware_object(): doc = parse("{ field }") - test_type = GraphQLObjectType('TestType', { - 'field': GraphQLField(GraphQLString)}) + test_type = GraphQLObjectType( + "TestType", {"field": GraphQLField(GraphQLString)} + ) with raises(TypeError) as exc_info: - execute(GraphQLSchema(test_type), doc, None, - middleware={'bad': 'value'}) + execute( + GraphQLSchema(test_type), doc, None, middleware={"bad": "value"} + ) assert str(exc_info.value) == ( - 'Middleware must be passed as a list or tuple of functions' - ' or objects, or as a single MiddlewareManager object.' - " Got {'bad': 'value'} instead.") + "Middleware must be passed as a list or tuple of functions" + " or objects, or as a single MiddlewareManager object." + " Got {'bad': 'value'} instead." + ) def list_of_functions(): doc = parse("{ field }") @@ -159,10 +171,11 @@ def list_of_functions(): # noinspection PyMethodMayBeStatic class Data: def field(self, _info): - return 'resolved' + return "resolved" - test_type = GraphQLObjectType('TestType', { - 'field': GraphQLField(GraphQLString)}) + test_type = GraphQLObjectType( + "TestType", {"field": GraphQLField(GraphQLString)} + ) log = [] @@ -172,18 +185,23 @@ def __init__(self, name): # noinspection PyMethodMayBeStatic def resolve(self, next_, *args, **kwargs): - log.append(f'enter {self.name}') + log.append(f"enter {self.name}") value = next_(*args, **kwargs) - log.append(f'exit {self.name}') + log.append(f"exit {self.name}") return value - middlewares = [ - LogMiddleware('A'), LogMiddleware('B'), LogMiddleware('C')] + middlewares = [LogMiddleware("A"), LogMiddleware("B"), LogMiddleware("C")] result = execute( - GraphQLSchema(test_type), doc, Data(), middleware=middlewares) - assert result.data == {'field': 'resolved'} + GraphQLSchema(test_type), doc, Data(), middleware=middlewares + ) + assert result.data == {"field": "resolved"} assert log == [ - 'enter C', 'enter B', 'enter A', - 'exit A', 'exit B', 'exit C'] + "enter C", + "enter B", + "enter A", + "exit A", + "exit B", + "exit C", + ] diff --git a/tests/execution/test_mutations.py b/tests/execution/test_mutations.py index 4e922a55..9bbb591d 100644 --- a/tests/execution/test_mutations.py +++ b/tests/execution/test_mutations.py @@ -5,8 +5,12 @@ from graphql.execution import execute from graphql.language import parse from graphql.type import ( - GraphQLArgument, GraphQLField, GraphQLInt, - GraphQLObjectType, GraphQLSchema) + GraphQLArgument, + GraphQLField, + GraphQLInt, + GraphQLObjectType, + GraphQLSchema, +) # noinspection PyPep8Naming @@ -30,51 +34,62 @@ def immediately_change_the_number(self, newNumber: int) -> NumberHolder: self.numberHolder.theNumber = newNumber return self.numberHolder - async def promise_to_change_the_number( - self, new_number: int) -> NumberHolder: + async def promise_to_change_the_number(self, new_number: int) -> NumberHolder: await asyncio.sleep(0) return self.immediately_change_the_number(new_number) def fail_to_change_the_number(self, newNumber: int): - raise RuntimeError(f'Cannot change the number to {newNumber}') + 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)}) +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)), - 'promiseToChangeTheNumber': GraphQLField( - numberHolderType, - args={'newNumber': GraphQLArgument(GraphQLInt)}, - resolve=lambda obj, _info, newNumber: - obj.promise_to_change_the_number(newNumber)), - 'failToChangeTheNumber': GraphQLField( - numberHolderType, - args={'newNumber': GraphQLArgument(GraphQLInt)}, - resolve=lambda obj, _info, newNumber: - obj.fail_to_change_the_number(newNumber)), - 'promiseAndFailToChangeTheNumber': GraphQLField( - numberHolderType, - args={'newNumber': GraphQLArgument(GraphQLInt)}, - resolve=lambda obj, _info, newNumber: - obj.promise_and_fail_to_change_the_number(newNumber))})) + 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 + ), + ), + "promiseToChangeTheNumber": GraphQLField( + numberHolderType, + args={"newNumber": GraphQLArgument(GraphQLInt)}, + resolve=lambda obj, _info, newNumber: obj.promise_to_change_the_number( + newNumber + ), + ), + "failToChangeTheNumber": GraphQLField( + numberHolderType, + args={"newNumber": GraphQLArgument(GraphQLInt)}, + resolve=lambda obj, _info, newNumber: obj.fail_to_change_the_number( + newNumber + ), + ), + "promiseAndFailToChangeTheNumber": GraphQLField( + numberHolderType, + args={"newNumber": GraphQLArgument(GraphQLInt)}, + resolve=lambda obj, _info, newNumber: obj.promise_and_fail_to_change_the_number( # noqa + newNumber + ), + ), + }, + ), +) def describe_execute_handles_mutation_execution_ordering(): - @mark.asyncio async def evaluates_mutations_serially(): doc = """ @@ -99,13 +114,16 @@ async def evaluates_mutations_serially(): mutation_result = await execute(schema, parse(doc), Root(6)) - assert mutation_result == ({ - 'first': {'theNumber': 1}, - 'second': {'theNumber': 2}, - 'third': {'theNumber': 3}, - 'fourth': {'theNumber': 4}, - 'fifth': {'theNumber': 5} - }, None) + assert mutation_result == ( + { + "first": {"theNumber": 1}, + "second": {"theNumber": 2}, + "third": {"theNumber": 3}, + "fourth": {"theNumber": 4}, + "fifth": {"theNumber": 5}, + }, + None, + ) @mark.asyncio async def evaluates_mutations_correctly_in_presence_of_a_failed_mutation(): @@ -134,25 +152,25 @@ async def evaluates_mutations_correctly_in_presence_of_a_failed_mutation(): result = await execute(schema, parse(doc), Root(6)) - assert result == ({ - 'first': { - 'theNumber': 1, - }, - 'second': { - 'theNumber': 2, - }, - 'third': None, - 'fourth': { - 'theNumber': 4, - }, - 'fifth': { - 'theNumber': 5, + assert result == ( + { + "first": {"theNumber": 1}, + "second": {"theNumber": 2}, + "third": None, + "fourth": {"theNumber": 4}, + "fifth": {"theNumber": 5}, + "sixth": None, }, - 'sixth': None - }, [{ - 'message': 'Cannot change the number to 3', - 'locations': [(9, 15)], 'path': ['third'] - }, { - 'message': 'Cannot change the number to 6', - 'locations': [(18, 15)], 'path': ['sixth'] - }]) + [ + { + "message": "Cannot change the number to 3", + "locations": [(9, 15)], + "path": ["third"], + }, + { + "message": "Cannot change the number to 6", + "locations": [(18, 15)], + "path": ["sixth"], + }, + ], + ) diff --git a/tests/execution/test_nonnull.py b/tests/execution/test_nonnull.py index c33f0a28..42208dd0 100644 --- a/tests/execution/test_nonnull.py +++ b/tests/execution/test_nonnull.py @@ -5,18 +5,22 @@ from graphql.execution import execute from graphql.language import parse from graphql.type import ( - GraphQLArgument, GraphQLField, GraphQLNonNull, GraphQLObjectType, - GraphQLSchema, GraphQLString) + GraphQLArgument, + GraphQLField, + GraphQLNonNull, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, +) -sync_error = RuntimeError('sync') -sync_non_null_error = RuntimeError('syncNonNull') -promise_error = RuntimeError('promise') -promise_non_null_error = RuntimeError('promiseNonNull') +sync_error = RuntimeError("sync") +sync_non_null_error = RuntimeError("syncNonNull") +promise_error = RuntimeError("promise") +promise_non_null_error = RuntimeError("promiseNonNull") # noinspection PyPep8Naming,PyMethodMayBeStatic class ThrowingData: - def sync(self, _info): raise sync_error @@ -44,7 +48,6 @@ async def promiseNonNullNest(self, _info): # noinspection PyPep8Naming,PyMethodMayBeStatic class NullingData: - def sync(self, _info): return None @@ -70,15 +73,19 @@ async def promiseNonNullNest(self, _info): return NullingData() -DataType = GraphQLObjectType('DataType', lambda: { - 'sync': GraphQLField(GraphQLString), - 'syncNonNull': GraphQLField(GraphQLNonNull(GraphQLString)), - 'promise': GraphQLField(GraphQLString), - 'promiseNonNull': GraphQLField(GraphQLNonNull(GraphQLString)), - 'syncNest': GraphQLField(DataType), - 'syncNonNullNest': GraphQLField(GraphQLNonNull(DataType)), - 'promiseNest': GraphQLField(DataType), - 'promiseNonNullNest': GraphQLField(GraphQLNonNull(DataType))}) +DataType = GraphQLObjectType( + "DataType", + lambda: { + "sync": GraphQLField(GraphQLString), + "syncNonNull": GraphQLField(GraphQLNonNull(GraphQLString)), + "promise": GraphQLField(GraphQLString), + "promiseNonNull": GraphQLField(GraphQLNonNull(GraphQLString)), + "syncNest": GraphQLField(DataType), + "syncNonNullNest": GraphQLField(GraphQLNonNull(DataType)), + "promiseNest": GraphQLField(DataType), + "promiseNonNullNest": GraphQLField(GraphQLNonNull(DataType)), + }, +) schema = GraphQLSchema(DataType) @@ -88,8 +95,9 @@ def execute_query(query, root_value): def patch(data): - return re.sub(r'\bsyncNonNull\b', 'promiseNonNull', re.sub( - r'\bsync\b', 'promise', data)) + return re.sub( + r"\bsyncNonNull\b", "promiseNonNull", re.sub(r"\bsync\b", "promise", data) + ) async def execute_sync_and_async(query, root_value): @@ -103,7 +111,6 @@ async def execute_sync_and_async(query, root_value): def describe_execute_handles_non_nullable_types(): - def describe_nulls_a_nullable_field(): query = """ { @@ -114,14 +121,21 @@ def describe_nulls_a_nullable_field(): @mark.asyncio async def returns_null(): result = await execute_sync_and_async(query, NullingData()) - assert result == ({'sync': None}, None) + assert result == ({"sync": None}, None) @mark.asyncio async def throws(): result = await execute_sync_and_async(query, ThrowingData()) - assert result == ({'sync': None}, [{ - 'message': str(sync_error), - 'path': ['sync'], 'locations': [(3, 15)]}]) + assert result == ( + {"sync": None}, + [ + { + "message": str(sync_error), + "path": ["sync"], + "locations": [(3, 15)], + } + ], + ) def describe_nulls_an_immediate_object_that_contains_a_non_null_field(): @@ -136,19 +150,31 @@ def describe_nulls_an_immediate_object_that_contains_a_non_null_field(): @mark.asyncio async def returns_null(): result = await execute_sync_and_async(query, NullingData()) - assert result == ({'syncNest': None}, [{ - 'message': 'Cannot return null for non-nullable field' - ' DataType.syncNonNull.', - 'path': ['syncNest', 'syncNonNull'], - 'locations': [(4, 17)]}]) + assert result == ( + {"syncNest": None}, + [ + { + "message": "Cannot return null for non-nullable field" + " DataType.syncNonNull.", + "path": ["syncNest", "syncNonNull"], + "locations": [(4, 17)], + } + ], + ) @mark.asyncio async def throws(): result = await execute_sync_and_async(query, ThrowingData()) - assert result == ({'syncNest': None}, [{ - 'message': str(sync_non_null_error), - 'path': ['syncNest', 'syncNonNull'], - 'locations': [(4, 17)]}]) + assert result == ( + {"syncNest": None}, + [ + { + "message": str(sync_non_null_error), + "path": ["syncNest", "syncNonNull"], + "locations": [(4, 17)], + } + ], + ) def describe_nulls_a_promised_object_that_contains_a_non_null_field(): query = """ @@ -162,19 +188,31 @@ def describe_nulls_a_promised_object_that_contains_a_non_null_field(): @mark.asyncio async def returns_null(): result = await execute_sync_and_async(query, NullingData()) - assert result == ({'promiseNest': None}, [{ - 'message': 'Cannot return null for non-nullable field' - ' DataType.syncNonNull.', - 'path': ['promiseNest', 'syncNonNull'], - 'locations': [(4, 17)]}]) + assert result == ( + {"promiseNest": None}, + [ + { + "message": "Cannot return null for non-nullable field" + " DataType.syncNonNull.", + "path": ["promiseNest", "syncNonNull"], + "locations": [(4, 17)], + } + ], + ) @mark.asyncio async def throws(): result = await execute_sync_and_async(query, ThrowingData()) - assert result == ({'promiseNest': None}, [{ - 'message': str(sync_non_null_error), - 'path': ['promiseNest', 'syncNonNull'], - 'locations': [(4, 17)]}]) + assert result == ( + {"promiseNest": None}, + [ + { + "message": str(sync_non_null_error), + "path": ["promiseNest", "syncNonNull"], + "locations": [(4, 17)], + } + ], + ) def describe_nulls_a_complex_tree_of_nullable_fields_each(): query = """ @@ -194,16 +232,19 @@ def describe_nulls_a_complex_tree_of_nullable_fields_each(): } """ data = { - 'syncNest': { - 'sync': None, - 'promise': None, - 'syncNest': {'sync': None, 'promise': None}, - 'promiseNest': {'sync': None, 'promise': None}}, - 'promiseNest': { - 'sync': None, - 'promise': None, - 'syncNest': {'sync': None, 'promise': None}, - 'promiseNest': {'sync': None, 'promise': None}}} + "syncNest": { + "sync": None, + "promise": None, + "syncNest": {"sync": None, "promise": None}, + "promiseNest": {"sync": None, "promise": None}, + }, + "promiseNest": { + "sync": None, + "promise": None, + "syncNest": {"sync": None, "promise": None}, + "promiseNest": {"sync": None, "promise": None}, + }, + } @mark.asyncio async def returns_null(): @@ -213,55 +254,71 @@ async def returns_null(): @mark.asyncio async def throws(): result = await execute_query(query, ThrowingData()) - assert result == (data, [{ - 'message': str(sync_error), - 'path': ['syncNest', 'sync'], - 'locations': [(4, 17)] - }, { - 'message': str(sync_error), - 'path': ['syncNest', 'syncNest', 'sync'], - 'locations': [(6, 28)] - }, { - 'message': str(promise_error), - 'path': ['syncNest', 'promise'], - 'locations': [(5, 17)] - }, { - 'message': str(promise_error), - 'path': ['syncNest', 'syncNest', 'promise'], - 'locations': [(6, 33)] - }, { - 'message': str(sync_error), - 'path': ['syncNest', 'promiseNest', 'sync'], - 'locations': [(7, 31)] - }, { - 'message': str(promise_error), - 'path': ['syncNest', 'promiseNest', 'promise'], - 'locations': [(7, 36)] - }, { - 'message': str(sync_error), - 'path': ['promiseNest', 'sync'], - 'locations': [(10, 17)] - }, { - 'message': str(sync_error), - 'path': ['promiseNest', 'syncNest', 'sync'], - 'locations': [(12, 28)] - }, { - 'message': str(promise_error), - 'path': ['promiseNest', 'promise'], - 'locations': [(11, 17)] - }, { - 'message': str(promise_error), - 'path': ['promiseNest', 'syncNest', 'promise'], - 'locations': [(12, 33)] - }, { - 'message': str(sync_error), - 'path': ['promiseNest', 'promiseNest', 'sync'], - 'locations': [(13, 31)] - }, { - 'message': str(promise_error), - 'path': ['promiseNest', 'promiseNest', 'promise'], - 'locations': [(13, 36)] - }]) + assert result == ( + data, + [ + { + "message": str(sync_error), + "path": ["syncNest", "sync"], + "locations": [(4, 17)], + }, + { + "message": str(sync_error), + "path": ["syncNest", "syncNest", "sync"], + "locations": [(6, 28)], + }, + { + "message": str(promise_error), + "path": ["syncNest", "promise"], + "locations": [(5, 17)], + }, + { + "message": str(promise_error), + "path": ["syncNest", "syncNest", "promise"], + "locations": [(6, 33)], + }, + { + "message": str(sync_error), + "path": ["syncNest", "promiseNest", "sync"], + "locations": [(7, 31)], + }, + { + "message": str(promise_error), + "path": ["syncNest", "promiseNest", "promise"], + "locations": [(7, 36)], + }, + { + "message": str(sync_error), + "path": ["promiseNest", "sync"], + "locations": [(10, 17)], + }, + { + "message": str(sync_error), + "path": ["promiseNest", "syncNest", "sync"], + "locations": [(12, 28)], + }, + { + "message": str(promise_error), + "path": ["promiseNest", "promise"], + "locations": [(11, 17)], + }, + { + "message": str(promise_error), + "path": ["promiseNest", "syncNest", "promise"], + "locations": [(12, 33)], + }, + { + "message": str(sync_error), + "path": ["promiseNest", "promiseNest", "sync"], + "locations": [(13, 31)], + }, + { + "message": str(promise_error), + "path": ["promiseNest", "promiseNest", "promise"], + "locations": [(13, 36)], + }, + ], + ) def describe_nulls_first_nullable_after_long_chain_of_non_null_fields(): query = """ @@ -313,76 +370,129 @@ def describe_nulls_first_nullable_after_long_chain_of_non_null_fields(): } """ data = { - 'syncNest': None, - 'promiseNest': None, - 'anotherNest': None, - 'anotherPromiseNest': None} + "syncNest": None, + "promiseNest": None, + "anotherNest": None, + "anotherPromiseNest": None, + } @mark.asyncio async def returns_null(): result = await execute_query(query, NullingData()) - assert result == (data, [{ - 'message': 'Cannot return null for non-nullable field' - ' DataType.syncNonNull.', - 'path': [ - 'syncNest', 'syncNonNullNest', 'promiseNonNullNest', - 'syncNonNullNest', 'promiseNonNullNest', 'syncNonNull'], - 'locations': [(8, 25)] - }, { - 'message': 'Cannot return null for non-nullable field' - ' DataType.syncNonNull.', - 'path': [ - 'promiseNest', 'syncNonNullNest', 'promiseNonNullNest', - 'syncNonNullNest', 'promiseNonNullNest', 'syncNonNull'], - 'locations': [(19, 25)] - - }, { - 'message': 'Cannot return null for non-nullable field' - ' DataType.promiseNonNull.', - 'path': [ - 'anotherNest', 'syncNonNullNest', 'promiseNonNullNest', - 'syncNonNullNest', 'promiseNonNullNest', 'promiseNonNull'], - 'locations': [(30, 25)] - }, { - 'message': 'Cannot return null for non-nullable field' - ' DataType.promiseNonNull.', - 'path': [ - 'anotherPromiseNest', 'syncNonNullNest', - 'promiseNonNullNest', 'syncNonNullNest', - 'promiseNonNullNest', 'promiseNonNull'], - 'locations': [(41, 25)] - }]) + assert result == ( + data, + [ + { + "message": "Cannot return null for non-nullable field" + " DataType.syncNonNull.", + "path": [ + "syncNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNull", + ], + "locations": [(8, 25)], + }, + { + "message": "Cannot return null for non-nullable field" + " DataType.syncNonNull.", + "path": [ + "promiseNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNull", + ], + "locations": [(19, 25)], + }, + { + "message": "Cannot return null for non-nullable field" + " DataType.promiseNonNull.", + "path": [ + "anotherNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNullNest", + "promiseNonNullNest", + "promiseNonNull", + ], + "locations": [(30, 25)], + }, + { + "message": "Cannot return null for non-nullable field" + " DataType.promiseNonNull.", + "path": [ + "anotherPromiseNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNullNest", + "promiseNonNullNest", + "promiseNonNull", + ], + "locations": [(41, 25)], + }, + ], + ) @mark.asyncio async def throws(): result = await execute_query(query, ThrowingData()) - assert result == (data, [{ - 'message': str(sync_non_null_error), - 'path': [ - 'syncNest', 'syncNonNullNest', 'promiseNonNullNest', - 'syncNonNullNest', 'promiseNonNullNest', 'syncNonNull'], - 'locations': [(8, 25)] - }, { - 'message': str(sync_non_null_error), - 'path': [ - 'promiseNest', 'syncNonNullNest', 'promiseNonNullNest', - 'syncNonNullNest', 'promiseNonNullNest', 'syncNonNull'], - 'locations': [(19, 25)] - - }, { - 'message': str(promise_non_null_error), - 'path': [ - 'anotherNest', 'syncNonNullNest', 'promiseNonNullNest', - 'syncNonNullNest', 'promiseNonNullNest', 'promiseNonNull'], - 'locations': [(30, 25)] - }, { - 'message': str(promise_non_null_error), - 'path': [ - 'anotherPromiseNest', 'syncNonNullNest', - 'promiseNonNullNest', 'syncNonNullNest', - 'promiseNonNullNest', 'promiseNonNull'], - 'locations': [(41, 25)] - }]) + assert result == ( + data, + [ + { + "message": str(sync_non_null_error), + "path": [ + "syncNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNull", + ], + "locations": [(8, 25)], + }, + { + "message": str(sync_non_null_error), + "path": [ + "promiseNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNull", + ], + "locations": [(19, 25)], + }, + { + "message": str(promise_non_null_error), + "path": [ + "anotherNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNullNest", + "promiseNonNullNest", + "promiseNonNull", + ], + "locations": [(30, 25)], + }, + { + "message": str(promise_non_null_error), + "path": [ + "anotherPromiseNest", + "syncNonNullNest", + "promiseNonNullNest", + "syncNonNullNest", + "promiseNonNullNest", + "promiseNonNull", + ], + "locations": [(41, 25)], + }, + ], + ) def describe_nulls_the_top_level_if_non_nullable_field(): query = """ @@ -394,17 +504,31 @@ def describe_nulls_the_top_level_if_non_nullable_field(): @mark.asyncio async def returns_null(): result = await execute_sync_and_async(query, NullingData()) - assert result == (None, [{ - 'message': 'Cannot return null for non-nullable field' - ' DataType.syncNonNull.', - 'path': ['syncNonNull'], 'locations': [(3, 17)]}]) + assert result == ( + None, + [ + { + "message": "Cannot return null for non-nullable field" + " DataType.syncNonNull.", + "path": ["syncNonNull"], + "locations": [(3, 17)], + } + ], + ) @mark.asyncio async def throws(): result = await execute_sync_and_async(query, ThrowingData()) - assert result == (None, [{ - 'message': str(sync_non_null_error), - 'path': ['syncNonNull'], 'locations': [(3, 17)]}]) + assert result == ( + None, + [ + { + "message": str(sync_non_null_error), + "path": ["syncNonNull"], + "locations": [(3, 17)], + } + ], + ) def describe_handles_non_null_argument(): @@ -412,98 +536,159 @@ def describe_handles_non_null_argument(): @fixture def resolve(_obj, _info, cannotBeNull): if isinstance(cannotBeNull, str): - return f'Passed: {cannotBeNull}' + return f"Passed: {cannotBeNull}" schema_with_non_null_arg = GraphQLSchema( - GraphQLObjectType('Query', { - 'withNonNullArg': GraphQLField(GraphQLString, args={ - 'cannotBeNull': - GraphQLArgument(GraphQLNonNull(GraphQLString)) - }, resolve=resolve)})) + GraphQLObjectType( + "Query", + { + "withNonNullArg": GraphQLField( + GraphQLString, + args={ + "cannotBeNull": GraphQLArgument( + GraphQLNonNull(GraphQLString) + ) + }, + resolve=resolve, + ) + }, + ) + ) def succeeds_when_passed_non_null_literal_value(): - result = execute(schema_with_non_null_arg, parse(""" + result = execute( + schema_with_non_null_arg, + parse( + """ query { withNonNullArg (cannotBeNull: "literal value") } - """)) + """ + ), + ) - assert result == ( - {'withNonNullArg': 'Passed: literal value'}, None) + assert result == ({"withNonNullArg": "Passed: literal value"}, None) def succeeds_when_passed_non_null_variable_value(): - result = execute(schema_with_non_null_arg, parse(""" + result = execute( + schema_with_non_null_arg, + parse( + """ query ($testVar: String = "default value") { withNonNullArg (cannotBeNull: $testVar) } - """), variable_values={}) # intentionally missing variable + """ + ), + variable_values={}, + ) # intentionally missing variable - assert result == ( - {'withNonNullArg': 'Passed: default value'}, None) + assert result == ({"withNonNullArg": "Passed: default value"}, None) def field_error_when_missing_non_null_arg(): # Note: validation should identify this issue first # (missing args rule) however execution should still # protect against this. - result = execute(schema_with_non_null_arg, parse(""" + result = execute( + schema_with_non_null_arg, + parse( + """ query { withNonNullArg } - """)) + """ + ), + ) assert result == ( - {'withNonNullArg': None}, [{ - 'message': "Argument 'cannotBeNull' of required type" - " 'String!' was not provided.", - 'locations': [(3, 19)], 'path': ['withNonNullArg'] - }]) + {"withNonNullArg": None}, + [ + { + "message": "Argument 'cannotBeNull' of required type" + " 'String!' was not provided.", + "locations": [(3, 19)], + "path": ["withNonNullArg"], + } + ], + ) def field_error_when_non_null_arg_provided_null(): # Note: validation should identify this issue first # (values of correct type rule) however execution # should still protect against this. - result = execute(schema_with_non_null_arg, parse(""" + result = execute( + schema_with_non_null_arg, + parse( + """ query { withNonNullArg(cannotBeNull: null) } - """)) + """ + ), + ) assert result == ( - {'withNonNullArg': None}, [{ - 'message': "Argument 'cannotBeNull' of non-null type" - " 'String!' must not be null.", - 'locations': [(3, 48)], 'path': ['withNonNullArg'] - }]) + {"withNonNullArg": None}, + [ + { + "message": "Argument 'cannotBeNull' of non-null type" + " 'String!' must not be null.", + "locations": [(3, 48)], + "path": ["withNonNullArg"], + } + ], + ) def field_error_when_non_null_arg_not_provided_variable_value(): # Note: validation should identify this issue first # (variables in allowed position rule) however execution # should still protect against this. - result = execute(schema_with_non_null_arg, parse(""" + result = execute( + schema_with_non_null_arg, + parse( + """ query ($testVar: String) { withNonNullArg(cannotBeNull: $testVar) } - """), variable_values={}) # intentionally missing variable + """ + ), + variable_values={}, + ) # intentionally missing variable assert result == ( - {'withNonNullArg': None}, [{ - 'message': "Argument 'cannotBeNull' of required type" - " 'String!' was provided the variable" - " '$testVar' which was not provided" - ' a runtime value.', - 'locations': [(3, 48)], 'path': ['withNonNullArg'] - }]) + {"withNonNullArg": None}, + [ + { + "message": "Argument 'cannotBeNull' of required type" + " 'String!' was provided the variable" + " '$testVar' which was not provided" + " a runtime value.", + "locations": [(3, 48)], + "path": ["withNonNullArg"], + } + ], + ) def field_error_when_non_null_arg_provided_explicit_null_variable(): - result = execute(schema_with_non_null_arg, parse(""" + result = execute( + schema_with_non_null_arg, + parse( + """ query ($testVar: String = "default value") { withNonNullArg (cannotBeNull: $testVar) } - """), variable_values={'testVar': None}) + """ + ), + variable_values={"testVar": None}, + ) assert result == ( - {'withNonNullArg': None}, [{ - 'message': "Argument 'cannotBeNull' of non-null type" - " 'String!' must not be null.", - 'locations': [(3, 49)], 'path': ['withNonNullArg'] - }]) + {"withNonNullArg": None}, + [ + { + "message": "Argument 'cannotBeNull' of non-null type" + " 'String!' must not be null.", + "locations": [(3, 49)], + "path": ["withNonNullArg"], + } + ], + ) diff --git a/tests/execution/test_resolve.py b/tests/execution/test_resolve.py index 5010b4a8..d2d52646 100644 --- a/tests/execution/test_resolve.py +++ b/tests/execution/test_resolve.py @@ -4,48 +4,56 @@ from graphql import graphql_sync from graphql.type import ( - GraphQLArgument, GraphQLField, GraphQLInt, - GraphQLObjectType, GraphQLSchema, GraphQLString) + GraphQLArgument, + GraphQLField, + GraphQLInt, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, +) def describe_execute_resolve_function(): - @fixture def test_schema(test_field): - return GraphQLSchema(GraphQLObjectType('Query', {'test': test_field})) + return GraphQLSchema(GraphQLObjectType("Query", {"test": test_field})) def default_function_accesses_attributes(): schema = test_schema(GraphQLField(GraphQLString)) class Source: - test = 'testValue' + test = "testValue" - assert graphql_sync(schema, '{ test }', Source()) == ( - {'test': 'testValue'}, None) + assert graphql_sync(schema, "{ test }", Source()) == ( + {"test": "testValue"}, + None, + ) def default_function_accesses_keys(): schema = test_schema(GraphQLField(GraphQLString)) - source = {'test': 'testValue'} + source = {"test": "testValue"} - assert graphql_sync(schema, '{ test }', source) == ( - {'test': 'testValue'}, None) + assert graphql_sync(schema, "{ test }", source) == ({"test": "testValue"}, None) def default_function_calls_methods(): schema = test_schema(GraphQLField(GraphQLString)) class Source: - _secret = 'testValue' + _secret = "testValue" def test(self, _info): return self._secret - assert graphql_sync(schema, '{ test }', Source()) == ( - {'test': 'testValue'}, None) + assert graphql_sync(schema, "{ test }", Source()) == ( + {"test": "testValue"}, + None, + ) def default_function_passes_args_and_context(): - schema = test_schema(GraphQLField(GraphQLInt, args={ - 'addend1': GraphQLArgument(GraphQLInt)})) + schema = test_schema( + GraphQLField(GraphQLInt, args={"addend1": GraphQLArgument(GraphQLInt)}) + ) class Adder: def __init__(self, num): @@ -59,27 +67,35 @@ def test(self, info, addend1): class Context: addend2 = 9 - assert graphql_sync( - schema, '{ test(addend1: 80) }', source, Context()) == ( - {'test': 789}, None) + assert graphql_sync(schema, "{ test(addend1: 80) }", source, Context()) == ( + {"test": 789}, + None, + ) def uses_provided_resolve_function(): - schema = test_schema(GraphQLField( - GraphQLString, args={ - 'aStr': GraphQLArgument(GraphQLString), - 'aInt': GraphQLArgument(GraphQLInt)}, - resolve=lambda source, info, **args: dumps([source, args]))) - - assert graphql_sync(schema, '{ test }') == ( - {'test': '[null, {}]'}, None) - - assert graphql_sync(schema, '{ test }', 'Source!') == ( - {'test': '["Source!", {}]'}, None) - - assert graphql_sync( - schema, '{ test(aStr: "String!") }', 'Source!') == ( - {'test': '["Source!", {"aStr": "String!"}]'}, None) + schema = test_schema( + GraphQLField( + GraphQLString, + args={ + "aStr": GraphQLArgument(GraphQLString), + "aInt": GraphQLArgument(GraphQLInt), + }, + resolve=lambda source, info, **args: dumps([source, args]), + ) + ) + + assert graphql_sync(schema, "{ test }") == ({"test": "[null, {}]"}, None) + + assert graphql_sync(schema, "{ test }", "Source!") == ( + {"test": '["Source!", {}]'}, + None, + ) + + assert graphql_sync(schema, '{ test(aStr: "String!") }', "Source!") == ( + {"test": '["Source!", {"aStr": "String!"}]'}, + None, + ) assert graphql_sync( - schema, '{ test(aInt: -123, aStr: "String!") }', 'Source!') == ( - {'test': '["Source!", {"aStr": "String!", "aInt": -123}]'}, None) + schema, '{ test(aInt: -123, aStr: "String!") }', "Source!" + ) == ({"test": '["Source!", {"aStr": "String!", "aInt": -123}]'}, None) diff --git a/tests/execution/test_schema.py b/tests/execution/test_schema.py index 55d4fcf4..979e9f35 100644 --- a/tests/execution/test_schema.py +++ b/tests/execution/test_schema.py @@ -1,45 +1,76 @@ from graphql.execution import execute from graphql.language import parse from graphql.type import ( - GraphQLArgument, GraphQLBoolean, GraphQLField, GraphQLID, - GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLSchema, GraphQLString) + GraphQLArgument, + GraphQLBoolean, + GraphQLField, + GraphQLID, + GraphQLInt, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, +) def describe_execute_handles_execution_with_a_complex_schema(): - def executes_using_a_schema(): - 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)}, - resolve=lambda obj, info, width, height: - obj.pic(info, width, height)), - 'recentArticle': GraphQLField(BlogArticle)}) - - BlogArticle = GraphQLObjectType('Article', { - 'id': GraphQLField(GraphQLNonNull(GraphQLString)), - 'isPublished': GraphQLField(GraphQLBoolean), - 'author': GraphQLField(BlogAuthor), - 'title': GraphQLField(GraphQLString), - 'body': GraphQLField(GraphQLString), - 'keywords': GraphQLField(GraphQLList(GraphQLString))}) + 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), + }, + resolve=lambda obj, info, width, height: obj.pic( + info, width, height + ), + ), + "recentArticle": GraphQLField(BlogArticle), + }, + ) + + BlogArticle = GraphQLObjectType( + "Article", + { + "id": GraphQLField(GraphQLNonNull(GraphQLString)), + "isPublished": GraphQLField(GraphQLBoolean), + "author": GraphQLField(BlogAuthor), + "title": GraphQLField(GraphQLString), + "body": GraphQLField(GraphQLString), + "keywords": GraphQLField(GraphQLList(GraphQLString)), + }, + ) # noinspection PyShadowingBuiltins - BlogQuery = GraphQLObjectType('Query', { - 'article': GraphQLField( - BlogArticle, args={'id': GraphQLArgument(GraphQLID)}, - resolve=lambda obj, info, id: Article(id)), - 'feed': GraphQLField( - GraphQLList(BlogArticle), - resolve=lambda *_args: [Article(n + 1) for n in range(10)])}) + BlogQuery = GraphQLObjectType( + "Query", + { + "article": GraphQLField( + BlogArticle, + args={"id": GraphQLArgument(GraphQLID)}, + resolve=lambda obj, info, id: Article(id), + ), + "feed": GraphQLField( + GraphQLList(BlogArticle), + resolve=lambda *_args: [Article(n + 1) for n in range(10)], + ), + }, + ) BlogSchema = GraphQLSchema(BlogQuery) @@ -50,14 +81,13 @@ def __init__(self, id): self.id = id self.isPublished = True self.author = JohnSmith() - self.title = f'My Article {id}' - self.body = 'This is a post' - self.hidden = 'This data is not exposed in the schema' - self.keywords = ['foo', 'bar', 1, True, None] + self.title = f"My Article {id}" + self.body = "This is a post" + self.hidden = "This data is not exposed in the schema" + self.keywords = ["foo", "bar", 1, True, None] # noinspection PyPep8Naming,PyMethodMayBeStatic class Author: - def pic(self, info_, width, height): return Pic(123, width, height) @@ -67,14 +97,13 @@ def recentArticle(self): class JohnSmith(Author): id = 123 - name = 'John Smith' + name = "John Smith" class Pic: - def __init__(self, uid, width, height): - self.url = f'cdn://{uid}' - self.width = f'{width}' - self.height = f'{height}' + self.url = f"cdn://{uid}" + self.width = f"{width}" + self.height = f"{height}" request = """ { @@ -112,34 +141,38 @@ def __init__(self, uid, width, height): # Note: this is intentionally not validating to ensure appropriate # behavior occurs when executing an invalid query. - assert execute(BlogSchema, parse(request)) == ({ - 'feed': [ - {'id': '1', 'title': 'My Article 1'}, - {'id': '2', 'title': 'My Article 2'}, - {'id': '3', 'title': 'My Article 3'}, - {'id': '4', 'title': 'My Article 4'}, - {'id': '5', 'title': 'My Article 5'}, - {'id': '6', 'title': 'My Article 6'}, - {'id': '7', 'title': 'My Article 7'}, - {'id': '8', 'title': 'My Article 8'}, - {'id': '9', 'title': 'My Article 9'}, - {'id': '10', 'title': 'My Article 10'}], - 'article': { - 'id': '1', - 'isPublished': True, - 'title': 'My Article 1', - 'body': 'This is a post', - 'author': { - 'id': '123', - 'name': 'John Smith', - 'pic': { - 'url': 'cdn://123', - 'width': 640, - 'height': 480}, - 'recentArticle': { - 'id': '1', - 'isPublished': True, - 'title': 'My Article 1', - 'body': 'This is a post', - 'keywords': ['foo', 'bar', '1', 'true', None]}}}}, - None) + assert execute(BlogSchema, parse(request)) == ( + { + "feed": [ + {"id": "1", "title": "My Article 1"}, + {"id": "2", "title": "My Article 2"}, + {"id": "3", "title": "My Article 3"}, + {"id": "4", "title": "My Article 4"}, + {"id": "5", "title": "My Article 5"}, + {"id": "6", "title": "My Article 6"}, + {"id": "7", "title": "My Article 7"}, + {"id": "8", "title": "My Article 8"}, + {"id": "9", "title": "My Article 9"}, + {"id": "10", "title": "My Article 10"}, + ], + "article": { + "id": "1", + "isPublished": True, + "title": "My Article 1", + "body": "This is a post", + "author": { + "id": "123", + "name": "John Smith", + "pic": {"url": "cdn://123", "width": 640, "height": 480}, + "recentArticle": { + "id": "1", + "isPublished": True, + "title": "My Article 1", + "body": "This is a post", + "keywords": ["foo", "bar", "1", "true", None], + }, + }, + }, + }, + None, + ) diff --git a/tests/execution/test_sync.py b/tests/execution/test_sync.py index 36f70b25..57f5eb86 100644 --- a/tests/execution/test_sync.py +++ b/tests/execution/test_sync.py @@ -5,12 +5,10 @@ from graphql import graphql_sync from graphql.execution import execute from graphql.language import parse -from graphql.type import ( - GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString) +from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString def describe_execute_synchronously_when_possible(): - @fixture def resolve_sync(root_value, info_): return root_value @@ -20,63 +18,90 @@ async def resolve_async(root_value, info_): return root_value schema = GraphQLSchema( - GraphQLObjectType('Query', { - 'syncField': GraphQLField(GraphQLString, resolve=resolve_sync), - 'asyncField': GraphQLField(GraphQLString, resolve=resolve_async)}), - GraphQLObjectType('Mutation', { - 'syncMutationField': GraphQLField( - GraphQLString, resolve=resolve_sync)})) + GraphQLObjectType( + "Query", + { + "syncField": GraphQLField(GraphQLString, resolve=resolve_sync), + "asyncField": GraphQLField(GraphQLString, resolve=resolve_async), + }, + ), + GraphQLObjectType( + "Mutation", + {"syncMutationField": GraphQLField(GraphQLString, resolve=resolve_sync)}, + ), + ) def does_not_return_a_promise_for_initial_errors(): - doc = 'fragment Example on Query { syncField }' - assert execute(schema, parse(doc), 'rootValue') == ( - None, [{'message': 'Must provide an operation.'}]) + doc = "fragment Example on Query { syncField }" + assert execute(schema, parse(doc), "rootValue") == ( + None, + [{"message": "Must provide an operation."}], + ) def does_not_return_a_promise_if_fields_are_all_synchronous(): - doc = 'query Example { syncField }' - assert execute(schema, parse(doc), 'rootValue') == ( - {'syncField': 'rootValue'}, None) + doc = "query Example { syncField }" + assert execute(schema, parse(doc), "rootValue") == ( + {"syncField": "rootValue"}, + None, + ) def does_not_return_a_promise_if_mutation_fields_are_all_synchronous(): - doc = 'mutation Example { syncMutationField }' - assert execute(schema, parse(doc), 'rootValue') == ( - {'syncMutationField': 'rootValue'}, None) + doc = "mutation Example { syncMutationField }" + assert execute(schema, parse(doc), "rootValue") == ( + {"syncMutationField": "rootValue"}, + None, + ) @mark.asyncio async def returns_a_promise_if_any_field_is_asynchronous(): - doc = 'query Example { syncField, asyncField }' - result = execute(schema, parse(doc), 'rootValue') + doc = "query Example { syncField, asyncField }" + result = execute(schema, parse(doc), "rootValue") assert isawaitable(result) assert await result == ( - {'syncField': 'rootValue', 'asyncField': 'rootValue'}, None) + {"syncField": "rootValue", "asyncField": "rootValue"}, + None, + ) def describe_graphql_sync(): - def does_not_return_a_promise_for_syntax_errors(): - doc = 'fragment Example on Query { { { syncField }' - assert graphql_sync(schema, doc) == (None, [{ - 'message': 'Syntax Error: Expected Name, found {', - 'locations': [(1, 29)]}]) + doc = "fragment Example on Query { { { syncField }" + assert graphql_sync(schema, doc) == ( + None, + [ + { + "message": "Syntax Error: Expected Name, found {", + "locations": [(1, 29)], + } + ], + ) def does_not_return_a_promise_for_validation_errors(): - doc = 'fragment Example on Query { unknownField }' - assert graphql_sync(schema, doc) == (None, [{ - 'message': "Cannot query field 'unknownField' on type 'Query'." - " Did you mean 'syncField' or 'asyncField'?", - 'locations': [(1, 29)] - }, { - 'message': "Fragment 'Example' is never used.", - 'locations': [(1, 1)] - }]) + doc = "fragment Example on Query { unknownField }" + assert graphql_sync(schema, doc) == ( + None, + [ + { + "message": "Cannot query field 'unknownField' on type 'Query'." + " Did you mean 'syncField' or 'asyncField'?", + "locations": [(1, 29)], + }, + { + "message": "Fragment 'Example' is never used.", + "locations": [(1, 1)], + }, + ], + ) def does_not_return_a_promise_for_sync_execution(): - doc = 'query Example { syncField }' - assert graphql_sync(schema, doc, 'rootValue') == ( - {'syncField': 'rootValue'}, None) + doc = "query Example { syncField }" + assert graphql_sync(schema, doc, "rootValue") == ( + {"syncField": "rootValue"}, + None, + ) def throws_if_encountering_async_operation(): - doc = 'query Example { syncField, asyncField }' + doc = "query Example { syncField, asyncField }" with raises(RuntimeError) as exc_info: - graphql_sync(schema, doc, 'rootValue') + graphql_sync(schema, doc, "rootValue") msg = str(exc_info.value) - assert msg == 'GraphQL execution failed to complete synchronously.' + assert msg == "GraphQL execution failed to complete synchronously." diff --git a/tests/execution/test_union_interface.py b/tests/execution/test_union_interface.py index f1474083..65287500 100644 --- a/tests/execution/test_union_interface.py +++ b/tests/execution/test_union_interface.py @@ -3,8 +3,15 @@ from graphql.execution import execute from graphql.language import parse from graphql.type import ( - GraphQLBoolean, GraphQLField, GraphQLInterfaceType, GraphQLList, - GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLUnionType) + GraphQLBoolean, + GraphQLField, + GraphQLInterfaceType, + GraphQLList, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, + GraphQLUnionType, +) class Dog(NamedTuple): @@ -26,23 +33,24 @@ class Person(NamedTuple): name: str pets: List[Pet] - friends: List['Person'] + friends: List["Person"] -NamedType = GraphQLInterfaceType('Named', { - 'name': GraphQLField(GraphQLString)}) +NamedType = GraphQLInterfaceType("Named", {"name": GraphQLField(GraphQLString)}) -DogType = GraphQLObjectType('Dog', { - 'name': GraphQLField(GraphQLString), - 'barks': GraphQLField(GraphQLBoolean)}, +DogType = GraphQLObjectType( + "Dog", + {"name": GraphQLField(GraphQLString), "barks": GraphQLField(GraphQLBoolean)}, interfaces=[NamedType], - is_type_of=lambda value, info: isinstance(value, Dog)) + is_type_of=lambda value, info: isinstance(value, Dog), +) -CatType = GraphQLObjectType('Cat', { - 'name': GraphQLField(GraphQLString), - 'meows': GraphQLField(GraphQLBoolean)}, +CatType = GraphQLObjectType( + "Cat", + {"name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean)}, interfaces=[NamedType], - is_type_of=lambda value, info: isinstance(value, Cat)) + is_type_of=lambda value, info: isinstance(value, Cat), +) def resolve_pet_type(value, info): @@ -52,28 +60,31 @@ def resolve_pet_type(value, info): return CatType -PetType = GraphQLUnionType( - 'Pet', [DogType, CatType], resolve_type=resolve_pet_type) +PetType = GraphQLUnionType("Pet", [DogType, CatType], resolve_type=resolve_pet_type) -PersonType = GraphQLObjectType('Person', { - 'name': GraphQLField(GraphQLString), - 'pets': GraphQLField(GraphQLList(PetType)), - 'friends': GraphQLField(GraphQLList(NamedType))}, +PersonType = GraphQLObjectType( + "Person", + { + "name": GraphQLField(GraphQLString), + "pets": GraphQLField(GraphQLList(PetType)), + "friends": GraphQLField(GraphQLList(NamedType)), + }, interfaces=[NamedType], - is_type_of=lambda value, info: isinstance(value, Person)) + is_type_of=lambda value, info: isinstance(value, Person), +) schema = GraphQLSchema(PersonType, types=[PetType]) -garfield = Cat('Garfield', False) -odie = Dog('Odie', True) -liz = Person('Liz', [], []) -john = Person('John', [garfield, odie], [liz, odie]) +garfield = Cat("Garfield", False) +odie = Dog("Odie", True) +liz = Person("Liz", [], []) +john = Person("John", [garfield, odie], [liz, odie]) def describe_execute_union_and_intersection_types(): - def can_introspect_on_union_and_intersection_types(): - ast = parse(""" + ast = parse( + """ { Named: __type(name: "Named") { kind @@ -94,31 +105,41 @@ def can_introspect_on_union_and_intersection_types(): inputFields { name } } } - """) - - assert execute(schema, ast) == ({ - 'Named': { - 'kind': 'INTERFACE', - 'name': 'Named', - 'fields': [{'name': 'name'}], - 'interfaces': None, - 'possibleTypes': [ - {'name': 'Person'}, {'name': 'Dog'}, {'name': 'Cat'}], - 'enumValues': None, - 'inputFields': None}, - 'Pet': { - 'kind': 'UNION', - 'name': 'Pet', - 'fields': None, - 'interfaces': None, - 'possibleTypes': [{'name': 'Dog'}, {'name': 'Cat'}], - 'enumValues': None, - 'inputFields': None}}, - None) + """ + ) + + assert execute(schema, ast) == ( + { + "Named": { + "kind": "INTERFACE", + "name": "Named", + "fields": [{"name": "name"}], + "interfaces": None, + "possibleTypes": [ + {"name": "Person"}, + {"name": "Dog"}, + {"name": "Cat"}, + ], + "enumValues": None, + "inputFields": None, + }, + "Pet": { + "kind": "UNION", + "name": "Pet", + "fields": None, + "interfaces": None, + "possibleTypes": [{"name": "Dog"}, {"name": "Cat"}], + "enumValues": None, + "inputFields": None, + }, + }, + None, + ) def executes_using_union_types(): # NOTE: This is an *invalid* query, but it should be *executable*. - ast = parse(""" + ast = parse( + """ { __typename name @@ -129,19 +150,25 @@ def executes_using_union_types(): meows } } - """) + """ + ) - assert execute(schema, ast, john) == ({ - '__typename': 'Person', - 'name': 'John', - 'pets': [ - {'__typename': 'Cat', 'name': 'Garfield', 'meows': False}, - {'__typename': 'Dog', 'name': 'Odie', 'barks': True}]}, - None) + assert execute(schema, ast, john) == ( + { + "__typename": "Person", + "name": "John", + "pets": [ + {"__typename": "Cat", "name": "Garfield", "meows": False}, + {"__typename": "Dog", "name": "Odie", "barks": True}, + ], + }, + None, + ) def executes_union_types_with_inline_fragment(): # This is the valid version of the query in the above test. - ast = parse(""" + ast = parse( + """ { __typename name @@ -157,19 +184,25 @@ def executes_union_types_with_inline_fragment(): } } } - """) + """ + ) - assert execute(schema, ast, john) == ({ - '__typename': 'Person', - 'name': 'John', - 'pets': [ - {'__typename': 'Cat', 'name': 'Garfield', 'meows': False}, - {'__typename': 'Dog', 'name': 'Odie', 'barks': True}]}, - None) + assert execute(schema, ast, john) == ( + { + "__typename": "Person", + "name": "John", + "pets": [ + {"__typename": "Cat", "name": "Garfield", "meows": False}, + {"__typename": "Dog", "name": "Odie", "barks": True}, + ], + }, + None, + ) def executes_using_interface_types(): # NOTE: This is an *invalid* query, but it should be a *executable*. - ast = parse(""" + ast = parse( + """ { __typename name @@ -180,19 +213,25 @@ def executes_using_interface_types(): meows } } - """) + """ + ) - assert execute(schema, ast, john) == ({ - '__typename': 'Person', - 'name': 'John', - 'friends': [ - {'__typename': 'Person', 'name': 'Liz'}, - {'__typename': 'Dog', 'name': 'Odie', 'barks': True}]}, - None) + assert execute(schema, ast, john) == ( + { + "__typename": "Person", + "name": "John", + "friends": [ + {"__typename": "Person", "name": "Liz"}, + {"__typename": "Dog", "name": "Odie", "barks": True}, + ], + }, + None, + ) def executes_interface_types_with_inline_fragment(): # This is the valid version of the query in the above test. - ast = parse(""" + ast = parse( + """ { __typename name @@ -207,18 +246,24 @@ def executes_interface_types_with_inline_fragment(): } } } - """) + """ + ) - assert execute(schema, ast, john) == ({ - '__typename': 'Person', - 'name': 'John', - 'friends': [ - {'__typename': 'Person', 'name': 'Liz'}, - {'__typename': 'Dog', 'name': 'Odie', 'barks': True}]}, - None) + assert execute(schema, ast, john) == ( + { + "__typename": "Person", + "name": "John", + "friends": [ + {"__typename": "Person", "name": "Liz"}, + {"__typename": "Dog", "name": "Odie", "barks": True}, + ], + }, + None, + ) def allows_fragment_conditions_to_be_abstract_types(): - ast = parse(""" + ast = parse( + """ { __typename name @@ -248,47 +293,62 @@ def allows_fragment_conditions_to_be_abstract_types(): meows } } - """) - - assert execute(schema, ast, john) == ({ - '__typename': 'Person', - 'name': 'John', - 'pets': [ - {'__typename': 'Cat', 'name': 'Garfield', 'meows': False}, - {'__typename': 'Dog', 'name': 'Odie', 'barks': True}], - 'friends': [ - {'__typename': 'Person', 'name': 'Liz'}, - {'__typename': 'Dog', 'name': 'Odie', 'barks': True}]}, - None) + """ + ) + + assert execute(schema, ast, john) == ( + { + "__typename": "Person", + "name": "John", + "pets": [ + {"__typename": "Cat", "name": "Garfield", "meows": False}, + {"__typename": "Dog", "name": "Odie", "barks": True}, + ], + "friends": [ + {"__typename": "Person", "name": "Liz"}, + {"__typename": "Dog", "name": "Odie", "barks": True}, + ], + }, + None, + ) def gets_execution_info_in_resolver(): encountered = {} def resolve_type(obj, info): - encountered['context'] = info.context - encountered['schema'] = info.schema - encountered['root_value'] = info.root_value + encountered["context"] = info.context + encountered["schema"] = info.schema + encountered["root_value"] = info.root_value return PersonType2 - NamedType2 = GraphQLInterfaceType('Named', { - 'name': GraphQLField(GraphQLString)}, - resolve_type=resolve_type) + NamedType2 = GraphQLInterfaceType( + "Named", {"name": GraphQLField(GraphQLString)}, resolve_type=resolve_type + ) - PersonType2 = GraphQLObjectType('Person', { - 'name': GraphQLField(GraphQLString), - 'friends': GraphQLField(GraphQLList(NamedType2))}, - interfaces=[NamedType2]) + PersonType2 = GraphQLObjectType( + "Person", + { + "name": GraphQLField(GraphQLString), + "friends": GraphQLField(GraphQLList(NamedType2)), + }, + interfaces=[NamedType2], + ) schema2 = GraphQLSchema(PersonType2) - john2 = Person('John', [], [liz]) + john2 = Person("John", [], [liz]) - context = {'authToken': '123abc'} + context = {"authToken": "123abc"} - ast = parse('{ name, friends { name } }') + ast = parse("{ name, friends { name } }") - assert execute(schema2, ast, john2, context) == ({ - 'name': 'John', 'friends': [{'name': 'Liz'}]}, None) + assert execute(schema2, ast, john2, context) == ( + {"name": "John", "friends": [{"name": "Liz"}]}, + None, + ) assert encountered == { - 'schema': schema2, 'root_value': john2, 'context': context} + "schema": schema2, + "root_value": john2, + "context": context, + } diff --git a/tests/execution/test_variables.py b/tests/execution/test_variables.py index 13b7d5fd..eb8d56a9 100644 --- a/tests/execution/test_variables.py +++ b/tests/execution/test_variables.py @@ -4,73 +4,110 @@ from graphql.execution import execute from graphql.language import parse from graphql.type import ( - GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, - GraphQLInputField, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, - GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString) + GraphQLArgument, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLScalarType, + GraphQLSchema, + GraphQLString, +) TestComplexScalar = GraphQLScalarType( - name='ComplexScalar', - serialize=lambda value: - 'SerializedValue' if value == 'DeserializedValue' else None, - parse_value=lambda value: - 'DeserializedValue' if value == 'SerializedValue' else None, - parse_literal=lambda ast, _variables=None: - 'DeserializedValue' if ast.value == 'SerializedValue' else None) - - -TestInputObject = GraphQLInputObjectType('TestInputObject', { - 'a': GraphQLInputField(GraphQLString), - 'b': GraphQLInputField(GraphQLList(GraphQLString)), - 'c': GraphQLInputField(GraphQLNonNull(GraphQLString)), - 'd': GraphQLInputField(TestComplexScalar)}) - - -TestNestedInputObject = GraphQLInputObjectType('TestNestedInputObject', { - 'na': GraphQLInputField(GraphQLNonNull(TestInputObject)), - 'nb': GraphQLInputField(GraphQLNonNull(GraphQLString))}) - - -TestEnum = GraphQLEnumType('TestEnum', { - 'NULL': None, - 'UNDEFINED': INVALID, - 'NAN': nan, - 'FALSE': False, - 'CUSTOM': 'custom value', - 'DEFAULT_VALUE': GraphQLEnumValue()}) + name="ComplexScalar", + serialize=lambda value: "SerializedValue" if value == "DeserializedValue" else None, + parse_value=lambda value: "DeserializedValue" + if value == "SerializedValue" + else None, + parse_literal=lambda ast, _variables=None: "DeserializedValue" + if ast.value == "SerializedValue" + else None, +) + + +TestInputObject = GraphQLInputObjectType( + "TestInputObject", + { + "a": GraphQLInputField(GraphQLString), + "b": GraphQLInputField(GraphQLList(GraphQLString)), + "c": GraphQLInputField(GraphQLNonNull(GraphQLString)), + "d": GraphQLInputField(TestComplexScalar), + }, +) + + +TestNestedInputObject = GraphQLInputObjectType( + "TestNestedInputObject", + { + "na": GraphQLInputField(GraphQLNonNull(TestInputObject)), + "nb": GraphQLInputField(GraphQLNonNull(GraphQLString)), + }, +) + + +TestEnum = GraphQLEnumType( + "TestEnum", + { + "NULL": None, + "UNDEFINED": INVALID, + "NAN": nan, + "FALSE": False, + "CUSTOM": "custom value", + "DEFAULT_VALUE": GraphQLEnumValue(), + }, +) def field_with_input_arg(input_arg: GraphQLArgument): return GraphQLField( - GraphQLString, args={'input': input_arg}, - resolve=lambda _obj, _info, **args: - repr(args['input']) if 'input' in args else None) - - -TestType = GraphQLObjectType('TestType', { - 'fieldWithEnumInput': field_with_input_arg(GraphQLArgument(TestEnum)), - 'fieldWithNonNullableEnumInput': field_with_input_arg(GraphQLArgument( - GraphQLNonNull(TestEnum))), - 'fieldWithObjectInput': field_with_input_arg(GraphQLArgument( - TestInputObject)), - 'fieldWithNullableStringInput': field_with_input_arg(GraphQLArgument( - GraphQLString)), - 'fieldWithNonNullableStringInput': field_with_input_arg(GraphQLArgument( - GraphQLNonNull(GraphQLString))), - 'fieldWithDefaultArgumentValue': field_with_input_arg(GraphQLArgument( - GraphQLString, default_value='Hello World')), - 'fieldWithNonNullableStringInputAndDefaultArgumentValue': - field_with_input_arg(GraphQLArgument(GraphQLNonNull( - GraphQLString), default_value='Hello World')), - 'fieldWithNestedInputObject': field_with_input_arg( - GraphQLArgument(TestNestedInputObject, default_value='Hello World')), - 'list': field_with_input_arg(GraphQLArgument( - GraphQLList(GraphQLString))), - 'nnList': field_with_input_arg(GraphQLArgument( - GraphQLNonNull(GraphQLList(GraphQLString)))), - 'listNN': field_with_input_arg(GraphQLArgument( - GraphQLList(GraphQLNonNull(GraphQLString)))), - 'nnListNN': field_with_input_arg(GraphQLArgument( - GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString)))))}) + GraphQLString, + args={"input": input_arg}, + resolve=lambda _obj, _info, **args: repr(args["input"]) + if "input" in args + else None, + ) + + +TestType = GraphQLObjectType( + "TestType", + { + "fieldWithEnumInput": field_with_input_arg(GraphQLArgument(TestEnum)), + "fieldWithNonNullableEnumInput": field_with_input_arg( + GraphQLArgument(GraphQLNonNull(TestEnum)) + ), + "fieldWithObjectInput": field_with_input_arg(GraphQLArgument(TestInputObject)), + "fieldWithNullableStringInput": field_with_input_arg( + GraphQLArgument(GraphQLString) + ), + "fieldWithNonNullableStringInput": field_with_input_arg( + GraphQLArgument(GraphQLNonNull(GraphQLString)) + ), + "fieldWithDefaultArgumentValue": field_with_input_arg( + GraphQLArgument(GraphQLString, default_value="Hello World") + ), + "fieldWithNonNullableStringInputAndDefaultArgumentValue": field_with_input_arg( + GraphQLArgument(GraphQLNonNull(GraphQLString), default_value="Hello World") + ), + "fieldWithNestedInputObject": field_with_input_arg( + GraphQLArgument(TestNestedInputObject, default_value="Hello World") + ), + "list": field_with_input_arg(GraphQLArgument(GraphQLList(GraphQLString))), + "nnList": field_with_input_arg( + GraphQLArgument(GraphQLNonNull(GraphQLList(GraphQLString))) + ), + "listNN": field_with_input_arg( + GraphQLArgument(GraphQLList(GraphQLNonNull(GraphQLString))) + ), + "nnListNN": field_with_input_arg( + GraphQLArgument(GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString)))) + ), + }, +) schema = GraphQLSchema(TestType) @@ -81,83 +118,104 @@ def execute_query(query, variable_values=None): def describe_execute_handles_inputs(): - def describe_handles_objects_and_nullability(): - def describe_using_inline_struct(): - def executes_with_complex_input(): - result = execute_query(""" + result = execute_query( + """ { fieldWithObjectInput( input: {a: "foo", b: ["bar"], c: "baz"}) } - """) + """ + ) - assert result == ({ - 'fieldWithObjectInput': - "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, None) + assert result == ( + {"fieldWithObjectInput": "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, + None, + ) def properly_parses_single_value_to_list(): - result = execute_query(""" + result = execute_query( + """ { fieldWithObjectInput( input: {a: "foo", b: "bar", c: "baz"}) } - """) + """ + ) - assert result == ({ - 'fieldWithObjectInput': - "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, None) + assert result == ( + {"fieldWithObjectInput": "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, + None, + ) def properly_parses_null_value_to_null(): - result = execute_query(""" + result = execute_query( + """ { fieldWithObjectInput( input: {a: null, b: null, c: "C", d: null}) } - """) + """ + ) - assert result == ({ - 'fieldWithObjectInput': - "{'a': None, 'b': None, 'c': 'C', 'd': None}"}, - None) + assert result == ( + { + "fieldWithObjectInput": "{'a': None, 'b': None, 'c': 'C', 'd': None}" # noqa + }, + None, + ) def properly_parses_null_value_in_list(): - result = execute_query(""" + result = execute_query( + """ { fieldWithObjectInput(input: {b: ["A",null,"C"], c: "C"}) } - """) + """ + ) - assert result == ({ - 'fieldWithObjectInput': - "{'b': ['A', None, 'C'], 'c': 'C'}"}, None) + assert result == ( + {"fieldWithObjectInput": "{'b': ['A', None, 'C'], 'c': 'C'}"}, + None, + ) def does_not_use_incorrect_value(): - result = execute_query(""" + result = execute_query( + """ { fieldWithObjectInput(input: ["foo", "bar", "baz"]) } - """) + """ + ) - assert result == ({'fieldWithObjectInput': None}, [{ - 'message': "Argument 'input' has invalid value" - ' ["foo", "bar", "baz"].', - 'path': ['fieldWithObjectInput'], - 'locations': [(3, 51)]}]) + assert result == ( + {"fieldWithObjectInput": None}, + [ + { + "message": "Argument 'input' has invalid value" + ' ["foo", "bar", "baz"].', + "path": ["fieldWithObjectInput"], + "locations": [(3, 51)], + } + ], + ) def properly_runs_parse_literal_on_complex_scalar_types(): - result = execute_query(""" + result = execute_query( + """ { fieldWithObjectInput( input: {c: "foo", d: "SerializedValue"}) } - """) + """ + ) - assert result == ({ - 'fieldWithObjectInput': - "{'c': 'foo', 'd': 'DeserializedValue'}"}, None) + assert result == ( + {"fieldWithObjectInput": "{'c': 'foo', 'd': 'DeserializedValue'}"}, + None, + ) def describe_using_variables(): doc = """ @@ -167,120 +225,157 @@ def describe_using_variables(): """ def executes_with_complex_input(): - params = {'input': {'a': 'foo', 'b': ['bar'], 'c': 'baz'}} + params = {"input": {"a": "foo", "b": ["bar"], "c": "baz"}} result = execute_query(doc, params) - assert result == ({ - 'fieldWithObjectInput': - "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, None) + assert result == ( + {"fieldWithObjectInput": "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, + None, + ) def uses_undefined_when_variable_not_provided(): - result = execute_query(""" + result = execute_query( + """ query q($input: String) { fieldWithNullableStringInput(input: $input) } - """, {}) # Intentionally missing variable values. + """, + {}, + ) # Intentionally missing variable values. - assert result == ({'fieldWithNullableStringInput': None}, None) + assert result == ({"fieldWithNullableStringInput": None}, None) def uses_null_when_variable_provided_explicit_null_value(): - result = execute_query(""" + result = execute_query( + """ query q($input: String) { fieldWithNullableStringInput(input: $input) } - """, {'input': None}) + """, + {"input": None}, + ) - assert result == ( - {'fieldWithNullableStringInput': 'None'}, None) + assert result == ({"fieldWithNullableStringInput": "None"}, None) def uses_default_value_when_not_provided(): - result = execute_query(""" + result = execute_query( + """ query ($input: TestInputObject = { a: "foo", b: ["bar"], c: "baz"}) { fieldWithObjectInput(input: $input) } - """) + """ + ) - assert result == ({ - 'fieldWithObjectInput': - "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, None) + assert result == ( + {"fieldWithObjectInput": "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, + None, + ) def does_not_use_default_value_when_provided(): - result = execute_query(""" + result = execute_query( + """ query q($input: String = "Default value") { fieldWithNullableStringInput(input: $input) } - """, {'input': 'Variable value'}) + """, + {"input": "Variable value"}, + ) assert result == ( - {'fieldWithNullableStringInput': "'Variable value'"}, None) + {"fieldWithNullableStringInput": "'Variable value'"}, + None, + ) def uses_explicit_null_value_instead_of_default_value(): - result = execute_query(""" + result = execute_query( + """ query q($input: String = "Default value") { fieldWithNullableStringInput(input: $input) } - """, {'input': None}) + """, + {"input": None}, + ) - assert result == ( - {'fieldWithNullableStringInput': 'None'}, None) + assert result == ({"fieldWithNullableStringInput": "None"}, None) def uses_null_default_value_when_not_provided(): - result = execute_query(""" + result = execute_query( + """ query q($input: String = null) { fieldWithNullableStringInput(input: $input) } - """, {}) # Intentionally missing variable values. + """, + {}, + ) # Intentionally missing variable values. - assert result == ( - {'fieldWithNullableStringInput': 'None'}, None) + assert result == ({"fieldWithNullableStringInput": "None"}, None) def properly_parses_single_value_to_list(): - params = {'input': {'a': 'foo', 'b': 'bar', 'c': 'baz'}} + params = {"input": {"a": "foo", "b": "bar", "c": "baz"}} result = execute_query(doc, params) - assert result == ({ - 'fieldWithObjectInput': - "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, None) + assert result == ( + {"fieldWithObjectInput": "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, + None, + ) def executes_with_complex_scalar_input(): - params = {'input': {'c': 'foo', 'd': 'SerializedValue'}} + params = {"input": {"c": "foo", "d": "SerializedValue"}} result = execute_query(doc, params) - assert result == ({ - 'fieldWithObjectInput': - "{'c': 'foo', 'd': 'DeserializedValue'}"}, None) + assert result == ( + {"fieldWithObjectInput": "{'c': 'foo', 'd': 'DeserializedValue'}"}, + None, + ) def errors_on_null_for_nested_non_null(): - params = {'input': {'a': 'foo', 'b': 'bar', 'c': None}} + params = {"input": {"a": "foo", "b": "bar", "c": None}} result = execute_query(doc, params) - assert result == (None, [{ - 'message': "Variable '$input' got invalid value" - " {'a': 'foo', 'b': 'bar', 'c': None};" - ' Expected non-nullable type String!' - ' not to be null at value.c.', - 'locations': [(2, 24)], 'path': None}]) + assert result == ( + None, + [ + { + "message": "Variable '$input' got invalid value" + " {'a': 'foo', 'b': 'bar', 'c': None};" + " Expected non-nullable type String!" + " not to be null at value.c.", + "locations": [(2, 24)], + "path": None, + } + ], + ) def errors_on_incorrect_type(): - result = execute_query(doc, {'input': 'foo bar'}) + result = execute_query(doc, {"input": "foo bar"}) - assert result == (None, [{ - 'message': - "Variable '$input' got invalid value 'foo bar';" - ' Expected type TestInputObject to be a dict.', - 'locations': [(2, 24)], 'path': None}]) + assert result == ( + None, + [ + { + "message": "Variable '$input' got invalid value 'foo bar';" + " Expected type TestInputObject to be a dict.", + "locations": [(2, 24)], + "path": None, + } + ], + ) def errors_on_omission_of_nested_non_null(): - result = execute_query( - doc, {'input': {'a': 'foo', 'b': 'bar'}}) + result = execute_query(doc, {"input": {"a": "foo", "b": "bar"}}) - assert result == (None, [{ - 'message': - "Variable '$input' got invalid value" - " {'a': 'foo', 'b': 'bar'}; Field value.c" - ' of required type String! was not provided.', - 'locations': [(2, 24)]}]) + assert result == ( + None, + [ + { + "message": "Variable '$input' got invalid value" + " {'a': 'foo', 'b': 'bar'}; Field value.c" + " of required type String! was not provided.", + "locations": [(2, 24)], + } + ], + ) def errors_on_deep_nested_errors_and_with_many_errors(): nested_doc = """ @@ -288,37 +383,46 @@ def errors_on_deep_nested_errors_and_with_many_errors(): fieldWithNestedObjectInput(input: $input) } """ - result = execute_query( - nested_doc, {'input': {'na': {'a': 'foo'}}}) - - assert result == (None, [{ - 'message': - "Variable '$input' got invalid value" - " {'na': {'a': 'foo'}}; Field value.na.c" - ' of required type String! was not provided.', - 'locations': [(2, 28)]}, { - 'message': - "Variable '$input' got invalid value" - " {'na': {'a': 'foo'}}; Field value.nb" - ' of required type String! was not provided.', - 'locations': [(2, 28)]}]) + result = execute_query(nested_doc, {"input": {"na": {"a": "foo"}}}) + + assert result == ( + None, + [ + { + "message": "Variable '$input' got invalid value" + " {'na': {'a': 'foo'}}; Field value.na.c" + " of required type String! was not provided.", + "locations": [(2, 28)], + }, + { + "message": "Variable '$input' got invalid value" + " {'na': {'a': 'foo'}}; Field value.nb" + " of required type String! was not provided.", + "locations": [(2, 28)], + }, + ], + ) def errors_on_addition_of_unknown_input_field(): - params = {'input': { - 'a': 'foo', 'b': 'bar', 'c': 'baz', 'extra': 'dog'}} + params = {"input": {"a": "foo", "b": "bar", "c": "baz", "extra": "dog"}} result = execute_query(doc, params) - assert result == (None, [{ - 'message': - "Variable '$input' got invalid value {'a': 'foo'," - " 'b': 'bar', 'c': 'baz', 'extra': 'dog'}; Field" - " 'extra' is not defined by type TestInputObject.", - 'locations': [(2, 24)]}]) + assert result == ( + None, + [ + { + "message": "Variable '$input' got invalid value {'a':" + " 'foo', 'b': 'bar', 'c': 'baz', 'extra': 'dog'}; Field" + " 'extra' is not defined by type TestInputObject.", + "locations": [(2, 24)], + } + ], + ) def describe_handles_custom_enum_values(): - def allows_custom_enum_values_as_inputs(): - result = execute_query(""" + result = execute_query( + """ { null: fieldWithEnumInput(input: NULL) NaN: fieldWithEnumInput(input: NAN) @@ -326,54 +430,65 @@ def allows_custom_enum_values_as_inputs(): customValue: fieldWithEnumInput(input: CUSTOM) defaultValue: fieldWithEnumInput(input: DEFAULT_VALUE) } - """) + """ + ) - assert result == ({ - 'null': 'None', - 'NaN': 'nan', - 'false': 'False', - 'customValue': "'custom value'", - # different from graphql.js, enum values are always wrapped - 'defaultValue': 'None' - }, None) + assert result == ( + { + "null": "None", + "NaN": "nan", + "false": "False", + "customValue": "'custom value'", + # different from graphql.js, enum values are always wrapped + "defaultValue": "None", + }, + None, + ) def allows_non_nullable_inputs_to_have_null_as_enum_custom_value(): - result = execute_query(""" + result = execute_query( + """ { fieldWithNonNullableEnumInput(input: NULL) } - """) + """ + ) - assert result == ({'fieldWithNonNullableEnumInput': 'None'}, None) + assert result == ({"fieldWithNonNullableEnumInput": "None"}, None) def describe_handles_nullable_scalars(): - def allows_nullable_inputs_to_be_omitted(): - result = execute_query(""" + result = execute_query( + """ { fieldWithNullableStringInput } - """) + """ + ) - assert result == ({'fieldWithNullableStringInput': None}, None) + assert result == ({"fieldWithNullableStringInput": None}, None) def allows_nullable_inputs_to_be_omitted_in_a_variable(): - result = execute_query(""" + result = execute_query( + """ query ($value: String) { fieldWithNullableStringInput(input: $value) } - """) + """ + ) - assert result == ({'fieldWithNullableStringInput': None}, None) + assert result == ({"fieldWithNullableStringInput": None}, None) def allows_nullable_inputs_to_be_omitted_in_an_unlisted_variable(): - result = execute_query(""" + result = execute_query( + """ query SetsNullable { fieldWithNullableStringInput(input: $value) } - """) + """ + ) - assert result == ({'fieldWithNullableStringInput': None}, None) + assert result == ({"fieldWithNullableStringInput": None}, None) def allows_nullable_inputs_to_be_set_to_null_in_a_variable(): doc = """ @@ -381,9 +496,9 @@ def allows_nullable_inputs_to_be_set_to_null_in_a_variable(): fieldWithNullableStringInput(input: $value) } """ - result = execute_query(doc, {'value': None}) + result = execute_query(doc, {"value": None}) - assert result == ({'fieldWithNullableStringInput': 'None'}, None) + assert result == ({"fieldWithNullableStringInput": "None"}, None) def allows_nullable_inputs_to_be_set_to_a_value_in_a_variable(): doc = """ @@ -391,42 +506,53 @@ def allows_nullable_inputs_to_be_set_to_a_value_in_a_variable(): fieldWithNullableStringInput(input: $value) } """ - result = execute_query(doc, {'value': 'a'}) + result = execute_query(doc, {"value": "a"}) - assert result == ({'fieldWithNullableStringInput': "'a'"}, None) + assert result == ({"fieldWithNullableStringInput": "'a'"}, None) def allows_nullable_inputs_to_be_set_to_a_value_directly(): - result = execute_query(""" + result = execute_query( + """ { fieldWithNullableStringInput(input: "a") } - """) + """ + ) - assert result == ({'fieldWithNullableStringInput': "'a'"}, None) + assert result == ({"fieldWithNullableStringInput": "'a'"}, None) def describe_handles_non_nullable_scalars(): - def allows_non_nullable_inputs_to_be_omitted_given_a_default(): - result = execute_query(""" + result = execute_query( + """ query ($value: String = "default") { fieldWithNonNullableStringInput(input: $value) } - """) + """ + ) - assert result == ({ - 'fieldWithNonNullableStringInput': "'default'"}, None) + assert result == ({"fieldWithNonNullableStringInput": "'default'"}, None) def does_not_allow_non_nullable_inputs_to_be_omitted_in_a_variable(): - result = execute_query(""" + result = execute_query( + """ query ($value: String!) { fieldWithNonNullableStringInput(input: $value) } - """) + """ + ) - assert result == (None, [{ - 'message': "Variable '$value' of required type 'String!'" - ' was not provided.', - 'locations': [(2, 24)], 'path': None}]) + assert result == ( + None, + [ + { + "message": "Variable '$value' of required type 'String!'" + " was not provided.", + "locations": [(2, 24)], + "path": None, + } + ], + ) def does_not_allow_non_nullable_inputs_to_be_set_to_null_in_variable(): doc = """ @@ -434,12 +560,19 @@ def does_not_allow_non_nullable_inputs_to_be_set_to_null_in_variable(): fieldWithNonNullableStringInput(input: $value) } """ - result = execute_query(doc, {'value': None}) + result = execute_query(doc, {"value": None}) - assert result == (None, [{ - 'message': "Variable '$value' of non-null type 'String!'" - ' must not be null.', - 'locations': [(2, 24)], 'path': None}]) + assert result == ( + None, + [ + { + "message": "Variable '$value' of non-null type 'String!'" + " must not be null.", + "locations": [(2, 24)], + "path": None, + } + ], + ) def allows_non_nullable_inputs_to_be_set_to_a_value_in_a_variable(): doc = """ @@ -447,27 +580,35 @@ def allows_non_nullable_inputs_to_be_set_to_a_value_in_a_variable(): fieldWithNonNullableStringInput(input: $value) } """ - result = execute_query(doc, {'value': 'a'}) + result = execute_query(doc, {"value": "a"}) - assert result == ({'fieldWithNonNullableStringInput': "'a'"}, None) + assert result == ({"fieldWithNonNullableStringInput": "'a'"}, None) def allows_non_nullable_inputs_to_be_set_to_a_value_directly(): - result = execute_query(""" + result = execute_query( + """ { fieldWithNonNullableStringInput(input: "a") } - """) + """ + ) - assert result == ({'fieldWithNonNullableStringInput': "'a'"}, None) + assert result == ({"fieldWithNonNullableStringInput": "'a'"}, None) def reports_error_for_missing_non_nullable_inputs(): - result = execute_query('{ fieldWithNonNullableStringInput }') + result = execute_query("{ fieldWithNonNullableStringInput }") - assert result == ({'fieldWithNonNullableStringInput': None}, [{ - 'message': "Argument 'input' of required type 'String!'" - ' was not provided.', - 'locations': [(1, 3)], - 'path': ['fieldWithNonNullableStringInput']}]) + assert result == ( + {"fieldWithNonNullableStringInput": None}, + [ + { + "message": "Argument 'input' of required type 'String!'" + " was not provided.", + "locations": [(1, 3)], + "path": ["fieldWithNonNullableStringInput"], + } + ], + ) def reports_error_for_array_passed_into_string_input(): doc = """ @@ -475,13 +616,20 @@ def reports_error_for_array_passed_into_string_input(): fieldWithNonNullableStringInput(input: $value) } """ - result = execute_query(doc, {'value': [1, 2, 3]}) + result = execute_query(doc, {"value": [1, 2, 3]}) - assert result == (None, [{ - 'message': "Variable '$value' got invalid value [1, 2, 3];" - ' Expected type String; String cannot represent' - ' a non string value: [1, 2, 3]', - 'locations': [(2, 24)], 'path':None}]) + assert result == ( + None, + [ + { + "message": "Variable '$value' got invalid value [1, 2, 3];" + " Expected type String; String cannot represent" + " a non string value: [1, 2, 3]", + "locations": [(2, 24)], + "path": None, + } + ], + ) def reports_error_for_non_provided_variables_for_non_nullable_inputs(): # Note: this test would typically fail validation before @@ -490,30 +638,37 @@ def reports_error_for_non_provided_variables_for_non_nullable_inputs(): # have introduced a breaking change to make a formerly non-required # argument required, this asserts failure before allowing the # underlying code to receive a non-null value. - result = execute_query(""" + result = execute_query( + """ { fieldWithNonNullableStringInput(input: $foo) } - """) + """ + ) - assert result == ({'fieldWithNonNullableStringInput': None}, [{ - 'message': "Argument 'input' of required type 'String!'" - " was provided the variable '$foo' which was" - ' not provided a runtime value.', - 'locations': [(3, 58)], - 'path': ['fieldWithNonNullableStringInput']}]) + assert result == ( + {"fieldWithNonNullableStringInput": None}, + [ + { + "message": "Argument 'input' of required type 'String!'" + " was provided the variable '$foo' which was" + " not provided a runtime value.", + "locations": [(3, 58)], + "path": ["fieldWithNonNullableStringInput"], + } + ], + ) def describe_handles_lists_and_nullability(): - def allows_lists_to_be_null(): doc = """ query ($input: [String]) { list(input: $input) } """ - result = execute_query(doc, {'input': None}) + result = execute_query(doc, {"input": None}) - assert result == ({'list': 'None'}, None) + assert result == ({"list": "None"}, None) def allows_lists_to_contain_values(): doc = """ @@ -521,9 +676,9 @@ def allows_lists_to_contain_values(): list(input: $input) } """ - result = execute_query(doc, {'input': ['A']}) + result = execute_query(doc, {"input": ["A"]}) - assert result == ({'list': "['A']"}, None) + assert result == ({"list": "['A']"}, None) def allows_lists_to_contain_null(): doc = """ @@ -532,9 +687,9 @@ def allows_lists_to_contain_null(): } """ - result = execute_query(doc, {'input': ['A', None, 'B']}) + result = execute_query(doc, {"input": ["A", None, "B"]}) - assert result == ({'list': "['A', None, 'B']"}, None) + assert result == ({"list": "['A', None, 'B']"}, None) def does_not_allow_non_null_lists_to_be_null(): doc = """ @@ -543,12 +698,19 @@ def does_not_allow_non_null_lists_to_be_null(): } """ - result = execute_query(doc, {'input': None}) + result = execute_query(doc, {"input": None}) - assert result == (None, [{ - 'message': "Variable '$input' of non-null type '[String]!'" - ' must not be null.', - 'locations': [(2, 24)], 'path': None}]) + assert result == ( + None, + [ + { + "message": "Variable '$input' of non-null type '[String]!'" + " must not be null.", + "locations": [(2, 24)], + "path": None, + } + ], + ) def allows_non_null_lists_to_contain_values(): doc = """ @@ -557,9 +719,9 @@ def allows_non_null_lists_to_contain_values(): } """ - result = execute_query(doc, {'input': ['A']}) + result = execute_query(doc, {"input": ["A"]}) - assert result == ({'nnList': "['A']"}, None) + assert result == ({"nnList": "['A']"}, None) def allows_non_null_lists_to_contain_null(): doc = """ @@ -568,9 +730,9 @@ def allows_non_null_lists_to_contain_null(): } """ - result = execute_query(doc, {'input': ['A', None, 'B']}) + result = execute_query(doc, {"input": ["A", None, "B"]}) - assert result == ({'nnList': "['A', None, 'B']"}, None) + assert result == ({"nnList": "['A', None, 'B']"}, None) def allows_lists_of_non_nulls_to_be_null(): doc = """ @@ -579,9 +741,9 @@ def allows_lists_of_non_nulls_to_be_null(): } """ - result = execute_query(doc, {'input': None}) + result = execute_query(doc, {"input": None}) - assert result == ({'listNN': 'None'}, None) + assert result == ({"listNN": "None"}, None) def allows_lists_of_non_nulls_to_contain_values(): doc = """ @@ -590,9 +752,9 @@ def allows_lists_of_non_nulls_to_contain_values(): } """ - result = execute_query(doc, {'input': ['A']}) + result = execute_query(doc, {"input": ["A"]}) - assert result == ({'listNN': "['A']"}, None) + assert result == ({"listNN": "['A']"}, None) def does_not_allow_lists_of_non_nulls_to_contain_null(): doc = """ @@ -600,13 +762,19 @@ def does_not_allow_lists_of_non_nulls_to_contain_null(): listNN(input: $input) } """ - result = execute_query(doc, {'input': ['A', None, 'B']}) + result = execute_query(doc, {"input": ["A", None, "B"]}) - assert result == (None, [{ - 'message': "Variable '$input' got invalid value" - " ['A', None, 'B']; Expected non-nullable type" - ' String! not to be null at value[1].', - 'locations': [(2, 24)]}]) + assert result == ( + None, + [ + { + "message": "Variable '$input' got invalid value" + " ['A', None, 'B']; Expected non-nullable type" + " String! not to be null at value[1].", + "locations": [(2, 24)], + } + ], + ) def does_not_allow_non_null_lists_of_non_nulls_to_be_null(): doc = """ @@ -614,12 +782,18 @@ def does_not_allow_non_null_lists_of_non_nulls_to_be_null(): nnListNN(input: $input) } """ - result = execute_query(doc, {'input': None}) + result = execute_query(doc, {"input": None}) - assert result == (None, [{ - 'message': "Variable '$input' of non-null type '[String!]!'" - ' must not be null.', - 'locations': [(2, 24)]}]) + assert result == ( + None, + [ + { + "message": "Variable '$input' of non-null type '[String!]!'" + " must not be null.", + "locations": [(2, 24)], + } + ], + ) def allows_non_null_lists_of_non_nulls_to_contain_values(): doc = """ @@ -627,9 +801,9 @@ def allows_non_null_lists_of_non_nulls_to_contain_values(): nnListNN(input: $input) } """ - result = execute_query(doc, {'input': ['A']}) + result = execute_query(doc, {"input": ["A"]}) - assert result == ({'nnListNN': "['A']"}, None) + assert result == ({"nnListNN": "['A']"}, None) def does_not_allow_non_null_lists_of_non_nulls_to_contain_null(): doc = """ @@ -637,13 +811,20 @@ def does_not_allow_non_null_lists_of_non_nulls_to_contain_null(): nnListNN(input: $input) } """ - result = execute_query(doc, {'input': ['A', None, 'B']}) + result = execute_query(doc, {"input": ["A", None, "B"]}) - assert result == (None, [{ - 'message': "Variable '$input' got invalid value" - " ['A', None, 'B']; Expected non-nullable type" - ' String! not to be null at value[1].', - 'locations': [(2, 24)], 'path': None}]) + assert result == ( + None, + [ + { + "message": "Variable '$input' got invalid value" + " ['A', None, 'B']; Expected non-nullable type" + " String! not to be null at value[1].", + "locations": [(2, 24)], + "path": None, + } + ], + ) def does_not_allow_invalid_types_to_be_used_as_values(): doc = """ @@ -651,13 +832,19 @@ def does_not_allow_invalid_types_to_be_used_as_values(): fieldWithObjectInput(input: $input) } """ - result = execute_query(doc, {'input': {'list': ['A', 'B']}}) + result = execute_query(doc, {"input": {"list": ["A", "B"]}}) - assert result == (None, [{ - 'message': "Variable '$input' expected value" - " of type 'TestType!' which cannot" - ' be used as an input type.', - 'locations': [(2, 32)]}]) + assert result == ( + None, + [ + { + "message": "Variable '$input' expected value" + " of type 'TestType!' which cannot" + " be used as an input type.", + "locations": [(2, 32)], + } + ], + ) def does_not_allow_unknown_types_to_be_used_as_values(): doc = """ @@ -665,53 +852,69 @@ def does_not_allow_unknown_types_to_be_used_as_values(): fieldWithObjectInput(input: $input) } """ - result = execute_query(doc, {'input': 'whoknows'}) + result = execute_query(doc, {"input": "whoknows"}) - assert result == (None, [{ - 'message': "Variable '$input' expected value" - " of type 'UnknownType!' which cannot" - ' be used as an input type.', - 'locations': [(2, 32)]}]) + assert result == ( + None, + [ + { + "message": "Variable '$input' expected value" + " of type 'UnknownType!' which cannot" + " be used as an input type.", + "locations": [(2, 32)], + } + ], + ) def describe_execute_uses_argument_default_values(): - def when_no_argument_provided(): - result = execute_query('{ fieldWithDefaultArgumentValue }') + result = execute_query("{ fieldWithDefaultArgumentValue }") - assert result == ({ - 'fieldWithDefaultArgumentValue': "'Hello World'"}, None) + assert result == ({"fieldWithDefaultArgumentValue": "'Hello World'"}, None) def when_omitted_variable_provided(): - result = execute_query(""" + result = execute_query( + """ query ($optional: String) { fieldWithDefaultArgumentValue(input: $optional) } - """) + """ + ) - assert result == ({ - 'fieldWithDefaultArgumentValue': "'Hello World'"}, None) + assert result == ({"fieldWithDefaultArgumentValue": "'Hello World'"}, None) def not_when_argument_cannot_be_coerced(): - result = execute_query(""" + result = execute_query( + """ { fieldWithDefaultArgumentValue(input: WRONG_TYPE) } - """) + """ + ) - assert result == ({ - 'fieldWithDefaultArgumentValue': None}, [{ - 'message': "Argument 'input' has invalid value" - ' WRONG_TYPE.', - 'locations': [(3, 56)], - 'path': ['fieldWithDefaultArgumentValue']}]) + assert result == ( + {"fieldWithDefaultArgumentValue": None}, + [ + { + "message": "Argument 'input' has invalid value" " WRONG_TYPE.", + "locations": [(3, 56)], + "path": ["fieldWithDefaultArgumentValue"], + } + ], + ) def when_no_runtime_value_is_provided_to_a_non_null_argument(): - result = execute_query(""" + result = execute_query( + """ query optionalVariable($optional: String) { fieldWithNonNullableStringInputAndDefaultArgumentValue(input: $optional) } - """) # noqa + """ # noqa + ) assert result == ( - {'fieldWithNonNullableStringInputAndDefaultArgumentValue': - "'Hello World'"}, None) + { + "fieldWithNonNullableStringInputAndDefaultArgumentValue": "'Hello World'" # noqa + }, + None, + ) diff --git a/tests/language/__init__.py b/tests/language/__init__.py index 626b98d6..215c7531 100644 --- a/tests/language/__init__.py +++ b/tests/language/__init__.py @@ -6,15 +6,15 @@ def read_graphql(name): - path = join(dirname(__file__), name + '.graphql') - return open(path, encoding='utf-8').read() + path = join(dirname(__file__), name + ".graphql") + return open(path, encoding="utf-8").read() -@fixture(scope='module') +@fixture(scope="module") def kitchen_sink(): - return read_graphql('kitchen_sink') + return read_graphql("kitchen_sink") -@fixture(scope='module') +@fixture(scope="module") def schema_kitchen_sink(): - return read_graphql('schema_kitchen_sink') + return read_graphql("schema_kitchen_sink") diff --git a/tests/language/test_ast.py b/tests/language/test_ast.py index 0a86e92a..6a7f3acb 100644 --- a/tests/language/test_ast.py +++ b/tests/language/test_ast.py @@ -4,11 +4,10 @@ class SampleTestNode(Node): - __slots__ = 'alpha', 'beta' + __slots__ = "alpha", "beta" def describe_node_class(): - def initializes_with_keywords(): node = SampleTestNode(alpha=1, beta=2, loc=0) assert node.alpha == 1 @@ -21,13 +20,13 @@ def initializes_with_keywords(): node = SampleTestNode(alpha=1, beta=2, gamma=3) assert node.alpha == 1 assert node.beta == 2 - assert not hasattr(node, 'gamma') + assert not hasattr(node, "gamma") def has_representation_with_loc(): node = SampleTestNode(alpha=1, beta=2) - assert repr(node) == 'SampleTestNode' + assert repr(node) == "SampleTestNode" node = SampleTestNode(alpha=1, beta=2, loc=3) - assert repr(node) == 'SampleTestNode at 3' + assert repr(node) == "SampleTestNode at 3" def can_check_equality(): node = SampleTestNode(alpha=1, beta=2) @@ -45,7 +44,7 @@ def can_create_shallow_copy(): assert node2 == node def provides_snake_cased_kind_as_class_attribute(): - assert SampleTestNode.kind == 'sample_test' + assert SampleTestNode.kind == "sample_test" def provides_keys_as_class_attribute(): - assert SampleTestNode.keys == ['loc', 'alpha', 'beta'] + assert SampleTestNode.keys == ["loc", "alpha", "beta"] diff --git a/tests/language/test_block_string_value.py b/tests/language/test_block_string_value.py index 2d4948ce..fe3d5464 100644 --- a/tests/language/test_block_string_value.py +++ b/tests/language/test_block_string_value.py @@ -2,72 +2,68 @@ def join(*args): - return '\n'.join(args) + return "\n".join(args) def describe_block_string_value(): - def removes_uniform_indentation_from_a_string(): raw_value = join( - '', - ' Hello,', - ' World!', - '', - ' Yours,', - ' GraphQL.') + "", " Hello,", " World!", "", " Yours,", " GraphQL." + ) assert block_string_value(raw_value) == join( - 'Hello,', ' World!', '', 'Yours,', ' GraphQL.') + "Hello,", " World!", "", "Yours,", " GraphQL." + ) def removes_empty_leading_and_trailing_lines(): raw_value = join( - '', - '', - ' Hello,', - ' World!', - '', - ' Yours,', - ' GraphQL.', - '', - '') + "", + "", + " Hello,", + " World!", + "", + " Yours,", + " GraphQL.", + "", + "", + ) assert block_string_value(raw_value) == join( - 'Hello,', ' World!', '', 'Yours,', ' GraphQL.') + "Hello,", " World!", "", "Yours,", " GraphQL." + ) def removes_blank_leading_and_trailing_lines(): raw_value = join( - ' ', - ' ', - ' Hello,', - ' World!', - '', - ' Yours,', - ' GraphQL.', - ' ', - ' ') + " ", + " ", + " Hello,", + " World!", + "", + " Yours,", + " GraphQL.", + " ", + " ", + ) assert block_string_value(raw_value) == join( - 'Hello,', ' World!', '', 'Yours,', ' GraphQL.') + "Hello,", " World!", "", "Yours,", " GraphQL." + ) def retains_indentation_from_first_line(): raw_value = join( - ' Hello,', - ' World!', - '', - ' Yours,', - ' GraphQL.') + " Hello,", " World!", "", " Yours,", " GraphQL." + ) assert block_string_value(raw_value) == join( - ' Hello,', ' World!', '', 'Yours,', ' GraphQL.') + " Hello,", " World!", "", "Yours,", " GraphQL." + ) def does_not_alter_trailing_spaces(): raw_value = join( - ' ', - ' Hello, ', - ' World! ', - ' ', - ' Yours, ', - ' GraphQL. ', - ' ') + " ", + " Hello, ", + " World! ", + " ", + " Yours, ", + " GraphQL. ", + " ", + ) assert block_string_value(raw_value) == join( - 'Hello, ', - ' World! ', - ' ', - 'Yours, ', - ' GraphQL. ') + "Hello, ", " World! ", " ", "Yours, ", " GraphQL. " + ) diff --git a/tests/language/test_lexer.py b/tests/language/test_lexer.py index fe782909..f3c107f2 100644 --- a/tests/language/test_lexer.py +++ b/tests/language/test_lexer.py @@ -1,8 +1,7 @@ from pytest import raises from graphql.error import GraphQLSyntaxError -from graphql.language import ( - Lexer, Source, SourceLocation, Token, TokenKind) +from graphql.language import Lexer, Source, SourceLocation, Token, TokenKind from graphql.pyutils import dedent @@ -20,40 +19,41 @@ def assert_syntax_error(text, message, location): def describe_lexer(): - def disallows_uncommon_control_characters(): assert_syntax_error( - '\x07', "Cannot contain the invalid character '\\x07'", (1, 1)) + "\x07", "Cannot contain the invalid character '\\x07'", (1, 1) + ) # noinspection PyArgumentEqualDefault def accepts_bom_header(): - token = lex_one('\uFEFF foo') - assert token == Token(TokenKind.NAME, 2, 5, 1, 3, None, 'foo') + token = lex_one("\uFEFF foo") + assert token == Token(TokenKind.NAME, 2, 5, 1, 3, None, "foo") # noinspection PyArgumentEqualDefault def records_line_and_column(): - token = lex_one('\n \r\n \r foo\n') - assert token == Token(TokenKind.NAME, 8, 11, 4, 3, None, 'foo') + token = lex_one("\n \r\n \r foo\n") + assert token == Token(TokenKind.NAME, 8, 11, 4, 3, None, "foo") def can_be_stringified(): - token = lex_one('foo') + token = lex_one("foo") assert repr(token) == "" assert token.desc == "Name 'foo'" # noinspection PyArgumentEqualDefault def skips_whitespace_and_comments(): - token = lex_one('\n\n foo\n\n\n') - assert token == Token(TokenKind.NAME, 6, 9, 3, 5, None, 'foo') - token = lex_one('\n #comment\n foo#comment\n') - assert token == Token(TokenKind.NAME, 18, 21, 3, 5, None, 'foo') - token = lex_one(',,,foo,,,') - assert token == Token(TokenKind.NAME, 3, 6, 1, 4, None, 'foo') + token = lex_one("\n\n foo\n\n\n") + assert token == Token(TokenKind.NAME, 6, 9, 3, 5, None, "foo") + token = lex_one("\n #comment\n foo#comment\n") + assert token == Token(TokenKind.NAME, 18, 21, 3, 5, None, "foo") + token = lex_one(",,,foo,,,") + assert token == Token(TokenKind.NAME, 3, 6, 1, 4, None, "foo") def errors_respect_whitespace(): with raises(GraphQLSyntaxError) as exc_info: - lex_one('\n\n ?\n\n\n') + lex_one("\n\n ?\n\n\n") - assert str(exc_info.value) == dedent(""" + assert str(exc_info.value) == dedent( + """ Syntax Error: Cannot parse the unexpected character '?'. GraphQL request (3:5) @@ -61,14 +61,16 @@ def errors_respect_whitespace(): 3: ? ^ 4:\x20 - """) + """ + ) def updates_line_numbers_in_error_for_file_context(): - s = '\n\n ?\n\n' - source = Source(s, 'foo.js', SourceLocation(11, 12)) + s = "\n\n ?\n\n" + source = Source(s, "foo.js", SourceLocation(11, 12)) with raises(GraphQLSyntaxError) as exc_info: Lexer(source).advance() - assert str(exc_info.value) == dedent(""" + assert str(exc_info.value) == dedent( + """ Syntax Error: Cannot parse the unexpected character '?'. foo.js (13:6) @@ -76,210 +78,236 @@ def updates_line_numbers_in_error_for_file_context(): 13: ? ^ 14:\x20 - """) + """ + ) def updates_column_numbers_in_error_for_file_context(): - source = Source('?', 'foo.js', SourceLocation(1, 5)) + source = Source("?", "foo.js", SourceLocation(1, 5)) with raises(GraphQLSyntaxError) as exc_info: Lexer(source).advance() - assert str(exc_info.value) == dedent(""" + assert str(exc_info.value) == dedent( + """ Syntax Error: Cannot parse the unexpected character '?'. foo.js (1:5) 1: ? ^ - """) + """ + ) # noinspection PyArgumentEqualDefault def lexes_strings(): assert lex_one('"simple"') == Token( - TokenKind.STRING, 0, 8, 1, 1, None, 'simple') + TokenKind.STRING, 0, 8, 1, 1, None, "simple" + ) assert lex_one('" white space "') == Token( - TokenKind.STRING, 0, 15, 1, 1, None, ' white space ') + TokenKind.STRING, 0, 15, 1, 1, None, " white space " + ) assert lex_one('"quote \\""') == Token( - TokenKind.STRING, 0, 10, 1, 1, None, 'quote "') + TokenKind.STRING, 0, 10, 1, 1, None, 'quote "' + ) assert lex_one('"escaped \\n\\r\\b\\t\\f"') == Token( - TokenKind.STRING, 0, 20, 1, 1, None, 'escaped \n\r\b\t\f') + TokenKind.STRING, 0, 20, 1, 1, None, "escaped \n\r\b\t\f" + ) assert lex_one('"slashes \\\\ \\/"') == Token( - TokenKind.STRING, 0, 15, 1, 1, None, 'slashes \\ /') + TokenKind.STRING, 0, 15, 1, 1, None, "slashes \\ /" + ) assert lex_one('"unicode \\u1234\\u5678\\u90AB\\uCDEF"') == Token( - TokenKind.STRING, 0, 34, 1, 1, None, - 'unicode \u1234\u5678\u90AB\uCDEF') + TokenKind.STRING, 0, 34, 1, 1, None, "unicode \u1234\u5678\u90AB\uCDEF" + ) def lex_reports_useful_string_errors(): - assert_syntax_error('"', 'Unterminated string.', (1, 2)) - assert_syntax_error('"no end quote', 'Unterminated string.', (1, 14)) + assert_syntax_error('"', "Unterminated string.", (1, 2)) + assert_syntax_error('"no end quote', "Unterminated string.", (1, 14)) assert_syntax_error( - "'single quotes'", "Unexpected single quote character ('), " - 'did you mean to use a double quote (")?', (1, 1)) + "'single quotes'", + "Unexpected single quote character ('), " + 'did you mean to use a double quote (")?', + (1, 1), + ) assert_syntax_error( - '"contains unescaped \x07 control char"', - "Invalid character within String: '\\x07'.", (1, 21)) + '"contains unescaped \x07 control char"', + "Invalid character within String: '\\x07'.", + (1, 21), + ) assert_syntax_error( '"null-byte is not \x00 end of file"', - "Invalid character within String: '\\x00'.", (1, 19)) - assert_syntax_error( - '"multi\nline"', 'Unterminated string', (1, 7)) + "Invalid character within String: '\\x00'.", + (1, 19), + ) + assert_syntax_error('"multi\nline"', "Unterminated string", (1, 7)) + assert_syntax_error('"multi\rline"', "Unterminated string", (1, 7)) assert_syntax_error( - '"multi\rline"', 'Unterminated string', (1, 7)) + '"bad \\x esc"', "Invalid character escape sequence: '\\x'.", (1, 7) + ) assert_syntax_error( - '"bad \\x esc"', "Invalid character escape sequence: '\\x'.", - (1, 7)) + '"bad \\u1 esc"', "Invalid character escape sequence: '\\u1 es'.", (1, 7) + ) assert_syntax_error( - '"bad \\u1 esc"', - "Invalid character escape sequence: '\\u1 es'.", (1, 7)) + '"bad \\u0XX1 esc"', "Invalid character escape sequence: '\\u0XX1'.", (1, 7) + ) assert_syntax_error( - '"bad \\u0XX1 esc"', - "Invalid character escape sequence: '\\u0XX1'.", (1, 7)) + '"bad \\uXXXX esc"', "Invalid character escape sequence: '\\uXXXX'.", (1, 7) + ) assert_syntax_error( - '"bad \\uXXXX esc"', - "Invalid character escape sequence: '\\uXXXX'.", (1, 7)) + '"bad \\uFXXX esc"', "Invalid character escape sequence: '\\uFXXX'.", (1, 7) + ) assert_syntax_error( - '"bad \\uFXXX esc"', - "Invalid character escape sequence: '\\uFXXX'.", (1, 7)) - assert_syntax_error( - '"bad \\uXXXF esc"', - "Invalid character escape sequence: '\\uXXXF'.", (1, 7)) + '"bad \\uXXXF esc"', "Invalid character escape sequence: '\\uXXXF'.", (1, 7) + ) # noinspection PyArgumentEqualDefault def lexes_block_strings(): assert lex_one('"""simple"""') == Token( - TokenKind.BLOCK_STRING, 0, 12, 1, 1, None, 'simple') + TokenKind.BLOCK_STRING, 0, 12, 1, 1, None, "simple" + ) assert lex_one('""" white space """') == Token( - TokenKind.BLOCK_STRING, 0, 19, 1, 1, None, ' white space ') + TokenKind.BLOCK_STRING, 0, 19, 1, 1, None, " white space " + ) assert lex_one('"""contains " quote"""') == Token( - TokenKind.BLOCK_STRING, 0, 22, 1, 1, None, 'contains " quote') + TokenKind.BLOCK_STRING, 0, 22, 1, 1, None, 'contains " quote' + ) assert lex_one('"""contains \\""" triplequote"""') == Token( - TokenKind.BLOCK_STRING, 0, 31, 1, 1, None, - 'contains """ triplequote') + TokenKind.BLOCK_STRING, 0, 31, 1, 1, None, 'contains """ triplequote' + ) assert lex_one('"""multi\nline"""') == Token( - TokenKind.BLOCK_STRING, 0, 16, 1, 1, None, 'multi\nline') + TokenKind.BLOCK_STRING, 0, 16, 1, 1, None, "multi\nline" + ) assert lex_one('"""multi\rline\r\nnormalized"""') == Token( - TokenKind.BLOCK_STRING, 0, 28, 1, 1, None, - 'multi\nline\nnormalized') + TokenKind.BLOCK_STRING, 0, 28, 1, 1, None, "multi\nline\nnormalized" + ) assert lex_one('"""unescaped \\n\\r\\b\\t\\f\\u1234"""') == Token( - TokenKind.BLOCK_STRING, 0, 32, 1, 1, None, - 'unescaped \\n\\r\\b\\t\\f\\u1234') + TokenKind.BLOCK_STRING, + 0, + 32, + 1, + 1, + None, + "unescaped \\n\\r\\b\\t\\f\\u1234", + ) assert lex_one('"""slashes \\\\ \\/"""') == Token( - TokenKind.BLOCK_STRING, 0, 19, 1, 1, None, 'slashes \\\\ \\/') + TokenKind.BLOCK_STRING, 0, 19, 1, 1, None, "slashes \\\\ \\/" + ) assert lex_one( '"""\n\n spans\n multiple\n' - ' lines\n\n """') == Token( - TokenKind.BLOCK_STRING, 0, 68, 1, 1, None, - 'spans\n multiple\n lines') + ' lines\n\n """' + ) == Token( + TokenKind.BLOCK_STRING, 0, 68, 1, 1, None, "spans\n multiple\n lines" + ) def lex_reports_useful_block_string_errors(): - assert_syntax_error('"""', 'Unterminated string.', (1, 4)) - assert_syntax_error('"""no end quote', 'Unterminated string.', (1, 16)) + assert_syntax_error('"""', "Unterminated string.", (1, 4)) + assert_syntax_error('"""no end quote', "Unterminated string.", (1, 16)) assert_syntax_error( '"""contains unescaped \x07 control char"""', - "Invalid character within String: '\\x07'.", (1, 23)) + "Invalid character within String: '\\x07'.", + (1, 23), + ) assert_syntax_error( '"""null-byte is not \x00 end of file"""', - "Invalid character within String: '\\x00'.", (1, 21)) + "Invalid character within String: '\\x00'.", + (1, 21), + ) # noinspection PyArgumentEqualDefault def lexes_numbers(): - assert lex_one('0') == Token(TokenKind.INT, 0, 1, 1, 1, None, '0') - assert lex_one('1') == Token(TokenKind.INT, 0, 1, 1, 1, None, '1') - assert lex_one('4') == Token(TokenKind.INT, 0, 1, 1, 1, None, '4') - assert lex_one('9') == Token(TokenKind.INT, 0, 1, 1, 1, None, '9') - assert lex_one('42') == Token(TokenKind.INT, 0, 2, 1, 1, None, '42') - assert lex_one('4.123') == Token( - TokenKind.FLOAT, 0, 5, 1, 1, None, '4.123') - assert lex_one('-4') == Token( - TokenKind.INT, 0, 2, 1, 1, None, '-4') - assert lex_one('-42') == Token( - TokenKind.INT, 0, 3, 1, 1, None, '-42') - assert lex_one('-4.123') == Token( - TokenKind.FLOAT, 0, 6, 1, 1, None, '-4.123') - assert lex_one('0.123') == Token( - TokenKind.FLOAT, 0, 5, 1, 1, None, '0.123') - assert lex_one('123e4') == Token( - TokenKind.FLOAT, 0, 5, 1, 1, None, '123e4') - assert lex_one('123E4') == Token( - TokenKind.FLOAT, 0, 5, 1, 1, None, '123E4') - assert lex_one('123e-4') == Token( - TokenKind.FLOAT, 0, 6, 1, 1, None, '123e-4') - assert lex_one('123e+4') == Token( - TokenKind.FLOAT, 0, 6, 1, 1, None, '123e+4') - assert lex_one('-1.123e4') == Token( - TokenKind.FLOAT, 0, 8, 1, 1, None, '-1.123e4') - assert lex_one('-1.123E4') == Token( - TokenKind.FLOAT, 0, 8, 1, 1, None, '-1.123E4') - assert lex_one('-1.123e-4') == Token( - TokenKind.FLOAT, 0, 9, 1, 1, None, '-1.123e-4') - assert lex_one('-1.123e+4') == Token( - TokenKind.FLOAT, 0, 9, 1, 1, None, '-1.123e+4') - assert lex_one('-1.123e4567') == Token( - TokenKind.FLOAT, 0, 11, 1, 1, None, '-1.123e4567') + assert lex_one("0") == Token(TokenKind.INT, 0, 1, 1, 1, None, "0") + assert lex_one("1") == Token(TokenKind.INT, 0, 1, 1, 1, None, "1") + assert lex_one("4") == Token(TokenKind.INT, 0, 1, 1, 1, None, "4") + assert lex_one("9") == Token(TokenKind.INT, 0, 1, 1, 1, None, "9") + assert lex_one("42") == Token(TokenKind.INT, 0, 2, 1, 1, None, "42") + assert lex_one("4.123") == Token(TokenKind.FLOAT, 0, 5, 1, 1, None, "4.123") + assert lex_one("-4") == Token(TokenKind.INT, 0, 2, 1, 1, None, "-4") + assert lex_one("-42") == Token(TokenKind.INT, 0, 3, 1, 1, None, "-42") + assert lex_one("-4.123") == Token(TokenKind.FLOAT, 0, 6, 1, 1, None, "-4.123") + assert lex_one("0.123") == Token(TokenKind.FLOAT, 0, 5, 1, 1, None, "0.123") + assert lex_one("123e4") == Token(TokenKind.FLOAT, 0, 5, 1, 1, None, "123e4") + assert lex_one("123E4") == Token(TokenKind.FLOAT, 0, 5, 1, 1, None, "123E4") + assert lex_one("123e-4") == Token(TokenKind.FLOAT, 0, 6, 1, 1, None, "123e-4") + assert lex_one("123e+4") == Token(TokenKind.FLOAT, 0, 6, 1, 1, None, "123e+4") + assert lex_one("-1.123e4") == Token( + TokenKind.FLOAT, 0, 8, 1, 1, None, "-1.123e4" + ) + assert lex_one("-1.123E4") == Token( + TokenKind.FLOAT, 0, 8, 1, 1, None, "-1.123E4" + ) + assert lex_one("-1.123e-4") == Token( + TokenKind.FLOAT, 0, 9, 1, 1, None, "-1.123e-4" + ) + assert lex_one("-1.123e+4") == Token( + TokenKind.FLOAT, 0, 9, 1, 1, None, "-1.123e+4" + ) + assert lex_one("-1.123e4567") == Token( + TokenKind.FLOAT, 0, 11, 1, 1, None, "-1.123e4567" + ) def lex_reports_useful_number_errors(): assert_syntax_error( - '00', "Invalid number, unexpected digit after 0: '0'.", (1, 2)) - assert_syntax_error( - '+1', "Cannot parse the unexpected character '+'.", (1, 1)) + "00", "Invalid number, unexpected digit after 0: '0'.", (1, 2) + ) + assert_syntax_error("+1", "Cannot parse the unexpected character '+'.", (1, 1)) assert_syntax_error( - '1.', 'Invalid number, expected digit but got: .', (1, 3)) + "1.", "Invalid number, expected digit but got: .", (1, 3) + ) assert_syntax_error( - '1.e1', "Invalid number, expected digit but got: 'e'.", (1, 3)) + "1.e1", "Invalid number, expected digit but got: 'e'.", (1, 3) + ) + assert_syntax_error(".123", "Cannot parse the unexpected character '.'", (1, 1)) assert_syntax_error( - '.123', "Cannot parse the unexpected character '.'", (1, 1)) + "1.A", "Invalid number, expected digit but got: 'A'.", (1, 3) + ) assert_syntax_error( - '1.A', "Invalid number, expected digit but got: 'A'.", (1, 3)) + "-A", "Invalid number, expected digit but got: 'A'.", (1, 2) + ) assert_syntax_error( - '-A', "Invalid number, expected digit but got: 'A'.", (1, 2)) + "1.0e", "Invalid number, expected digit but got: .", (1, 5) + ) assert_syntax_error( - '1.0e', 'Invalid number, expected digit but got: .', (1, 5)) - assert_syntax_error( - '1.0eA', "Invalid number, expected digit but got: 'A'.", (1, 5)) + "1.0eA", "Invalid number, expected digit but got: 'A'.", (1, 5) + ) # noinspection PyArgumentEqualDefault def lexes_punctuation(): - assert lex_one('!') == Token(TokenKind.BANG, 0, 1, 1, 1, None, None) - assert lex_one('$') == Token(TokenKind.DOLLAR, 0, 1, 1, 1, None, None) - assert lex_one('(') == Token(TokenKind.PAREN_L, 0, 1, 1, 1, None, None) - assert lex_one(')') == Token(TokenKind.PAREN_R, 0, 1, 1, 1, None, None) - assert lex_one('...') == Token( - TokenKind.SPREAD, 0, 3, 1, 1, None, None) - assert lex_one(':') == Token(TokenKind.COLON, 0, 1, 1, 1, None, None) - assert lex_one('=') == Token(TokenKind.EQUALS, 0, 1, 1, 1, None, None) - assert lex_one('@') == Token(TokenKind.AT, 0, 1, 1, 1, None, None) - assert lex_one('[') == Token( - TokenKind.BRACKET_L, 0, 1, 1, 1, None, None) - assert lex_one(']') == Token( - TokenKind.BRACKET_R, 0, 1, 1, 1, None, None) - assert lex_one('{') == Token(TokenKind.BRACE_L, 0, 1, 1, 1, None, None) - assert lex_one('}') == Token(TokenKind.BRACE_R, 0, 1, 1, 1, None, None) - assert lex_one('|') == Token(TokenKind.PIPE, 0, 1, 1, 1, None, None) + assert lex_one("!") == Token(TokenKind.BANG, 0, 1, 1, 1, None, None) + assert lex_one("$") == Token(TokenKind.DOLLAR, 0, 1, 1, 1, None, None) + assert lex_one("(") == Token(TokenKind.PAREN_L, 0, 1, 1, 1, None, None) + assert lex_one(")") == Token(TokenKind.PAREN_R, 0, 1, 1, 1, None, None) + assert lex_one("...") == Token(TokenKind.SPREAD, 0, 3, 1, 1, None, None) + assert lex_one(":") == Token(TokenKind.COLON, 0, 1, 1, 1, None, None) + assert lex_one("=") == Token(TokenKind.EQUALS, 0, 1, 1, 1, None, None) + assert lex_one("@") == Token(TokenKind.AT, 0, 1, 1, 1, None, None) + assert lex_one("[") == Token(TokenKind.BRACKET_L, 0, 1, 1, 1, None, None) + assert lex_one("]") == Token(TokenKind.BRACKET_R, 0, 1, 1, 1, None, None) + assert lex_one("{") == Token(TokenKind.BRACE_L, 0, 1, 1, 1, None, None) + assert lex_one("}") == Token(TokenKind.BRACE_R, 0, 1, 1, 1, None, None) + assert lex_one("|") == Token(TokenKind.PIPE, 0, 1, 1, 1, None, None) def lex_reports_useful_unknown_character_error(): + assert_syntax_error("..", "Cannot parse the unexpected character '.'", (1, 1)) + assert_syntax_error("?", "Cannot parse the unexpected character '?'", (1, 1)) assert_syntax_error( - '..', "Cannot parse the unexpected character '.'", (1, 1)) - assert_syntax_error( - '?', "Cannot parse the unexpected character '?'", (1, 1)) - assert_syntax_error( - '\u203B', "Cannot parse the unexpected character '\u203B'", - (1, 1)) + "\u203B", "Cannot parse the unexpected character '\u203B'", (1, 1) + ) assert_syntax_error( - '\u200b', "Cannot parse the unexpected character '\\u200b'", - (1, 1)) + "\u200b", "Cannot parse the unexpected character '\\u200b'", (1, 1) + ) # noinspection PyArgumentEqualDefault def lex_reports_useful_information_for_dashes_in_names(): - q = 'a-b' + q = "a-b" lexer = Lexer(Source(q)) first_token = lexer.advance() - assert first_token == Token(TokenKind.NAME, 0, 1, 1, 1, None, 'a') + assert first_token == Token(TokenKind.NAME, 0, 1, 1, 1, None, "a") with raises(GraphQLSyntaxError) as exc_info: lexer.advance() error = exc_info.value assert error.message == ( - "Syntax Error: Invalid number, expected digit but got: 'b'.") + "Syntax Error: Invalid number, expected digit but got: 'b'." + ) assert error.locations == [(1, 3)] def produces_double_linked_list_of_tokens_including_comments(): - lexer = Lexer(Source('{\n #comment\n field\n }')) + lexer = Lexer(Source("{\n #comment\n field\n }")) start_token = lexer.token while True: end_token = lexer.advance() @@ -295,4 +323,10 @@ def produces_double_linked_list_of_tokens_including_comments(): tokens.append(tok) tok = tok.next assert [tok.kind.value for tok in tokens] == [ - '', '{', 'Comment', 'Name', '}', ''] + "", + "{", + "Comment", + "Name", + "}", + "", + ] diff --git a/tests/language/test_parser.py b/tests/language/test_parser.py index 64d30c54..3441e9a0 100644 --- a/tests/language/test_parser.py +++ b/tests/language/test_parser.py @@ -5,11 +5,28 @@ from graphql.pyutils import dedent from graphql.error import GraphQLSyntaxError from graphql.language import ( - ArgumentNode, DefinitionNode, DocumentNode, - FieldNode, IntValueNode, ListTypeNode, ListValueNode, NameNode, - NamedTypeNode, NonNullTypeNode, NullValueNode, OperationDefinitionNode, - OperationType, SelectionSetNode, StringValueNode, ValueNode, - Token, parse, parse_type, parse_value, Source) + ArgumentNode, + DefinitionNode, + DocumentNode, + FieldNode, + IntValueNode, + ListTypeNode, + ListValueNode, + NameNode, + NamedTypeNode, + NonNullTypeNode, + NullValueNode, + OperationDefinitionNode, + OperationType, + SelectionSetNode, + StringValueNode, + ValueNode, + Token, + parse, + parse_type, + parse_value, + Source, +) # noinspection PyUnresolvedReferences from . import kitchen_sink # noqa: F401 @@ -24,86 +41,94 @@ def assert_syntax_error(text, message, location): def describe_parser(): - def asserts_that_a_source_to_parse_was_provided(): with raises(TypeError) as exc_info: # noinspection PyArgumentList assert parse() msg = str(exc_info.value) - assert 'missing' in msg - assert 'source' in msg + assert "missing" in msg + assert "source" in msg with raises(TypeError) as exc_info: # noinspection PyTypeChecker assert parse(None) msg = str(exc_info.value) - assert 'Must provide Source. Received: None' in msg + assert "Must provide Source. Received: None" in msg with raises(TypeError) as exc_info: # noinspection PyTypeChecker assert parse({}) msg = str(exc_info.value) - assert 'Must provide Source. Received: {}' in msg + assert "Must provide Source. Received: {}" in msg def parse_provides_useful_errors(): with raises(GraphQLSyntaxError) as exc_info: - parse('{') + parse("{") error = exc_info.value - assert error.message == 'Syntax Error: Expected Name, found ' + assert error.message == "Syntax Error: Expected Name, found " assert error.positions == [1] assert error.locations == [(1, 2)] - assert str(error) == dedent(""" + assert str(error) == dedent( + """ Syntax Error: Expected Name, found GraphQL request (1:2) 1: { ^ - """) + """ + ) assert_syntax_error( - '\n { ...MissingOn }\n fragment MissingOn Type', - "Expected 'on', found Name 'Type'", (3, 26)) - assert_syntax_error('{ field: {} }', 'Expected Name, found {', (1, 10)) + "\n { ...MissingOn }\n fragment MissingOn Type", + "Expected 'on', found Name 'Type'", + (3, 26), + ) + assert_syntax_error("{ field: {} }", "Expected Name, found {", (1, 10)) assert_syntax_error( - 'notanoperation Foo { field }', - "Unexpected Name 'notanoperation'", (1, 1)) - assert_syntax_error('...', 'Unexpected ...', (1, 1)) + "notanoperation Foo { field }", "Unexpected Name 'notanoperation'", (1, 1) + ) + assert_syntax_error("...", "Unexpected ...", (1, 1)) def parse_provides_useful_error_when_using_source(): with raises(GraphQLSyntaxError) as exc_info: - parse(Source('query', 'MyQuery.graphql')) + parse(Source("query", "MyQuery.graphql")) error = exc_info.value assert str(error) == ( - 'Syntax Error: Expected {, found \n\n' - 'MyQuery.graphql (1:6)\n1: query\n ^\n') + "Syntax Error: Expected {, found \n\n" + "MyQuery.graphql (1:6)\n1: query\n ^\n" + ) def parses_variable_inline_values(): - parse('{ field(complex: { a: { b: [ $var ] } }) }') + parse("{ field(complex: { a: { b: [ $var ] } }) }") def parses_constant_default_values(): assert_syntax_error( - 'query Foo($x: Complex = { a: { b: [ $var ] } }) { field }', - 'Unexpected $', (1, 37)) + "query Foo($x: Complex = { a: { b: [ $var ] } }) { field }", + "Unexpected $", + (1, 37), + ) def experimental_parses_variable_definition_directives(): - parse('query Foo($x: Boolean = false @bar) { field }', - experimental_variable_definition_directives=True) + parse( + "query Foo($x: Boolean = false @bar) { field }", + experimental_variable_definition_directives=True, + ) def does_not_accept_fragments_named_on(): - assert_syntax_error( - 'fragment on on on { on }', "Unexpected Name 'on'", (1, 10)) + assert_syntax_error("fragment on on on { on }", "Unexpected Name 'on'", (1, 10)) def does_not_accept_fragments_spread_of_on(): - assert_syntax_error('{ ...on }', 'Expected Name, found }', (1, 9)) + assert_syntax_error("{ ...on }", "Expected Name, found }", (1, 9)) def parses_multi_byte_characters(): # Note: \u0A0A could be naively interpreted as two line-feed chars. - doc = parse(""" + doc = parse( + """ # This comment has a \u0A0A multi-byte character. { field(arg: "Has a \u0A0A multi-byte character.") } - """) + """ + ) definitions = doc.definitions assert isinstance(definitions, list) assert len(definitions) == 1 - selection_set = cast( - OperationDefinitionNode, definitions[0]).selection_set + selection_set = cast(OperationDefinitionNode, definitions[0]).selection_set selections = selection_set.selections assert isinstance(selections, list) assert len(selections) == 1 @@ -112,18 +137,25 @@ def parses_multi_byte_characters(): assert len(arguments) == 1 value = arguments[0].value assert isinstance(value, StringValueNode) - assert value.value == 'Has a \u0A0A multi-byte character.' + assert value.value == "Has a \u0A0A multi-byte character." # noinspection PyShadowingNames def parses_kitchen_sink(kitchen_sink): # noqa: F811 parse(kitchen_sink) def allows_non_keywords_anywhere_a_name_is_allowed(): - non_keywords = ('on', 'fragment', 'query', 'mutation', 'subscription', - 'true', 'false') + non_keywords = ( + "on", + "fragment", + "query", + "mutation", + "subscription", + "true", + "false", + ) for keyword in non_keywords: # You can't define or reference a fragment named `on`. - fragment_name = 'a' if keyword == 'on' else keyword + fragment_name = "a" if keyword == "on" else keyword document = f""" query {keyword} {{ ... {fragment_name} @@ -137,42 +169,54 @@ def allows_non_keywords_anywhere_a_name_is_allowed(): parse(document) def parses_anonymous_mutation_operations(): - parse(""" + parse( + """ mutation { mutationField } - """) + """ + ) def parses_anonymous_subscription_operations(): - parse(""" + parse( + """ subscription { subscriptionField } - """) + """ + ) def parses_named_mutation_operations(): - parse(""" + parse( + """ mutation Foo { mutationField } - """) + """ + ) def parses_named_subscription_operations(): - parse(""" + parse( + """ subscription Foo { subscriptionField } - """) + """ + ) def creates_ast(): - doc = parse(dedent(""" + doc = parse( + dedent( + """ { node(id: 4) { id, name } } - """)) + """ + ) + ) assert isinstance(doc, DocumentNode) assert doc.loc == (0, 41) definitions = doc.definitions @@ -198,7 +242,7 @@ def creates_ast(): name = field.name assert isinstance(name, NameNode) assert name.loc == (4, 8) - assert name.value == 'node' + assert name.value == "node" arguments = field.arguments assert isinstance(arguments, list) assert len(arguments) == 1 @@ -207,12 +251,12 @@ def creates_ast(): name = argument.name assert isinstance(name, NameNode) assert name.loc == (9, 11) - assert name.value == 'id' + assert name.value == "id" value = argument.value assert isinstance(value, ValueNode) assert isinstance(value, IntValueNode) assert value.loc == (13, 14) - assert value.value == '4' + assert value.value == "4" assert argument.loc == (9, 14) assert field.directives == [] selection_set = field.selection_set @@ -227,7 +271,7 @@ def creates_ast(): name = field.name assert isinstance(name, NameNode) assert name.loc == (22, 24) - assert name.value == 'id' + assert name.value == "id" assert field.arguments == [] assert field.directives == [] assert field.selection_set is None @@ -238,7 +282,7 @@ def creates_ast(): name = field.name assert isinstance(name, NameNode) assert name.loc == (22, 24) - assert name.value == 'id' + assert name.value == "id" assert field.arguments == [] assert field.directives == [] assert field.selection_set is None @@ -249,19 +293,23 @@ def creates_ast(): name = field.name assert isinstance(name, NameNode) assert name.loc == (30, 34) - assert name.value == 'name' + assert name.value == "name" assert field.arguments == [] assert field.directives == [] assert field.selection_set is None def creates_ast_from_nameless_query_without_variables(): - doc = parse(dedent(""" + doc = parse( + dedent( + """ query { node { id } } - """)) + """ + ) + ) assert isinstance(doc, DocumentNode) assert doc.loc == (0, 30) definitions = doc.definitions @@ -287,7 +335,7 @@ def creates_ast_from_nameless_query_without_variables(): name = field.name assert isinstance(name, NameNode) assert name.loc == (10, 14) - assert name.value == 'node' + assert name.value == "node" assert field.arguments == [] assert field.directives == [] selection_set = field.selection_set @@ -303,44 +351,43 @@ def creates_ast_from_nameless_query_without_variables(): name = field.name assert isinstance(name, NameNode) assert name.loc == (21, 23) - assert name.value == 'id' + assert name.value == "id" assert field.arguments == [] assert field.directives == [] assert field.selection_set is None def allows_parsing_without_source_location_information(): - result = parse('{ id }', no_location=True) + result = parse("{ id }", no_location=True) assert result.loc is None def experimental_allows_parsing_fragment_defined_variables(): - document = 'fragment a($v: Boolean = false) on t { f(v: $v) }' + document = "fragment a($v: Boolean = false) on t { f(v: $v) }" parse(document, experimental_fragment_variables=True) with raises(GraphQLSyntaxError): parse(document) def contains_location_information_that_only_stringifies_start_end(): - result = parse('{ id }') - assert str(result.loc) == '0:6' + result = parse("{ id }") + assert str(result.loc) == "0:6" def contains_references_to_source(): - source = Source('{ id }') + source = Source("{ id }") result = parse(source) assert result.loc.source is source def contains_references_to_start_and_end_tokens(): - result = parse('{ id }') + result = parse("{ id }") start_token = result.loc.start_token assert isinstance(start_token, Token) - assert start_token.desc == '' + assert start_token.desc == "" end_token = result.loc.end_token assert isinstance(end_token, Token) - assert end_token.desc == '' + assert end_token.desc == "" def describe_parse_value(): - def parses_null_value(): - result = parse_value('null') + result = parse_value("null") assert isinstance(result, NullValueNode) assert result.loc == (0, 4) @@ -354,11 +401,11 @@ def parses_list_values(): value = values[0] assert isinstance(value, IntValueNode) assert value.loc == (1, 4) - assert value.value == '123' + assert value.value == "123" value = values[1] assert isinstance(value, StringValueNode) assert value.loc == (5, 10) - assert value.value == 'abc' + assert value.value == "abc" def parses_block_strings(): result = parse_value('["""long""" "short"]') @@ -370,37 +417,36 @@ def parses_block_strings(): value = values[0] assert isinstance(value, StringValueNode) assert value.loc == (1, 11) - assert value.value == 'long' + assert value.value == "long" assert value.block is True value = values[1] assert isinstance(value, StringValueNode) assert value.loc == (12, 19) - assert value.value == 'short' + assert value.value == "short" assert value.block is False def describe_parse_type(): - def parses_well_known_types(): - result = parse_type('String') + result = parse_type("String") assert isinstance(result, NamedTypeNode) assert result.loc == (0, 6) name = result.name assert isinstance(name, NameNode) assert name.loc == (0, 6) - assert name.value == 'String' + assert name.value == "String" def parses_custom_types(): - result = parse_type('MyType') + result = parse_type("MyType") assert isinstance(result, NamedTypeNode) assert result.loc == (0, 6) name = result.name assert isinstance(name, NameNode) assert name.loc == (0, 6) - assert name.value == 'MyType' + assert name.value == "MyType" def parses_list_types(): - result = parse_type('[MyType]') + result = parse_type("[MyType]") assert isinstance(result, ListTypeNode) assert result.loc == (0, 8) type_ = result.type @@ -409,10 +455,10 @@ def parses_list_types(): name = type_.name assert isinstance(name, NameNode) assert name.loc == (1, 7) - assert name.value == 'MyType' + assert name.value == "MyType" def parses_non_null_types(): - result = parse_type('MyType!') + result = parse_type("MyType!") assert isinstance(result, NonNullTypeNode) assert result.loc == (0, 7) type_ = result.type @@ -421,10 +467,10 @@ def parses_non_null_types(): name = type_.name assert isinstance(name, NameNode) assert name.loc == (0, 6) - assert name.value == 'MyType' + assert name.value == "MyType" def parses_nested_types(): - result = parse_type('[MyType!]') + result = parse_type("[MyType!]") assert isinstance(result, ListTypeNode) assert result.loc == (0, 9) type_ = result.type @@ -436,4 +482,4 @@ def parses_nested_types(): name = type_.name assert isinstance(name, NameNode) assert name.loc == (1, 7) - assert name.value == 'MyType' + assert name.value == "MyType" diff --git a/tests/language/test_predicates.py b/tests/language/test_predicates.py index 697b74a2..8f96c9de 100644 --- a/tests/language/test_predicates.py +++ b/tests/language/test_predicates.py @@ -1,18 +1,38 @@ from graphql.language import ( - DefinitionNode, DocumentNode, ExecutableDefinitionNode, - FieldDefinitionNode, FieldNode, InlineFragmentNode, IntValueNode, Node, - NonNullTypeNode, ObjectValueNode, ScalarTypeDefinitionNode, - ScalarTypeExtensionNode, SchemaDefinitionNode, SchemaExtensionNode, - SelectionNode, SelectionSetNode, TypeDefinitionNode, TypeExtensionNode, - TypeNode, TypeSystemDefinitionNode, ValueNode, - is_definition_node, is_executable_definition_node, - is_selection_node, is_value_node, is_type_node, - is_type_system_definition_node, is_type_definition_node, - is_type_system_extension_node, is_type_extension_node) + DefinitionNode, + DocumentNode, + ExecutableDefinitionNode, + FieldDefinitionNode, + FieldNode, + InlineFragmentNode, + IntValueNode, + Node, + NonNullTypeNode, + ObjectValueNode, + ScalarTypeDefinitionNode, + ScalarTypeExtensionNode, + SchemaDefinitionNode, + SchemaExtensionNode, + SelectionNode, + SelectionSetNode, + TypeDefinitionNode, + TypeExtensionNode, + TypeNode, + TypeSystemDefinitionNode, + ValueNode, + is_definition_node, + is_executable_definition_node, + is_selection_node, + is_value_node, + is_type_node, + is_type_system_definition_node, + is_type_definition_node, + is_type_system_extension_node, + is_type_extension_node, +) def describe_predicates(): - def check_definition_node(): assert not is_definition_node(Node()) assert not is_definition_node(DocumentNode()) diff --git a/tests/language/test_printer.py b/tests/language/test_printer.py index 474de09c..eaf6cb46 100644 --- a/tests/language/test_printer.py +++ b/tests/language/test_printer.py @@ -19,11 +19,11 @@ def does_not_alter_ast(kitchen_sink): # noqa: F811 assert ast == ast_before def prints_minimal_ast(): - ast = FieldNode(name=NameNode(value='foo')) - assert print_ast(ast) == 'foo' + ast = FieldNode(name=NameNode(value="foo")) + assert print_ast(ast) == "foo" def produces_helpful_error_messages(): - bad_ast = {'random': 'Data'} + bad_ast = {"random": "Data"} with raises(TypeError) as exc_info: # noinspection PyTypeChecker print_ast(bad_ast) @@ -31,66 +31,78 @@ def produces_helpful_error_messages(): assert msg == "Not an AST Node: {'random': 'Data'}" def correctly_prints_query_operation_without_name(): - query_ast_shorthanded = parse('query { id, name }') - assert print_ast(query_ast_shorthanded) == '{\n id\n name\n}\n' + query_ast_shorthanded = parse("query { id, name }") + assert print_ast(query_ast_shorthanded) == "{\n id\n name\n}\n" def correctly_prints_mutation_operation_without_name(): - mutation_ast = parse('mutation { id, name }') - assert print_ast(mutation_ast) == 'mutation {\n id\n name\n}\n' + mutation_ast = parse("mutation { id, name }") + assert print_ast(mutation_ast) == "mutation {\n id\n name\n}\n" def correctly_prints_query_operation_with_artifacts(): query_ast_with_artifacts = parse( - 'query ($foo: TestType) @testDirective { id, name }') - assert print_ast(query_ast_with_artifacts) == dedent(""" + "query ($foo: TestType) @testDirective { id, name }" + ) + assert print_ast(query_ast_with_artifacts) == dedent( + """ query ($foo: TestType) @testDirective { id name } - """) + """ + ) def correctly_prints_mutation_operation_with_artifacts(): mutation_ast_with_artifacts = parse( - 'mutation ($foo: TestType) @testDirective { id, name }') - assert print_ast(mutation_ast_with_artifacts) == dedent(""" + "mutation ($foo: TestType) @testDirective { id, name }" + ) + assert print_ast(mutation_ast_with_artifacts) == dedent( + """ mutation ($foo: TestType) @testDirective { id name } - """) + """ + ) def experimental_prints_query_with_variable_directives(): query_ast_with_variable_directive = parse( - 'query ($foo: TestType = {a: 123}' - ' @testDirective(if: true) @test) { id }', - experimental_variable_definition_directives=True) - assert print_ast(query_ast_with_variable_directive) == dedent(""" + "query ($foo: TestType = {a: 123}" + " @testDirective(if: true) @test) { id }", + experimental_variable_definition_directives=True, + ) + assert print_ast(query_ast_with_variable_directive) == dedent( + """ query ($foo: TestType = {a: 123} @testDirective(if: true) @test) { id } - """) + """ + ) def experimental_prints_fragment_with_variable_directives(): query_ast_with_variable_directive = parse( - 'fragment Foo($foo: TestType @test) on TestType' - ' @testDirective { id }', + "fragment Foo($foo: TestType @test) on TestType" " @testDirective { id }", experimental_fragment_variables=True, - experimental_variable_definition_directives=True) - assert print_ast(query_ast_with_variable_directive) == dedent(""" + experimental_variable_definition_directives=True, + ) + assert print_ast(query_ast_with_variable_directive) == dedent( + """ fragment Foo($foo: TestType @test) on TestType @testDirective { id } - """) + """ + ) def describe_block_string(): - def correctly_prints_single_line_block_strings_with_leading_space(): ast_with_artifacts = parse('{ field(arg: """ space-led value""") }') - assert print_ast(ast_with_artifacts) == dedent(''' + assert print_ast(ast_with_artifacts) == dedent( + ''' { field(arg: """ space-led value""") } - ''') + ''' + ) def correctly_prints_string_with_a_first_line_indentation(): source = ''' @@ -121,15 +133,15 @@ def experimental_correctly_prints_fragment_defined_variables(): id } """ - fragment_with_variable = parse( - source, experimental_fragment_variables=True) + fragment_with_variable = parse(source, experimental_fragment_variables=True) assert print_ast(fragment_with_variable) == dedent(source) # noinspection PyShadowingNames def prints_kitchen_sink(kitchen_sink): # noqa: F811 ast = parse(kitchen_sink) printed = print_ast(ast) - assert printed == dedent(r''' + assert printed == dedent( + r''' query queryName($foo: ComplexType, $site: Site = MOBILE) { whoever123is: node(id: [123, 456]) { id @@ -182,4 +194,5 @@ def prints_kitchen_sink(kitchen_sink): # noqa: F811 unnamed(truthy: true, falsey: false, nullish: null) query } - ''') # noqa + ''' + ) # noqa diff --git a/tests/language/test_schema_parser.py b/tests/language/test_schema_parser.py index d60c180a..5bef03d8 100644 --- a/tests/language/test_schema_parser.py +++ b/tests/language/test_schema_parser.py @@ -4,14 +4,29 @@ from graphql.error import GraphQLSyntaxError from graphql.language import ( - BooleanValueNode, DocumentNode, EnumTypeDefinitionNode, - EnumValueDefinitionNode, FieldDefinitionNode, - InputObjectTypeDefinitionNode, InputValueDefinitionNode, - InterfaceTypeDefinitionNode, ListTypeNode, NameNode, NamedTypeNode, - NonNullTypeNode, ObjectTypeDefinitionNode, - ObjectTypeExtensionNode, OperationType, OperationTypeDefinitionNode, - ScalarTypeDefinitionNode, SchemaExtensionNode, DirectiveNode, - StringValueNode, UnionTypeDefinitionNode, parse) + BooleanValueNode, + DocumentNode, + EnumTypeDefinitionNode, + EnumValueDefinitionNode, + FieldDefinitionNode, + InputObjectTypeDefinitionNode, + InputValueDefinitionNode, + InterfaceTypeDefinitionNode, + ListTypeNode, + NameNode, + NamedTypeNode, + NonNullTypeNode, + ObjectTypeDefinitionNode, + ObjectTypeExtensionNode, + OperationType, + OperationTypeDefinitionNode, + ScalarTypeDefinitionNode, + SchemaExtensionNode, + DirectiveNode, + StringValueNode, + UnionTypeDefinitionNode, + parse, +) def assert_syntax_error(text, message, location): @@ -46,8 +61,8 @@ def field_node(name, type_, loc): def field_node_with_args(name, type_, args, loc): return FieldDefinitionNode( - name=name, arguments=args, type=type_, directives=[], loc=loc, - description=None) + name=name, arguments=args, type=type_, directives=[], loc=loc, description=None + ) def non_null_type(type_, loc): @@ -56,14 +71,19 @@ def non_null_type(type_, loc): def enum_value_node(name, loc): return EnumValueDefinitionNode( - name=name_node(name, loc), directives=[], loc=loc, - description=None) + name=name_node(name, loc), directives=[], loc=loc, description=None + ) def input_value_node(name, type_, default_value, loc): return InputValueDefinitionNode( - name=name, type=type_, default_value=default_value, directives=[], - loc=loc, description=None) + name=name, + type=type_, + default_value=default_value, + directives=[], + loc=loc, + description=None, + ) def boolean_value_node(value, loc): @@ -76,12 +96,12 @@ def list_type_node(type_, loc): def schema_extension_node(directives, operation_types, loc): return SchemaExtensionNode( - directives=directives, operation_types=operation_types, loc=loc) + directives=directives, operation_types=operation_types, loc=loc + ) def operation_type_definition(operation, type_, loc): - return OperationTypeDefinitionNode( - operation=operation, type=type_, loc=loc) + return OperationTypeDefinitionNode(operation=operation, type=type_, loc=loc) def directive_node(name, arguments, loc): @@ -89,103 +109,118 @@ def directive_node(name, arguments, loc): def describe_schema_parser(): - def simple_type(): - body = '\ntype Hello {\n world: String\n}' + body = "\ntype Hello {\n world: String\n}" definition = assert_definitions(body, (0, 31)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (6, 11)) + assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == [] assert definition.directives == [] - assert definition.fields == [field_node( - name_node('world', (16, 21)), - type_node('String', (23, 29)), (16, 29))] + assert definition.fields == [ + field_node( + name_node("world", (16, 21)), type_node("String", (23, 29)), (16, 29) + ) + ] assert definition.loc == (1, 31) def parses_type_with_description_string(): body = '\n"Description"\ntype Hello {\n world: String\n}' definition = assert_definitions(body, (0, 45)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (20, 25)) + assert definition.name == name_node("Hello", (20, 25)) description = definition.description assert isinstance(description, StringValueNode) - assert description.value == 'Description' + assert description.value == "Description" assert description.block is False assert description.loc == (1, 14) def parses_type_with_description_multi_line_string(): - body = dedent(''' + body = dedent( + ''' """ Description """ # Even with comments between them type Hello { world: String - }''') + }''' + ) definition = assert_definitions(body, (0, 85)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (60, 65)) + assert definition.name == name_node("Hello", (60, 65)) description = definition.description assert isinstance(description, StringValueNode) - assert description.value == 'Description' + assert description.value == "Description" assert description.block is True assert description.loc == (1, 20) def simple_extension(): - body = '\nextend type Hello {\n world: String\n}\n' + body = "\nextend type Hello {\n world: String\n}\n" extension = assert_definitions(body, (0, 39)) assert isinstance(extension, ObjectTypeExtensionNode) - assert extension.name == name_node('Hello', (13, 18)) + assert extension.name == name_node("Hello", (13, 18)) assert extension.interfaces == [] assert extension.directives == [] - assert extension.fields == [field_node( - name_node('world', (23, 28)), - type_node('String', (30, 36)), (23, 36))] + assert extension.fields == [ + field_node( + name_node("world", (23, 28)), type_node("String", (30, 36)), (23, 36) + ) + ] assert extension.loc == (1, 38) def extension_without_fields(): - body = 'extend type Hello implements Greeting' + body = "extend type Hello implements Greeting" extension = assert_definitions(body, (0, 37)) assert isinstance(extension, ObjectTypeExtensionNode) - assert extension.name == name_node('Hello', (12, 17)) - assert extension.interfaces == [type_node('Greeting', (29, 37))] + assert extension.name == name_node("Hello", (12, 17)) + assert extension.interfaces == [type_node("Greeting", (29, 37))] assert extension.directives == [] assert extension.fields == [] assert extension.loc == (0, 37) def extension_without_fields_followed_by_extension(): - body = ('\n extend type Hello implements Greeting\n\n' - ' extend type Hello implements SecondGreeting\n ') + body = ( + "\n extend type Hello implements Greeting\n\n" + " extend type Hello implements SecondGreeting\n " + ) extensions = assert_definitions(body, (0, 100), 2) extension = extensions[0] assert isinstance(extension, ObjectTypeExtensionNode) - assert extension.name == name_node('Hello', (19, 24)) - assert extension.interfaces == [type_node('Greeting', (36, 44))] + assert extension.name == name_node("Hello", (19, 24)) + assert extension.interfaces == [type_node("Greeting", (36, 44))] assert extension.directives == [] assert extension.fields == [] assert extension.loc == (7, 44) extension = extensions[1] assert isinstance(extension, ObjectTypeExtensionNode) - assert extension.name == name_node('Hello', (64, 69)) - assert extension.interfaces == [type_node('SecondGreeting', (81, 95))] + assert extension.name == name_node("Hello", (64, 69)) + assert extension.interfaces == [type_node("SecondGreeting", (81, 95))] assert extension.directives == [] assert extension.fields == [] assert extension.loc == (52, 95) def extension_without_anything_throws(): - assert_syntax_error('extend type Hello', 'Unexpected ', (1, 18)) + assert_syntax_error("extend type Hello", "Unexpected ", (1, 18)) def extension_do_not_include_descriptions(): - assert_syntax_error(""" + assert_syntax_error( + """ "Description" extend type Hello { world: String - }""", "Unexpected Name 'extend'", (3, 13)) - assert_syntax_error(""" + }""", + "Unexpected Name 'extend'", + (3, 13), + ) + assert_syntax_error( + """ extend "Description" type Hello { world: String - }""", "Unexpected String 'Description'", (2, 18)) + }""", + "Unexpected String 'Description'", + (2, 18), + ) def schema_extension(): body = """ @@ -195,253 +230,343 @@ def schema_extension(): doc = parse(body) assert isinstance(doc, DocumentNode) assert doc.loc == (0, 75) - assert doc.definitions == [schema_extension_node( - [], [operation_type_definition(OperationType.MUTATION, type_node( - 'Mutation', (53, 61)), (43, 61))], (13, 75))] + assert doc.definitions == [ + schema_extension_node( + [], + [ + operation_type_definition( + OperationType.MUTATION, + type_node("Mutation", (53, 61)), + (43, 61), + ) + ], + (13, 75), + ) + ] def schema_extension_with_only_directives(): - body = 'extend schema @directive' + body = "extend schema @directive" doc = parse(body) assert isinstance(doc, DocumentNode) assert doc.loc == (0, 24) - assert doc.definitions == [schema_extension_node( - [directive_node(name_node('directive', (15, 24)), [], (14, 24))], - [], (0, 24))] + assert doc.definitions == [ + schema_extension_node( + [directive_node(name_node("directive", (15, 24)), [], (14, 24))], + [], + (0, 24), + ) + ] def schema_extension_without_anything_throws(): - assert_syntax_error('extend schema', 'Unexpected ', (1, 14)) + assert_syntax_error("extend schema", "Unexpected ", (1, 14)) def simple_non_null_type(): - body = '\ntype Hello {\n world: String!\n}' + body = "\ntype Hello {\n world: String!\n}" definition = assert_definitions(body, (0, 32)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (6, 11)) + assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == [] assert definition.directives == [] - assert definition.fields == [field_node( - name_node('world', (16, 21)), - non_null_type(type_node('String', (23, 29)), (23, 30)), (16, 30))] + assert definition.fields == [ + field_node( + name_node("world", (16, 21)), + non_null_type(type_node("String", (23, 29)), (23, 30)), + (16, 30), + ) + ] assert definition.loc == (1, 32) def simple_type_inheriting_interface(): - body = 'type Hello implements World { field: String }' + body = "type Hello implements World { field: String }" definition = assert_definitions(body, (0, 45)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (5, 10)) + assert definition.name == name_node("Hello", (5, 10)) assert definition.description is None - assert definition.interfaces == [type_node('World', (22, 27))] + assert definition.interfaces == [type_node("World", (22, 27))] assert definition.directives == [] - assert definition.fields == [field_node( - name_node('field', (30, 35)), - type_node('String', (37, 43)), (30, 43))] + assert definition.fields == [ + field_node( + name_node("field", (30, 35)), type_node("String", (37, 43)), (30, 43) + ) + ] assert definition.loc == (0, 45) def simple_type_inheriting_multiple_interfaces(): - body = 'type Hello implements Wo & rld { field: String }' + body = "type Hello implements Wo & rld { field: String }" definition = assert_definitions(body, (0, 48)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (5, 10)) + assert definition.name == name_node("Hello", (5, 10)) assert definition.description is None assert definition.interfaces == [ - type_node('Wo', (22, 24)), type_node('rld', (27, 30))] + type_node("Wo", (22, 24)), + type_node("rld", (27, 30)), + ] assert definition.directives == [] - assert definition.fields == [field_node( - name_node('field', (33, 38)), - type_node('String', (40, 46)), (33, 46))] + assert definition.fields == [ + field_node( + name_node("field", (33, 38)), type_node("String", (40, 46)), (33, 46) + ) + ] assert definition.loc == (0, 48) def simple_type_inheriting_multiple_interfaces_with_leading_ampersand(): - body = 'type Hello implements & Wo & rld { field: String }' + body = "type Hello implements & Wo & rld { field: String }" definition = assert_definitions(body, (0, 50)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (5, 10)) + assert definition.name == name_node("Hello", (5, 10)) assert definition.description is None assert definition.interfaces == [ - type_node('Wo', (24, 26)), type_node('rld', (29, 32))] + type_node("Wo", (24, 26)), + type_node("rld", (29, 32)), + ] assert definition.directives == [] - assert definition.fields == [field_node( - name_node('field', (35, 40)), - type_node('String', (42, 48)), (35, 48))] + assert definition.fields == [ + field_node( + name_node("field", (35, 40)), type_node("String", (42, 48)), (35, 48) + ) + ] assert definition.loc == (0, 50) def single_value_enum(): - body = 'enum Hello { WORLD }' + body = "enum Hello { WORLD }" definition = assert_definitions(body, (0, 20)) assert isinstance(definition, EnumTypeDefinitionNode) - assert definition.name == name_node('Hello', (5, 10)) + assert definition.name == name_node("Hello", (5, 10)) assert definition.description is None assert definition.directives == [] - assert definition.values == [enum_value_node('WORLD', (13, 18))] + assert definition.values == [enum_value_node("WORLD", (13, 18))] assert definition.loc == (0, 20) def double_value_enum(): - body = 'enum Hello { WO, RLD }' + body = "enum Hello { WO, RLD }" definition = assert_definitions(body, (0, 22)) assert isinstance(definition, EnumTypeDefinitionNode) - assert definition.name == name_node('Hello', (5, 10)) + assert definition.name == name_node("Hello", (5, 10)) assert definition.description is None assert definition.directives == [] assert definition.values == [ - enum_value_node('WO', (13, 15)), - enum_value_node('RLD', (17, 20))] + enum_value_node("WO", (13, 15)), + enum_value_node("RLD", (17, 20)), + ] assert definition.loc == (0, 22) def simple_interface(): - body = '\ninterface Hello {\n world: String\n}' + body = "\ninterface Hello {\n world: String\n}" definition = assert_definitions(body, (0, 36)) assert isinstance(definition, InterfaceTypeDefinitionNode) - assert definition.name == name_node('Hello', (11, 16)) + assert definition.name == name_node("Hello", (11, 16)) assert definition.description is None assert definition.directives == [] - assert definition.fields == [field_node( - name_node('world', (21, 26)), - type_node('String', (28, 34)), (21, 34))] + assert definition.fields == [ + field_node( + name_node("world", (21, 26)), type_node("String", (28, 34)), (21, 34) + ) + ] assert definition.loc == (1, 36) def simple_field_with_arg(): - body = '\ntype Hello {\n world(flag: Boolean): String\n}' + body = "\ntype Hello {\n world(flag: Boolean): String\n}" definition = assert_definitions(body, (0, 46)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (6, 11)) + assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == [] assert definition.directives == [] - assert definition.fields == [field_node_with_args( - name_node('world', (16, 21)), - type_node('String', (38, 44)), [input_value_node( - name_node('flag', (22, 26)), - type_node('Boolean', (28, 35)), None, (22, 35))], (16, 44))] + assert definition.fields == [ + field_node_with_args( + name_node("world", (16, 21)), + type_node("String", (38, 44)), + [ + input_value_node( + name_node("flag", (22, 26)), + type_node("Boolean", (28, 35)), + None, + (22, 35), + ) + ], + (16, 44), + ) + ] assert definition.loc == (1, 46) def simple_field_with_arg_with_default_value(): - body = '\ntype Hello {\n world(flag: Boolean = true): String\n}' + body = "\ntype Hello {\n world(flag: Boolean = true): String\n}" definition = assert_definitions(body, (0, 53)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (6, 11)) + assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == [] assert definition.directives == [] - assert definition.fields == [field_node_with_args( - name_node('world', (16, 21)), - type_node('String', (45, 51)), [input_value_node( - name_node('flag', (22, 26)), - type_node('Boolean', (28, 35)), - boolean_value_node(True, (38, 42)), (22, 42))], (16, 51))] + assert definition.fields == [ + field_node_with_args( + name_node("world", (16, 21)), + type_node("String", (45, 51)), + [ + input_value_node( + name_node("flag", (22, 26)), + type_node("Boolean", (28, 35)), + boolean_value_node(True, (38, 42)), + (22, 42), + ) + ], + (16, 51), + ) + ] assert definition.loc == (1, 53) def simple_field_with_list_arg(): - body = '\ntype Hello {\n world(things: [String]): String\n}' + body = "\ntype Hello {\n world(things: [String]): String\n}" definition = assert_definitions(body, (0, 49)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (6, 11)) + assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == [] assert definition.directives == [] - assert definition.fields == [field_node_with_args( - name_node('world', (16, 21)), - type_node('String', (41, 47)), [input_value_node( - name_node('things', (22, 28)), - list_type_node(type_node('String', (31, 37)), (30, 38)), - None, (22, 38))], (16, 47))] + assert definition.fields == [ + field_node_with_args( + name_node("world", (16, 21)), + type_node("String", (41, 47)), + [ + input_value_node( + name_node("things", (22, 28)), + list_type_node(type_node("String", (31, 37)), (30, 38)), + None, + (22, 38), + ) + ], + (16, 47), + ) + ] assert definition.loc == (1, 49) def simple_field_with_two_args(): - body = ('\ntype Hello {\n' - ' world(argOne: Boolean, argTwo: Int): String\n}') + body = "\ntype Hello {\n" " world(argOne: Boolean, argTwo: Int): String\n}" definition = assert_definitions(body, (0, 61)) assert isinstance(definition, ObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (6, 11)) + assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == [] assert definition.directives == [] - assert definition.fields == [field_node_with_args( - name_node('world', (16, 21)), - type_node('String', (53, 59)), [ - input_value_node( - name_node('argOne', (22, 28)), - type_node('Boolean', (30, 37)), None, (22, 37)), - input_value_node( - name_node('argTwo', (39, 45)), - type_node('Int', (47, 50)), None, (39, 50))], (16, 59))] + assert definition.fields == [ + field_node_with_args( + name_node("world", (16, 21)), + type_node("String", (53, 59)), + [ + input_value_node( + name_node("argOne", (22, 28)), + type_node("Boolean", (30, 37)), + None, + (22, 37), + ), + input_value_node( + name_node("argTwo", (39, 45)), + type_node("Int", (47, 50)), + None, + (39, 50), + ), + ], + (16, 59), + ) + ] assert definition.loc == (1, 61) def simple_union(): - body = 'union Hello = World' + body = "union Hello = World" definition = assert_definitions(body, (0, 19)) assert isinstance(definition, UnionTypeDefinitionNode) - assert definition.name == name_node('Hello', (6, 11)) + assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.directives == [] - assert definition.types == [type_node('World', (14, 19))] + assert definition.types == [type_node("World", (14, 19))] assert definition.loc == (0, 19) def union_with_two_types(): - body = 'union Hello = Wo | Rld' + body = "union Hello = Wo | Rld" definition = assert_definitions(body, (0, 22)) assert isinstance(definition, UnionTypeDefinitionNode) - assert definition.name == name_node('Hello', (6, 11)) + assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.directives == [] assert definition.types == [ - type_node('Wo', (14, 16)), type_node('Rld', (19, 22))] + type_node("Wo", (14, 16)), + type_node("Rld", (19, 22)), + ] assert definition.loc == (0, 22) def union_with_two_types_and_leading_pipe(): - body = 'union Hello = | Wo | Rld' + body = "union Hello = | Wo | Rld" definition = assert_definitions(body, (0, 24)) assert isinstance(definition, UnionTypeDefinitionNode) - assert definition.name == name_node('Hello', (6, 11)) + assert definition.name == name_node("Hello", (6, 11)) assert definition.directives == [] assert definition.types == [ - type_node('Wo', (16, 18)), type_node('Rld', (21, 24))] + type_node("Wo", (16, 18)), + type_node("Rld", (21, 24)), + ] assert definition.loc == (0, 24) def union_fails_with_no_types(): - assert_syntax_error('union Hello = |', - 'Expected Name, found ', (1, 16)) + assert_syntax_error("union Hello = |", "Expected Name, found ", (1, 16)) def union_fails_with_leading_double_pipe(): - assert_syntax_error('union Hello = || Wo | Rld', - 'Expected Name, found |', (1, 16)) + assert_syntax_error( + "union Hello = || Wo | Rld", "Expected Name, found |", (1, 16) + ) def union_fails_with_trailing_pipe(): - assert_syntax_error('union Hello = | Wo | Rld |', - 'Expected Name, found ', (1, 27)) + assert_syntax_error( + "union Hello = | Wo | Rld |", "Expected Name, found ", (1, 27) + ) def scalar(): - body = 'scalar Hello' + body = "scalar Hello" definition = assert_definitions(body, (0, 12)) assert isinstance(definition, ScalarTypeDefinitionNode) - assert definition.name == name_node('Hello', (7, 12)) + assert definition.name == name_node("Hello", (7, 12)) assert definition.description is None assert definition.directives == [] assert definition.loc == (0, 12) def simple_input_object(): - body = '\ninput Hello {\n world: String\n}' + body = "\ninput Hello {\n world: String\n}" definition = assert_definitions(body, (0, 32)) assert isinstance(definition, InputObjectTypeDefinitionNode) - assert definition.name == name_node('Hello', (7, 12)) + assert definition.name == name_node("Hello", (7, 12)) assert definition.description is None assert definition.directives == [] - assert definition.fields == [input_value_node( - name_node('world', (17, 22)), - type_node('String', (24, 30)), None, (17, 30))] + assert definition.fields == [ + input_value_node( + name_node("world", (17, 22)), + type_node("String", (24, 30)), + None, + (17, 30), + ) + ] assert definition.loc == (1, 32) def simple_input_object_with_args_should_fail(): - assert_syntax_error('\ninput Hello {\n world(foo : Int): String\n}', - 'Expected :, found (', (3, 8)) + assert_syntax_error( + "\ninput Hello {\n world(foo : Int): String\n}", + "Expected :, found (", + (3, 8), + ) def directive_with_incorrect_locations(): - assert_syntax_error('\ndirective @foo on FIELD | INCORRECT_LOCATION', - "Unexpected Name 'INCORRECT_LOCATION'", (2, 27)) + assert_syntax_error( + "\ndirective @foo on FIELD | INCORRECT_LOCATION", + "Unexpected Name 'INCORRECT_LOCATION'", + (2, 27), + ) def disallow_legacy_sdl_empty_fields_supports_type_with_empty_fields(): - assert_syntax_error('type Hello { }', - 'Syntax Error: Expected Name, found }', (1, 14)) + assert_syntax_error( + "type Hello { }", "Syntax Error: Expected Name, found }", (1, 14) + ) def disallow_legacy_sdl_implements_interfaces(): - assert_syntax_error('type Hello implements Wo rld { field: String }', - "Syntax Error: Unexpected Name 'rld'", (1, 26)) + assert_syntax_error( + "type Hello implements Wo rld { field: String }", + "Syntax Error: Unexpected Name 'rld'", + (1, 26), + ) diff --git a/tests/language/test_schema_printer.py b/tests/language/test_schema_printer.py index fce3a9ea..9b0497b5 100644 --- a/tests/language/test_schema_printer.py +++ b/tests/language/test_schema_printer.py @@ -2,8 +2,7 @@ from pytest import raises -from graphql.language import ( - ScalarTypeDefinitionNode, NameNode, print_ast, parse) +from graphql.language import ScalarTypeDefinitionNode, NameNode, print_ast, parse from graphql.pyutils import dedent # noinspection PyUnresolvedReferences @@ -11,13 +10,12 @@ def describe_printer_sdl_document(): - def prints_minimal_ast(): - node = ScalarTypeDefinitionNode(name=NameNode(value='foo')) - assert print_ast(node) == 'scalar foo' + node = ScalarTypeDefinitionNode(name=NameNode(value="foo")) + assert print_ast(node) == "scalar foo" def produces_helpful_error_messages(): - bad_ast1 = {'random': 'Data'} + bad_ast1 = {"random": "Data"} with raises(TypeError) as exc_info: # noinspection PyTypeChecker print_ast(bad_ast1) @@ -36,7 +34,8 @@ def prints_kitchen_sink(kitchen_sink): # noqa: F811 ast = parse(kitchen_sink) printed = print_ast(ast) - assert printed == dedent(''' + assert printed == dedent( + ''' schema { query: QueryType mutation: MutationType @@ -157,4 +156,5 @@ def prints_kitchen_sink(kitchen_sink): # noqa: F811 extend schema @onSchema { subscription: SubscriptionType } - ''') # noqa + ''' # noqa + ) diff --git a/tests/language/test_visitor.py b/tests/language/test_visitor.py index be5407cc..58b64da8 100644 --- a/tests/language/test_visitor.py +++ b/tests/language/test_visitor.py @@ -3,12 +3,25 @@ from pytest import fail from graphql.language import ( - Node, FieldNode, NameNode, SelectionSetNode, parse, print_ast, - visit, BREAK, REMOVE, SKIP, ParallelVisitor, TypeInfoVisitor, Visitor) + Node, + FieldNode, + NameNode, + SelectionSetNode, + parse, + print_ast, + visit, + BREAK, + REMOVE, + SKIP, + ParallelVisitor, + TypeInfoVisitor, + Visitor, +) from graphql.type import get_named_type, is_composite_type from graphql.utilities import TypeInfo from ..validation.harness import test_schema + # noinspection PyUnresolvedReferences from . import kitchen_sink # noqa: F401 @@ -21,20 +34,19 @@ def get_node_by_path(ast, path): try: result = result[key] except IndexError: - fail(f'invalid index {key} in node list {result}') + fail(f"invalid index {key} in node list {result}") elif isinstance(key, str): assert isinstance(result, Node) try: result = getattr(result, key) except AttributeError: - fail(f'invalid key {key} in node {result}') + fail(f"invalid key {key} in node {result}") else: - fail(f'invalid key {key!r} in path {path}') + fail(f"invalid key {key!r} in path {path}") return result -def check_visitor_fn_args( - ast, node, key, parent, path, ancestors, is_edited=False): +def check_visitor_fn_args(ast, node, key, parent, path, ancestors, is_edited=False): assert isinstance(node, Node) is_root = key is None @@ -62,44 +74,40 @@ def check_visitor_fn_args( def describe_visitor(): - def validates_path_argument(): - ast = parse('{ a }', no_location=True) + ast = parse("{ a }", no_location=True) visited = [] # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) - visited.append(['enter', *args[3]]) + visited.append(["enter", *args[3]]) def leave(self, *args): check_visitor_fn_args(ast, *args) - visited.append(['leave', *args[3]]) + visited.append(["leave", *args[3]]) visit(ast, TestVisitor()) assert visited == [ - ['enter'], - ['enter', 'definitions', 0], - ['enter', 'definitions', 0, 'selection_set'], - ['enter', 'definitions', 0, 'selection_set', 'selections', 0], - ['enter', - 'definitions', 0, 'selection_set', 'selections', 0, 'name'], - ['leave', - 'definitions', 0, 'selection_set', 'selections', 0, 'name'], - ['leave', 'definitions', 0, 'selection_set', 'selections', 0], - ['leave', 'definitions', 0, 'selection_set'], - ['leave', 'definitions', 0], - ['leave']] + ["enter"], + ["enter", "definitions", 0], + ["enter", "definitions", 0, "selection_set"], + ["enter", "definitions", 0, "selection_set", "selections", 0], + ["enter", "definitions", 0, "selection_set", "selections", 0, "name"], + ["leave", "definitions", 0, "selection_set", "selections", 0, "name"], + ["leave", "definitions", 0, "selection_set", "selections", 0], + ["leave", "definitions", 0, "selection_set"], + ["leave", "definitions", 0], + ["leave"], + ] def validates_ancestors_argument(): - ast = parse('{ a }', no_location=True) + ast = parse("{ a }", no_location=True) visited_nodes = [] # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, node, key, parent, path, ancestors): in_array = isinstance(key, int) if in_array: @@ -119,7 +127,7 @@ def leave(self, node, key, parent, path, ancestors): visit(ast, TestVisitor()) def allows_editing_a_node_both_on_enter_and_on_leave(): - ast = parse('{ a, b, c { a, b, c } }', no_location=True) + ast = parse("{ a, b, c { a, b, c } }", no_location=True) visited = [] class TestVisitor(Visitor): @@ -131,7 +139,7 @@ def enter_operation_definition(self, *args): assert len(node.selection_set.selections) == 3 self.selection_set = node.selection_set node.selection_set = SelectionSetNode(selections=[]) - visited.append('enter') + visited.append("enter") return node def leave_operation_definition(self, *args): @@ -139,48 +147,46 @@ def leave_operation_definition(self, *args): node = copy(args[0]) assert not node.selection_set.selections node.selection_set = self.selection_set - visited.append('leave') + visited.append("leave") return node edited_ast = visit(ast, TestVisitor()) assert edited_ast == ast - assert visited == ['enter', 'leave'] + assert visited == ["enter", "leave"] def allows_for_editing_on_enter(): - ast = parse('{ a, b, c { a, b, c } }', no_location=True) + ast = parse("{ a, b, c { a, b, c } }", no_location=True) # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - if isinstance(node, FieldNode) and node.name.value == 'b': + if isinstance(node, FieldNode) and node.name.value == "b": return REMOVE edited_ast = visit(ast, TestVisitor()) - assert ast == parse('{ a, b, c { a, b, c } }', no_location=True) - assert edited_ast == parse('{ a, c { a, c } }', no_location=True) + assert ast == parse("{ a, b, c { a, b, c } }", no_location=True) + assert edited_ast == parse("{ a, c { a, c } }", no_location=True) def allows_for_editing_on_leave(): - ast = parse('{ a, b, c { a, b, c } }', no_location=True) + ast = parse("{ a, b, c { a, b, c } }", no_location=True) # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def leave(self, *args): check_visitor_fn_args(ast, *args, is_edited=True) node = args[0] - if isinstance(node, FieldNode) and node.name.value == 'b': + if isinstance(node, FieldNode) and node.name.value == "b": return REMOVE edited_ast = visit(ast, TestVisitor()) - assert ast == parse('{ a, b, c { a, b, c } }', no_location=True) - assert edited_ast == parse('{ a, c { a, c } }', no_location=True) + assert ast == parse("{ a, b, c { a, b, c } }", no_location=True) + assert edited_ast == parse("{ a, c { a, c } }", no_location=True) def visits_edited_node(): - ast = parse('{ a { x } }', no_location=True) - added_field = FieldNode(name=NameNode(value='__typename')) + ast = parse("{ a { x } }", no_location=True) + added_field = FieldNode(name=NameNode(value="__typename")) class TestVisitor(Visitor): did_visit_added_field = False @@ -188,11 +194,12 @@ class TestVisitor(Visitor): def enter(self, *args): check_visitor_fn_args(ast, *args, is_edited=True) node = args[0] - if isinstance(node, FieldNode) and node.name.value == 'a': + if isinstance(node, FieldNode) and node.name.value == "a": node = copy(node) # noinspection PyTypeChecker node.selection_set.selections = [ - added_field] + node.selection_set.selections + added_field + ] + node.selection_set.selections return node if node == added_field: self.did_visit_added_field = True @@ -202,205 +209,208 @@ def enter(self, *args): assert visitor.did_visit_added_field def allows_skipping_a_sub_tree(): - ast = parse('{ a, b { x }, c }', no_location=True) + ast = parse("{ a, b { x }, c }", no_location=True) visited = [] # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) - if kind == 'field' and node.name.value == 'b': + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) + if kind == "field" and node.name.value == "b": return SKIP def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['leave', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["leave", kind, value]) visit(ast, TestVisitor()) assert visited == [ - ['enter', 'document', None], - ['enter', 'operation_definition', None], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['leave', 'field', None], - ['enter', 'field', None], - ['enter', 'field', None], - ['enter', 'name', 'c'], - ['leave', 'name', 'c'], - ['leave', 'field', None], - ['leave', 'selection_set', None], - ['leave', 'operation_definition', None], - ['leave', 'document', None]] + ["enter", "document", None], + ["enter", "operation_definition", None], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["leave", "field", None], + ["enter", "field", None], + ["enter", "field", None], + ["enter", "name", "c"], + ["leave", "name", "c"], + ["leave", "field", None], + ["leave", "selection_set", None], + ["leave", "operation_definition", None], + ["leave", "document", None], + ] def allows_early_exit_while_visiting(): - ast = parse('{ a, b { x }, c }', no_location=True) + ast = parse("{ a, b { x }, c }", no_location=True) visited = [] # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) - if kind == 'name' and node.value == 'x': + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) + if kind == "name" and node.value == "x": return BREAK def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['leave', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["leave", kind, value]) visit(ast, TestVisitor()) assert visited == [ - ['enter', 'document', None], - ['enter', 'operation_definition', None], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['leave', 'field', None], - ['enter', 'field', None], - ['enter', 'name', 'b'], - ['leave', 'name', 'b'], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'x']] + ["enter", "document", None], + ["enter", "operation_definition", None], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["leave", "field", None], + ["enter", "field", None], + ["enter", "name", "b"], + ["leave", "name", "b"], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "x"], + ] def allows_early_exit_while_leaving(): - ast = parse('{ a, b { x }, c }', no_location=True) + ast = parse("{ a, b { x }, c }", no_location=True) visited = [] # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['leave', kind, value]) - if kind == 'name' and node.value == 'x': + kind, value = node.kind, getattr(node, "value", None) + visited.append(["leave", kind, value]) + if kind == "name" and node.value == "x": return BREAK visit(ast, TestVisitor()) assert visited == [ - ['enter', 'document', None], - ['enter', 'operation_definition', None], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['leave', 'field', None], - ['enter', 'field', None], - ['enter', 'name', 'b'], - ['leave', 'name', 'b'], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'x'], - ['leave', 'name', 'x']] + ["enter", "document", None], + ["enter", "operation_definition", None], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["leave", "field", None], + ["enter", "field", None], + ["enter", "name", "b"], + ["leave", "name", "b"], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "x"], + ["leave", "name", "x"], + ] def allows_a_named_functions_visitor_api(): - ast = parse('{ a, b { x }, c }', no_location=True) + ast = parse("{ a, b { x }, c }", no_location=True) visited = [] # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter_name(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) def enter_selection_set(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) def leave_selection_set(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['leave', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["leave", kind, value]) visit(ast, TestVisitor()) assert visited == [ - ['enter', 'selection_set', None], - ['enter', 'name', 'a'], - ['enter', 'name', 'b'], - ['enter', 'selection_set', None], - ['enter', 'name', 'x'], - ['leave', 'selection_set', None], - ['enter', 'name', 'c'], - ['leave', 'selection_set', None]] + ["enter", "selection_set", None], + ["enter", "name", "a"], + ["enter", "name", "b"], + ["enter", "selection_set", None], + ["enter", "name", "x"], + ["leave", "selection_set", None], + ["enter", "name", "c"], + ["leave", "selection_set", None], + ] def experimental_visits_variables_defined_in_fragments(): - ast = parse('fragment a($v: Boolean = false) on t { f }', - no_location=True, experimental_fragment_variables=True) + ast = parse( + "fragment a($v: Boolean = false) on t { f }", + no_location=True, + experimental_fragment_variables=True, + ) visited = [] # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['leave', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["leave", kind, value]) visit(ast, TestVisitor()) assert visited == [ - ['enter', 'document', None], - ['enter', 'fragment_definition', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['enter', 'variable_definition', None], - ['enter', 'variable', None], - ['enter', 'name', 'v'], - ['leave', 'name', 'v'], - ['leave', 'variable', None], - ['enter', 'named_type', None], - ['enter', 'name', 'Boolean'], - ['leave', 'name', 'Boolean'], - ['leave', 'named_type', None], - ['enter', 'boolean_value', False], - ['leave', 'boolean_value', False], - ['leave', 'variable_definition', None], - ['enter', 'named_type', None], - ['enter', 'name', 't'], - ['leave', 'name', 't'], - ['leave', 'named_type', None], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'f'], - ['leave', 'name', 'f'], - ['leave', 'field', None], - ['leave', 'selection_set', None], - ['leave', 'fragment_definition', None], - ['leave', 'document', None]] + ["enter", "document", None], + ["enter", "fragment_definition", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["enter", "variable_definition", None], + ["enter", "variable", None], + ["enter", "name", "v"], + ["leave", "name", "v"], + ["leave", "variable", None], + ["enter", "named_type", None], + ["enter", "name", "Boolean"], + ["leave", "name", "Boolean"], + ["leave", "named_type", None], + ["enter", "boolean_value", False], + ["leave", "boolean_value", False], + ["leave", "variable_definition", None], + ["enter", "named_type", None], + ["enter", "name", "t"], + ["leave", "name", "t"], + ["leave", "named_type", None], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "f"], + ["leave", "name", "f"], + ["leave", "field", None], + ["leave", "selection_set", None], + ["leave", "fragment_definition", None], + ["leave", "document", None], + ] # noinspection PyShadowingNames def visits_kitchen_sink(kitchen_sink): # noqa: F811 @@ -409,786 +419,770 @@ def visits_kitchen_sink(kitchen_sink): # noqa: F811 # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node, key, parent = args[:3] parent_kind = parent.kind if isinstance(parent, Node) else None - visited.append(['enter', node.kind, key, parent_kind]) + visited.append(["enter", node.kind, key, parent_kind]) def leave(self, *args): check_visitor_fn_args(ast, *args) node, key, parent = args[:3] parent_kind = parent.kind if isinstance(parent, Node) else None - visited.append(['leave', node.kind, key, parent_kind]) + visited.append(["leave", node.kind, key, parent_kind]) visit(ast, TestVisitor()) assert visited == [ - ['enter', 'document', None, None], - ['enter', 'operation_definition', 0, None], - ['enter', 'name', 'name', 'operation_definition'], - ['leave', 'name', 'name', 'operation_definition'], - ['enter', 'variable_definition', 0, None], - ['enter', 'variable', 'variable', 'variable_definition'], - ['enter', 'name', 'name', 'variable'], - ['leave', 'name', 'name', 'variable'], - ['leave', 'variable', 'variable', 'variable_definition'], - ['enter', 'named_type', 'type', 'variable_definition'], - ['enter', 'name', 'name', 'named_type'], - ['leave', 'name', 'name', 'named_type'], - ['leave', 'named_type', 'type', 'variable_definition'], - ['leave', 'variable_definition', 0, None], - ['enter', 'variable_definition', 1, None], - ['enter', 'variable', 'variable', 'variable_definition'], - ['enter', 'name', 'name', 'variable'], - ['leave', 'name', 'name', 'variable'], - ['leave', 'variable', 'variable', 'variable_definition'], - ['enter', 'named_type', 'type', 'variable_definition'], - ['enter', 'name', 'name', 'named_type'], - ['leave', 'name', 'name', 'named_type'], - ['leave', 'named_type', 'type', 'variable_definition'], - ['enter', 'enum_value', 'default_value', 'variable_definition'], - ['leave', 'enum_value', 'default_value', 'variable_definition'], - ['leave', 'variable_definition', 1, None], - ['enter', 'selection_set', 'selection_set', - 'operation_definition'], - ['enter', 'field', 0, None], - ['enter', 'name', 'alias', 'field'], - ['leave', 'name', 'alias', 'field'], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'argument', 0, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'list_value', 'value', 'argument'], - ['enter', 'int_value', 0, None], - ['leave', 'int_value', 0, None], - ['enter', 'int_value', 1, None], - ['leave', 'int_value', 1, None], - ['leave', 'list_value', 'value', 'argument'], - ['leave', 'argument', 0, None], - ['enter', 'selection_set', 'selection_set', 'field'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['leave', 'field', 0, None], - ['enter', 'inline_fragment', 1, None], - ['enter', 'named_type', 'type_condition', 'inline_fragment'], - ['enter', 'name', 'name', 'named_type'], - ['leave', 'name', 'name', 'named_type'], - ['leave', 'named_type', 'type_condition', 'inline_fragment'], - ['enter', 'directive', 0, None], - ['enter', 'name', 'name', 'directive'], - ['leave', 'name', 'name', 'directive'], - ['leave', 'directive', 0, None], - ['enter', 'selection_set', 'selection_set', 'inline_fragment'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'selection_set', 'selection_set', 'field'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['leave', 'field', 0, None], - ['enter', 'field', 1, None], - ['enter', 'name', 'alias', 'field'], - ['leave', 'name', 'alias', 'field'], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'argument', 0, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'int_value', 'value', 'argument'], - ['leave', 'int_value', 'value', 'argument'], - ['leave', 'argument', 0, None], - ['enter', 'argument', 1, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'variable', 'value', 'argument'], - ['enter', 'name', 'name', 'variable'], - ['leave', 'name', 'name', 'variable'], - ['leave', 'variable', 'value', 'argument'], - ['leave', 'argument', 1, None], - ['enter', 'directive', 0, None], - ['enter', 'name', 'name', 'directive'], - ['leave', 'name', 'name', 'directive'], - ['enter', 'argument', 0, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'variable', 'value', 'argument'], - ['enter', 'name', 'name', 'variable'], - ['leave', 'name', 'name', 'variable'], - ['leave', 'variable', 'value', 'argument'], - ['leave', 'argument', 0, None], - ['leave', 'directive', 0, None], - ['enter', 'selection_set', 'selection_set', 'field'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['leave', 'field', 0, None], - ['enter', 'fragment_spread', 1, None], - ['enter', 'name', 'name', 'fragment_spread'], - ['leave', 'name', 'name', 'fragment_spread'], - ['leave', 'fragment_spread', 1, None], - ['leave', 'selection_set', 'selection_set', 'field'], - ['leave', 'field', 1, None], - ['leave', 'selection_set', 'selection_set', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', 'inline_fragment'], - ['leave', 'inline_fragment', 1, None], - ['enter', 'inline_fragment', 2, None], - ['enter', 'directive', 0, None], - ['enter', 'name', 'name', 'directive'], - ['leave', 'name', 'name', 'directive'], - ['enter', 'argument', 0, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'variable', 'value', 'argument'], - ['enter', 'name', 'name', 'variable'], - ['leave', 'name', 'name', 'variable'], - ['leave', 'variable', 'value', 'argument'], - ['leave', 'argument', 0, None], - ['leave', 'directive', 0, None], - ['enter', 'selection_set', 'selection_set', 'inline_fragment'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', 'inline_fragment'], - ['leave', 'inline_fragment', 2, None], - ['enter', 'inline_fragment', 3, None], - ['enter', 'selection_set', 'selection_set', 'inline_fragment'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', 'inline_fragment'], - ['leave', 'inline_fragment', 3, None], - ['leave', 'selection_set', 'selection_set', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', - 'operation_definition'], - ['leave', 'operation_definition', 0, None], - ['enter', 'operation_definition', 1, None], - ['enter', 'name', 'name', 'operation_definition'], - ['leave', 'name', 'name', 'operation_definition'], - ['enter', 'selection_set', 'selection_set', - 'operation_definition'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'argument', 0, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'int_value', 'value', 'argument'], - ['leave', 'int_value', 'value', 'argument'], - ['leave', 'argument', 0, None], - ['enter', 'directive', 0, None], - ['enter', 'name', 'name', 'directive'], - ['leave', 'name', 'name', 'directive'], - ['leave', 'directive', 0, None], - ['enter', 'selection_set', 'selection_set', 'field'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'selection_set', 'selection_set', 'field'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', - 'operation_definition'], - ['leave', 'operation_definition', 1, None], - ['enter', 'operation_definition', 2, None], - ['enter', 'name', 'name', 'operation_definition'], - ['leave', 'name', 'name', 'operation_definition'], - ['enter', 'variable_definition', 0, None], - ['enter', 'variable', 'variable', 'variable_definition'], - ['enter', 'name', 'name', 'variable'], - ['leave', 'name', 'name', 'variable'], - ['leave', 'variable', 'variable', 'variable_definition'], - ['enter', 'named_type', 'type', 'variable_definition'], - ['enter', 'name', 'name', 'named_type'], - ['leave', 'name', 'name', 'named_type'], - ['leave', 'named_type', 'type', 'variable_definition'], - ['leave', 'variable_definition', 0, None], - ['enter', 'selection_set', 'selection_set', - 'operation_definition'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'argument', 0, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'variable', 'value', 'argument'], - ['enter', 'name', 'name', 'variable'], - ['leave', 'name', 'name', 'variable'], - ['leave', 'variable', 'value', 'argument'], - ['leave', 'argument', 0, None], - ['enter', 'selection_set', 'selection_set', 'field'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'selection_set', 'selection_set', 'field'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'selection_set', 'selection_set', 'field'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', 'field'], - ['leave', 'field', 0, None], - ['enter', 'field', 1, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'selection_set', 'selection_set', 'field'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', 'field'], - ['leave', 'field', 1, None], - ['leave', 'selection_set', 'selection_set', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', 'field'], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', - 'operation_definition'], - ['leave', 'operation_definition', 2, None], - ['enter', 'fragment_definition', 3, None], - ['enter', 'name', 'name', 'fragment_definition'], - ['leave', 'name', 'name', 'fragment_definition'], - ['enter', 'named_type', 'type_condition', - 'fragment_definition'], - ['enter', 'name', 'name', 'named_type'], - ['leave', 'name', 'name', 'named_type'], - ['leave', 'named_type', 'type_condition', - 'fragment_definition'], - ['enter', 'selection_set', 'selection_set', - 'fragment_definition'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'argument', 0, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'variable', 'value', 'argument'], - ['enter', 'name', 'name', 'variable'], - ['leave', 'name', 'name', 'variable'], - ['leave', 'variable', 'value', 'argument'], - ['leave', 'argument', 0, None], - ['enter', 'argument', 1, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'variable', 'value', 'argument'], - ['enter', 'name', 'name', 'variable'], - ['leave', 'name', 'name', 'variable'], - ['leave', 'variable', 'value', 'argument'], - ['leave', 'argument', 1, None], - ['enter', 'argument', 2, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'object_value', 'value', 'argument'], - ['enter', 'object_field', 0, None], - ['enter', 'name', 'name', 'object_field'], - ['leave', 'name', 'name', 'object_field'], - ['enter', 'string_value', 'value', 'object_field'], - ['leave', 'string_value', 'value', 'object_field'], - ['leave', 'object_field', 0, None], - ['enter', 'object_field', 1, None], - ['enter', 'name', 'name', 'object_field'], - ['leave', 'name', 'name', 'object_field'], - ['enter', 'string_value', 'value', 'object_field'], - ['leave', 'string_value', 'value', 'object_field'], - ['leave', 'object_field', 1, None], - ['leave', 'object_value', 'value', 'argument'], - ['leave', 'argument', 2, None], - ['leave', 'field', 0, None], - ['leave', 'selection_set', 'selection_set', - 'fragment_definition'], - ['leave', 'fragment_definition', 3, None], - ['enter', 'operation_definition', 4, None], - ['enter', 'selection_set', 'selection_set', - 'operation_definition'], - ['enter', 'field', 0, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['enter', 'argument', 0, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'boolean_value', 'value', 'argument'], - ['leave', 'boolean_value', 'value', 'argument'], - ['leave', 'argument', 0, None], - ['enter', 'argument', 1, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'boolean_value', 'value', 'argument'], - ['leave', 'boolean_value', 'value', 'argument'], - ['leave', 'argument', 1, None], - ['enter', 'argument', 2, None], - ['enter', 'name', 'name', 'argument'], - ['leave', 'name', 'name', 'argument'], - ['enter', 'null_value', 'value', 'argument'], - ['leave', 'null_value', 'value', 'argument'], - ['leave', 'argument', 2, None], - ['leave', 'field', 0, None], - ['enter', 'field', 1, None], - ['enter', 'name', 'name', 'field'], - ['leave', 'name', 'name', 'field'], - ['leave', 'field', 1, None], - ['leave', 'selection_set', 'selection_set', - 'operation_definition'], - ['leave', 'operation_definition', 4, None], - ['leave', 'document', None, None]] + ["enter", "document", None, None], + ["enter", "operation_definition", 0, None], + ["enter", "name", "name", "operation_definition"], + ["leave", "name", "name", "operation_definition"], + ["enter", "variable_definition", 0, None], + ["enter", "variable", "variable", "variable_definition"], + ["enter", "name", "name", "variable"], + ["leave", "name", "name", "variable"], + ["leave", "variable", "variable", "variable_definition"], + ["enter", "named_type", "type", "variable_definition"], + ["enter", "name", "name", "named_type"], + ["leave", "name", "name", "named_type"], + ["leave", "named_type", "type", "variable_definition"], + ["leave", "variable_definition", 0, None], + ["enter", "variable_definition", 1, None], + ["enter", "variable", "variable", "variable_definition"], + ["enter", "name", "name", "variable"], + ["leave", "name", "name", "variable"], + ["leave", "variable", "variable", "variable_definition"], + ["enter", "named_type", "type", "variable_definition"], + ["enter", "name", "name", "named_type"], + ["leave", "name", "name", "named_type"], + ["leave", "named_type", "type", "variable_definition"], + ["enter", "enum_value", "default_value", "variable_definition"], + ["leave", "enum_value", "default_value", "variable_definition"], + ["leave", "variable_definition", 1, None], + ["enter", "selection_set", "selection_set", "operation_definition"], + ["enter", "field", 0, None], + ["enter", "name", "alias", "field"], + ["leave", "name", "alias", "field"], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "argument", 0, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "list_value", "value", "argument"], + ["enter", "int_value", 0, None], + ["leave", "int_value", 0, None], + ["enter", "int_value", 1, None], + ["leave", "int_value", 1, None], + ["leave", "list_value", "value", "argument"], + ["leave", "argument", 0, None], + ["enter", "selection_set", "selection_set", "field"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["leave", "field", 0, None], + ["enter", "inline_fragment", 1, None], + ["enter", "named_type", "type_condition", "inline_fragment"], + ["enter", "name", "name", "named_type"], + ["leave", "name", "name", "named_type"], + ["leave", "named_type", "type_condition", "inline_fragment"], + ["enter", "directive", 0, None], + ["enter", "name", "name", "directive"], + ["leave", "name", "name", "directive"], + ["leave", "directive", 0, None], + ["enter", "selection_set", "selection_set", "inline_fragment"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "selection_set", "selection_set", "field"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["leave", "field", 0, None], + ["enter", "field", 1, None], + ["enter", "name", "alias", "field"], + ["leave", "name", "alias", "field"], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "argument", 0, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "int_value", "value", "argument"], + ["leave", "int_value", "value", "argument"], + ["leave", "argument", 0, None], + ["enter", "argument", 1, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "variable", "value", "argument"], + ["enter", "name", "name", "variable"], + ["leave", "name", "name", "variable"], + ["leave", "variable", "value", "argument"], + ["leave", "argument", 1, None], + ["enter", "directive", 0, None], + ["enter", "name", "name", "directive"], + ["leave", "name", "name", "directive"], + ["enter", "argument", 0, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "variable", "value", "argument"], + ["enter", "name", "name", "variable"], + ["leave", "name", "name", "variable"], + ["leave", "variable", "value", "argument"], + ["leave", "argument", 0, None], + ["leave", "directive", 0, None], + ["enter", "selection_set", "selection_set", "field"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["leave", "field", 0, None], + ["enter", "fragment_spread", 1, None], + ["enter", "name", "name", "fragment_spread"], + ["leave", "name", "name", "fragment_spread"], + ["leave", "fragment_spread", 1, None], + ["leave", "selection_set", "selection_set", "field"], + ["leave", "field", 1, None], + ["leave", "selection_set", "selection_set", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "inline_fragment"], + ["leave", "inline_fragment", 1, None], + ["enter", "inline_fragment", 2, None], + ["enter", "directive", 0, None], + ["enter", "name", "name", "directive"], + ["leave", "name", "name", "directive"], + ["enter", "argument", 0, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "variable", "value", "argument"], + ["enter", "name", "name", "variable"], + ["leave", "name", "name", "variable"], + ["leave", "variable", "value", "argument"], + ["leave", "argument", 0, None], + ["leave", "directive", 0, None], + ["enter", "selection_set", "selection_set", "inline_fragment"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "inline_fragment"], + ["leave", "inline_fragment", 2, None], + ["enter", "inline_fragment", 3, None], + ["enter", "selection_set", "selection_set", "inline_fragment"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "inline_fragment"], + ["leave", "inline_fragment", 3, None], + ["leave", "selection_set", "selection_set", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "operation_definition"], + ["leave", "operation_definition", 0, None], + ["enter", "operation_definition", 1, None], + ["enter", "name", "name", "operation_definition"], + ["leave", "name", "name", "operation_definition"], + ["enter", "selection_set", "selection_set", "operation_definition"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "argument", 0, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "int_value", "value", "argument"], + ["leave", "int_value", "value", "argument"], + ["leave", "argument", 0, None], + ["enter", "directive", 0, None], + ["enter", "name", "name", "directive"], + ["leave", "name", "name", "directive"], + ["leave", "directive", 0, None], + ["enter", "selection_set", "selection_set", "field"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "selection_set", "selection_set", "field"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "operation_definition"], + ["leave", "operation_definition", 1, None], + ["enter", "operation_definition", 2, None], + ["enter", "name", "name", "operation_definition"], + ["leave", "name", "name", "operation_definition"], + ["enter", "variable_definition", 0, None], + ["enter", "variable", "variable", "variable_definition"], + ["enter", "name", "name", "variable"], + ["leave", "name", "name", "variable"], + ["leave", "variable", "variable", "variable_definition"], + ["enter", "named_type", "type", "variable_definition"], + ["enter", "name", "name", "named_type"], + ["leave", "name", "name", "named_type"], + ["leave", "named_type", "type", "variable_definition"], + ["leave", "variable_definition", 0, None], + ["enter", "selection_set", "selection_set", "operation_definition"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "argument", 0, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "variable", "value", "argument"], + ["enter", "name", "name", "variable"], + ["leave", "name", "name", "variable"], + ["leave", "variable", "value", "argument"], + ["leave", "argument", 0, None], + ["enter", "selection_set", "selection_set", "field"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "selection_set", "selection_set", "field"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "selection_set", "selection_set", "field"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "field"], + ["leave", "field", 0, None], + ["enter", "field", 1, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "selection_set", "selection_set", "field"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "field"], + ["leave", "field", 1, None], + ["leave", "selection_set", "selection_set", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "field"], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "operation_definition"], + ["leave", "operation_definition", 2, None], + ["enter", "fragment_definition", 3, None], + ["enter", "name", "name", "fragment_definition"], + ["leave", "name", "name", "fragment_definition"], + ["enter", "named_type", "type_condition", "fragment_definition"], + ["enter", "name", "name", "named_type"], + ["leave", "name", "name", "named_type"], + ["leave", "named_type", "type_condition", "fragment_definition"], + ["enter", "selection_set", "selection_set", "fragment_definition"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "argument", 0, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "variable", "value", "argument"], + ["enter", "name", "name", "variable"], + ["leave", "name", "name", "variable"], + ["leave", "variable", "value", "argument"], + ["leave", "argument", 0, None], + ["enter", "argument", 1, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "variable", "value", "argument"], + ["enter", "name", "name", "variable"], + ["leave", "name", "name", "variable"], + ["leave", "variable", "value", "argument"], + ["leave", "argument", 1, None], + ["enter", "argument", 2, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "object_value", "value", "argument"], + ["enter", "object_field", 0, None], + ["enter", "name", "name", "object_field"], + ["leave", "name", "name", "object_field"], + ["enter", "string_value", "value", "object_field"], + ["leave", "string_value", "value", "object_field"], + ["leave", "object_field", 0, None], + ["enter", "object_field", 1, None], + ["enter", "name", "name", "object_field"], + ["leave", "name", "name", "object_field"], + ["enter", "string_value", "value", "object_field"], + ["leave", "string_value", "value", "object_field"], + ["leave", "object_field", 1, None], + ["leave", "object_value", "value", "argument"], + ["leave", "argument", 2, None], + ["leave", "field", 0, None], + ["leave", "selection_set", "selection_set", "fragment_definition"], + ["leave", "fragment_definition", 3, None], + ["enter", "operation_definition", 4, None], + ["enter", "selection_set", "selection_set", "operation_definition"], + ["enter", "field", 0, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["enter", "argument", 0, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "boolean_value", "value", "argument"], + ["leave", "boolean_value", "value", "argument"], + ["leave", "argument", 0, None], + ["enter", "argument", 1, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "boolean_value", "value", "argument"], + ["leave", "boolean_value", "value", "argument"], + ["leave", "argument", 1, None], + ["enter", "argument", 2, None], + ["enter", "name", "name", "argument"], + ["leave", "name", "name", "argument"], + ["enter", "null_value", "value", "argument"], + ["leave", "null_value", "value", "argument"], + ["leave", "argument", 2, None], + ["leave", "field", 0, None], + ["enter", "field", 1, None], + ["enter", "name", "name", "field"], + ["leave", "name", "name", "field"], + ["leave", "field", 1, None], + ["leave", "selection_set", "selection_set", "operation_definition"], + ["leave", "operation_definition", 4, None], + ["leave", "document", None, None], + ] def describe_visit_in_parallel(): - def allows_skipping_a_sub_tree(): # Note: nearly identical to the above test but using ParallelVisitor - ast = parse('{ a, b { x }, c }') + ast = parse("{ a, b { x }, c }") visited = [] # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) - if kind == 'field' and node.name.value == 'b': + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) + if kind == "field" and node.name.value == "b": return SKIP def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['leave', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["leave", kind, value]) visit(ast, ParallelVisitor([TestVisitor()])) assert visited == [ - ['enter', 'document', None], - ['enter', 'operation_definition', None], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['leave', 'field', None], - ['enter', 'field', None], - ['enter', 'field', None], - ['enter', 'name', 'c'], - ['leave', 'name', 'c'], - ['leave', 'field', None], - ['leave', 'selection_set', None], - ['leave', 'operation_definition', None], - ['leave', 'document', None]] + ["enter", "document", None], + ["enter", "operation_definition", None], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["leave", "field", None], + ["enter", "field", None], + ["enter", "field", None], + ["enter", "name", "c"], + ["leave", "name", "c"], + ["leave", "field", None], + ["leave", "selection_set", None], + ["leave", "operation_definition", None], + ["leave", "document", None], + ] def allows_skipping_different_sub_trees(): - ast = parse('{ a { x }, b { y} }') + ast = parse("{ a { x }, b { y} }") visited = [] class TestVisitor(Visitor): - def __init__(self, name): self.name = name def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) + kind, value = node.kind, getattr(node, "value", None) name = self.name - visited.append([f'no-{name}', 'enter', kind, value]) - if kind == 'field' and node.name.value == name: + visited.append([f"no-{name}", "enter", kind, value]) + if kind == "field" and node.name.value == name: return SKIP def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) + kind, value = node.kind, getattr(node, "value", None) name = self.name - visited.append([f'no-{name}', 'leave', kind, value]) + visited.append([f"no-{name}", "leave", kind, value]) - visit(ast, ParallelVisitor([TestVisitor('a'), TestVisitor('b')])) + visit(ast, ParallelVisitor([TestVisitor("a"), TestVisitor("b")])) assert visited == [ - ['no-a', 'enter', 'document', None], - ['no-b', 'enter', 'document', None], - ['no-a', 'enter', 'operation_definition', None], - ['no-b', 'enter', 'operation_definition', None], - ['no-a', 'enter', 'selection_set', None], - ['no-b', 'enter', 'selection_set', None], - ['no-a', 'enter', 'field', None], - ['no-b', 'enter', 'field', None], - ['no-b', 'enter', 'name', 'a'], - ['no-b', 'leave', 'name', 'a'], - ['no-b', 'enter', 'selection_set', None], - ['no-b', 'enter', 'field', None], - ['no-b', 'enter', 'name', 'x'], - ['no-b', 'leave', 'name', 'x'], - ['no-b', 'leave', 'field', None], - ['no-b', 'leave', 'selection_set', None], - ['no-b', 'leave', 'field', None], - ['no-a', 'enter', 'field', None], - ['no-b', 'enter', 'field', None], - ['no-a', 'enter', 'name', 'b'], - ['no-a', 'leave', 'name', 'b'], - ['no-a', 'enter', 'selection_set', None], - ['no-a', 'enter', 'field', None], - ['no-a', 'enter', 'name', 'y'], - ['no-a', 'leave', 'name', 'y'], - ['no-a', 'leave', 'field', None], - ['no-a', 'leave', 'selection_set', None], - ['no-a', 'leave', 'field', None], - ['no-a', 'leave', 'selection_set', None], - ['no-b', 'leave', 'selection_set', None], - ['no-a', 'leave', 'operation_definition', None], - ['no-b', 'leave', 'operation_definition', None], - ['no-a', 'leave', 'document', None], - ['no-b', 'leave', 'document', None]] + ["no-a", "enter", "document", None], + ["no-b", "enter", "document", None], + ["no-a", "enter", "operation_definition", None], + ["no-b", "enter", "operation_definition", None], + ["no-a", "enter", "selection_set", None], + ["no-b", "enter", "selection_set", None], + ["no-a", "enter", "field", None], + ["no-b", "enter", "field", None], + ["no-b", "enter", "name", "a"], + ["no-b", "leave", "name", "a"], + ["no-b", "enter", "selection_set", None], + ["no-b", "enter", "field", None], + ["no-b", "enter", "name", "x"], + ["no-b", "leave", "name", "x"], + ["no-b", "leave", "field", None], + ["no-b", "leave", "selection_set", None], + ["no-b", "leave", "field", None], + ["no-a", "enter", "field", None], + ["no-b", "enter", "field", None], + ["no-a", "enter", "name", "b"], + ["no-a", "leave", "name", "b"], + ["no-a", "enter", "selection_set", None], + ["no-a", "enter", "field", None], + ["no-a", "enter", "name", "y"], + ["no-a", "leave", "name", "y"], + ["no-a", "leave", "field", None], + ["no-a", "leave", "selection_set", None], + ["no-a", "leave", "field", None], + ["no-a", "leave", "selection_set", None], + ["no-b", "leave", "selection_set", None], + ["no-a", "leave", "operation_definition", None], + ["no-b", "leave", "operation_definition", None], + ["no-a", "leave", "document", None], + ["no-b", "leave", "document", None], + ] def allows_early_exit_while_visiting(): # Note: nearly identical to the above test but using ParallelVisitor. - ast = parse('{ a, b { x }, c }') + ast = parse("{ a, b { x }, c }") visited = [] # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) - if kind == 'name' and node.value == 'x': + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) + if kind == "name" and node.value == "x": return BREAK def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['leave', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["leave", kind, value]) visit(ast, ParallelVisitor([TestVisitor()])) assert visited == [ - ['enter', 'document', None], - ['enter', 'operation_definition', None], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['leave', 'field', None], - ['enter', 'field', None], - ['enter', 'name', 'b'], - ['leave', 'name', 'b'], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'x']] + ["enter", "document", None], + ["enter", "operation_definition", None], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["leave", "field", None], + ["enter", "field", None], + ["enter", "name", "b"], + ["leave", "name", "b"], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "x"], + ] def allows_early_exit_from_different_points(): - ast = parse('{ a { y }, b { x } }') + ast = parse("{ a { y }, b { x } }") visited = [] class TestVisitor(Visitor): - def __init__(self, name): self.name = name def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) + kind, value = node.kind, getattr(node, "value", None) name = self.name - visited.append([f'break-{name}', 'enter', kind, value]) - if kind == 'name' and node.value == name: + visited.append([f"break-{name}", "enter", kind, value]) + if kind == "name" and node.value == name: return BREAK def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) + kind, value = node.kind, getattr(node, "value", None) name = self.name - visited.append([f'break-{name}', 'leave', kind, value]) + visited.append([f"break-{name}", "leave", kind, value]) - visit(ast, ParallelVisitor([TestVisitor('a'), TestVisitor('b')])) + visit(ast, ParallelVisitor([TestVisitor("a"), TestVisitor("b")])) assert visited == [ - ['break-a', 'enter', 'document', None], - ['break-b', 'enter', 'document', None], - ['break-a', 'enter', 'operation_definition', None], - ['break-b', 'enter', 'operation_definition', None], - ['break-a', 'enter', 'selection_set', None], - ['break-b', 'enter', 'selection_set', None], - ['break-a', 'enter', 'field', None], - ['break-b', 'enter', 'field', None], - ['break-a', 'enter', 'name', 'a'], - ['break-b', 'enter', 'name', 'a'], - ['break-b', 'leave', 'name', 'a'], - ['break-b', 'enter', 'selection_set', None], - ['break-b', 'enter', 'field', None], - ['break-b', 'enter', 'name', 'y'], - ['break-b', 'leave', 'name', 'y'], - ['break-b', 'leave', 'field', None], - ['break-b', 'leave', 'selection_set', None], - ['break-b', 'leave', 'field', None], - ['break-b', 'enter', 'field', None], - ['break-b', 'enter', 'name', 'b']] + ["break-a", "enter", "document", None], + ["break-b", "enter", "document", None], + ["break-a", "enter", "operation_definition", None], + ["break-b", "enter", "operation_definition", None], + ["break-a", "enter", "selection_set", None], + ["break-b", "enter", "selection_set", None], + ["break-a", "enter", "field", None], + ["break-b", "enter", "field", None], + ["break-a", "enter", "name", "a"], + ["break-b", "enter", "name", "a"], + ["break-b", "leave", "name", "a"], + ["break-b", "enter", "selection_set", None], + ["break-b", "enter", "field", None], + ["break-b", "enter", "name", "y"], + ["break-b", "leave", "name", "y"], + ["break-b", "leave", "field", None], + ["break-b", "leave", "selection_set", None], + ["break-b", "leave", "field", None], + ["break-b", "enter", "field", None], + ["break-b", "enter", "name", "b"], + ] def allows_early_exit_while_leaving(): # Note: nearly identical to the above test but using ParallelVisitor. - ast = parse('{ a, b { x }, c }') + ast = parse("{ a, b { x }, c }") visited = [] # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['leave', kind, value]) - if kind == 'name' and node.value == 'x': + kind, value = node.kind, getattr(node, "value", None) + visited.append(["leave", kind, value]) + if kind == "name" and node.value == "x": return BREAK visit(ast, ParallelVisitor([TestVisitor()])) assert visited == [ - ['enter', 'document', None], - ['enter', 'operation_definition', None], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['leave', 'field', None], - ['enter', 'field', None], - ['enter', 'name', 'b'], - ['leave', 'name', 'b'], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'x'], - ['leave', 'name', 'x']] + ["enter", "document", None], + ["enter", "operation_definition", None], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["leave", "field", None], + ["enter", "field", None], + ["enter", "name", "b"], + ["leave", "name", "b"], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "x"], + ["leave", "name", "x"], + ] def allows_early_exit_from_leaving_different_points(): - ast = parse('{ a { y }, b { x } }') + ast = parse("{ a { y }, b { x } }") visited = [] class TestVisitor(Visitor): - def __init__(self, name): self.name = name def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) + kind, value = node.kind, getattr(node, "value", None) name = self.name - visited.append([f'break-{name}', 'enter', kind, value]) + visited.append([f"break-{name}", "enter", kind, value]) def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) + kind, value = node.kind, getattr(node, "value", None) name = self.name - visited.append([f'break-{name}', 'leave', kind, value]) - if kind == 'field' and node.name.value == name: + visited.append([f"break-{name}", "leave", kind, value]) + if kind == "field" and node.name.value == name: return BREAK - visit(ast, ParallelVisitor([TestVisitor('a'), TestVisitor('b')])) + visit(ast, ParallelVisitor([TestVisitor("a"), TestVisitor("b")])) assert visited == [ - ['break-a', 'enter', 'document', None], - ['break-b', 'enter', 'document', None], - ['break-a', 'enter', 'operation_definition', None], - ['break-b', 'enter', 'operation_definition', None], - ['break-a', 'enter', 'selection_set', None], - ['break-b', 'enter', 'selection_set', None], - ['break-a', 'enter', 'field', None], - ['break-b', 'enter', 'field', None], - ['break-a', 'enter', 'name', 'a'], - ['break-b', 'enter', 'name', 'a'], - ['break-a', 'leave', 'name', 'a'], - ['break-b', 'leave', 'name', 'a'], - ['break-a', 'enter', 'selection_set', None], - ['break-b', 'enter', 'selection_set', None], - ['break-a', 'enter', 'field', None], - ['break-b', 'enter', 'field', None], - ['break-a', 'enter', 'name', 'y'], - ['break-b', 'enter', 'name', 'y'], - ['break-a', 'leave', 'name', 'y'], - ['break-b', 'leave', 'name', 'y'], - ['break-a', 'leave', 'field', None], - ['break-b', 'leave', 'field', None], - ['break-a', 'leave', 'selection_set', None], - ['break-b', 'leave', 'selection_set', None], - ['break-a', 'leave', 'field', None], - ['break-b', 'leave', 'field', None], - ['break-b', 'enter', 'field', None], - ['break-b', 'enter', 'name', 'b'], - ['break-b', 'leave', 'name', 'b'], - ['break-b', 'enter', 'selection_set', None], - ['break-b', 'enter', 'field', None], - ['break-b', 'enter', 'name', 'x'], - ['break-b', 'leave', 'name', 'x'], - ['break-b', 'leave', 'field', None], - ['break-b', 'leave', 'selection_set', None], - ['break-b', 'leave', 'field', None]] + ["break-a", "enter", "document", None], + ["break-b", "enter", "document", None], + ["break-a", "enter", "operation_definition", None], + ["break-b", "enter", "operation_definition", None], + ["break-a", "enter", "selection_set", None], + ["break-b", "enter", "selection_set", None], + ["break-a", "enter", "field", None], + ["break-b", "enter", "field", None], + ["break-a", "enter", "name", "a"], + ["break-b", "enter", "name", "a"], + ["break-a", "leave", "name", "a"], + ["break-b", "leave", "name", "a"], + ["break-a", "enter", "selection_set", None], + ["break-b", "enter", "selection_set", None], + ["break-a", "enter", "field", None], + ["break-b", "enter", "field", None], + ["break-a", "enter", "name", "y"], + ["break-b", "enter", "name", "y"], + ["break-a", "leave", "name", "y"], + ["break-b", "leave", "name", "y"], + ["break-a", "leave", "field", None], + ["break-b", "leave", "field", None], + ["break-a", "leave", "selection_set", None], + ["break-b", "leave", "selection_set", None], + ["break-a", "leave", "field", None], + ["break-b", "leave", "field", None], + ["break-b", "enter", "field", None], + ["break-b", "enter", "name", "b"], + ["break-b", "leave", "name", "b"], + ["break-b", "enter", "selection_set", None], + ["break-b", "enter", "field", None], + ["break-b", "enter", "name", "x"], + ["break-b", "leave", "name", "x"], + ["break-b", "leave", "field", None], + ["break-b", "leave", "selection_set", None], + ["break-b", "leave", "field", None], + ] def allows_for_editing_on_enter(): - ast = parse('{ a, b, c { a, b, c } }', no_location=True) + ast = parse("{ a, b, c { a, b, c } }", no_location=True) visited = [] # noinspection PyMethodMayBeStatic class TestVisitor1(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - if node.kind == 'field' and node.name.value == 'b': + if node.kind == "field" and node.name.value == "b": return REMOVE # noinspection PyMethodMayBeStatic class TestVisitor2(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) def leave(self, *args): check_visitor_fn_args(ast, *args, is_edited=True) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['leave', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["leave", kind, value]) - edited_ast = visit( - ast, ParallelVisitor([TestVisitor1(), TestVisitor2()])) - assert ast == parse('{ a, b, c { a, b, c } }', no_location=True) - assert edited_ast == parse('{ a, c { a, c } }', no_location=True) + edited_ast = visit(ast, ParallelVisitor([TestVisitor1(), TestVisitor2()])) + assert ast == parse("{ a, b, c { a, b, c } }", no_location=True) + assert edited_ast == parse("{ a, c { a, c } }", no_location=True) assert visited == [ - ['enter', 'document', None], - ['enter', 'operation_definition', None], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['leave', 'field', None], - ['enter', 'field', None], - ['enter', 'name', 'c'], - ['leave', 'name', 'c'], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['leave', 'field', None], - ['enter', 'field', None], - ['enter', 'name', 'c'], - ['leave', 'name', 'c'], - ['leave', 'field', None], - ['leave', 'selection_set', None], - ['leave', 'field', None], - ['leave', 'selection_set', None], - ['leave', 'operation_definition', None], - ['leave', 'document', None]] + ["enter", "document", None], + ["enter", "operation_definition", None], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["leave", "field", None], + ["enter", "field", None], + ["enter", "name", "c"], + ["leave", "name", "c"], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["leave", "field", None], + ["enter", "field", None], + ["enter", "name", "c"], + ["leave", "name", "c"], + ["leave", "field", None], + ["leave", "selection_set", None], + ["leave", "field", None], + ["leave", "selection_set", None], + ["leave", "operation_definition", None], + ["leave", "document", None], + ] def allows_for_editing_on_leave(): - ast = parse('{ a, b, c { a, b, c } }', no_location=True) + ast = parse("{ a, b, c { a, b, c } }", no_location=True) visited = [] # noinspection PyMethodMayBeStatic class TestVisitor1(Visitor): - def leave(self, *args): check_visitor_fn_args(ast, *args, is_edited=True) node = args[0] - if node.kind == 'field' and node.name.value == 'b': + if node.kind == "field" and node.name.value == "b": return REMOVE # noinspection PyMethodMayBeStatic class TestVisitor2(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['enter', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["enter", kind, value]) def leave(self, *args): check_visitor_fn_args(ast, *args, is_edited=True) node = args[0] - kind, value = node.kind, getattr(node, 'value', None) - visited.append(['leave', kind, value]) + kind, value = node.kind, getattr(node, "value", None) + visited.append(["leave", kind, value]) - edited_ast = visit( - ast, ParallelVisitor([TestVisitor1(), TestVisitor2()])) - assert ast == parse('{ a, b, c { a, b, c } }', no_location=True) - assert edited_ast == parse('{ a, c { a, c } }', no_location=True) + edited_ast = visit(ast, ParallelVisitor([TestVisitor1(), TestVisitor2()])) + assert ast == parse("{ a, b, c { a, b, c } }", no_location=True) + assert edited_ast == parse("{ a, c { a, c } }", no_location=True) assert visited == [ - ['enter', 'document', None], - ['enter', 'operation_definition', None], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['leave', 'field', None], - ['enter', 'field', None], - ['enter', 'name', 'b'], - ['leave', 'name', 'b'], - ['enter', 'field', None], - ['enter', 'name', 'c'], - ['leave', 'name', 'c'], - ['enter', 'selection_set', None], - ['enter', 'field', None], - ['enter', 'name', 'a'], - ['leave', 'name', 'a'], - ['leave', 'field', None], - ['enter', 'field', None], - ['enter', 'name', 'b'], - ['leave', 'name', 'b'], - ['enter', 'field', None], - ['enter', 'name', 'c'], - ['leave', 'name', 'c'], - ['leave', 'field', None], - ['leave', 'selection_set', None], - ['leave', 'field', None], - ['leave', 'selection_set', None], - ['leave', 'operation_definition', None], - ['leave', 'document', None]] + ["enter", "document", None], + ["enter", "operation_definition", None], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["leave", "field", None], + ["enter", "field", None], + ["enter", "name", "b"], + ["leave", "name", "b"], + ["enter", "field", None], + ["enter", "name", "c"], + ["leave", "name", "c"], + ["enter", "selection_set", None], + ["enter", "field", None], + ["enter", "name", "a"], + ["leave", "name", "a"], + ["leave", "field", None], + ["enter", "field", None], + ["enter", "name", "b"], + ["leave", "name", "b"], + ["enter", "field", None], + ["enter", "name", "c"], + ["leave", "name", "c"], + ["leave", "field", None], + ["leave", "selection_set", None], + ["leave", "field", None], + ["leave", "selection_set", None], + ["leave", "operation_definition", None], + ["leave", "document", None], + ] def describe_visit_with_type_info(): - def maintains_type_info_during_visit(): visited = [] - ast = parse( - '{ human(id: 4) { name, pets { ... { name } }, unknown } }') + ast = parse("{ human(id: 4) { name, pets { ... { name } }, unknown } }") type_info = TypeInfo(test_schema) # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args) parent_type = type_info.get_parent_type() type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] - visited.append([ - 'enter', node.kind, - node.value if node.kind == 'name' else None, - str(parent_type) if parent_type else None, - str(type_) if type_ else None, - str(input_type) if input_type else None]) + visited.append( + [ + "enter", + node.kind, + node.value if node.kind == "name" else None, + str(parent_type) if parent_type else None, + str(type_) if type_ else None, + str(input_type) if input_type else None, + ] + ) def leave(self, *args): check_visitor_fn_args(ast, *args) @@ -1196,90 +1190,102 @@ def leave(self, *args): type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] - visited.append([ - 'leave', node.kind, - node.value if node.kind == 'name' else None, - str(parent_type) if parent_type else None, - str(type_) if type_ else None, - str(input_type) if input_type else None]) + visited.append( + [ + "leave", + node.kind, + node.value if node.kind == "name" else None, + str(parent_type) if parent_type else None, + str(type_) if type_ else None, + str(input_type) if input_type else None, + ] + ) visit(ast, TypeInfoVisitor(type_info, TestVisitor())) assert visited == [ - ['enter', 'document', None, None, None, None], - ['enter', 'operation_definition', None, None, 'QueryRoot', None], - ['enter', 'selection_set', None, 'QueryRoot', 'QueryRoot', None], - ['enter', 'field', None, 'QueryRoot', 'Human', None], - ['enter', 'name', 'human', 'QueryRoot', 'Human', None], - ['leave', 'name', 'human', 'QueryRoot', 'Human', None], - ['enter', 'argument', None, 'QueryRoot', 'Human', 'ID'], - ['enter', 'name', 'id', 'QueryRoot', 'Human', 'ID'], - ['leave', 'name', 'id', 'QueryRoot', 'Human', 'ID'], - ['enter', 'int_value', None, 'QueryRoot', 'Human', 'ID'], - ['leave', 'int_value', None, 'QueryRoot', 'Human', 'ID'], - ['leave', 'argument', None, 'QueryRoot', 'Human', 'ID'], - ['enter', 'selection_set', None, 'Human', 'Human', None], - ['enter', 'field', None, 'Human', 'String', None], - ['enter', 'name', 'name', 'Human', 'String', None], - ['leave', 'name', 'name', 'Human', 'String', None], - ['leave', 'field', None, 'Human', 'String', None], - ['enter', 'field', None, 'Human', '[Pet]', None], - ['enter', 'name', 'pets', 'Human', '[Pet]', None], - ['leave', 'name', 'pets', 'Human', '[Pet]', None], - ['enter', 'selection_set', None, 'Pet', '[Pet]', None], - ['enter', 'inline_fragment', None, 'Pet', 'Pet', None], - ['enter', 'selection_set', None, 'Pet', 'Pet', None], - ['enter', 'field', None, 'Pet', 'String', None], - ['enter', 'name', 'name', 'Pet', 'String', None], - ['leave', 'name', 'name', 'Pet', 'String', None], - ['leave', 'field', None, 'Pet', 'String', None], - ['leave', 'selection_set', None, 'Pet', 'Pet', None], - ['leave', 'inline_fragment', None, 'Pet', 'Pet', None], - ['leave', 'selection_set', None, 'Pet', '[Pet]', None], - ['leave', 'field', None, 'Human', '[Pet]', None], - ['enter', 'field', None, 'Human', None, None], - ['enter', 'name', 'unknown', 'Human', None, None], - ['leave', 'name', 'unknown', 'Human', None, None], - ['leave', 'field', None, 'Human', None, None], - ['leave', 'selection_set', None, 'Human', 'Human', None], - ['leave', 'field', None, 'QueryRoot', 'Human', None], - ['leave', 'selection_set', None, 'QueryRoot', 'QueryRoot', None], - ['leave', 'operation_definition', None, None, 'QueryRoot', None], - ['leave', 'document', None, None, None, None], + ["enter", "document", None, None, None, None], + ["enter", "operation_definition", None, None, "QueryRoot", None], + ["enter", "selection_set", None, "QueryRoot", "QueryRoot", None], + ["enter", "field", None, "QueryRoot", "Human", None], + ["enter", "name", "human", "QueryRoot", "Human", None], + ["leave", "name", "human", "QueryRoot", "Human", None], + ["enter", "argument", None, "QueryRoot", "Human", "ID"], + ["enter", "name", "id", "QueryRoot", "Human", "ID"], + ["leave", "name", "id", "QueryRoot", "Human", "ID"], + ["enter", "int_value", None, "QueryRoot", "Human", "ID"], + ["leave", "int_value", None, "QueryRoot", "Human", "ID"], + ["leave", "argument", None, "QueryRoot", "Human", "ID"], + ["enter", "selection_set", None, "Human", "Human", None], + ["enter", "field", None, "Human", "String", None], + ["enter", "name", "name", "Human", "String", None], + ["leave", "name", "name", "Human", "String", None], + ["leave", "field", None, "Human", "String", None], + ["enter", "field", None, "Human", "[Pet]", None], + ["enter", "name", "pets", "Human", "[Pet]", None], + ["leave", "name", "pets", "Human", "[Pet]", None], + ["enter", "selection_set", None, "Pet", "[Pet]", None], + ["enter", "inline_fragment", None, "Pet", "Pet", None], + ["enter", "selection_set", None, "Pet", "Pet", None], + ["enter", "field", None, "Pet", "String", None], + ["enter", "name", "name", "Pet", "String", None], + ["leave", "name", "name", "Pet", "String", None], + ["leave", "field", None, "Pet", "String", None], + ["leave", "selection_set", None, "Pet", "Pet", None], + ["leave", "inline_fragment", None, "Pet", "Pet", None], + ["leave", "selection_set", None, "Pet", "[Pet]", None], + ["leave", "field", None, "Human", "[Pet]", None], + ["enter", "field", None, "Human", None, None], + ["enter", "name", "unknown", "Human", None, None], + ["leave", "name", "unknown", "Human", None, None], + ["leave", "field", None, "Human", None, None], + ["leave", "selection_set", None, "Human", "Human", None], + ["leave", "field", None, "QueryRoot", "Human", None], + ["leave", "selection_set", None, "QueryRoot", "QueryRoot", None], + ["leave", "operation_definition", None, None, "QueryRoot", None], + ["leave", "document", None, None, None, None], ] def maintains_type_info_during_edit(): visited = [] type_info = TypeInfo(test_schema) - ast = parse('{ human(id: 4) { name, pets }, alien }') + ast = parse("{ human(id: 4) { name, pets }, alien }") # noinspection PyMethodMayBeStatic class TestVisitor(Visitor): - def enter(self, *args): check_visitor_fn_args(ast, *args, is_edited=True) parent_type = type_info.get_parent_type() type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] - visited.append([ - 'enter', node.kind, - node.value if node.kind == 'name' else None, - str(parent_type) if parent_type else None, - str(type_) if type_ else None, - str(input_type) if input_type else None]) + visited.append( + [ + "enter", + node.kind, + node.value if node.kind == "name" else None, + str(parent_type) if parent_type else None, + str(type_) if type_ else None, + str(input_type) if input_type else None, + ] + ) # Make a query valid by adding missing selection sets. - if (node.kind == 'field' and not node.selection_set and - is_composite_type(get_named_type(type_))): + if ( + node.kind == "field" + and not node.selection_set + and is_composite_type(get_named_type(type_)) + ): return FieldNode( alias=node.alias, name=node.name, arguments=node.arguments, directives=node.directives, - selection_set=SelectionSetNode(selections=[ - FieldNode(name=NameNode(value='__typename'))])) + selection_set=SelectionSetNode( + selections=[FieldNode(name=NameNode(value="__typename"))] + ), + ) def leave(self, *args): check_visitor_fn_args(ast, *args, is_edited=True) @@ -1287,62 +1293,69 @@ def leave(self, *args): type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] - visited.append([ - 'leave', node.kind, - node.value if node.kind == 'name' else None, - str(parent_type) if parent_type else None, - str(type_) if type_ else None, - str(input_type) if input_type else None]) + visited.append( + [ + "leave", + node.kind, + node.value if node.kind == "name" else None, + str(parent_type) if parent_type else None, + str(type_) if type_ else None, + str(input_type) if input_type else None, + ] + ) edited_ast = visit(ast, TypeInfoVisitor(type_info, TestVisitor())) - assert ast == parse('{ human(id: 4) { name, pets }, alien }') + assert ast == parse("{ human(id: 4) { name, pets }, alien }") - assert print_ast(edited_ast) == print_ast(parse( - '{ human(id: 4) { name, pets { __typename } },' - ' alien { __typename } }')) + assert print_ast(edited_ast) == print_ast( + parse( + "{ human(id: 4) { name, pets { __typename } }," + " alien { __typename } }" + ) + ) assert visited == [ - ['enter', 'document', None, None, None, None], - ['enter', 'operation_definition', None, None, 'QueryRoot', None], - ['enter', 'selection_set', None, 'QueryRoot', 'QueryRoot', None], - ['enter', 'field', None, 'QueryRoot', 'Human', None], - ['enter', 'name', 'human', 'QueryRoot', 'Human', None], - ['leave', 'name', 'human', 'QueryRoot', 'Human', None], - ['enter', 'argument', None, 'QueryRoot', 'Human', 'ID'], - ['enter', 'name', 'id', 'QueryRoot', 'Human', 'ID'], - ['leave', 'name', 'id', 'QueryRoot', 'Human', 'ID'], - ['enter', 'int_value', None, 'QueryRoot', 'Human', 'ID'], - ['leave', 'int_value', None, 'QueryRoot', 'Human', 'ID'], - ['leave', 'argument', None, 'QueryRoot', 'Human', 'ID'], - ['enter', 'selection_set', None, 'Human', 'Human', None], - ['enter', 'field', None, 'Human', 'String', None], - ['enter', 'name', 'name', 'Human', 'String', None], - ['leave', 'name', 'name', 'Human', 'String', None], - ['leave', 'field', None, 'Human', 'String', None], - ['enter', 'field', None, 'Human', '[Pet]', None], - ['enter', 'name', 'pets', 'Human', '[Pet]', None], - ['leave', 'name', 'pets', 'Human', '[Pet]', None], - ['enter', 'selection_set', None, 'Pet', '[Pet]', None], - ['enter', 'field', None, 'Pet', 'String!', None], - ['enter', 'name', '__typename', 'Pet', 'String!', None], - ['leave', 'name', '__typename', 'Pet', 'String!', None], - ['leave', 'field', None, 'Pet', 'String!', None], - ['leave', 'selection_set', None, 'Pet', '[Pet]', None], - ['leave', 'field', None, 'Human', '[Pet]', None], - ['leave', 'selection_set', None, 'Human', 'Human', None], - ['leave', 'field', None, 'QueryRoot', 'Human', None], - ['enter', 'field', None, 'QueryRoot', 'Alien', None], - ['enter', 'name', 'alien', 'QueryRoot', 'Alien', None], - ['leave', 'name', 'alien', 'QueryRoot', 'Alien', None], - ['enter', 'selection_set', None, 'Alien', 'Alien', None], - ['enter', 'field', None, 'Alien', 'String!', None], - ['enter', 'name', '__typename', 'Alien', 'String!', None], - ['leave', 'name', '__typename', 'Alien', 'String!', None], - ['leave', 'field', None, 'Alien', 'String!', None], - ['leave', 'selection_set', None, 'Alien', 'Alien', None], - ['leave', 'field', None, 'QueryRoot', 'Alien', None], - ['leave', 'selection_set', None, 'QueryRoot', 'QueryRoot', None], - ['leave', 'operation_definition', None, None, 'QueryRoot', None], - ['leave', 'document', None, None, None, None], + ["enter", "document", None, None, None, None], + ["enter", "operation_definition", None, None, "QueryRoot", None], + ["enter", "selection_set", None, "QueryRoot", "QueryRoot", None], + ["enter", "field", None, "QueryRoot", "Human", None], + ["enter", "name", "human", "QueryRoot", "Human", None], + ["leave", "name", "human", "QueryRoot", "Human", None], + ["enter", "argument", None, "QueryRoot", "Human", "ID"], + ["enter", "name", "id", "QueryRoot", "Human", "ID"], + ["leave", "name", "id", "QueryRoot", "Human", "ID"], + ["enter", "int_value", None, "QueryRoot", "Human", "ID"], + ["leave", "int_value", None, "QueryRoot", "Human", "ID"], + ["leave", "argument", None, "QueryRoot", "Human", "ID"], + ["enter", "selection_set", None, "Human", "Human", None], + ["enter", "field", None, "Human", "String", None], + ["enter", "name", "name", "Human", "String", None], + ["leave", "name", "name", "Human", "String", None], + ["leave", "field", None, "Human", "String", None], + ["enter", "field", None, "Human", "[Pet]", None], + ["enter", "name", "pets", "Human", "[Pet]", None], + ["leave", "name", "pets", "Human", "[Pet]", None], + ["enter", "selection_set", None, "Pet", "[Pet]", None], + ["enter", "field", None, "Pet", "String!", None], + ["enter", "name", "__typename", "Pet", "String!", None], + ["leave", "name", "__typename", "Pet", "String!", None], + ["leave", "field", None, "Pet", "String!", None], + ["leave", "selection_set", None, "Pet", "[Pet]", None], + ["leave", "field", None, "Human", "[Pet]", None], + ["leave", "selection_set", None, "Human", "Human", None], + ["leave", "field", None, "QueryRoot", "Human", None], + ["enter", "field", None, "QueryRoot", "Alien", None], + ["enter", "name", "alien", "QueryRoot", "Alien", None], + ["leave", "name", "alien", "QueryRoot", "Alien", None], + ["enter", "selection_set", None, "Alien", "Alien", None], + ["enter", "field", None, "Alien", "String!", None], + ["enter", "name", "__typename", "Alien", "String!", None], + ["leave", "name", "__typename", "Alien", "String!", None], + ["leave", "field", None, "Alien", "String!", None], + ["leave", "selection_set", None, "Alien", "Alien", None], + ["leave", "field", None, "QueryRoot", "Alien", None], + ["leave", "selection_set", None, "QueryRoot", "QueryRoot", None], + ["leave", "operation_definition", None, None, "QueryRoot", None], + ["leave", "document", None, None, None, None], ] diff --git a/tests/pyutils/test_cached_property.py b/tests/pyutils/test_cached_property.py index 7b20ccd1..1c8ad24c 100644 --- a/tests/pyutils/test_cached_property.py +++ b/tests/pyutils/test_cached_property.py @@ -2,11 +2,8 @@ def describe_cached_property(): - def works_like_a_normal_property(): - class TestClass: - @cached_property def value(self): return 42 @@ -14,7 +11,6 @@ def value(self): assert TestClass().value == 42 def caches_the_value(): - class TestClass: evaluations = 0 diff --git a/tests/pyutils/test_contain_subset.py b/tests/pyutils/test_contain_subset.py index 2db8be8c..cf9c2a47 100644 --- a/tests/pyutils/test_contain_subset.py +++ b/tests/pyutils/test_contain_subset.py @@ -7,134 +7,125 @@ def describe_plain_object(): - tested_object = {'a': 'b', 'c': 'd'} + tested_object = {"a": "b", "c": "d"} def should_pass_for_smaller_object(): - assert contain_subset(tested_object, {'a': 'b'}) + assert contain_subset(tested_object, {"a": "b"}) def should_pass_for_same_object(): - assert contain_subset(tested_object, {'a': 'b', 'c': 'd'}) + assert contain_subset(tested_object, {"a": "b", "c": "d"}) def should_pass_for_similar_but_not_the_same_object(): - assert not contain_subset(tested_object, {'a': 'notB', 'c': 'd'}) + assert not contain_subset(tested_object, {"a": "notB", "c": "d"}) def describe_complex_object(): - tested_object = { - 'a': 'b', 'c': 'd', 'e': {'foo': 'bar', 'baz': {'qux': 'quux'}}} + tested_object = {"a": "b", "c": "d", "e": {"foo": "bar", "baz": {"qux": "quux"}}} def should_pass_for_smaller_object_1(): - assert contain_subset(tested_object, {'a': 'b', 'e': {'foo': 'bar'}}) + assert contain_subset(tested_object, {"a": "b", "e": {"foo": "bar"}}) def should_pass_for_smaller_object_2(): assert contain_subset( - tested_object, {'e': {'foo': 'bar', 'baz': {'qux': 'quux'}}}) + tested_object, {"e": {"foo": "bar", "baz": {"qux": "quux"}}} + ) def should_pass_for_same_object(): - assert contain_subset(tested_object, { - 'a': 'b', 'c': 'd', 'e': {'foo': 'bar', 'baz': {'qux': 'quux'}}}) + assert contain_subset( + tested_object, + {"a": "b", "c": "d", "e": {"foo": "bar", "baz": {"qux": "quux"}}}, + ) def should_pass_for_similar_but_not_the_same_object(): - assert not contain_subset(tested_object, { - 'e': {'foo': 'bar', 'baz': {'qux': 'notAQuux'}}}) + assert not contain_subset( + tested_object, {"e": {"foo": "bar", "baz": {"qux": "notAQuux"}}} + ) def should_fail_if_comparing_when_comparing_objects_to_dates(): - assert not contain_subset(tested_object, {'e': date.today()}) + assert not contain_subset(tested_object, {"e": date.today()}) def describe_circular_objects(): - @fixture def test_object(): obj = {} - obj['arr'] = [obj, obj] - obj['arr'].append(obj['arr']) - obj['obj'] = obj + obj["arr"] = [obj, obj] + obj["arr"].append(obj["arr"]) + obj["obj"] = obj return obj # noinspection PyShadowingNames def should_contain_subdocument(test_object): - assert contain_subset(test_object, { - 'arr': [ - {'arr': []}, - {'arr': []}, - [ - {'arr': []}, - {'arr': []} - ] - ]}) + assert contain_subset( + test_object, {"arr": [{"arr": []}, {"arr": []}, [{"arr": []}, {"arr": []}]]} + ) # noinspection PyShadowingNames def should_not_contain_similar_object(test_object): - assert not contain_subset(test_object, { - 'arr': [ - {'arr': ['just random field']}, - {'arr': []}, - [ - {'arr': []}, - {'arr': []} + assert not contain_subset( + test_object, + { + "arr": [ + {"arr": ["just random field"]}, + {"arr": []}, + [{"arr": []}, {"arr": []}], ] - ]}) + }, + ) def describe_object_with_compare_function(): - def should_pass_when_function_returns_true(): - assert contain_subset({'a': 5}, {'a': lambda a: a}) + assert contain_subset({"a": 5}, {"a": lambda a: a}) def should_fail_when_function_returns_false(): - assert not contain_subset({'a': 5}, {'a': lambda a: not a}) + assert not contain_subset({"a": 5}, {"a": lambda a: not a}) def should_pass_for_function_with_no_arguments(): - assert contain_subset({'a': 5}, {'a': lambda: True}) + assert contain_subset({"a": 5}, {"a": lambda: True}) def describe_comparison_of_non_objects(): - def should_fail_if_actual_subset_is_null(): - assert not contain_subset(None, {'a': 1}) + assert not contain_subset(None, {"a": 1}) def should_fail_if_expected_subset_is_not_an_object(): - assert not contain_subset({'a': 1}, None) + assert not contain_subset({"a": 1}, None) def should_not_fail_for_same_non_object_string_variables(): - assert contain_subset('string', 'string') + assert contain_subset("string", "string") def describe_comparison_of_dates(): - def should_pass_for_the_same_date(): assert contain_subset(date(2015, 11, 30), date(2015, 11, 30)) def should_pass_for_the_same_date_if_nested(): - assert contain_subset( - {'a': date(2015, 11, 30)}, {'a': date(2015, 11, 30)}) + assert contain_subset({"a": date(2015, 11, 30)}, {"a": date(2015, 11, 30)}) def should_fail_for_a_different_date(): assert not contain_subset(date(2015, 11, 30), date(2012, 2, 22)) def should_fail_for_a_different_date_if_nested(): - assert not contain_subset( - {'a': date(2015, 11, 30)}, {'a': date(2015, 2, 22)}) + assert not contain_subset({"a": date(2015, 11, 30)}, {"a": date(2015, 2, 22)}) def describe_cyclic_objects(): - def should_pass(): child = {} - parent = {'children': [child]} - child['parent'] = parent + parent = {"children": [child]} + child["parent"] = parent - my_object = {'a': 1, 'b': 'two', 'c': parent} - assert contain_subset(my_object, {'a': 1, 'c': parent}) + my_object = {"a": 1, "b": "two", "c": parent} + assert contain_subset(my_object, {"a": 1, "c": parent}) def describe_list_objects(): - test_list = [{'a': 'a', 'b': 'b'}, {'v': 'f', 'd': {'z': 'g'}}] + test_list = [{"a": "a", "b": "b"}, {"v": "f", "d": {"z": "g"}}] def works_well_with_lists(): - assert contain_subset(test_list, [{'a': 'a'}]) - assert contain_subset(test_list, [{'a': 'a', 'b': 'b'}]) - assert not contain_subset(test_list, [{'a': 'a', 'b': 'bd'}]) + assert contain_subset(test_list, [{"a": "a"}]) + assert contain_subset(test_list, [{"a": "a", "b": "b"}]) + assert not contain_subset(test_list, [{"a": "a", "b": "bd"}]) diff --git a/tests/pyutils/test_convert_case.py b/tests/pyutils/test_convert_case.py index adfc2d6f..30a0d325 100644 --- a/tests/pyutils/test_convert_case.py +++ b/tests/pyutils/test_convert_case.py @@ -2,52 +2,50 @@ def describe_camel_to_snake(): - def converts_typical_names(): - result = camel_to_snake('CamelCase') - assert result == 'camel_case' - result = camel_to_snake('InputObjectTypeExtensionNode') - assert result == 'input_object_type_extension_node' + result = camel_to_snake("CamelCase") + assert result == "camel_case" + result = camel_to_snake("InputObjectTypeExtensionNode") + assert result == "input_object_type_extension_node" def may_start_with_lowercase(): - result = camel_to_snake('CamelCase') - assert result == 'camel_case' + result = camel_to_snake("CamelCase") + assert result == "camel_case" def works_with_acronyms(): - result = camel_to_snake('SlowXMLParser') - assert result == 'slow_xml_parser' - result = camel_to_snake('FastGraphQLParser') - assert result == 'fast_graph_ql_parser' + result = camel_to_snake("SlowXMLParser") + assert result == "slow_xml_parser" + result = camel_to_snake("FastGraphQLParser") + assert result == "fast_graph_ql_parser" def keeps_already_snake(): - result = camel_to_snake('snake_case') - assert result == 'snake_case' + result = camel_to_snake("snake_case") + assert result == "snake_case" def describe_snake_to_camel(): - def converts_typical_names(): - result = snake_to_camel('snake_case') - assert result == 'SnakeCase' - result = snake_to_camel('input_object_type_extension_node') - assert result == 'InputObjectTypeExtensionNode' + result = snake_to_camel("snake_case") + assert result == "SnakeCase" + result = snake_to_camel("input_object_type_extension_node") + assert result == "InputObjectTypeExtensionNode" def may_start_with_uppercase(): - result = snake_to_camel('Snake_case') - assert result == 'SnakeCase' + result = snake_to_camel("Snake_case") + assert result == "SnakeCase" def works_with_acronyms(): - result = snake_to_camel('slow_xml_parser') - assert result == 'SlowXmlParser' - result = snake_to_camel('fast_graph_ql_parser') - assert result == 'FastGraphQlParser' + result = snake_to_camel("slow_xml_parser") + assert result == "SlowXmlParser" + result = snake_to_camel("fast_graph_ql_parser") + assert result == "FastGraphQlParser" def keeps_already_camel(): - result = snake_to_camel('CamelCase') - assert result == 'CamelCase' + result = snake_to_camel("CamelCase") + assert result == "CamelCase" def can_produce_lower_camel_case(): - result = snake_to_camel('snake_case', upper=False) - assert result == 'snakeCase' - result = snake_to_camel('input_object_type_extension_node', False) - assert result == 'inputObjectTypeExtensionNode' + result = snake_to_camel("snake_case", upper=False) + assert result == "snakeCase" + result = snake_to_camel("input_object_type_extension_node", False) + assert result == "inputObjectTypeExtensionNode" diff --git a/tests/pyutils/test_dedent.py b/tests/pyutils/test_dedent.py index 66981fff..441f9173 100644 --- a/tests/pyutils/test_dedent.py +++ b/tests/pyutils/test_dedent.py @@ -2,9 +2,10 @@ def describe_dedent(): - def removes_indentation_in_typical_usage(): - assert dedent(""" + assert ( + dedent( + """ type Query { me: User } @@ -13,58 +14,95 @@ def removes_indentation_in_typical_usage(): id: ID name: String } - """) == ( - 'type Query {\n me: User\n}\n\n' + - 'type User {\n id: ID\n name: String\n}\n') + """ + ) + == ( + "type Query {\n me: User\n}\n\n" + + "type User {\n id: ID\n name: String\n}\n" + ) + ) def removes_only_the_first_level_of_indentation(): - assert dedent(""" + assert ( + dedent( + """ qux quux quuux quuuux - """) == 'qux\n quux\n quuux\n quuuux\n' + """ + ) + == "qux\n quux\n quuux\n quuuux\n" + ) def does_not_escape_special_characters(): - assert dedent(""" + assert ( + dedent( + """ type Root { field(arg: String = "wi\th de\fault"): String } - """) == ( - 'type Root {\n' - ' field(arg: String = "wi\th de\fault"): String\n}\n') + """ + ) + == ("type Root {\n" ' field(arg: String = "wi\th de\fault"): String\n}\n') + ) def also_removes_indentation_using_tabs(): - assert dedent(""" + assert ( + dedent( + """ \t\t type Query { \t\t me: User \t\t } - """) == 'type Query {\n me: User\n}\n' + """ + ) + == "type Query {\n me: User\n}\n" + ) def removes_leading_newlines(): - assert dedent(""" + assert ( + dedent( + """ type Query { me: User - }""") == 'type Query {\n me: User\n}' + }""" + ) + == "type Query {\n me: User\n}" + ) def does_not_remove_trailing_newlines(): - assert dedent(""" + assert ( + dedent( + """ type Query { me: User } - """) == 'type Query {\n me: User\n}\n\n' + """ + ) + == "type Query {\n me: User\n}\n\n" + ) def removes_all_trailing_spaces_and_tabs(): - assert dedent(""" + assert ( + dedent( + """ type Query { me: User } - \t\t \t """) == 'type Query {\n me: User\n}\n' + \t\t \t """ + ) + == "type Query {\n me: User\n}\n" + ) def works_on_text_without_leading_newline(): - assert dedent(""" type Query { + assert ( + dedent( + """ type Query { me: User - }""") == 'type Query {\n me: User\n}' + }""" + ) + == "type Query {\n me: User\n}" + ) diff --git a/tests/pyutils/test_event_emitter.py b/tests/pyutils/test_event_emitter.py index e87915f2..8225b243 100644 --- a/tests/pyutils/test_event_emitter.py +++ b/tests/pyutils/test_event_emitter.py @@ -5,7 +5,6 @@ def describe_event_emitter(): - def add_and_remove_listeners(): emitter = EventEmitter() @@ -15,19 +14,19 @@ def listener1(value): def listener2(value): pass - emitter.add_listener('foo', listener1) - emitter.add_listener('foo', listener2) - emitter.add_listener('bar', listener1) - assert emitter.listeners['foo'] == [listener1, listener2] - assert emitter.listeners['bar'] == [listener1] - emitter.remove_listener('foo', listener1) - assert emitter.listeners['foo'] == [listener2] - assert emitter.listeners['bar'] == [listener1] - emitter.remove_listener('foo', listener2) - assert emitter.listeners['foo'] == [] - assert emitter.listeners['bar'] == [listener1] - emitter.remove_listener('bar', listener1) - assert emitter.listeners['bar'] == [] + emitter.add_listener("foo", listener1) + emitter.add_listener("foo", listener2) + emitter.add_listener("bar", listener1) + assert emitter.listeners["foo"] == [listener1, listener2] + assert emitter.listeners["bar"] == [listener1] + emitter.remove_listener("foo", listener1) + assert emitter.listeners["foo"] == [listener2] + assert emitter.listeners["bar"] == [listener1] + emitter.remove_listener("foo", listener2) + assert emitter.listeners["foo"] == [] + assert emitter.listeners["bar"] == [listener1] + emitter.remove_listener("bar", listener1) + assert emitter.listeners["bar"] == [] def emit_sync(): emitter = EventEmitter() @@ -36,11 +35,11 @@ def emit_sync(): def listener(value): emitted.append(value) - emitter.add_listener('foo', listener) - assert emitter.emit('foo', 'bar') is True - assert emitted == ['bar'] - assert emitter.emit('bar', 'baz') is False - assert emitted == ['bar'] + emitter.add_listener("foo", listener) + assert emitter.emit("foo", "bar") is True + assert emitted == ["bar"] + assert emitter.emit("bar", "baz") is False + assert emitted == ["bar"] @mark.asyncio async def emit_async(): @@ -50,40 +49,39 @@ async def emit_async(): async def listener(value): emitted.append(value) - emitter.add_listener('foo', listener) - emitter.emit('foo', 'bar') - emitter.emit('bar', 'baz') + emitter.add_listener("foo", listener) + emitter.emit("foo", "bar") + emitter.emit("bar", "baz") await sleep(0) - assert emitted == ['bar'] + assert emitted == ["bar"] def describe_event_emitter_async_iterator(): - @mark.asyncio async def subscribe_async_iterator_mock(): # Create an AsyncIterator from an EventEmitter emitter = EventEmitter() - iterator = EventEmitterAsyncIterator(emitter, 'publish') + iterator = EventEmitterAsyncIterator(emitter, "publish") # Queue up publishes - assert emitter.emit('publish', 'Apple') is True - assert emitter.emit('publish', 'Banana') is True + assert emitter.emit("publish", "Apple") is True + assert emitter.emit("publish", "Banana") is True # Read payloads - assert await iterator.__anext__() == 'Apple' - assert await iterator.__anext__() == 'Banana' + assert await iterator.__anext__() == "Apple" + assert await iterator.__anext__() == "Banana" # Read ahead i3 = iterator.__anext__() i4 = iterator.__anext__() # Publish - assert emitter.emit('publish', 'Coconut') is True - assert emitter.emit('publish', 'Durian') is True + assert emitter.emit("publish", "Coconut") is True + assert emitter.emit("publish", "Durian") is True # Await results - assert await i3 == 'Coconut' - assert await i4 == 'Durian' + assert await i3 == "Coconut" + assert await i4 == "Durian" # Read ahead i5 = iterator.__anext__() @@ -92,7 +90,7 @@ async def subscribe_async_iterator_mock(): await iterator.aclose() # Publish is not caught after terminate - assert emitter.emit('publish', 'Fig') is False + assert emitter.emit("publish", "Fig") is False # Find that cancelled read-ahead got a "done" result with raises(StopAsyncIteration): diff --git a/tests/pyutils/test_is_finite.py b/tests/pyutils/test_is_finite.py index 289f0ea4..25696965 100644 --- a/tests/pyutils/test_is_finite.py +++ b/tests/pyutils/test_is_finite.py @@ -5,7 +5,6 @@ def describe_is_finite(): - def null_is_not_finite(): assert is_finite(None) is False @@ -15,7 +14,7 @@ def booleans_are_finite(): assert is_finite(True) is True def strings_are_not_finite(): - assert is_finite('string') is False + assert is_finite("string") is False def ints_are_finite(): assert is_finite(0) is True diff --git a/tests/pyutils/test_is_integer.py b/tests/pyutils/test_is_integer.py index a251cfb1..c6b1dc43 100644 --- a/tests/pyutils/test_is_integer.py +++ b/tests/pyutils/test_is_integer.py @@ -5,7 +5,6 @@ def describe_is_integer(): - def null_is_not_integer(): assert is_integer(None) is False @@ -17,7 +16,7 @@ def booleans_are_not_integer(): assert is_integer(True) is False def strings_are_not_integer(): - assert is_integer('string') is False + assert is_integer("string") is False def ints_are_integer(): assert is_integer(0) is True diff --git a/tests/pyutils/test_is_invalid.py b/tests/pyutils/test_is_invalid.py index d39c12e2..498d168c 100644 --- a/tests/pyutils/test_is_invalid.py +++ b/tests/pyutils/test_is_invalid.py @@ -5,18 +5,17 @@ def describe_is_invalid(): - def null_is_not_invalid(): assert is_invalid(None) is False def falsy_objects_are_not_invalid(): - assert is_invalid('') is False + assert is_invalid("") is False assert is_invalid(0) is False assert is_invalid([]) is False assert is_invalid({}) is False def truthy_objects_are_not_invalid(): - assert is_invalid('str') is False + assert is_invalid("str") is False assert is_invalid(1) is False assert is_invalid([0]) is False assert is_invalid({None: None}) is False diff --git a/tests/pyutils/test_is_nullish.py b/tests/pyutils/test_is_nullish.py index 0a2b8274..9e71b00a 100644 --- a/tests/pyutils/test_is_nullish.py +++ b/tests/pyutils/test_is_nullish.py @@ -5,18 +5,17 @@ def describe_is_nullish(): - def null_is_nullish(): assert is_nullish(None) is True def falsy_objects_are_not_nullish(): - assert is_nullish('') is False + assert is_nullish("") is False assert is_nullish(0) is False assert is_nullish([]) is False assert is_nullish({}) is False def truthy_objects_are_not_nullish(): - assert is_nullish('str') is False + assert is_nullish("str") is False assert is_nullish(1) is False assert is_nullish([0]) is False assert is_nullish({None: None}) is False diff --git a/tests/pyutils/test_or_list.py b/tests/pyutils/test_or_list.py index 840d67dc..c02b331b 100644 --- a/tests/pyutils/test_or_list.py +++ b/tests/pyutils/test_or_list.py @@ -4,26 +4,25 @@ def describe_or_list(): - def returns_none_for_empty_list(): with raises(TypeError): or_list([]) def prints_list_with_one_item(): - assert or_list(['one']) == 'one' + assert or_list(["one"]) == "one" def prints_list_with_two_items(): - assert or_list(['one', 'two']) == 'one or two' + assert or_list(["one", "two"]) == "one or two" def prints_list_with_three_items(): - assert or_list(['A', 'B', 'C']) == 'A, B or C' - assert or_list(['one', 'two', 'three']) == 'one, two or three' + assert or_list(["A", "B", "C"]) == "A, B or C" + assert or_list(["one", "two", "three"]) == "one, two or three" def prints_list_with_five_items(): - assert or_list(['A', 'B', 'C', 'D', 'E']) == 'A, B, C, D or E' + assert or_list(["A", "B", "C", "D", "E"]) == "A, B, C, D or E" def prints_shortened_list_with_six_items(): - assert or_list(['A', 'B', 'C', 'D', 'E', 'F']) == 'A, B, C, D or E' + assert or_list(["A", "B", "C", "D", "E", "F"]) == "A, B, C, D or E" def prints_tuple_with_three_items(): - assert or_list(('A', 'B', 'C')) == 'A, B or C' + assert or_list(("A", "B", "C")) == "A, B or C" diff --git a/tests/pyutils/test_quoted_or_list.py b/tests/pyutils/test_quoted_or_list.py index 842fb28e..2bb367c3 100644 --- a/tests/pyutils/test_quoted_or_list.py +++ b/tests/pyutils/test_quoted_or_list.py @@ -4,20 +4,21 @@ def describe_quoted_or_list(): - def does_not_accept_an_empty_list(): with raises(TypeError): quoted_or_list([]) def returns_single_quoted_item(): - assert quoted_or_list(['A']) == "'A'" + assert quoted_or_list(["A"]) == "'A'" def returns_two_item_list(): - assert quoted_or_list(['A', 'B']) == "'A' or 'B'" + assert quoted_or_list(["A", "B"]) == "'A' or 'B'" def returns_comma_separated_many_item_list(): - assert quoted_or_list(['A', 'B', 'C']) == "'A', 'B' or 'C'" + assert quoted_or_list(["A", "B", "C"]) == "'A', 'B' or 'C'" def limits_to_five_items(): - assert quoted_or_list( - ['A', 'B', 'C', 'D', 'E', 'F']) == "'A', 'B', 'C', 'D' or 'E'" + assert ( + quoted_or_list(["A", "B", "C", "D", "E", "F"]) + == "'A', 'B', 'C', 'D' or 'E'" + ) diff --git a/tests/pyutils/test_suggesion_list.py b/tests/pyutils/test_suggesion_list.py index 19428099..7841177f 100644 --- a/tests/pyutils/test_suggesion_list.py +++ b/tests/pyutils/test_suggesion_list.py @@ -2,21 +2,19 @@ def describe_suggestion_list(): - def returns_results_when_input_is_empty(): - assert suggestion_list('', ['a']) == ['a'] + assert suggestion_list("", ["a"]) == ["a"] def returns_empty_array_when_there_are_no_options(): - assert suggestion_list('input', []) == [] + assert suggestion_list("input", []) == [] def returns_options_sorted_based_on_similarity(): - assert suggestion_list( - 'abc', ['a', 'ab', 'abc']) == ['abc', 'ab'] + assert suggestion_list("abc", ["a", "ab", "abc"]) == ["abc", "ab"] assert suggestion_list( - 'csutomer', ['store', 'customer', 'stomer', 'some', 'more']) == [ - 'customer', 'stomer', 'store', 'some'] + "csutomer", ["store", "customer", "stomer", "some", "more"] + ) == ["customer", "stomer", "store", "some"] assert suggestion_list( - 'GraphQl', ['graphics', 'SQL', 'GraphQL', 'quarks', 'mark']) == [ - 'GraphQL', 'graphics'] + "GraphQl", ["graphics", "SQL", "GraphQL", "quarks", "mark"] + ) == ["GraphQL", "graphics"] diff --git a/tests/star_wars_data.py b/tests/star_wars_data.py index 233fe336..bdba57ef 100644 --- a/tests/star_wars_data.py +++ b/tests/star_wars_data.py @@ -7,9 +7,7 @@ from typing import Sequence, Iterator -__all__ = [ - 'get_droid', 'get_friends', 'get_hero', 'get_human', - 'get_secret_backstory'] +__all__ = ["get_droid", "get_friends", "get_hero", "get_human", "get_secret_backstory"] # These are classes which correspond to the schema. # They represent the shape of the data visited during field resolution. @@ -24,7 +22,7 @@ class Character: # noinspection PyPep8Naming class Human(Character): - type = 'Human' + type = "Human" homePlanet: str # noinspection PyShadowingBuiltins @@ -36,7 +34,7 @@ def __init__(self, id, name, friends, appearsIn, homePlanet): # noinspection PyPep8Naming class Droid(Character): - type = 'Droid' + type = "Droid" primaryFunction: str # noinspection PyShadowingBuiltins @@ -47,59 +45,60 @@ def __init__(self, id, name, friends, appearsIn, primaryFunction): luke = Human( - id='1000', - name='Luke Skywalker', - friends=['1002', '1003', '2000', '2001'], + id="1000", + name="Luke Skywalker", + friends=["1002", "1003", "2000", "2001"], appearsIn=[4, 5, 6], - homePlanet='Tatooine') + homePlanet="Tatooine", +) vader = Human( - id='1001', - name='Darth Vader', - friends=['1004'], + id="1001", + name="Darth Vader", + friends=["1004"], appearsIn=[4, 5, 6], - homePlanet='Tatooine') + homePlanet="Tatooine", +) han = Human( - id='1002', - name='Han Solo', - friends=['1000', '1003', '2001'], + id="1002", + name="Han Solo", + friends=["1000", "1003", "2001"], appearsIn=[4, 5, 6], - homePlanet=None) + homePlanet=None, +) leia = Human( - id='1003', - name='Leia Organa', - friends=['1000', '1002', '2000', '2001'], + id="1003", + name="Leia Organa", + friends=["1000", "1002", "2000", "2001"], appearsIn=[4, 5, 6], - homePlanet='Alderaan') + homePlanet="Alderaan", +) tarkin = Human( - id='1004', - name='Wilhuff Tarkin', - friends=['1001'], - appearsIn=[4], - homePlanet=None) + id="1004", name="Wilhuff Tarkin", friends=["1001"], appearsIn=[4], homePlanet=None +) -human_data = { - '1000': luke, '1001': vader, '1002': han, '1003': leia, '1004': tarkin} +human_data = {"1000": luke, "1001": vader, "1002": han, "1003": leia, "1004": tarkin} threepio = Droid( - id='2000', - name='C-3PO', - friends=['1000', '1002', '1003', '2001'], + id="2000", + name="C-3PO", + friends=["1000", "1002", "1003", "2001"], appearsIn=[4, 5, 6], - primaryFunction='Protocol') + primaryFunction="Protocol", +) artoo = Droid( - id='2001', - name='R2-D2', - friends=['1000', '1002', '1003'], + id="2001", + name="R2-D2", + friends=["1000", "1002", "1003"], appearsIn=[4, 5, 6], - primaryFunction='Astromech') + primaryFunction="Astromech", +) -droid_data = { - '2000': threepio, '2001': artoo} +droid_data = {"2000": threepio, "2001": artoo} # noinspection PyShadowingBuiltins @@ -136,4 +135,4 @@ def get_droid(id: str) -> Droid: def get_secret_backstory(character: Character) -> str: """Raise an error when attempting to get the secret backstory.""" - raise RuntimeError('secretBackstory is secret.') + raise RuntimeError("secretBackstory is secret.") diff --git a/tests/star_wars_schema.py b/tests/star_wars_schema.py index ffff3a67..460d2263 100644 --- a/tests/star_wars_schema.py +++ b/tests/star_wars_schema.py @@ -44,13 +44,26 @@ """ from graphql.type import ( - GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, - GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLSchema, GraphQLString) + GraphQLArgument, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, +) from tests.star_wars_data import ( - get_droid, get_friends, get_hero, get_human, get_secret_backstory) + get_droid, + get_friends, + get_hero, + get_human, + get_secret_backstory, +) -__all__ = ['star_wars_schema'] +__all__ = ["star_wars_schema"] # We begin by setting up our schema. @@ -59,11 +72,15 @@ # This implements the following type system shorthand: # enum Episode { NEWHOPE, EMPIRE, JEDI } -episode_enum = GraphQLEnumType('Episode', { - 'NEWHOPE': GraphQLEnumValue(4, description='Released in 1977.'), - 'EMPIRE': GraphQLEnumValue(5, description='Released in 1980.'), - 'JEDI': GraphQLEnumValue(6, description='Released in 1983.') - }, description='One of the films in the Star Wars Trilogy') +episode_enum = GraphQLEnumType( + "Episode", + { + "NEWHOPE": GraphQLEnumValue(4, description="Released in 1977."), + "EMPIRE": GraphQLEnumValue(5, description="Released in 1980."), + "JEDI": GraphQLEnumValue(6, description="Released in 1983."), + }, + description="One of the films in the Star Wars Trilogy", +) # Characters in the Star Wars trilogy are either humans or droids. # @@ -75,26 +92,31 @@ # appearsIn: [Episode] # secretBackstory: String -character_interface = GraphQLInterfaceType('Character', lambda: { - 'id': GraphQLField( - GraphQLNonNull(GraphQLString), - description='The id of the character.'), - 'name': GraphQLField( - GraphQLString, - description='The name of the character.'), - 'friends': GraphQLField( - GraphQLList(character_interface), - description='The friends of the character,' - ' or an empty list if they have none.'), - 'appearsIn': GraphQLField( - GraphQLList(episode_enum), - description='Which movies they appear in.'), - 'secretBackstory': GraphQLField( - GraphQLString, - description='All secrets about their past.')}, - resolve_type=lambda character, _info: - {'Human': human_type, 'Droid': droid_type}.get(character.type), - description='A character in the Star Wars Trilogy') +character_interface = GraphQLInterfaceType( + "Character", + lambda: { + "id": GraphQLField( + GraphQLNonNull(GraphQLString), description="The id of the character." + ), + "name": GraphQLField(GraphQLString, description="The name of the character."), + "friends": GraphQLField( + GraphQLList(character_interface), + description="The friends of the character," + " or an empty list if they have none.", + ), + "appearsIn": GraphQLField( + GraphQLList(episode_enum), description="Which movies they appear in." + ), + "secretBackstory": GraphQLField( + GraphQLString, description="All secrets about their past." + ), + }, + resolve_type=lambda character, _info: { + "Human": human_type, + "Droid": droid_type, + }.get(character.type), + description="A character in the Star Wars Trilogy", +) # We define our human type, which implements the character interface. # @@ -107,31 +129,35 @@ # secretBackstory: String # } -human_type = GraphQLObjectType('Human', lambda: { - 'id': GraphQLField( - GraphQLNonNull(GraphQLString), - description='The id of the human.'), - 'name': GraphQLField( - GraphQLString, - description='The name of the human.'), - 'friends': GraphQLField( - GraphQLList(character_interface), - description='The friends of the human,' - ' or an empty list if they have none.', - resolve=lambda human, _info: get_friends(human)), - 'appearsIn': GraphQLField( - GraphQLList(episode_enum), - description='Which movies they appear in.'), - 'homePlanet': GraphQLField( - GraphQLString, - description='The home planet of the human, or null if unknown.'), - 'secretBackstory': GraphQLField( - GraphQLString, - resolve=lambda human, _info: get_secret_backstory(human), - description='Where are they from' - ' and how they came to be who they are.')}, +human_type = GraphQLObjectType( + "Human", + lambda: { + "id": GraphQLField( + GraphQLNonNull(GraphQLString), description="The id of the human." + ), + "name": GraphQLField(GraphQLString, description="The name of the human."), + "friends": GraphQLField( + GraphQLList(character_interface), + description="The friends of the human," + " or an empty list if they have none.", + resolve=lambda human, _info: get_friends(human), + ), + "appearsIn": GraphQLField( + GraphQLList(episode_enum), description="Which movies they appear in." + ), + "homePlanet": GraphQLField( + GraphQLString, + description="The home planet of the human, or null if unknown.", + ), + "secretBackstory": GraphQLField( + GraphQLString, + resolve=lambda human, _info: get_secret_backstory(human), + description="Where are they from" " and how they came to be who they are.", + ), + }, interfaces=[character_interface], - description='A humanoid creature in the Star Wars universe.') + description="A humanoid creature in the Star Wars universe.", +) # The other type of character in Star Wars is a droid. # @@ -145,32 +171,34 @@ # primaryFunction: String # } -droid_type = GraphQLObjectType('Droid', lambda: { - 'id': GraphQLField( - GraphQLNonNull(GraphQLString), - description='The id of the droid.'), - 'name': GraphQLField( - GraphQLString, - description='The name of the droid.'), - 'friends': GraphQLField( - GraphQLList(character_interface), - description='The friends of the droid,' - ' or an empty list if they have none.', - resolve=lambda droid, _info: get_friends(droid), - ), - 'appearsIn': GraphQLField( - GraphQLList(episode_enum), - description='Which movies they appear in.'), - 'secretBackstory': GraphQLField( - GraphQLString, - resolve=lambda droid, _info: get_secret_backstory(droid), - description='Construction date and the name of the designer.'), - 'primaryFunction': GraphQLField( - GraphQLString, - description='The primary function of the droid.') +droid_type = GraphQLObjectType( + "Droid", + lambda: { + "id": GraphQLField( + GraphQLNonNull(GraphQLString), description="The id of the droid." + ), + "name": GraphQLField(GraphQLString, description="The name of the droid."), + "friends": GraphQLField( + GraphQLList(character_interface), + description="The friends of the droid," + " or an empty list if they have none.", + resolve=lambda droid, _info: get_friends(droid), + ), + "appearsIn": GraphQLField( + GraphQLList(episode_enum), description="Which movies they appear in." + ), + "secretBackstory": GraphQLField( + GraphQLString, + resolve=lambda droid, _info: get_secret_backstory(droid), + description="Construction date and the name of the designer.", + ), + "primaryFunction": GraphQLField( + GraphQLString, description="The primary function of the droid." + ), }, interfaces=[character_interface], - description='A mechanical creature in the Star Wars universe.') + description="A mechanical creature in the Star Wars universe.", +) # This is the type that will be the root of our query, and the # entry point into our schema. It gives us the ability to fetch @@ -185,20 +213,42 @@ # } # noinspection PyShadowingBuiltins -query_type = GraphQLObjectType('Query', lambda: { - 'hero': GraphQLField(character_interface, args={ - 'episode': GraphQLArgument(episode_enum, description=( - 'If omitted, returns the hero of the whole saga.' - ' If provided, returns the hero of that particular episode.'))}, - resolve=lambda root, _info, episode=None: get_hero(episode)), - 'human': GraphQLField(human_type, args={ - 'id': GraphQLArgument( - GraphQLNonNull(GraphQLString), description='id of the human')}, - resolve=lambda root, _info, id: get_human(id)), - 'droid': GraphQLField(droid_type, args={ - 'id': GraphQLArgument( - GraphQLNonNull(GraphQLString), description='id of the droid')}, - resolve=lambda root, _info, id: get_droid(id))}) +query_type = GraphQLObjectType( + "Query", + lambda: { + "hero": GraphQLField( + character_interface, + args={ + "episode": GraphQLArgument( + episode_enum, + description=( + "If omitted, returns the hero of the whole saga." + " If provided, returns the hero of that particular episode." + ), + ) + }, + resolve=lambda root, _info, episode=None: get_hero(episode), + ), + "human": GraphQLField( + human_type, + args={ + "id": GraphQLArgument( + GraphQLNonNull(GraphQLString), description="id of the human" + ) + }, + resolve=lambda root, _info, id: get_human(id), + ), + "droid": GraphQLField( + droid_type, + args={ + "id": GraphQLArgument( + GraphQLNonNull(GraphQLString), description="id of the droid" + ) + }, + resolve=lambda root, _info, id: get_droid(id), + ), + }, +) # Finally, we construct our schema (whose starting query type is the query # type we defined above) and export it. diff --git a/tests/subscription/test_map_async_iterator.py b/tests/subscription/test_map_async_iterator.py index 5c6bfe77..461ffc6e 100644 --- a/tests/subscription/test_map_async_iterator.py +++ b/tests/subscription/test_map_async_iterator.py @@ -12,7 +12,6 @@ async def anext(iterable): def describe_map_async_iterator(): - @mark.asyncio async def maps_over_async_values(): async def source(): @@ -67,8 +66,8 @@ async def source(): yield 2 yield 3 finally: - yield 'done' - yield 'last' + yield "done" + yield "last" doubles = MapAsyncIterator(source(), lambda x: x + x) @@ -79,7 +78,7 @@ async def source(): await doubles.aclose() # Subsequent nexts may yield from finally block - assert await anext(doubles) == 'lastlast' + assert await anext(doubles) == "lastlast" with raises(GeneratorExit): assert await anext(doubles) @@ -97,9 +96,9 @@ async def source(): # Throw error with raises(RuntimeError) as exc_info: - await doubles.athrow(RuntimeError('ouch')) + await doubles.athrow(RuntimeError("ouch")) - assert str(exc_info.value) == 'ouch' + assert str(exc_info.value) == "ouch" with raises(StopAsyncIteration): await anext(doubles) @@ -122,7 +121,7 @@ async def source(): assert await anext(doubles) == 4 # Throw error - await doubles.athrow(RuntimeError('ouch')) + await doubles.athrow(RuntimeError("ouch")) with raises(StopAsyncIteration): await anext(doubles) @@ -132,12 +131,12 @@ async def source(): @mark.asyncio async def does_not_normally_map_over_thrown_errors(): async def source(): - yield 'Hello' - raise RuntimeError('Goodbye') + yield "Hello" + raise RuntimeError("Goodbye") doubles = MapAsyncIterator(source(), lambda x: x + x) - assert await anext(doubles) == 'HelloHello' + assert await anext(doubles) == "HelloHello" with raises(RuntimeError): await anext(doubles) @@ -145,29 +144,28 @@ async def source(): @mark.asyncio async def does_not_normally_map_over_externally_thrown_errors(): async def source(): - yield 'Hello' + yield "Hello" doubles = MapAsyncIterator(source(), lambda x: x + x) - assert await anext(doubles) == 'HelloHello' + assert await anext(doubles) == "HelloHello" with raises(RuntimeError): - await doubles.athrow(RuntimeError('Goodbye')) + await doubles.athrow(RuntimeError("Goodbye")) @mark.asyncio async def maps_over_thrown_errors_if_second_callback_provided(): async def source(): - yield 'Hello' - raise RuntimeError('Goodbye') + yield "Hello" + raise RuntimeError("Goodbye") - doubles = MapAsyncIterator( - source(), lambda x: x + x, lambda error: error) + doubles = MapAsyncIterator(source(), lambda x: x + x, lambda error: error) - assert await anext(doubles) == 'HelloHello' + assert await anext(doubles) == "HelloHello" result = await anext(doubles) assert isinstance(result, RuntimeError) - assert str(result) == 'Goodbye' + assert str(result) == "Goodbye" with raises(StopAsyncIteration): await anext(doubles) @@ -216,16 +214,16 @@ async def __anext__(self): # Throw error with raises(RuntimeError) as exc_info: - await doubles.athrow(RuntimeError('ouch')) + await doubles.athrow(RuntimeError("ouch")) - assert str(exc_info.value) == 'ouch' + assert str(exc_info.value) == "ouch" with raises(StopAsyncIteration): await anext(doubles) with raises(StopAsyncIteration): await anext(doubles) - await doubles.athrow(RuntimeError('no more ouch')) + await doubles.athrow(RuntimeError("no more ouch")) with raises(StopAsyncIteration): await anext(doubles) @@ -238,7 +236,7 @@ async def __anext__(self): assert await anext(doubles) == 4 try: - raise ValueError('bad') + raise ValueError("bad") except ValueError: tb = sys.exc_info()[2] diff --git a/tests/subscription/test_subscribe.py b/tests/subscription/test_subscribe.py index 118145e7..f08ebdb8 100644 --- a/tests/subscription/test_subscribe.py +++ b/tests/subscription/test_subscribe.py @@ -3,29 +3,48 @@ from graphql.language import parse from graphql.pyutils import EventEmitter, EventEmitterAsyncIterator from graphql.type import ( - GraphQLArgument, GraphQLBoolean, GraphQLField, GraphQLInt, GraphQLList, - GraphQLObjectType, GraphQLSchema, GraphQLString) + GraphQLArgument, + GraphQLBoolean, + GraphQLField, + GraphQLInt, + GraphQLList, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, +) from graphql.subscription import subscribe -EmailType = GraphQLObjectType('Email', { - 'from': GraphQLField(GraphQLString), - 'subject': GraphQLField(GraphQLString), - 'message': GraphQLField(GraphQLString), - 'unread': GraphQLField(GraphQLBoolean)}) - -InboxType = GraphQLObjectType('Inbox', { - 'total': GraphQLField( - GraphQLInt, resolve=lambda inbox, _info: len(inbox['emails'])), - 'unread': GraphQLField( - GraphQLInt, resolve=lambda inbox, _info: sum( - 1 for email in inbox['emails'] if email['unread'])), - 'emails': GraphQLField(GraphQLList(EmailType))}) - -QueryType = GraphQLObjectType('Query', {'inbox': GraphQLField(InboxType)}) - -EmailEventType = GraphQLObjectType('EmailEvent', { - 'email': GraphQLField(EmailType), - 'inbox': GraphQLField(InboxType)}) +EmailType = GraphQLObjectType( + "Email", + { + "from": GraphQLField(GraphQLString), + "subject": GraphQLField(GraphQLString), + "message": GraphQLField(GraphQLString), + "unread": GraphQLField(GraphQLBoolean), + }, +) + +InboxType = GraphQLObjectType( + "Inbox", + { + "total": GraphQLField( + GraphQLInt, resolve=lambda inbox, _info: len(inbox["emails"]) + ), + "unread": GraphQLField( + GraphQLInt, + resolve=lambda inbox, _info: sum( + 1 for email in inbox["emails"] if email["unread"] + ), + ), + "emails": GraphQLField(GraphQLList(EmailType)), + }, +) + +QueryType = GraphQLObjectType("Query", {"inbox": GraphQLField(InboxType)}) + +EmailEventType = GraphQLObjectType( + "EmailEvent", {"email": GraphQLField(EmailType), "inbox": GraphQLField(InboxType)} +) async def anext(iterable): @@ -36,41 +55,52 @@ async def anext(iterable): def email_schema_with_resolvers(subscribe_fn=None, resolve_fn=None): return GraphQLSchema( query=QueryType, - subscription=GraphQLObjectType('Subscription', { - 'importantEmail': GraphQLField( - EmailEventType, - args={'priority': GraphQLArgument(GraphQLInt)}, - resolve=resolve_fn, - subscribe=subscribe_fn)})) + subscription=GraphQLObjectType( + "Subscription", + { + "importantEmail": GraphQLField( + EmailEventType, + args={"priority": GraphQLArgument(GraphQLInt)}, + resolve=resolve_fn, + subscribe=subscribe_fn, + ) + }, + ), + ) email_schema = email_schema_with_resolvers() async def create_subscription( - pubsub, schema: GraphQLSchema=email_schema, ast=None, variables=None): + pubsub, schema: GraphQLSchema = email_schema, ast=None, variables=None +): data = { - 'inbox': { - 'emails': [{ - 'from': 'joe@graphql.org', - 'subject': 'Hello', - 'message': 'Hello World', - 'unread': False - }] + "inbox": { + "emails": [ + { + "from": "joe@graphql.org", + "subject": "Hello", + "message": "Hello World", + "unread": False, + } + ] }, - 'importantEmail': lambda _info, priority=None: - EventEmitterAsyncIterator(pubsub, 'importantEmail') + "importantEmail": lambda _info, priority=None: EventEmitterAsyncIterator( + pubsub, "importantEmail" + ), } def send_important_email(new_email): - data['inbox']['emails'].append(new_email) + data["inbox"]["emails"].append(new_email) # Returns true if the event was consumed by a subscriber. - return pubsub.emit('importantEmail', { - 'importantEmail': { - 'email': new_email, - 'inbox': data['inbox']}}) + return pubsub.emit( + "importantEmail", + {"importantEmail": {"email": new_email, "inbox": data["inbox"]}}, + ) - default_ast = parse(""" + default_ast = parse( + """ subscription ($priority: Int = 0) { importantEmail(priority: $priority) { email { @@ -83,49 +113,63 @@ def send_important_email(new_email): } } } - """) + """ + ) # `subscribe` yields AsyncIterator or ExecutionResult - return send_important_email, await subscribe( - schema, ast or default_ast, data, variable_values=variables) + return ( + send_important_email, + await subscribe(schema, ast or default_ast, data, variable_values=variables), + ) # Check all error cases when initializing the subscription. def describe_subscription_initialization_phase(): - @mark.asyncio async def accepts_an_object_with_named_properties_as_arguments(): - document = parse(""" + document = parse( + """ subscription { importantEmail } - """) + """ + ) async def empty_async_iterator(_info): for value in (): yield value await subscribe( - email_schema, document, {'importantEmail': empty_async_iterator}) + email_schema, document, {"importantEmail": empty_async_iterator} + ) @mark.asyncio async def accepts_multiple_subscription_fields_defined_in_schema(): pubsub = EventEmitter() - SubscriptionTypeMultiple = GraphQLObjectType('Subscription', { - 'importantEmail': GraphQLField(EmailEventType), - 'nonImportantEmail': GraphQLField(EmailEventType)}) + SubscriptionTypeMultiple = GraphQLObjectType( + "Subscription", + { + "importantEmail": GraphQLField(EmailEventType), + "nonImportantEmail": GraphQLField(EmailEventType), + }, + ) test_schema = GraphQLSchema( - query=QueryType, subscription=SubscriptionTypeMultiple) + query=QueryType, subscription=SubscriptionTypeMultiple + ) send_important_email, subscription = await create_subscription( - pubsub, test_schema) - - send_important_email({ - 'from': 'yuzhi@graphql.org', - 'subject': 'Alright', - 'message': 'Tests are good', - 'unread': True}) + pubsub, test_schema + ) + + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Alright", + "message": "Tests are good", + "unread": True, + } + ) await anext(subscription) @@ -134,23 +178,31 @@ async def accepts_type_definition_with_sync_subscribe_function(): pubsub = EventEmitter() def subscribe_email(_inbox, _info): - return EventEmitterAsyncIterator(pubsub, 'importantEmail') + return EventEmitterAsyncIterator(pubsub, "importantEmail") schema = GraphQLSchema( query=QueryType, - subscription=GraphQLObjectType('Subscription', { - 'importantEmail': GraphQLField( - GraphQLString, subscribe=subscribe_email)})) + subscription=GraphQLObjectType( + "Subscription", + { + "importantEmail": GraphQLField( + GraphQLString, subscribe=subscribe_email + ) + }, + ), + ) - ast = parse(""" + ast = parse( + """ subscription { importantEmail } - """) + """ + ) subscription = await subscribe(schema, ast) - pubsub.emit('importantEmail', {'importantEmail': {}}) + pubsub.emit("importantEmail", {"importantEmail": {}}) await anext(subscription) @@ -159,59 +211,76 @@ async def accepts_type_definition_with_async_subscribe_function(): pubsub = EventEmitter() async def subscribe_email(_inbox, _info): - return EventEmitterAsyncIterator(pubsub, 'importantEmail') + return EventEmitterAsyncIterator(pubsub, "importantEmail") schema = GraphQLSchema( query=QueryType, - subscription=GraphQLObjectType('Subscription', { - 'importantEmail': GraphQLField( - GraphQLString, subscribe=subscribe_email)})) + subscription=GraphQLObjectType( + "Subscription", + { + "importantEmail": GraphQLField( + GraphQLString, subscribe=subscribe_email + ) + }, + ), + ) - ast = parse(""" + ast = parse( + """ subscription { importantEmail } - """) + """ + ) subscription = await subscribe(schema, ast) - pubsub.emit('importantEmail', {'importantEmail': {}}) + pubsub.emit("importantEmail", {"importantEmail": {}}) await anext(subscription) @mark.asyncio async def should_only_resolve_the_first_field_of_invalid_multi_field(): - did_resolve = {'importantEmail': False, 'nonImportantEmail': False} + did_resolve = {"importantEmail": False, "nonImportantEmail": False} def subscribe_important(_inbox, _info): - did_resolve['importantEmail'] = True - return EventEmitterAsyncIterator(EventEmitter(), 'event') + did_resolve["importantEmail"] = True + return EventEmitterAsyncIterator(EventEmitter(), "event") def subscribe_non_important(_inbox, _info): - did_resolve['nonImportantEmail'] = True - return EventEmitterAsyncIterator(EventEmitter(), 'event') - - SubscriptionTypeMultiple = GraphQLObjectType('Subscription', { - 'importantEmail': GraphQLField( - EmailEventType, subscribe=subscribe_important), - 'nonImportantEmail': GraphQLField( - EmailEventType, subscribe=subscribe_non_important)}) + did_resolve["nonImportantEmail"] = True + return EventEmitterAsyncIterator(EventEmitter(), "event") + + SubscriptionTypeMultiple = GraphQLObjectType( + "Subscription", + { + "importantEmail": GraphQLField( + EmailEventType, subscribe=subscribe_important + ), + "nonImportantEmail": GraphQLField( + EmailEventType, subscribe=subscribe_non_important + ), + }, + ) test_schema = GraphQLSchema( - query=QueryType, subscription=SubscriptionTypeMultiple) + query=QueryType, subscription=SubscriptionTypeMultiple + ) - ast = parse(""" + ast = parse( + """ subscription { importantEmail nonImportantEmail } - """) + """ + ) subscription = await subscribe(test_schema, ast) ignored = anext(subscription) # Ask for a result, but ignore it. - assert did_resolve['importantEmail'] is True - assert did_resolve['nonImportantEmail'] is False + assert did_resolve["importantEmail"] is True + assert did_resolve["nonImportantEmail"] is False # Close subscription # noinspection PyUnresolvedReferences @@ -223,24 +292,26 @@ def subscribe_non_important(_inbox, _info): # noinspection PyArgumentList @mark.asyncio async def throws_an_error_if_schema_is_missing(): - document = parse(""" + document = parse( + """ subscription { importantEmail } - """) + """ + ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker await subscribe(None, document) - assert str(exc_info.value) == 'Expected None to be a GraphQL schema.' + assert str(exc_info.value) == "Expected None to be a GraphQL schema." with raises(TypeError) as exc_info: # noinspection PyTypeChecker await subscribe(document=document) msg = str(exc_info.value) - assert 'missing' in msg and "argument: 'schema'" in msg + assert "missing" in msg and "argument: 'schema'" in msg # noinspection PyArgumentList @mark.asyncio @@ -249,38 +320,52 @@ async def throws_an_error_if_document_is_missing(): # noinspection PyTypeChecker await subscribe(email_schema, None) - assert str(exc_info.value) == 'Must provide document' + assert str(exc_info.value) == "Must provide document" with raises(TypeError) as exc_info: # noinspection PyTypeChecker await subscribe(schema=email_schema) msg = str(exc_info.value) - assert 'missing' in msg and "argument: 'document'" in msg + assert "missing" in msg and "argument: 'document'" in msg @mark.asyncio async def resolves_to_an_error_for_unknown_subscription_field(): - ast = parse(""" + ast = parse( + """ subscription { unknownField } - """) + """ + ) pubsub = EventEmitter() subscription = (await create_subscription(pubsub, ast=ast))[1] - assert subscription == (None, [{ - 'message': "The subscription field 'unknownField' is not defined.", - 'locations': [(3, 15)]}]) + assert subscription == ( + None, + [ + { + "message": "The subscription field 'unknownField' is not defined.", + "locations": [(3, 15)], + } + ], + ) @mark.asyncio async def throws_an_error_if_subscribe_does_not_return_an_iterator(): invalid_email_schema = GraphQLSchema( query=QueryType, - subscription=GraphQLObjectType('Subscription', { - 'importantEmail': GraphQLField( - GraphQLString, subscribe=lambda _inbox, _info: 'test')})) + subscription=GraphQLObjectType( + "Subscription", + { + "importantEmail": GraphQLField( + GraphQLString, subscribe=lambda _inbox, _info: "test" + ) + }, + ), + ) pubsub = EventEmitter() @@ -288,54 +373,60 @@ async def throws_an_error_if_subscribe_does_not_return_an_iterator(): await create_subscription(pubsub, invalid_email_schema) assert str(exc_info.value) == ( - "Subscription field must return AsyncIterable. Received: 'test'") + "Subscription field must return AsyncIterable. Received: 'test'" + ) @mark.asyncio async def resolves_to_an_error_for_subscription_resolver_errors(): - async def test_reports_error(schema): result = await subscribe( schema, - parse(""" + parse( + """ subscription { importantEmail } - """)) - - assert result == (None, [{ - 'message': 'test error', - 'locations': [(3, 23)], 'path': ['importantEmail']}]) + """ + ), + ) + + assert result == ( + None, + [ + { + "message": "test error", + "locations": [(3, 23)], + "path": ["importantEmail"], + } + ], + ) # Returning an error def return_error(*args): - return TypeError('test error') + return TypeError("test error") - subscription_returning_error_schema = email_schema_with_resolvers( - return_error) + subscription_returning_error_schema = email_schema_with_resolvers(return_error) await test_reports_error(subscription_returning_error_schema) # Throwing an error def throw_error(*args): - raise TypeError('test error') + raise TypeError("test error") - subscription_throwing_error_schema = email_schema_with_resolvers( - throw_error) + subscription_throwing_error_schema = email_schema_with_resolvers(throw_error) await test_reports_error(subscription_throwing_error_schema) # Resolving to an error async def resolve_error(*args): - return TypeError('test error') + return TypeError("test error") - subscription_resolving_error_schema = email_schema_with_resolvers( - resolve_error) + subscription_resolving_error_schema = email_schema_with_resolvers(resolve_error) await test_reports_error(subscription_resolving_error_schema) # Rejecting with an error async def reject_error(*args): - return TypeError('test error') + return TypeError("test error") - subscription_rejecting_error_schema = email_schema_with_resolvers( - reject_error) + subscription_rejecting_error_schema = email_schema_with_resolvers(reject_error) await test_reports_error(subscription_rejecting_error_schema) @mark.asyncio @@ -343,7 +434,8 @@ async def resolves_to_an_error_if_variables_were_wrong_type(): # If we receive variables that cannot be coerced correctly, subscribe() # will resolve to an ExecutionResult that contains an informative error # description. - ast = parse(""" + ast = parse( + """ subscription ($priority: Int) { importantEmail(priority: $priority) { email { @@ -356,36 +448,46 @@ async def resolves_to_an_error_if_variables_were_wrong_type(): } } } - """) + """ + ) pubsub = EventEmitter() data = { - 'inbox': { - 'emails': [{ - 'from': 'joe@graphql.org', - 'subject': 'Hello', - 'message': 'Hello World', - 'unread': False - }] + "inbox": { + "emails": [ + { + "from": "joe@graphql.org", + "subject": "Hello", + "message": "Hello World", + "unread": False, + } + ] }, - 'importantEmail': lambda _info: EventEmitterAsyncIterator( - pubsub, 'importantEmail')} + "importantEmail": lambda _info: EventEmitterAsyncIterator( + pubsub, "importantEmail" + ), + } result = await subscribe( - email_schema, ast, data, variable_values={'priority': 'meow'}) - - assert result == (None, [{ - 'message': - "Variable '$priority' got invalid value 'meow'; Expected" - " type Int; Int cannot represent non-integer value: 'meow'", - 'locations': [(2, 27)]}]) + email_schema, ast, data, variable_values={"priority": "meow"} + ) + + assert result == ( + None, + [ + { + "message": "Variable '$priority' got invalid value 'meow'; Expected" + " type Int; Int cannot represent non-integer value: 'meow'", + "locations": [(2, 27)], + } + ], + ) assert result.errors[0].original_error is not None # Once a subscription returns a valid AsyncIterator, it can still yield errors. def describe_subscription_publish_phase(): - @mark.asyncio async def produces_a_payload_for_multiple_subscribe_in_same_subscription(): pubsub = EventEmitter() @@ -395,22 +497,22 @@ async def produces_a_payload_for_multiple_subscribe_in_same_subscription(): payload1 = anext(subscription) payload2 = anext(second[1]) - assert send_important_email({ - 'from': 'yuzhi@graphql.org', - 'subject': 'Alright', - 'message': 'Tests are good', - 'unread': True}) is True + assert ( + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Alright", + "message": "Tests are good", + "unread": True, + } + ) + is True + ) expected_payload = { - 'importantEmail': { - 'email': { - 'from': 'yuzhi@graphql.org', - 'subject': 'Alright' - }, - 'inbox': { - 'unread': 1, - 'total': 2 - }, + "importantEmail": { + "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, + "inbox": {"unread": 1, "total": 2}, } } @@ -426,57 +528,69 @@ async def produces_a_payload_per_subscription_event(): payload = anext(subscription) # A new email arrives! - assert send_important_email({ - 'from': 'yuzhi@graphql.org', - 'subject': 'Alright', - 'message': 'Tests are good', - 'unread': True}) is True + assert ( + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Alright", + "message": "Tests are good", + "unread": True, + } + ) + is True + ) # The previously waited on payload now has a value. - assert await payload == ({ - 'importantEmail': { - 'email': { - 'from': 'yuzhi@graphql.org', - 'subject': 'Alright' - }, - 'inbox': { - 'unread': 1, - 'total': 2 - }, - } - }, None) + assert await payload == ( + { + "importantEmail": { + "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, + "inbox": {"unread": 1, "total": 2}, + } + }, + None, + ) # Another new email arrives, before subscription.___anext__ is called. - assert send_important_email({ - 'from': 'hyo@graphql.org', - 'subject': 'Tools', - 'message': 'I <3 making things', - 'unread': True}) is True + assert ( + send_important_email( + { + "from": "hyo@graphql.org", + "subject": "Tools", + "message": "I <3 making things", + "unread": True, + } + ) + is True + ) # The next waited on payload will have a value. - assert await anext(subscription) == ({ - 'importantEmail': { - 'email': { - 'from': 'hyo@graphql.org', - 'subject': 'Tools' - }, - 'inbox': { - 'unread': 2, - 'total': 3 - }, - } - }, None) + assert await anext(subscription) == ( + { + "importantEmail": { + "email": {"from": "hyo@graphql.org", "subject": "Tools"}, + "inbox": {"unread": 2, "total": 3}, + } + }, + None, + ) # The client decides to disconnect. # noinspection PyUnresolvedReferences await subscription.aclose() # Which may result in disconnecting upstream services as well. - assert send_important_email({ - 'from': 'adam@graphql.org', - 'subject': 'Important', - 'message': 'Read me please', - 'unread': True}) is False # No more listeners. + assert ( + send_important_email( + { + "from": "adam@graphql.org", + "subject": "Important", + "message": "Read me please", + "unread": True, + } + ) + is False + ) # No more listeners. # Awaiting subscription after closing it results in completed results. with raises(StopAsyncIteration): @@ -490,63 +604,71 @@ async def event_order_is_correct_for_multiple_publishes(): payload = anext(subscription) # A new email arrives! - assert send_important_email({ - 'from': 'yuzhi@graphql.org', - 'subject': 'Message', - 'message': 'Tests are good', - 'unread': True}) is True + assert ( + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Message", + "message": "Tests are good", + "unread": True, + } + ) + is True + ) # A new email arrives! - assert send_important_email({ - 'from': 'yuzhi@graphql.org', - 'subject': 'Message 2', - 'message': 'Tests are good 2', - 'unread': True}) is True - - assert await payload == ({ - 'importantEmail': { - 'email': { - 'from': 'yuzhi@graphql.org', - 'subject': 'Message' - }, - 'inbox': { - 'unread': 2, - 'total': 3 - }, - } - }, None) + assert ( + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Message 2", + "message": "Tests are good 2", + "unread": True, + } + ) + is True + ) + + assert await payload == ( + { + "importantEmail": { + "email": {"from": "yuzhi@graphql.org", "subject": "Message"}, + "inbox": {"unread": 2, "total": 3}, + } + }, + None, + ) payload = subscription.__anext__() - assert await payload == ({ - 'importantEmail': { - 'email': { - 'from': 'yuzhi@graphql.org', - 'subject': 'Message 2' - }, - 'inbox': { - 'unread': 2, - 'total': 3 - }, - } - }, None) + assert await payload == ( + { + "importantEmail": { + "email": {"from": "yuzhi@graphql.org", "subject": "Message 2"}, + "inbox": {"unread": 2, "total": 3}, + } + }, + None, + ) @mark.asyncio async def should_handle_error_during_execution_of_source_event(): async def subscribe_fn(_event, _info): - yield {'email': {'subject': 'Hello'}} - yield {'email': {'subject': 'Goodbye'}} - yield {'email': {'subject': 'Bonjour'}} + yield {"email": {"subject": "Hello"}} + yield {"email": {"subject": "Goodbye"}} + yield {"email": {"subject": "Bonjour"}} def resolve_fn(event, _info): - if event['email']['subject'] == 'Goodbye': - raise RuntimeError('Never leave') + if event["email"]["subject"] == "Goodbye": + raise RuntimeError("Never leave") return event - erroring_email_schema = email_schema_with_resolvers( - subscribe_fn, resolve_fn) + erroring_email_schema = email_schema_with_resolvers(subscribe_fn, resolve_fn) - subscription = await subscribe(erroring_email_schema, parse(""" + subscription = await subscribe( + erroring_email_schema, + parse( + """ subscription { importantEmail { email { @@ -554,47 +676,46 @@ def resolve_fn(event, _info): } } } - """)) + """ + ), + ) payload1 = await anext(subscription) - assert payload1 == ({ - 'importantEmail': { - 'email': { - 'subject': 'Hello' - }, - }, - }, None) + assert payload1 == ({"importantEmail": {"email": {"subject": "Hello"}}}, None) # An error in execution is presented as such. payload2 = await anext(subscription) - assert payload2 == ({'importantEmail': None}, [{ - 'message': 'Never leave', - 'locations': [(3, 15)], 'path': ['importantEmail']}]) + assert payload2 == ( + {"importantEmail": None}, + [ + { + "message": "Never leave", + "locations": [(3, 15)], + "path": ["importantEmail"], + } + ], + ) # However that does not close the response event stream. Subsequent # events are still executed. payload3 = await anext(subscription) - assert payload3 == ({ - 'importantEmail': { - 'email': { - 'subject': 'Bonjour' - }, - }, - }, None) + assert payload3 == ({"importantEmail": {"email": {"subject": "Bonjour"}}}, None) @mark.asyncio async def should_pass_through_error_thrown_in_source_event_stream(): async def subscribe_fn(_event, _info): - yield {'email': {'subject': 'Hello'}} - raise RuntimeError('test error') + yield {"email": {"subject": "Hello"}} + raise RuntimeError("test error") def resolve_fn(event, _info): return event - erroring_email_schema = email_schema_with_resolvers( - subscribe_fn, resolve_fn) + erroring_email_schema = email_schema_with_resolvers(subscribe_fn, resolve_fn) - subscription = await subscribe(erroring_email_schema, parse(""" + subscription = await subscribe( + erroring_email_schema, + parse( + """ subscription { importantEmail { email { @@ -602,21 +723,17 @@ def resolve_fn(event, _info): } } } - """)) + """ + ), + ) payload1 = await anext(subscription) - assert payload1 == ({ - 'importantEmail': { - 'email': { - 'subject': 'Hello' - } - } - }, None) + assert payload1 == ({"importantEmail": {"email": {"subject": "Hello"}}}, None) with raises(RuntimeError) as exc_info: await anext(subscription) - assert str(exc_info.value) == 'test error' + assert str(exc_info.value) == "test error" with raises(StopAsyncIteration): await anext(subscription) diff --git a/tests/test_star_wars_introspection.py b/tests/test_star_wars_introspection.py index 24ec482c..eced2cfd 100644 --- a/tests/test_star_wars_introspection.py +++ b/tests/test_star_wars_introspection.py @@ -4,9 +4,7 @@ def describe_star_wars_introspection_tests(): - def describe_basic_introspection(): - def allows_querying_the_schema_for_types(): query = """ query IntrospectionTypeQuery { @@ -18,38 +16,24 @@ def allows_querying_the_schema_for_types(): } """ expected = { - '__schema': { - 'types': [{ - 'name': 'Query' - }, { - 'name': 'Episode' - }, { - 'name': 'Character' - }, { - 'name': 'String' - }, { - 'name': 'Human' - }, { - 'name': 'Droid' - }, { - 'name': '__Schema' - }, { - 'name': '__Type' - }, { - 'name': '__TypeKind' - }, { - 'name': 'Boolean' - }, { - 'name': '__Field' - }, { - 'name': '__InputValue' - }, { - 'name': '__EnumValue' - }, { - 'name': '__Directive' - }, { - 'name': '__DirectiveLocation' - }] + "__schema": { + "types": [ + {"name": "Query"}, + {"name": "Episode"}, + {"name": "Character"}, + {"name": "String"}, + {"name": "Human"}, + {"name": "Droid"}, + {"name": "__Schema"}, + {"name": "__Type"}, + {"name": "__TypeKind"}, + {"name": "Boolean"}, + {"name": "__Field"}, + {"name": "__InputValue"}, + {"name": "__EnumValue"}, + {"name": "__Directive"}, + {"name": "__DirectiveLocation"}, + ] } } @@ -66,13 +50,7 @@ def allows_querying_the_schema_for_query_type(): } } """ - expected = { - '__schema': { - 'queryType': { - 'name': 'Query' - } - } - } + expected = {"__schema": {"queryType": {"name": "Query"}}} result = graphql_sync(star_wars_schema, query) assert result == (expected, None) @@ -84,11 +62,7 @@ def allows_querying_the_schema_for_a_specific_type(): } } """ - expected = { - '__type': { - 'name': 'Droid' - } - } + expected = {"__type": {"name": "Droid"}} result = graphql_sync(star_wars_schema, query) assert result == (expected, None) @@ -101,12 +75,7 @@ def allows_querying_the_schema_for_an_object_kind(): } } """ - expected = { - '__type': { - 'name': 'Droid', - 'kind': 'OBJECT' - } - } + expected = {"__type": {"name": "Droid", "kind": "OBJECT"}} result = graphql_sync(star_wars_schema, query) assert result == (expected, None) @@ -119,12 +88,7 @@ def allows_querying_the_schema_for_an_interface_kind(): } } """ - expected = { - '__type': { - 'name': 'Character', - 'kind': 'INTERFACE' - } - } + expected = {"__type": {"name": "Character", "kind": "INTERFACE"}} result = graphql_sync(star_wars_schema, query) assert result == (expected, None) @@ -144,45 +108,22 @@ def allows_querying_the_schema_for_object_fields(): } """ expected = { - '__type': { - 'name': 'Droid', - 'fields': [{ - 'name': 'id', - 'type': { - 'name': None, - 'kind': 'NON_NULL' - } - }, { - 'name': 'name', - 'type': { - 'name': 'String', - 'kind': 'SCALAR' - } - }, { - 'name': 'friends', - 'type': { - 'name': None, - 'kind': 'LIST' - } - }, { - 'name': 'appearsIn', - 'type': { - 'name': None, - 'kind': 'LIST' - } - }, { - 'name': 'secretBackstory', - 'type': { - 'name': 'String', - 'kind': 'SCALAR' - } - }, { - 'name': 'primaryFunction', - 'type': { - 'name': 'String', - 'kind': 'SCALAR' - } - }] + "__type": { + "name": "Droid", + "fields": [ + {"name": "id", "type": {"name": None, "kind": "NON_NULL"}}, + {"name": "name", "type": {"name": "String", "kind": "SCALAR"}}, + {"name": "friends", "type": {"name": None, "kind": "LIST"}}, + {"name": "appearsIn", "type": {"name": None, "kind": "LIST"}}, + { + "name": "secretBackstory", + "type": {"name": "String", "kind": "SCALAR"}, + }, + { + "name": "primaryFunction", + "type": {"name": "String", "kind": "SCALAR"}, + }, + ], } } result = graphql_sync(star_wars_schema, query) @@ -208,60 +149,58 @@ def allows_querying_the_schema_for_nested_object_fields(): } """ expected = { - '__type': { - 'name': 'Droid', - 'fields': [{ - 'name': 'id', - 'type': { - 'name': None, - 'kind': 'NON_NULL', - 'ofType': { - 'name': 'String', - 'kind': 'SCALAR' - } - } - }, { - 'name': 'name', - 'type': { - 'name': 'String', - 'kind': 'SCALAR', - 'ofType': None - } - }, { - 'name': 'friends', - 'type': { - 'name': None, - 'kind': 'LIST', - 'ofType': { - 'name': 'Character', - 'kind': 'INTERFACE' - } - } - }, { - 'name': 'appearsIn', - 'type': { - 'name': None, - 'kind': 'LIST', - 'ofType': { - 'name': 'Episode', - 'kind': 'ENUM' - } - } - }, { - 'name': 'secretBackstory', - 'type': { - 'name': 'String', - 'kind': 'SCALAR', - 'ofType': None - } - }, { - 'name': 'primaryFunction', - 'type': { - 'name': 'String', - 'kind': 'SCALAR', - 'ofType': None - } - }] + "__type": { + "name": "Droid", + "fields": [ + { + "name": "id", + "type": { + "name": None, + "kind": "NON_NULL", + "ofType": {"name": "String", "kind": "SCALAR"}, + }, + }, + { + "name": "name", + "type": { + "name": "String", + "kind": "SCALAR", + "ofType": None, + }, + }, + { + "name": "friends", + "type": { + "name": None, + "kind": "LIST", + "ofType": {"name": "Character", "kind": "INTERFACE"}, + }, + }, + { + "name": "appearsIn", + "type": { + "name": None, + "kind": "LIST", + "ofType": {"name": "Episode", "kind": "ENUM"}, + }, + }, + { + "name": "secretBackstory", + "type": { + "name": "String", + "kind": "SCALAR", + "ofType": None, + }, + }, + { + "name": "primaryFunction", + "type": { + "name": "String", + "kind": "SCALAR", + "ofType": None, + }, + }, + ], } } result = graphql_sync(star_wars_schema, query) @@ -293,54 +232,63 @@ def allows_querying_the_schema_for_field_args(): } """ expected = { - '__schema': { - 'queryType': { - 'fields': [{ - 'name': 'hero', - 'args': [{ - 'defaultValue': None, - 'description': - 'If omitted, returns the hero of the whole' - ' saga. If provided, returns the hero of' - ' that particular episode.', - 'name': 'episode', - 'type': { - 'kind': 'ENUM', - 'name': 'Episode', - 'ofType': None - } - }] - }, { - 'name': 'human', - 'args': [{ - 'name': 'id', - 'description': 'id of the human', - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'String' + "__schema": { + "queryType": { + "fields": [ + { + "name": "hero", + "args": [ + { + "defaultValue": None, + "description": "If omitted, returns the hero of" + " the whole saga. If provided, returns the hero" + " of that particular episode.", + "name": "episode", + "type": { + "kind": "ENUM", + "name": "Episode", + "ofType": None, + }, + } + ], + }, + { + "name": "human", + "args": [ + { + "name": "id", + "description": "id of the human", + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "String", + }, + }, + "defaultValue": None, } - }, - 'defaultValue': None - }] - }, { - 'name': 'droid', - 'args': [{ - 'name': 'id', - 'description': 'id of the droid', - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'String' + ], + }, + { + "name": "droid", + "args": [ + { + "name": "id", + "description": "id of the droid", + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "String", + }, + }, + "defaultValue": None, } - }, - 'defaultValue': None - }] - }] + ], + }, + ] } } } @@ -357,10 +305,9 @@ def allows_querying_the_schema_for_documentation(): } """ expected = { - '__type': { - 'name': 'Droid', - 'description': - 'A mechanical creature in the Star Wars universe.' + "__type": { + "name": "Droid", + "description": "A mechanical creature in the Star Wars universe.", } } result = graphql_sync(star_wars_schema, query) diff --git a/tests/test_star_wars_query.py b/tests/test_star_wars_query.py index 4a3479ee..66cdc8d6 100644 --- a/tests/test_star_wars_query.py +++ b/tests/test_star_wars_query.py @@ -6,9 +6,7 @@ def describe_star_wars_query_tests(): - def describe_basic_queries(): - @mark.asyncio async def correctly_identifies_r2_d2_as_hero_of_the_star_wars_saga(): query = """ @@ -19,7 +17,7 @@ async def correctly_identifies_r2_d2_as_hero_of_the_star_wars_saga(): } """ result = await graphql(star_wars_schema, query) - assert result == ({'hero': {'name': 'R2-D2'}}, None) + assert result == ({"hero": {"name": "R2-D2"}}, None) @mark.asyncio async def accepts_an_object_with_named_properties_to_graphql(): @@ -31,7 +29,7 @@ async def accepts_an_object_with_named_properties_to_graphql(): } """ result = await graphql(schema=star_wars_schema, source=query) - assert result == ({'hero': {'name': 'R2-D2'}}, None) + assert result == ({"hero": {"name": "R2-D2"}}, None) @mark.asyncio async def allows_us_to_query_for_the_id_and_friends_of_r2_d2(): @@ -47,20 +45,22 @@ async def allows_us_to_query_for_the_id_and_friends_of_r2_d2(): } """ result = await graphql(star_wars_schema, query) - assert result == ({ - 'hero': { - 'id': '2001', - 'name': 'R2-D2', - 'friends': [ - {'name': 'Luke Skywalker'}, - {'name': 'Han Solo'}, - {'name': 'Leia Organa'}, - ] - } - }, None) + assert result == ( + { + "hero": { + "id": "2001", + "name": "R2-D2", + "friends": [ + {"name": "Luke Skywalker"}, + {"name": "Han Solo"}, + {"name": "Leia Organa"}, + ], + } + }, + None, + ) def describe_nested_queries(): - @mark.asyncio async def allows_us_to_query_for_the_friends_of_friends_of_r2_d2(): query = """ @@ -78,67 +78,47 @@ async def allows_us_to_query_for_the_friends_of_friends_of_r2_d2(): } """ result = await graphql(star_wars_schema, query) - assert result == ({ - 'hero': { - 'name': 'R2-D2', - 'friends': [ - { - 'name': 'Luke Skywalker', - 'appearsIn': ['NEWHOPE', 'EMPIRE', 'JEDI'], - 'friends': [ - { - 'name': 'Han Solo', - }, - { - 'name': 'Leia Organa', - }, - { - 'name': 'C-3PO', - }, - { - 'name': 'R2-D2', - }, - ] - }, - { - 'name': 'Han Solo', - 'appearsIn': ['NEWHOPE', 'EMPIRE', 'JEDI'], - 'friends': [ - { - 'name': 'Luke Skywalker', - }, - { - 'name': 'Leia Organa', - }, - { - 'name': 'R2-D2', - }, - ] - }, - { - 'name': 'Leia Organa', - 'appearsIn': ['NEWHOPE', 'EMPIRE', 'JEDI'], - 'friends': [ - { - 'name': 'Luke Skywalker', - }, - { - 'name': 'Han Solo', - }, - { - 'name': 'C-3PO', - }, - { - 'name': 'R2-D2', - }, - ] - }, - ] - } - }, None) + assert result == ( + { + "hero": { + "name": "R2-D2", + "friends": [ + { + "name": "Luke Skywalker", + "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], + "friends": [ + {"name": "Han Solo"}, + {"name": "Leia Organa"}, + {"name": "C-3PO"}, + {"name": "R2-D2"}, + ], + }, + { + "name": "Han Solo", + "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], + "friends": [ + {"name": "Luke Skywalker"}, + {"name": "Leia Organa"}, + {"name": "R2-D2"}, + ], + }, + { + "name": "Leia Organa", + "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], + "friends": [ + {"name": "Luke Skywalker"}, + {"name": "Han Solo"}, + {"name": "C-3PO"}, + {"name": "R2-D2"}, + ], + }, + ], + } + }, + None, + ) def describe_using_ids_and_query_parameters_to_refetch_objects(): - @mark.asyncio async def allows_us_to_query_for_r2_d2_directly_using_his_id(): query = """ @@ -149,7 +129,7 @@ async def allows_us_to_query_for_r2_d2_directly_using_his_id(): } """ result = await graphql(star_wars_schema, query) - assert result == ({'droid': {'name': 'R2-D2'}}, None) + assert result == ({"droid": {"name": "R2-D2"}}, None) @mark.asyncio async def allows_us_to_query_for_luke_directly_using_his_id(): @@ -161,7 +141,7 @@ async def allows_us_to_query_for_luke_directly_using_his_id(): } """ result = await graphql(star_wars_schema, query) - assert result == ({'human': {'name': 'Luke Skywalker'}}, None) + assert result == ({"human": {"name": "Luke Skywalker"}}, None) @mark.asyncio async def allows_creating_a_generic_query_to_fetch_luke_using_his_id(): @@ -172,10 +152,9 @@ async def allows_creating_a_generic_query_to_fetch_luke_using_his_id(): } } """ - params = {'someId': '1000'} - result = await graphql(star_wars_schema, query, - variable_values=params) - assert result == ({'human': {'name': 'Luke Skywalker'}}, None) + params = {"someId": "1000"} + result = await graphql(star_wars_schema, query, variable_values=params) + assert result == ({"human": {"name": "Luke Skywalker"}}, None) @mark.asyncio async def allows_creating_a_generic_query_to_fetch_han_using_his_id(): @@ -186,10 +165,9 @@ async def allows_creating_a_generic_query_to_fetch_han_using_his_id(): } } """ - params = {'someId': '1002'} - result = await graphql(star_wars_schema, query, - variable_values=params) - assert result == ({'human': {'name': 'Han Solo'}}, None) + params = {"someId": "1002"} + result = await graphql(star_wars_schema, query, variable_values=params) + assert result == ({"human": {"name": "Han Solo"}}, None) @mark.asyncio async def generic_query_that_gets_null_back_when_passed_invalid_id(): @@ -200,13 +178,11 @@ async def generic_query_that_gets_null_back_when_passed_invalid_id(): } } """ - params = {'id': 'not a valid id'} - result = await graphql(star_wars_schema, query, - variable_values=params) - assert result == ({'human': None}, None) + params = {"id": "not a valid id"} + result = await graphql(star_wars_schema, query, variable_values=params) + assert result == ({"human": None}, None) def describe_using_aliases_to_change_the_key_in_the_response(): - @mark.asyncio async def allows_us_to_query_for_luke_changing_his_key_with_an_alias(): query = """ @@ -217,7 +193,7 @@ async def allows_us_to_query_for_luke_changing_his_key_with_an_alias(): } """ result = await graphql(star_wars_schema, query) - assert result == ({'luke': {'name': 'Luke Skywalker'}}, None) + assert result == ({"luke": {"name": "Luke Skywalker"}}, None) @mark.asyncio async def query_for_luke_and_leia_using_two_root_fields_and_an_alias(): @@ -232,17 +208,12 @@ async def query_for_luke_and_leia_using_two_root_fields_and_an_alias(): } """ result = await graphql(star_wars_schema, query) - assert result == ({ - 'luke': { - 'name': 'Luke Skywalker', - }, - 'leia': { - 'name': 'Leia Organa', - } - }, None) + assert result == ( + {"luke": {"name": "Luke Skywalker"}, "leia": {"name": "Leia Organa"}}, + None, + ) def describe_uses_fragments_to_express_more_complex_queries(): - @mark.asyncio async def allows_us_to_query_using_duplicated_content(): query = """ @@ -258,16 +229,13 @@ async def allows_us_to_query_using_duplicated_content(): } """ result = await graphql(star_wars_schema, query) - assert result == ({ - 'luke': { - 'name': 'Luke Skywalker', - 'homePlanet': 'Tatooine', + assert result == ( + { + "luke": {"name": "Luke Skywalker", "homePlanet": "Tatooine"}, + "leia": {"name": "Leia Organa", "homePlanet": "Alderaan"}, }, - 'leia': { - 'name': 'Leia Organa', - 'homePlanet': 'Alderaan', - } - }, None) + None, + ) @mark.asyncio async def allows_us_to_use_a_fragment_to_avoid_duplicating_content(): @@ -286,19 +254,15 @@ async def allows_us_to_use_a_fragment_to_avoid_duplicating_content(): } """ result = await graphql(star_wars_schema, query) - assert result == ({ - 'luke': { - 'name': 'Luke Skywalker', - 'homePlanet': 'Tatooine', + assert result == ( + { + "luke": {"name": "Luke Skywalker", "homePlanet": "Tatooine"}, + "leia": {"name": "Leia Organa", "homePlanet": "Alderaan"}, }, - 'leia': { - 'name': 'Leia Organa', - 'homePlanet': 'Alderaan', - } - }, None) + None, + ) def describe_using_typename_to_find_the_type_of_an_object(): - @mark.asyncio async def allows_us_to_verify_that_r2_d2_is_a_droid(): query = """ @@ -310,12 +274,7 @@ async def allows_us_to_verify_that_r2_d2_is_a_droid(): } """ result = await graphql(star_wars_schema, query) - assert result == ({ - 'hero': { - '__typename': 'Droid', - 'name': 'R2-D2', - } - }, None) + assert result == ({"hero": {"__typename": "Droid", "name": "R2-D2"}}, None) @mark.asyncio async def allows_us_to_verify_that_luke_is_a_human(): @@ -328,15 +287,12 @@ async def allows_us_to_verify_that_luke_is_a_human(): } """ result = await graphql(star_wars_schema, query) - assert result == ({ - 'hero': { - '__typename': 'Human', - 'name': 'Luke Skywalker', - } - }, None) + assert result == ( + {"hero": {"__typename": "Human", "name": "Luke Skywalker"}}, + None, + ) def describe_reporting_errors_raised_in_resolvers(): - @mark.asyncio async def correctly_reports_error_on_accessing_secret_backstory(): query = """ @@ -348,15 +304,16 @@ async def correctly_reports_error_on_accessing_secret_backstory(): } """ result = await graphql(star_wars_schema, query) - assert result == ({ - 'hero': { - 'name': 'R2-D2', - 'secretBackstory': None - } - }, [{ - 'message': 'secretBackstory is secret.', - 'locations': [(5, 21)], 'path': ['hero', 'secretBackstory'] - }]) + assert result == ( + {"hero": {"name": "R2-D2", "secretBackstory": None}}, + [ + { + "message": "secretBackstory is secret.", + "locations": [(5, 21)], + "path": ["hero", "secretBackstory"], + } + ], + ) @mark.asyncio async def correctly_reports_error_on_accessing_backstory_in_a_list(): @@ -372,33 +329,35 @@ async def correctly_reports_error_on_accessing_backstory_in_a_list(): } """ result = await graphql(star_wars_schema, query) - assert result == ({ - 'hero': { - 'name': 'R2-D2', - 'friends': [{ - 'name': 'Luke Skywalker', - 'secretBackstory': None - }, { - 'name': 'Han Solo', - 'secretBackstory': None - }, { - 'name': 'Leia Organa', - 'secretBackstory': None - }], - } - }, [{ - 'message': 'secretBackstory is secret.', - 'locations': [(7, 23)], - 'path': ['hero', 'friends', 0, 'secretBackstory'] - }, { - 'message': 'secretBackstory is secret.', - 'locations': [(7, 23)], - 'path': ['hero', 'friends', 1, 'secretBackstory'] - }, { - 'message': 'secretBackstory is secret.', - 'locations': [(7, 23)], - 'path': ['hero', 'friends', 2, 'secretBackstory'] - }]) + assert result == ( + { + "hero": { + "name": "R2-D2", + "friends": [ + {"name": "Luke Skywalker", "secretBackstory": None}, + {"name": "Han Solo", "secretBackstory": None}, + {"name": "Leia Organa", "secretBackstory": None}, + ], + } + }, + [ + { + "message": "secretBackstory is secret.", + "locations": [(7, 23)], + "path": ["hero", "friends", 0, "secretBackstory"], + }, + { + "message": "secretBackstory is secret.", + "locations": [(7, 23)], + "path": ["hero", "friends", 1, "secretBackstory"], + }, + { + "message": "secretBackstory is secret.", + "locations": [(7, 23)], + "path": ["hero", "friends", 2, "secretBackstory"], + }, + ], + ) @mark.asyncio async def correctly_reports_error_on_accessing_through_an_alias(): @@ -411,12 +370,13 @@ async def correctly_reports_error_on_accessing_through_an_alias(): } """ result = await graphql(star_wars_schema, query) - assert result == ({ - 'mainHero': { - 'name': 'R2-D2', - 'story': None - } - }, [{ - 'message': 'secretBackstory is secret.', - 'locations': [(5, 21)], 'path': ['mainHero', 'story'] - }]) + assert result == ( + {"mainHero": {"name": "R2-D2", "story": None}}, + [ + { + "message": "secretBackstory is secret.", + "locations": [(5, 21)], + "path": ["mainHero", "story"], + } + ], + ) diff --git a/tests/test_star_wars_validation.py b/tests/test_star_wars_validation.py index 7c630151..5ec26f14 100644 --- a/tests/test_star_wars_validation.py +++ b/tests/test_star_wars_validation.py @@ -6,15 +6,13 @@ def validation_errors(query): """Helper function to test a query and the expected response.""" - source = Source(query, 'StarWars.graphql') + source = Source(query, "StarWars.graphql") ast = parse(source) return validate(star_wars_schema, ast) def describe_star_wars_validation_tests(): - def describe_basic_queries(): - def validates_a_complex_but_valid_query(): query = """ query NestedQueryWithFragment { diff --git a/tests/type/test_definition.py b/tests/type/test_definition.py index 5301b88b..9faede6e 100644 --- a/tests/type/test_definition.py +++ b/tests/type/test_definition.py @@ -4,156 +4,186 @@ from graphql.error import INVALID from graphql.type import ( - GraphQLArgument, GraphQLBoolean, GraphQLField, - GraphQLInt, GraphQLString, GraphQLObjectType, GraphQLList, - GraphQLScalarType, GraphQLInterfaceType, GraphQLUnionType, - GraphQLEnumType, GraphQLEnumValue, GraphQLInputObjectType, GraphQLSchema, - GraphQLOutputType, GraphQLInputField, GraphQLNonNull, 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), - }), - 'recentArticle': GraphQLField(BlogArticle)}) - - -BlogArticle = GraphQLObjectType('Article', lambda: { - 'id': GraphQLField(GraphQLString), - 'isPublished': GraphQLField(GraphQLBoolean), - 'author': GraphQLField(BlogAuthor), - 'title': GraphQLField(GraphQLString), - 'body': GraphQLField(GraphQLString)}) - - -BlogQuery = GraphQLObjectType('Query', { - 'article': GraphQLField( - BlogArticle, - args={ - 'id': GraphQLArgument(GraphQLString), - }), - 'feed': GraphQLField(GraphQLList(BlogArticle))}) - - -BlogMutation = GraphQLObjectType('Mutation', { - 'writeArticle': GraphQLField(BlogArticle)}) - - -BlogSubscription = GraphQLObjectType('Subscription', { - 'articleSubscribe': GraphQLField( - args={'id': GraphQLArgument(GraphQLString)}, - type_=BlogArticle - ) -}) - -ObjectType = GraphQLObjectType('Object', {}) -InterfaceType = GraphQLInterfaceType('Interface') -UnionType = GraphQLUnionType('Union', [ObjectType], resolve_type=lambda: None) -EnumType = GraphQLEnumType('Enum', {'foo': GraphQLEnumValue()}) -InputObjectType = GraphQLInputObjectType('InputObject', {}) + GraphQLArgument, + GraphQLBoolean, + GraphQLField, + GraphQLInt, + GraphQLString, + GraphQLObjectType, + GraphQLList, + GraphQLScalarType, + GraphQLInterfaceType, + GraphQLUnionType, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLInputObjectType, + GraphQLSchema, + GraphQLOutputType, + GraphQLInputField, + GraphQLNonNull, + 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), + }, + ), + "recentArticle": GraphQLField(BlogArticle), + }, +) + + +BlogArticle = GraphQLObjectType( + "Article", + lambda: { + "id": GraphQLField(GraphQLString), + "isPublished": GraphQLField(GraphQLBoolean), + "author": GraphQLField(BlogAuthor), + "title": GraphQLField(GraphQLString), + "body": GraphQLField(GraphQLString), + }, +) + + +BlogQuery = GraphQLObjectType( + "Query", + { + "article": GraphQLField( + BlogArticle, args={"id": GraphQLArgument(GraphQLString)} + ), + "feed": GraphQLField(GraphQLList(BlogArticle)), + }, +) + + +BlogMutation = GraphQLObjectType( + "Mutation", {"writeArticle": GraphQLField(BlogArticle)} +) + + +BlogSubscription = GraphQLObjectType( + "Subscription", + { + "articleSubscribe": GraphQLField( + args={"id": GraphQLArgument(GraphQLString)}, type_=BlogArticle + ) + }, +) + +ObjectType = GraphQLObjectType("Object", {}) +InterfaceType = GraphQLInterfaceType("Interface") +UnionType = GraphQLUnionType("Union", [ObjectType], resolve_type=lambda: None) +EnumType = GraphQLEnumType("Enum", {"foo": GraphQLEnumValue()}) +InputObjectType = GraphQLInputObjectType("InputObject", {}) ScalarType = GraphQLScalarType( - 'Scalar', serialize=lambda: None, - parse_value=lambda: None, parse_literal=lambda: None) + "Scalar", + serialize=lambda: None, + parse_value=lambda: None, + parse_literal=lambda: None, +) def schema_with_field_type(type_: GraphQLOutputType) -> GraphQLSchema: return GraphQLSchema( - query=GraphQLObjectType('Query', {'field': GraphQLField(type_)}), - types=[type_]) + query=GraphQLObjectType("Query", {"field": GraphQLField(type_)}), types=[type_] + ) def describe_type_system_example(): - def defines_a_query_only_schema(): BlogSchema = GraphQLSchema(BlogQuery) assert BlogSchema.query_type == BlogQuery - article_field = BlogQuery.fields['article'] + article_field = BlogQuery.fields["article"] assert article_field.type == BlogArticle - assert article_field.type.name == 'Article' + assert article_field.type.name == "Article" article_field_type = article_field.type assert isinstance(article_field_type, GraphQLObjectType) - title_field = article_field_type.fields['title'] + title_field = article_field_type.fields["title"] assert title_field.type == GraphQLString - assert title_field.type.name == 'String' + assert title_field.type.name == "String" - author_field = article_field_type.fields['author'] + author_field = article_field_type.fields["author"] author_field_type = author_field.type assert isinstance(author_field_type, GraphQLObjectType) - recent_article_field = author_field_type.fields['recentArticle'] + recent_article_field = author_field_type.fields["recentArticle"] assert recent_article_field.type == BlogArticle - feed_field = BlogQuery.fields['feed'] + feed_field = BlogQuery.fields["feed"] assert feed_field.type.of_type == BlogArticle def defines_a_mutation_schema(): - BlogSchema = GraphQLSchema( - query=BlogQuery, - mutation=BlogMutation) + BlogSchema = GraphQLSchema(query=BlogQuery, mutation=BlogMutation) assert BlogSchema.mutation_type == BlogMutation - write_mutation = BlogMutation.fields['writeArticle'] + write_mutation = BlogMutation.fields["writeArticle"] assert write_mutation.type == BlogArticle - assert write_mutation.type.name == 'Article' + assert write_mutation.type.name == "Article" def defines_a_subscription_schema(): - BlogSchema = GraphQLSchema( - query=BlogQuery, - subscription=BlogSubscription) + BlogSchema = GraphQLSchema(query=BlogQuery, subscription=BlogSubscription) assert BlogSchema.subscription_type == BlogSubscription - subscription = BlogSubscription.fields['articleSubscribe'] + subscription = BlogSubscription.fields["articleSubscribe"] assert subscription.type == BlogArticle - assert subscription.type.name == 'Article' + assert subscription.type.name == "Article" def defines_an_enum_type_with_deprecated_value(): EnumTypeWithDeprecatedValue = GraphQLEnumType( - name='EnumWithDeprecatedValue', - values={'foo': GraphQLEnumValue( - deprecation_reason='Just because')}) + name="EnumWithDeprecatedValue", + values={"foo": GraphQLEnumValue(deprecation_reason="Just because")}, + ) - deprecated_value = EnumTypeWithDeprecatedValue.values['foo'] - assert deprecated_value == GraphQLEnumValue( - deprecation_reason='Just because') + deprecated_value = EnumTypeWithDeprecatedValue.values["foo"] + assert deprecated_value == GraphQLEnumValue(deprecation_reason="Just because") assert deprecated_value.is_deprecated is True - assert deprecated_value.deprecation_reason == 'Just because' + assert deprecated_value.deprecation_reason == "Just because" assert deprecated_value.value is None assert deprecated_value.ast_node is None def defines_an_enum_type_with_a_value_of_none_and_invalid(): EnumTypeWithNullishValue = GraphQLEnumType( - name='EnumWithNullishValue', - values={'NULL': None, 'UNDEFINED': INVALID}) + name="EnumWithNullishValue", values={"NULL": None, "UNDEFINED": INVALID} + ) assert EnumTypeWithNullishValue.values == { - 'NULL': GraphQLEnumValue(), - 'UNDEFINED': GraphQLEnumValue(INVALID)} - null_value = EnumTypeWithNullishValue.values['NULL'] + "NULL": GraphQLEnumValue(), + "UNDEFINED": GraphQLEnumValue(INVALID), + } + null_value = EnumTypeWithNullishValue.values["NULL"] assert null_value.description is None assert null_value.is_deprecated is False assert null_value.deprecation_reason is None assert null_value.value is None assert null_value.ast_node is None - undefined_value = EnumTypeWithNullishValue.values['UNDEFINED'] + undefined_value = EnumTypeWithNullishValue.values["UNDEFINED"] assert undefined_value.description is None assert undefined_value.is_deprecated is False assert undefined_value.deprecation_reason is None @@ -161,71 +191,92 @@ def defines_an_enum_type_with_a_value_of_none_and_invalid(): assert undefined_value.ast_node is None def defines_an_object_type_with_deprecated_field(): - TypeWithDeprecatedField = GraphQLObjectType('foo', { - 'bar': GraphQLField(GraphQLString, - deprecation_reason='A terrible reason')}) - - deprecated_field = TypeWithDeprecatedField.fields['bar'] + TypeWithDeprecatedField = GraphQLObjectType( + "foo", + { + "bar": GraphQLField( + GraphQLString, deprecation_reason="A terrible reason" + ) + }, + ) + + deprecated_field = TypeWithDeprecatedField.fields["bar"] assert deprecated_field == GraphQLField( - GraphQLString, deprecation_reason='A terrible reason') + GraphQLString, deprecation_reason="A terrible reason" + ) assert deprecated_field.is_deprecated is True - assert deprecated_field.deprecation_reason == 'A terrible reason' + assert deprecated_field.deprecation_reason == "A terrible reason" assert deprecated_field.type is GraphQLString assert deprecated_field.args == {} def includes_nested_input_objects_in_the_map(): - NestedInputObject = GraphQLInputObjectType('NestedInputObject', { - 'value': GraphQLInputField(GraphQLString)}) - SomeInputObject = GraphQLInputObjectType('SomeInputObject', { - 'nested': GraphQLInputField(NestedInputObject)}) - SomeMutation = GraphQLObjectType('SomeMutation', { - 'mutateSomething': GraphQLField(BlogArticle, { - 'input': GraphQLArgument(SomeInputObject)})}) - SomeSubscription = GraphQLObjectType('SomeSubscription', { - 'subscribeToSomething': GraphQLField(BlogArticle, { - 'input': GraphQLArgument(SomeInputObject)})}) + NestedInputObject = GraphQLInputObjectType( + "NestedInputObject", {"value": GraphQLInputField(GraphQLString)} + ) + SomeInputObject = GraphQLInputObjectType( + "SomeInputObject", {"nested": GraphQLInputField(NestedInputObject)} + ) + SomeMutation = GraphQLObjectType( + "SomeMutation", + { + "mutateSomething": GraphQLField( + BlogArticle, {"input": GraphQLArgument(SomeInputObject)} + ) + }, + ) + SomeSubscription = GraphQLObjectType( + "SomeSubscription", + { + "subscribeToSomething": GraphQLField( + BlogArticle, {"input": GraphQLArgument(SomeInputObject)} + ) + }, + ) schema = GraphQLSchema( - query=BlogQuery, - mutation=SomeMutation, - subscription=SomeSubscription) - assert schema.type_map['NestedInputObject'] is NestedInputObject + query=BlogQuery, mutation=SomeMutation, subscription=SomeSubscription + ) + assert schema.type_map["NestedInputObject"] is NestedInputObject def includes_interface_possible_types_in_the_type_map(): - SomeInterface = GraphQLInterfaceType('SomeInterface', { - 'f': GraphQLField(GraphQLInt)}) - SomeSubtype = GraphQLObjectType('SomeSubtype', { - 'f': GraphQLField(GraphQLInt)}, - interfaces=[SomeInterface]) + SomeInterface = GraphQLInterfaceType( + "SomeInterface", {"f": GraphQLField(GraphQLInt)} + ) + SomeSubtype = GraphQLObjectType( + "SomeSubtype", {"f": GraphQLField(GraphQLInt)}, interfaces=[SomeInterface] + ) schema = GraphQLSchema( - query=GraphQLObjectType('Query', { - 'iface': GraphQLField(SomeInterface)}), - types=[SomeSubtype]) - assert schema.type_map['SomeSubtype'] is SomeSubtype + query=GraphQLObjectType("Query", {"iface": GraphQLField(SomeInterface)}), + types=[SomeSubtype], + ) + assert schema.type_map["SomeSubtype"] is SomeSubtype def includes_interfaces_thunk_subtypes_in_the_type_map(): - SomeInterface = GraphQLInterfaceType('SomeInterface', { - 'f': GraphQLField(GraphQLInt)}) - SomeSubtype = GraphQLObjectType('SomeSubtype', { - 'f': GraphQLField(GraphQLInt)}, - interfaces=lambda: [SomeInterface]) + SomeInterface = GraphQLInterfaceType( + "SomeInterface", {"f": GraphQLField(GraphQLInt)} + ) + SomeSubtype = GraphQLObjectType( + "SomeSubtype", + {"f": GraphQLField(GraphQLInt)}, + interfaces=lambda: [SomeInterface], + ) schema = GraphQLSchema( - query=GraphQLObjectType('Query', { - 'iface': GraphQLField(SomeInterface)}), - types=[SomeSubtype]) - assert schema.type_map['SomeSubtype'] is SomeSubtype + query=GraphQLObjectType("Query", {"iface": GraphQLField(SomeInterface)}), + types=[SomeSubtype], + ) + assert schema.type_map["SomeSubtype"] is SomeSubtype def stringifies_simple_types(): - assert str(GraphQLInt) == 'Int' - assert str(BlogArticle) == 'Article' - assert str(InterfaceType) == 'Interface' - assert str(UnionType) == 'Union' - assert str(EnumType) == 'Enum' - assert str(InputObjectType) == 'InputObject' - assert str(GraphQLNonNull(GraphQLInt)) == 'Int!' - assert str(GraphQLList(GraphQLInt)) == '[Int]' - assert str(GraphQLNonNull(GraphQLList(GraphQLInt))) == '[Int]!' - assert str(GraphQLList(GraphQLNonNull(GraphQLInt))) == '[Int!]' - assert str(GraphQLList(GraphQLList(GraphQLInt))) == '[[Int]]' + assert str(GraphQLInt) == "Int" + assert str(BlogArticle) == "Article" + assert str(InterfaceType) == "Interface" + assert str(UnionType) == "Union" + assert str(EnumType) == "Enum" + assert str(InputObjectType) == "InputObject" + assert str(GraphQLNonNull(GraphQLInt)) == "Int!" + assert str(GraphQLList(GraphQLInt)) == "[Int]" + assert str(GraphQLNonNull(GraphQLList(GraphQLInt))) == "[Int]!" + assert str(GraphQLList(GraphQLNonNull(GraphQLInt))) == "[Int!]" + assert str(GraphQLList(GraphQLList(GraphQLInt))) == "[[Int]]" def identifies_input_types(): expected = ( @@ -234,7 +285,8 @@ def identifies_input_types(): (InterfaceType, False), (UnionType, False), (EnumType, True), - (InputObjectType, True)) + (InputObjectType, True), + ) for type_, answer in expected: assert is_input_type(type_) is answer @@ -248,7 +300,8 @@ def identifies_output_types(): (InterfaceType, True), (UnionType, True), (EnumType, True), - (InputObjectType, False)) + (InputObjectType, False), + ) for type_, answer in expected: assert is_output_type(type_) is answer @@ -261,10 +314,11 @@ def prohibits_nesting_nonnull_inside_nonnull(): GraphQLNonNull(GraphQLNonNull(GraphQLInt)) msg = str(exc_info.value) assert msg == ( - 'Can only create NonNull of a Nullable GraphQLType but got: Int!.') + "Can only create NonNull of a Nullable GraphQLType but got: Int!." + ) def allows_a_thunk_for_union_member_types(): - union = GraphQLUnionType('ThunkUnion', lambda: [ObjectType]) + union = GraphQLUnionType("ThunkUnion", lambda: [ObjectType]) types = union.types assert len(types) == 1 @@ -272,129 +326,145 @@ def allows_a_thunk_for_union_member_types(): def does_not_mutate_passed_field_definitions(): fields = { - 'field1': GraphQLField(GraphQLString), - 'field2': GraphQLField(GraphQLString, args={ - 'id': GraphQLArgument(GraphQLString)})} + "field1": GraphQLField(GraphQLString), + "field2": GraphQLField( + GraphQLString, args={"id": GraphQLArgument(GraphQLString)} + ), + } - TestObject1 = GraphQLObjectType('Test1', fields) - TestObject2 = GraphQLObjectType('Test2', fields) + TestObject1 = GraphQLObjectType("Test1", fields) + TestObject2 = GraphQLObjectType("Test2", fields) assert TestObject1.fields == TestObject2.fields assert fields == { - 'field1': GraphQLField(GraphQLString), - 'field2': GraphQLField(GraphQLString, args={ - 'id': GraphQLArgument(GraphQLString)})} + "field1": GraphQLField(GraphQLString), + "field2": GraphQLField( + GraphQLString, args={"id": GraphQLArgument(GraphQLString)} + ), + } input_fields = { - 'field1': GraphQLInputField(GraphQLString), - 'field2': GraphQLInputField(GraphQLString)} + "field1": GraphQLInputField(GraphQLString), + "field2": GraphQLInputField(GraphQLString), + } - TestInputObject1 = GraphQLInputObjectType('Test1', input_fields) - TestInputObject2 = GraphQLInputObjectType('Test2', input_fields) + TestInputObject1 = GraphQLInputObjectType("Test1", input_fields) + TestInputObject2 = GraphQLInputObjectType("Test2", input_fields) assert TestInputObject1.fields == TestInputObject2.fields assert input_fields == { - 'field1': GraphQLInputField(GraphQLString), - 'field2': GraphQLInputField(GraphQLString)} + "field1": GraphQLInputField(GraphQLString), + "field2": GraphQLInputField(GraphQLString), + } def describe_field_config_must_be_a_dict(): - def accepts_an_object_type_with_a_field_function(): - obj_type = GraphQLObjectType('SomeObject', lambda: { - 'f': GraphQLField(GraphQLString)}) - assert obj_type.fields['f'].type is GraphQLString + obj_type = GraphQLObjectType( + "SomeObject", lambda: {"f": GraphQLField(GraphQLString)} + ) + assert obj_type.fields["f"].type is GraphQLString def thunk_for_fields_of_object_type_is_resolved_only_once(): def fields(): nonlocal calls calls += 1 - return {'f': GraphQLField(GraphQLString)} + return {"f": GraphQLField(GraphQLString)} + calls = 0 - obj_type = GraphQLObjectType('SomeObject', fields) - assert 'f' in obj_type.fields + obj_type = GraphQLObjectType("SomeObject", fields) + assert "f" in obj_type.fields assert calls == 1 - assert 'f' in obj_type.fields + assert "f" in obj_type.fields assert calls == 1 def rejects_an_object_type_field_with_undefined_config(): undefined_field = cast(GraphQLField, None) - obj_type = GraphQLObjectType('SomeObject', {'f': undefined_field}) + obj_type = GraphQLObjectType("SomeObject", {"f": undefined_field}) with raises(TypeError) as exc_info: if obj_type.fields: pass msg = str(exc_info.value) - assert msg == ( - 'SomeObject fields must be GraphQLField or output type objects.') + assert msg == ("SomeObject fields must be GraphQLField or output type objects.") def rejects_an_object_type_with_incorrectly_typed_fields(): invalid_field = cast(GraphQLField, [GraphQLField(GraphQLString)]) - obj_type = GraphQLObjectType('SomeObject', {'f': invalid_field}) + obj_type = GraphQLObjectType("SomeObject", {"f": invalid_field}) with raises(TypeError) as exc_info: if obj_type.fields: pass msg = str(exc_info.value) - assert msg == ( - 'SomeObject fields must be GraphQLField or output type objects.') + assert msg == ("SomeObject fields must be GraphQLField or output type objects.") def accepts_an_object_type_with_output_type_as_field(): # this is a shortcut syntax for simple fields - obj_type = GraphQLObjectType('SomeObject', {'f': GraphQLString}) - field = obj_type.fields['f'] + obj_type = GraphQLObjectType("SomeObject", {"f": GraphQLString}) + field = obj_type.fields["f"] assert isinstance(field, GraphQLField) assert field.type is GraphQLString def rejects_an_object_type_field_function_that_returns_incorrect_type(): - obj_type = GraphQLObjectType('SomeObject', - lambda: [GraphQLField(GraphQLString)]) + obj_type = GraphQLObjectType( + "SomeObject", lambda: [GraphQLField(GraphQLString)] + ) with raises(TypeError) as exc_info: if obj_type.fields: pass msg = str(exc_info.value) assert msg == ( - 'SomeObject fields must be a dict with field names as keys' - ' or a function which returns such an object.') + "SomeObject fields must be a dict with field names as keys" + " or a function which returns such an object." + ) def describe_field_args_must_be_a_dict(): - def accepts_an_object_type_with_field_args(): - obj_type = GraphQLObjectType('SomeObject', { - 'goodField': GraphQLField(GraphQLString, args={ - 'goodArg': GraphQLArgument(GraphQLString)})}) - assert 'goodArg' in obj_type.fields['goodField'].args + obj_type = GraphQLObjectType( + "SomeObject", + { + "goodField": GraphQLField( + GraphQLString, args={"goodArg": GraphQLArgument(GraphQLString)} + ) + }, + ) + assert "goodArg" in obj_type.fields["goodField"].args def rejects_an_object_type_with_incorrectly_typed_field_args(): - invalid_args = [{'bad_args': GraphQLArgument(GraphQLString)}] + invalid_args = [{"bad_args": GraphQLArgument(GraphQLString)}] invalid_args = cast(Dict[str, GraphQLArgument], invalid_args) with raises(TypeError) as exc_info: - GraphQLObjectType('SomeObject', { - 'badField': GraphQLField(GraphQLString, args=invalid_args)}) + GraphQLObjectType( + "SomeObject", + {"badField": GraphQLField(GraphQLString, args=invalid_args)}, + ) msg = str(exc_info.value) - assert msg == ( - 'Field args must be a dict with argument names as keys.') + assert msg == ("Field args must be a dict with argument names as keys.") def does_not_accept_is_deprecated_as_argument(): kwargs = dict(is_deprecated=True) with raises(TypeError) as exc_info: - GraphQLObjectType('OldObject', { - 'field': GraphQLField(GraphQLString, **kwargs)}) + GraphQLObjectType( + "OldObject", {"field": GraphQLField(GraphQLString, **kwargs)} + ) msg = str(exc_info.value) assert "got an unexpected keyword argument 'is_deprecated'" in msg def describe_object_interfaces_must_be_a_sequence(): - def accepts_an_object_type_with_list_interfaces(): obj_type = GraphQLObjectType( - 'SomeObject', interfaces=[InterfaceType], - fields={'f': GraphQLField(GraphQLString)}) + "SomeObject", + interfaces=[InterfaceType], + fields={"f": GraphQLField(GraphQLString)}, + ) assert obj_type.interfaces == [InterfaceType] def accepts_object_type_with_interfaces_as_a_function_returning_a_list(): obj_type = GraphQLObjectType( - 'SomeObject', interfaces=lambda: [InterfaceType], - fields={'f': GraphQLField(GraphQLString)}) + "SomeObject", + interfaces=lambda: [InterfaceType], + fields={"f": GraphQLField(GraphQLString)}, + ) assert obj_type.interfaces == [InterfaceType] def thunk_for_interfaces_of_object_type_is_resolved_only_once(): @@ -402,10 +472,13 @@ def interfaces(): nonlocal calls calls += 1 return [InterfaceType] + calls = 0 obj_type = GraphQLObjectType( - 'SomeObject', interfaces=interfaces, - fields={'f': GraphQLField(GraphQLString)}) + "SomeObject", + interfaces=interfaces, + fields={"f": GraphQLField(GraphQLString)}, + ) assert obj_type.interfaces == [InterfaceType] assert calls == 1 assert obj_type.interfaces == [InterfaceType] @@ -413,37 +486,43 @@ def interfaces(): def rejects_an_object_type_with_incorrectly_typed_interfaces(): obj_type = GraphQLObjectType( - 'SomeObject', interfaces={}, - fields={'f': GraphQLField(GraphQLString)}) + "SomeObject", interfaces={}, fields={"f": GraphQLField(GraphQLString)} + ) with raises(TypeError) as exc_info: if obj_type.interfaces: pass msg = str(exc_info.value) assert msg == ( - 'SomeObject interfaces must be a list/tuple' - ' or a function which returns a list/tuple.') + "SomeObject interfaces must be a list/tuple" + " or a function which returns a list/tuple." + ) def rejects_object_type_with_incorrectly_typed_interfaces_as_a_function(): obj_type = GraphQLObjectType( - 'SomeObject', interfaces=lambda: {}, - fields={'f': GraphQLField(GraphQLString)}) + "SomeObject", + interfaces=lambda: {}, + fields={"f": GraphQLField(GraphQLString)}, + ) with raises(TypeError) as exc_info: if obj_type.interfaces: pass msg = str(exc_info.value) assert msg == ( - 'SomeObject interfaces must be a list/tuple' - ' or a function which returns a list/tuple.') + "SomeObject interfaces must be a list/tuple" + " or a function which returns a list/tuple." + ) def describe_type_system_object_fields_must_have_valid_resolve_values(): - @fixture def schema_with_object_with_field_resolver(resolve_value): - BadResolverType = GraphQLObjectType('BadResolver', { - 'bad_field': GraphQLField(GraphQLString, resolve=resolve_value)}) - return GraphQLSchema(GraphQLObjectType('Query', { - 'f': GraphQLField(BadResolverType)})) + BadResolverType = GraphQLObjectType( + "BadResolver", + {"bad_field": GraphQLField(GraphQLString, resolve=resolve_value)}, + ) + return GraphQLSchema( + GraphQLObjectType("Query", {"f": GraphQLField(BadResolverType)}) + ) def accepts_a_lambda_as_an_object_field_resolver(): schema_with_object_with_field_resolver(lambda _obj, _info: {}) @@ -452,270 +531,298 @@ def rejects_an_empty_object_field_resolver(): with raises(TypeError) as exc_info: schema_with_object_with_field_resolver({}) msg = str(exc_info.value) - assert msg == ( - 'Field resolver must be a function if provided, but got: {}.') + assert msg == ("Field resolver must be a function if provided, but got: {}.") def rejects_a_constant_scalar_value_resolver(): with raises(TypeError) as exc_info: schema_with_object_with_field_resolver(0) msg = str(exc_info.value) - assert msg == ( - 'Field resolver must be a function if provided, but got: 0.') + assert msg == ("Field resolver must be a function if provided, but got: 0.") def describe_type_system_interface_types_must_be_resolvable(): - def accepts_an_interface_type_defining_resolve_type(): - AnotherInterfaceType = GraphQLInterfaceType('AnotherInterface', { - 'f': GraphQLField(GraphQLString)}) + AnotherInterfaceType = GraphQLInterfaceType( + "AnotherInterface", {"f": GraphQLField(GraphQLString)} + ) - schema = schema_with_field_type(GraphQLObjectType('SomeObject', { - 'f': GraphQLField(GraphQLString)}, [AnotherInterfaceType])) + schema = schema_with_field_type( + GraphQLObjectType( + "SomeObject", {"f": GraphQLField(GraphQLString)}, [AnotherInterfaceType] + ) + ) - assert schema.query_type.fields[ - 'field'].type.interfaces[0] is AnotherInterfaceType + assert ( + schema.query_type.fields["field"].type.interfaces[0] is AnotherInterfaceType + ) def rejects_an_interface_type_with_an_incorrect_type_for_resolve_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker - GraphQLInterfaceType('AnotherInterface', { - 'f': GraphQLField(GraphQLString)}, resolve_type={}) + GraphQLInterfaceType( + "AnotherInterface", {"f": GraphQLField(GraphQLString)}, resolve_type={} + ) msg = str(exc_info.value) assert msg == ( "AnotherInterface must provide 'resolve_type' as a function," - ' but got: {}.') + " but got: {}." + ) def describe_type_system_union_types_must_be_resolvable(): - ObjectWithIsTypeOf = GraphQLObjectType('ObjectWithIsTypeOf', { - 'f': GraphQLField(GraphQLString)}) + ObjectWithIsTypeOf = GraphQLObjectType( + "ObjectWithIsTypeOf", {"f": GraphQLField(GraphQLString)} + ) def accepts_a_union_type_defining_resolve_type(): - schema_with_field_type(GraphQLUnionType('SomeUnion', [ObjectType])) + schema_with_field_type(GraphQLUnionType("SomeUnion", [ObjectType])) def accepts_a_union_of_object_types_defining_is_type_of(): - schema_with_field_type(GraphQLUnionType( - 'SomeUnion', [ObjectWithIsTypeOf])) + schema_with_field_type(GraphQLUnionType("SomeUnion", [ObjectWithIsTypeOf])) def rejects_an_interface_type_with_an_incorrect_type_for_resolve_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker - schema_with_field_type(GraphQLUnionType( - 'SomeUnion', [ObjectWithIsTypeOf], resolve_type={})) + schema_with_field_type( + GraphQLUnionType("SomeUnion", [ObjectWithIsTypeOf], resolve_type={}) + ) msg = str(exc_info.value) assert msg == ( - "SomeUnion must provide 'resolve_type' as a function," - ' but got: {}.') + "SomeUnion must provide 'resolve_type' as a function," " but got: {}." + ) def describe_type_system_scalar_types_must_be_serializable(): - def accepts_a_scalar_type_defining_serialize(): - schema_with_field_type(GraphQLScalarType('SomeScalar', lambda: None)) + schema_with_field_type(GraphQLScalarType("SomeScalar", lambda: None)) def rejects_a_scalar_type_not_defining_serialize(): with raises(TypeError) as exc_info: # noinspection PyArgumentList - schema_with_field_type(GraphQLScalarType('SomeScalar')) + schema_with_field_type(GraphQLScalarType("SomeScalar")) msg = str(exc_info.value) assert "missing 1 required positional argument: 'serialize'" in msg with raises(TypeError) as exc_info: # noinspection PyTypeChecker - schema_with_field_type(GraphQLScalarType('SomeScalar', None)) + schema_with_field_type(GraphQLScalarType("SomeScalar", None)) msg = str(exc_info.value) assert msg == ( "SomeScalar must provide 'serialize' function." - ' If this custom Scalar is also used as an input type,' + " If this custom Scalar is also used as an input type," " ensure 'parse_value' and 'parse_literal' functions" - ' are also provided.') + " are also provided." + ) def rejects_a_scalar_type_defining_serialize_with_incorrect_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker - schema_with_field_type(GraphQLScalarType('SomeScalar', {})) + schema_with_field_type(GraphQLScalarType("SomeScalar", {})) msg = str(exc_info.value) assert msg == ( "SomeScalar must provide 'serialize' function." - ' If this custom Scalar is also used as an input type,' + " If this custom Scalar is also used as an input type," " ensure 'parse_value' and 'parse_literal' functions" - ' are also provided.') + " are also provided." + ) def accepts_a_scalar_type_defining_parse_value_and_parse_literal(): - schema_with_field_type(GraphQLScalarType( - 'SomeScalar', serialize=lambda: None, - parse_value=lambda: None, parse_literal=lambda: None)) + schema_with_field_type( + GraphQLScalarType( + "SomeScalar", + serialize=lambda: None, + parse_value=lambda: None, + parse_literal=lambda: None, + ) + ) def rejects_a_scalar_type_defining_parse_value_but_not_parse_literal(): with raises(TypeError) as exc_info: - schema_with_field_type(GraphQLScalarType( - 'SomeScalar', lambda: None, parse_value=lambda: None)) + schema_with_field_type( + GraphQLScalarType("SomeScalar", lambda: None, parse_value=lambda: None) + ) msg = str(exc_info.value) - assert msg == ('SomeScalar must provide both' - " 'parse_value' and 'parse_literal' functions.") + assert msg == ( + "SomeScalar must provide both" + " 'parse_value' and 'parse_literal' functions." + ) def rejects_a_scalar_type_defining_parse_literal_but_not_parse_value(): with raises(TypeError) as exc_info: - schema_with_field_type(GraphQLScalarType( - 'SomeScalar', lambda: None, parse_literal=lambda: None)) + schema_with_field_type( + GraphQLScalarType( + "SomeScalar", lambda: None, parse_literal=lambda: None + ) + ) msg = str(exc_info.value) - assert msg == ('SomeScalar must provide both' - " 'parse_value' and 'parse_literal' functions.") + assert msg == ( + "SomeScalar must provide both" + " 'parse_value' and 'parse_literal' functions." + ) def rejects_a_scalar_type_incorrectly_defining_parse_literal_and_value(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker - schema_with_field_type(GraphQLScalarType( - 'SomeScalar', lambda: None, parse_value={}, parse_literal={})) + schema_with_field_type( + GraphQLScalarType( + "SomeScalar", lambda: None, parse_value={}, parse_literal={} + ) + ) msg = str(exc_info.value) - assert msg == ('SomeScalar must provide both' - " 'parse_value' and 'parse_literal' functions.") + assert msg == ( + "SomeScalar must provide both" + " 'parse_value' and 'parse_literal' functions." + ) def describe_type_system_object_types_must_be_assertable(): - def accepts_an_object_type_with_an_is_type_of_function(): - schema_with_field_type(GraphQLObjectType('AnotherObject', { - 'f': GraphQLField(GraphQLString)})) + schema_with_field_type( + GraphQLObjectType("AnotherObject", {"f": GraphQLField(GraphQLString)}) + ) def rejects_an_object_type_with_an_incorrect_type_for_is_type_of(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker - schema_with_field_type(GraphQLObjectType('AnotherObject', { - 'f': GraphQLField(GraphQLString)}, is_type_of={})) + schema_with_field_type( + GraphQLObjectType( + "AnotherObject", {"f": GraphQLField(GraphQLString)}, is_type_of={} + ) + ) msg = str(exc_info.value) assert msg == ( - "AnotherObject must provide 'is_type_of' as a function," - ' but got: {}.') + "AnotherObject must provide 'is_type_of' as a function," " but got: {}." + ) def describe_union_types_must_be_list(): - def accepts_a_union_type_with_list_types(): - schema_with_field_type(GraphQLUnionType('SomeUnion', [ObjectType])) + schema_with_field_type(GraphQLUnionType("SomeUnion", [ObjectType])) def accepts_a_union_type_with_function_returning_a_list_of_types(): - schema_with_field_type(GraphQLUnionType( - 'SomeUnion', lambda: [ObjectType])) + schema_with_field_type(GraphQLUnionType("SomeUnion", lambda: [ObjectType])) def rejects_a_union_type_without_types(): with raises(TypeError) as exc_info: # noinspection PyArgumentList - schema_with_field_type(GraphQLUnionType('SomeUnion')) + schema_with_field_type(GraphQLUnionType("SomeUnion")) msg = str(exc_info.value) assert "missing 1 required positional argument: 'types'" in msg - schema_with_field_type(GraphQLUnionType('SomeUnion', None)) + schema_with_field_type(GraphQLUnionType("SomeUnion", None)) def rejects_a_union_type_with_incorrectly_typed_types(): with raises(TypeError) as exc_info: - schema_with_field_type(GraphQLUnionType( - 'SomeUnion', {'type': ObjectType})) + schema_with_field_type(GraphQLUnionType("SomeUnion", {"type": ObjectType})) msg = str(exc_info.value) assert msg == ( - 'SomeUnion types must be a list/tuple' - ' or a function which returns a list/tuple.') + "SomeUnion types must be a list/tuple" + " or a function which returns a list/tuple." + ) def describe_type_system_input_objects_must_have_fields(): - def accepts_an_input_object_type_with_fields(): - input_obj_type = GraphQLInputObjectType('SomeInputObject', { - 'f': GraphQLInputField(GraphQLString)}) - assert input_obj_type.fields['f'].type is GraphQLString + input_obj_type = GraphQLInputObjectType( + "SomeInputObject", {"f": GraphQLInputField(GraphQLString)} + ) + assert input_obj_type.fields["f"].type is GraphQLString def accepts_an_input_object_type_with_a_field_function(): - input_obj_type = GraphQLInputObjectType('SomeInputObject', lambda: { - 'f': GraphQLInputField(GraphQLString)}) - assert input_obj_type.fields['f'].type is GraphQLString + input_obj_type = GraphQLInputObjectType( + "SomeInputObject", lambda: {"f": GraphQLInputField(GraphQLString)} + ) + assert input_obj_type.fields["f"].type is GraphQLString def rejects_an_input_object_type_with_incorrect_fields(): - input_obj_type = GraphQLInputObjectType('SomeInputObject', []) + input_obj_type = GraphQLInputObjectType("SomeInputObject", []) with raises(TypeError) as exc_info: if input_obj_type.fields: pass msg = str(exc_info.value) assert msg == ( - 'SomeInputObject fields must be a dict with field names as keys' - ' or a function which returns such an object.') + "SomeInputObject fields must be a dict with field names as keys" + " or a function which returns such an object." + ) def accepts_an_input_object_type_with_input_type_as_field(): # this is a shortcut syntax for simple input fields - input_obj_type = GraphQLInputObjectType('SomeInputObject', { - 'f': GraphQLString}) - field = input_obj_type.fields['f'] + input_obj_type = GraphQLInputObjectType("SomeInputObject", {"f": GraphQLString}) + field = input_obj_type.fields["f"] assert isinstance(field, GraphQLInputField) assert field.type is GraphQLString def rejects_an_input_object_type_with_incorrect_fields_function(): - input_obj_type = GraphQLInputObjectType('SomeInputObject', lambda: []) + input_obj_type = GraphQLInputObjectType("SomeInputObject", lambda: []) with raises(TypeError) as exc_info: if input_obj_type.fields: pass msg = str(exc_info.value) assert msg == ( - 'SomeInputObject fields must be a dict with field names as keys' - ' or a function which returns such an object.') + "SomeInputObject fields must be a dict with field names as keys" + " or a function which returns such an object." + ) def describe_type_system_input_objects_fields_must_not_have_resolvers(): - def rejects_an_input_object_type_with_resolvers(): with raises(TypeError) as exc_info: # noinspection PyArgumentList - GraphQLInputObjectType('SomeInputObject', { - 'f': GraphQLInputField(GraphQLString, resolve=lambda: 0)}) + GraphQLInputObjectType( + "SomeInputObject", + {"f": GraphQLInputField(GraphQLString, resolve=lambda: 0)}, + ) msg = str(exc_info.value) assert "got an unexpected keyword argument 'resolve'" in msg - input_obj_type = GraphQLInputObjectType('SomeInputObject', { - 'f': GraphQLField(GraphQLString, resolve=lambda: 0)}) + input_obj_type = GraphQLInputObjectType( + "SomeInputObject", {"f": GraphQLField(GraphQLString, resolve=lambda: 0)} + ) with raises(TypeError) as exc_info: if input_obj_type.fields: pass msg = str(exc_info.value) assert msg == ( - 'SomeInputObject fields must be GraphQLInputField' - ' or input type objects.') + "SomeInputObject fields must be GraphQLInputField" " or input type objects." + ) def rejects_an_input_object_type_with_resolver_constant(): with raises(TypeError) as exc_info: # noinspection PyArgumentList - GraphQLInputObjectType('SomeInputObject', { - 'f': GraphQLInputField(GraphQLString, resolve={})}) + GraphQLInputObjectType( + "SomeInputObject", {"f": GraphQLInputField(GraphQLString, resolve={})} + ) msg = str(exc_info.value) assert "got an unexpected keyword argument 'resolve'" in msg def describe_type_system_enum_types_must_be_well_defined(): - def accepts_a_well_defined_enum_type_with_empty_value_definition(): - enum_type = GraphQLEnumType('SomeEnum', {'FOO': None, 'BAR': None}) - assert enum_type.values['FOO'].value is None - assert enum_type.values['BAR'].value is None + enum_type = GraphQLEnumType("SomeEnum", {"FOO": None, "BAR": None}) + assert enum_type.values["FOO"].value is None + assert enum_type.values["BAR"].value is None def accepts_a_well_defined_enum_type_with_internal_value_definition(): - enum_type = GraphQLEnumType('SomeEnum', {'FOO': 10, 'BAR': 20}) - assert enum_type.values['FOO'].value == 10 - assert enum_type.values['BAR'].value == 20 - enum_type = GraphQLEnumType('SomeEnum', { - 'FOO': GraphQLEnumValue(10), - 'BAR': GraphQLEnumValue(20)}) - assert enum_type.values['FOO'].value == 10 - assert enum_type.values['BAR'].value == 20 + enum_type = GraphQLEnumType("SomeEnum", {"FOO": 10, "BAR": 20}) + assert enum_type.values["FOO"].value == 10 + assert enum_type.values["BAR"].value == 20 + enum_type = GraphQLEnumType( + "SomeEnum", {"FOO": GraphQLEnumValue(10), "BAR": GraphQLEnumValue(20)} + ) + assert enum_type.values["FOO"].value == 10 + assert enum_type.values["BAR"].value == 20 def rejects_an_enum_type_with_incorrectly_typed_values(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker - GraphQLEnumType('SomeEnum', [{'FOO': 10}]) # type: ignore + GraphQLEnumType("SomeEnum", [{"FOO": 10}]) # type: ignore msg = str(exc_info.value) assert msg == ( - 'SomeEnum values must be an Enum' - ' or a dict with value names as keys.') + "SomeEnum values must be an Enum" " or a dict with value names as keys." + ) def does_not_allow_is_deprecated(): with raises(TypeError) as exc_info: # noinspection PyArgumentList - GraphQLEnumType('SomeEnum', { - 'FOO': GraphQLEnumValue(is_deprecated=True)}) + GraphQLEnumType("SomeEnum", {"FOO": GraphQLEnumValue(is_deprecated=True)}) msg = str(exc_info.value) assert "got an unexpected keyword argument 'is_deprecated'" in msg @@ -723,99 +830,125 @@ def does_not_allow_is_deprecated(): def describe_type_system_list_must_accept_only_types(): types = [ - GraphQLString, ScalarType, ObjectType, - UnionType, InterfaceType, EnumType, InputObjectType, - GraphQLList(GraphQLString), GraphQLNonNull(GraphQLString)] + GraphQLString, + ScalarType, + ObjectType, + UnionType, + InterfaceType, + EnumType, + InputObjectType, + GraphQLList(GraphQLString), + GraphQLNonNull(GraphQLString), + ] not_types = [{}, dict, str, object, None] - @mark.parametrize('type_', types) + @mark.parametrize("type_", types) def accepts_a_type_as_item_type_of_list(type_): assert GraphQLList(type_) - @mark.parametrize('type_', not_types) + @mark.parametrize("type_", not_types) def rejects_a_non_type_as_item_type_of_list(type_): with raises(TypeError) as exc_info: assert GraphQLList(type_) msg = str(exc_info.value) assert msg == ( - 'Can only create a wrapper for a GraphQLType,' - f' but got: {type_}.') + "Can only create a wrapper for a GraphQLType," f" but got: {type_}." + ) def describe_type_system_non_null_must_only_accept_non_nullable_types(): nullable_types = [ - GraphQLString, ScalarType, ObjectType, - UnionType, InterfaceType, EnumType, InputObjectType, - GraphQLList(GraphQLString), GraphQLList(GraphQLNonNull(GraphQLString))] - - not_nullable_types = [ - GraphQLNonNull(GraphQLString), {}, dict, str, object, None] - - @mark.parametrize('type_', nullable_types) + GraphQLString, + ScalarType, + ObjectType, + UnionType, + InterfaceType, + EnumType, + InputObjectType, + GraphQLList(GraphQLString), + GraphQLList(GraphQLNonNull(GraphQLString)), + ] + + not_nullable_types = [GraphQLNonNull(GraphQLString), {}, dict, str, object, None] + + @mark.parametrize("type_", nullable_types) def accepts_a_type_as_nullable_type_of_non_null(type_): assert GraphQLNonNull(type_) - @mark.parametrize('type_', not_nullable_types) + @mark.parametrize("type_", not_nullable_types) def rejects_a_non_type_as_nullable_type_of_non_null(type_): with raises(TypeError) as exc_info: assert GraphQLNonNull(type_) msg = str(exc_info.value) - assert msg == ( - 'Can only create NonNull of a Nullable GraphQLType' - f' but got: {type_}.') if isinstance(type_, GraphQLNonNull) else ( - 'Can only create a wrapper for a GraphQLType,' - f' but got: {type_}.') + assert ( + msg + == ( + "Can only create NonNull of a Nullable GraphQLType" + f" but got: {type_}." + ) + if isinstance(type_, GraphQLNonNull) + else ("Can only create a wrapper for a GraphQLType," f" but got: {type_}.") + ) def describe_type_system_a_schema_must_contain_uniquely_named_types(): - def rejects_a_schema_which_redefines_a_built_in_type(): - FakeString = GraphQLScalarType('String', serialize=lambda: None) + FakeString = GraphQLScalarType("String", serialize=lambda: None) - QueryType = GraphQLObjectType('Query', { - 'normal': GraphQLField(GraphQLString), - 'fake': GraphQLField(FakeString)}) + QueryType = GraphQLObjectType( + "Query", + {"normal": GraphQLField(GraphQLString), "fake": GraphQLField(FakeString)}, + ) with raises(TypeError) as exc_info: GraphQLSchema(QueryType) msg = str(exc_info.value) assert msg == ( - 'Schema must contain unique named types' - f" but contains multiple types named 'String'.") + "Schema must contain unique named types" + f" but contains multiple types named 'String'." + ) def rejects_a_schema_which_defines_an_object_twice(): - A = GraphQLObjectType('SameName', {'f': GraphQLField(GraphQLString)}) - B = GraphQLObjectType('SameName', {'f': GraphQLField(GraphQLString)}) + A = GraphQLObjectType("SameName", {"f": GraphQLField(GraphQLString)}) + B = GraphQLObjectType("SameName", {"f": GraphQLField(GraphQLString)}) - QueryType = GraphQLObjectType('Query', {'a': A, 'b': B}) + QueryType = GraphQLObjectType("Query", {"a": A, "b": B}) with raises(TypeError) as exc_info: GraphQLSchema(QueryType) msg = str(exc_info.value) assert msg == ( - 'Schema must contain unique named types' - f" but contains multiple types named 'SameName'.") + "Schema must contain unique named types" + f" but contains multiple types named 'SameName'." + ) def rejects_a_schema_with_same_named_objects_implementing_an_interface(): - AnotherInterface = GraphQLInterfaceType('AnotherInterface', { - 'f': GraphQLField(GraphQLString)}) + AnotherInterface = GraphQLInterfaceType( + "AnotherInterface", {"f": GraphQLField(GraphQLString)} + ) FirstBadObject = GraphQLObjectType( - 'BadObject', {'f': GraphQLField(GraphQLString)}, - interfaces=[AnotherInterface]) + "BadObject", + {"f": GraphQLField(GraphQLString)}, + interfaces=[AnotherInterface], + ) SecondBadObject = GraphQLObjectType( - 'BadObject', {'f': GraphQLField(GraphQLString)}, - interfaces=[AnotherInterface]) + "BadObject", + {"f": GraphQLField(GraphQLString)}, + interfaces=[AnotherInterface], + ) - QueryType = GraphQLObjectType('Query', { - 'iface': GraphQLField(AnotherInterface)}) + QueryType = GraphQLObjectType( + "Query", {"iface": GraphQLField(AnotherInterface)} + ) with raises(TypeError) as exc_info: GraphQLSchema(QueryType, types=[FirstBadObject, SecondBadObject]) msg = str(exc_info.value) assert msg == ( - 'Schema must contain unique named types' - f" but contains multiple types named 'BadObject'.") + "Schema must contain unique named types" + f" but contains multiple types named 'BadObject'." + ) diff --git a/tests/type/test_directives.py b/tests/type/test_directives.py index 37f0dc00..6452798e 100644 --- a/tests/type/test_directives.py +++ b/tests/type/test_directives.py @@ -2,49 +2,57 @@ from graphql.language import DirectiveLocation, DirectiveDefinitionNode, Node from graphql.type import ( - GraphQLArgument, GraphQLDirective, GraphQLString, GraphQLSkipDirective, - is_directive, is_specified_directive) + GraphQLArgument, + GraphQLDirective, + GraphQLString, + GraphQLSkipDirective, + is_directive, + is_specified_directive, +) def describe_graphql_directive(): - def can_create_instance(): - arg = GraphQLArgument(GraphQLString, description='arg description') + arg = GraphQLArgument(GraphQLString, description="arg description") node = DirectiveDefinitionNode() locations = [DirectiveLocation.SCHEMA, DirectiveLocation.OBJECT] directive = GraphQLDirective( - name='test', + name="test", locations=[DirectiveLocation.SCHEMA, DirectiveLocation.OBJECT], - args={'arg': arg}, - description='test description', - ast_node=node) - assert directive.name == 'test' + args={"arg": arg}, + description="test description", + ast_node=node, + ) + assert directive.name == "test" assert directive.locations == locations - assert directive.args == {'arg': arg} - assert directive.description == 'test description' + assert directive.args == {"arg": arg} + assert directive.description == "test description" assert directive.ast_node is node def has_str(): - directive = GraphQLDirective('test', []) - assert str(directive) == '@test' + directive = GraphQLDirective("test", []) + assert str(directive) == "@test" def has_repr(): - directive = GraphQLDirective('test', []) - assert repr(directive) == '' + directive = GraphQLDirective("test", []) + assert repr(directive) == "" def accepts_strings_as_locations(): # noinspection PyTypeChecker directive = GraphQLDirective( - name='test', locations=['SCHEMA', 'OBJECT']) # type: ignore + name="test", locations=["SCHEMA", "OBJECT"] + ) # type: ignore assert directive.locations == [ - DirectiveLocation.SCHEMA, DirectiveLocation.OBJECT] + DirectiveLocation.SCHEMA, + DirectiveLocation.OBJECT, + ] def accepts_input_types_as_arguments(): # noinspection PyTypeChecker directive = GraphQLDirective( - name='test', locations=[], - args={'arg': GraphQLString}) # type: ignore - arg = directive.args['arg'] + name="test", locations=[], args={"arg": GraphQLString} + ) # type: ignore + arg = directive.args["arg"] assert isinstance(arg, GraphQLArgument) assert arg.type is GraphQLString @@ -52,69 +60,69 @@ def does_not_accept_a_bad_name(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective(None, locations=[]) # type: ignore - assert str(exc_info.value) == 'Directive must be named.' + assert str(exc_info.value) == "Directive must be named." with raises(TypeError) as exc_info: # noinspection PyTypeChecker - GraphQLDirective({'bad': True}, locations=[]) # type: ignore - assert str(exc_info.value) == 'The directive name must be a string.' + GraphQLDirective({"bad": True}, locations=[]) # type: ignore + assert str(exc_info.value) == "The directive name must be a string." def does_not_accept_bad_locations(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker - GraphQLDirective('test', locations='bad') # type: ignore - assert str(exc_info.value) == 'test locations must be a list/tuple.' + GraphQLDirective("test", locations="bad") # type: ignore + assert str(exc_info.value) == "test locations must be a list/tuple." with raises(TypeError) as exc_info: # noinspection PyTypeChecker - GraphQLDirective('test', locations=['bad']) # type: ignore + GraphQLDirective("test", locations=["bad"]) # type: ignore assert str(exc_info.value) == ( - 'test locations must be DirectiveLocation objects.') + "test locations must be DirectiveLocation objects." + ) def does_not_accept_bad_args(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker - GraphQLDirective( - 'test', locations=[], args=['arg']) # type: ignore + GraphQLDirective("test", locations=[], args=["arg"]) # type: ignore assert str(exc_info.value) == ( - 'test args must be a dict with argument names as keys.') + "test args must be a dict with argument names as keys." + ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective( - 'test', locations=[], - args={1: GraphQLArgument(GraphQLString)}) # type: ignore + "test", locations=[], args={1: GraphQLArgument(GraphQLString)} + ) # type: ignore assert str(exc_info.value) == ( - 'test args must be a dict with argument names as keys.') + "test args must be a dict with argument names as keys." + ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective( - 'test', locations=[], - args={'arg': GraphQLDirective('test', [])}) # type: ignore + "test", locations=[], args={"arg": GraphQLDirective("test", [])} + ) # type: ignore assert str(exc_info.value) == ( - 'test args must be GraphQLArgument or input type objects.') + "test args must be GraphQLArgument or input type objects." + ) def does_not_accept_a_bad_description(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective( - 'test', locations=[], - description={'bad': True}) # type: ignore - assert str(exc_info.value) == 'test description must be a string.' + "test", locations=[], description={"bad": True} + ) # type: ignore + assert str(exc_info.value) == "test description must be a string." def does_not_accept_a_bad_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker - GraphQLDirective( - 'test', locations=[], - ast_node=Node()) # type: ignore + GraphQLDirective("test", locations=[], ast_node=Node()) # type: ignore assert str(exc_info.value) == ( - 'test AST node must be a DirectiveDefinitionNode.') + "test AST node must be a DirectiveDefinitionNode." + ) def describe_directive_predicates(): - def describe_is_directive(): - def returns_true_for_directive(): - directive = GraphQLDirective('test', []) + directive = GraphQLDirective("test", []) assert is_directive(directive) is True def returns_false_for_type_class_rather_than_instance(): @@ -125,13 +133,12 @@ def returns_false_for_other_instances(): def returns_false_for_random_garbage(): assert is_directive(None) is False - assert is_directive({'what': 'is this'}) is False + assert is_directive({"what": "is this"}) is False def describe_is_specified_directive(): - def returns_true_for_specified_directive(): assert is_specified_directive(GraphQLSkipDirective) is True def returns_false_for_unspecified_directive(): - directive = GraphQLDirective('test', []) + directive = GraphQLDirective("test", []) assert is_specified_directive(directive) is False diff --git a/tests/type/test_enum.py b/tests/type/test_enum.py index 8b930773..1b8ffac2 100644 --- a/tests/type/test_enum.py +++ b/tests/type/test_enum.py @@ -2,14 +2,18 @@ from graphql import graphql_sync from graphql.type import ( - GraphQLArgument, GraphQLBoolean, GraphQLEnumType, GraphQLField, - GraphQLInt, GraphQLObjectType, GraphQLSchema, GraphQLString) + GraphQLArgument, + GraphQLBoolean, + GraphQLEnumType, + GraphQLField, + GraphQLInt, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, +) from graphql.utilities import introspection_from_schema -ColorType = GraphQLEnumType('Color', values={ - 'RED': 0, - 'GREEN': 1, - 'BLUE': 2}) +ColorType = GraphQLEnumType("Color", values={"RED": 0, "GREEN": 1, "BLUE": 2}) class ColorTypeEnumValues(Enum): @@ -28,58 +32,84 @@ class Complex2: some_random_value = 123 def __repr__(self): - return 'Complex2' + return "Complex2" complex1 = Complex1() complex2 = Complex2() -ComplexEnum = GraphQLEnumType('Complex', { - 'ONE': complex1, - 'TWO': complex2}) - -ColorType2 = GraphQLEnumType('Color', ColorTypeEnumValues) - -QueryType = GraphQLObjectType('Query', { - 'colorEnum': GraphQLField(ColorType, args={ - 'fromEnum': GraphQLArgument(ColorType), - 'fromInt': GraphQLArgument(GraphQLInt), - 'fromString': GraphQLArgument(GraphQLString)}, - resolve=lambda value, info, **args: - args.get('fromInt') or - args.get('fromString') or args.get('fromEnum')), - 'colorInt': GraphQLField(GraphQLInt, args={ - 'fromEnum': GraphQLArgument(ColorType), - 'fromInt': GraphQLArgument(GraphQLInt)}, - resolve=lambda value, info, **args: - args.get('fromInt') or args.get('fromEnum')), - 'complexEnum': GraphQLField(ComplexEnum, args={ - # Note: default_value is provided an *internal* representation for - # Enums, rather than the string name. - 'fromEnum': GraphQLArgument(ComplexEnum, default_value=complex1), - 'provideGoodValue': GraphQLArgument(GraphQLBoolean), - 'provideBadValue': GraphQLArgument(GraphQLBoolean)}, - resolve=lambda value, info, **args: +ComplexEnum = GraphQLEnumType("Complex", {"ONE": complex1, "TWO": complex2}) + +ColorType2 = GraphQLEnumType("Color", ColorTypeEnumValues) + +QueryType = GraphQLObjectType( + "Query", + { + "colorEnum": GraphQLField( + ColorType, + args={ + "fromEnum": GraphQLArgument(ColorType), + "fromInt": GraphQLArgument(GraphQLInt), + "fromString": GraphQLArgument(GraphQLString), + }, + resolve=lambda value, info, **args: args.get("fromInt") + or args.get("fromString") + or args.get("fromEnum"), + ), + "colorInt": GraphQLField( + GraphQLInt, + args={ + "fromEnum": GraphQLArgument(ColorType), + "fromInt": GraphQLArgument(GraphQLInt), + }, + resolve=lambda value, info, **args: args.get("fromInt") + or args.get("fromEnum"), + ), + "complexEnum": GraphQLField( + ComplexEnum, + args={ + # Note: default_value is provided an *internal* representation for + # Enums, rather than the string name. + "fromEnum": GraphQLArgument(ComplexEnum, default_value=complex1), + "provideGoodValue": GraphQLArgument(GraphQLBoolean), + "provideBadValue": GraphQLArgument(GraphQLBoolean), + }, + resolve=lambda value, info, **args: # Note: this is one of the references of the internal values # which ComplexEnum allows. - complex2 if args.get('provideGoodValue') + complex2 if args.get("provideGoodValue") # Note: similar object, but not the same *reference* as # complex2 above. Enum internal values require object equality. - else Complex2() if args.get('provideBadValue') - else args.get('fromEnum'))}) - -MutationType = GraphQLObjectType('Mutation', { - 'favoriteEnum': GraphQLField(ColorType, args={ - 'color': GraphQLArgument(ColorType)}, - resolve=lambda value, info, color=None: color)}) - -SubscriptionType = GraphQLObjectType('Subscription', { - 'subscribeToEnum': GraphQLField(ColorType, args={ - 'color': GraphQLArgument(ColorType)}, - resolve=lambda value, info, color=None: color)}) + else Complex2() if args.get("provideBadValue") else args.get("fromEnum"), + ), + }, +) + +MutationType = GraphQLObjectType( + "Mutation", + { + "favoriteEnum": GraphQLField( + ColorType, + args={"color": GraphQLArgument(ColorType)}, + resolve=lambda value, info, color=None: color, + ) + }, +) + +SubscriptionType = GraphQLObjectType( + "Subscription", + { + "subscribeToEnum": GraphQLField( + ColorType, + args={"color": GraphQLArgument(ColorType)}, + resolve=lambda value, info, color=None: color, + ) + }, +) schema = GraphQLSchema( - query=QueryType, mutation=MutationType, subscription=SubscriptionType) + query=QueryType, mutation=MutationType, subscription=SubscriptionType +) def execute_query(source, variable_values=None): @@ -87,7 +117,6 @@ def execute_query(source, variable_values=None): def describe_type_system_enum_values(): - def can_use_python_enums_instead_of_dicts(): assert ColorType2.values == ColorType.values keys = [key for key in ColorType.values] @@ -98,154 +127,209 @@ def can_use_python_enums_instead_of_dicts(): assert values2 == values def accepts_enum_literals_as_input(): - result = execute_query('{ colorInt(fromEnum: GREEN) }') + result = execute_query("{ colorInt(fromEnum: GREEN) }") - assert result == ({'colorInt': 1}, None) + assert result == ({"colorInt": 1}, None) def enum_may_be_output_type(): - result = execute_query('{ colorEnum(fromInt: 1) }') + result = execute_query("{ colorEnum(fromInt: 1) }") - assert result == ({'colorEnum': 'GREEN'}, None) + assert result == ({"colorEnum": "GREEN"}, None) def enum_may_be_both_input_and_output_type(): - result = execute_query('{ colorEnum(fromEnum: GREEN) }') + result = execute_query("{ colorEnum(fromEnum: GREEN) }") - assert result == ({'colorEnum': 'GREEN'}, None) + assert result == ({"colorEnum": "GREEN"}, None) def does_not_accept_string_literals(): result = execute_query('{ colorEnum(fromEnum: "GREEN") }') - assert result == (None, [{ - 'message': 'Expected type Color, found "GREEN";' - ' Did you mean the enum value GREEN?', - 'locations': [(1, 23)]}]) + assert result == ( + None, + [ + { + "message": 'Expected type Color, found "GREEN";' + " Did you mean the enum value GREEN?", + "locations": [(1, 23)], + } + ], + ) def does_not_accept_values_not_in_the_enum(): - result = execute_query('{ colorEnum(fromEnum: GREENISH) }') - - assert result == (None, [{ - 'message': 'Expected type Color, found GREENISH;' - ' Did you mean the enum value GREEN?', - 'locations': [(1, 23)]}]) + result = execute_query("{ colorEnum(fromEnum: GREENISH) }") + + assert result == ( + None, + [ + { + "message": "Expected type Color, found GREENISH;" + " Did you mean the enum value GREEN?", + "locations": [(1, 23)], + } + ], + ) def does_not_accept_values_with_incorrect_casing(): - result = execute_query('{ colorEnum(fromEnum: green) }') - - assert result == (None, [{ - 'message': 'Expected type Color, found green;' - ' Did you mean the enum value GREEN?', - 'locations': [(1, 23)]}]) + result = execute_query("{ colorEnum(fromEnum: green) }") + + assert result == ( + None, + [ + { + "message": "Expected type Color, found green;" + " Did you mean the enum value GREEN?", + "locations": [(1, 23)], + } + ], + ) def does_not_accept_incorrect_internal_value(): result = execute_query('{ colorEnum(fromString: "GREEN") }') - assert result == ({'colorEnum': None}, [{ - 'message': "Expected a value of type 'Color'" - " but received: 'GREEN'", - 'locations': [(1, 3)], 'path': ['colorEnum']}]) + assert result == ( + {"colorEnum": None}, + [ + { + "message": "Expected a value of type 'Color'" + " but received: 'GREEN'", + "locations": [(1, 3)], + "path": ["colorEnum"], + } + ], + ) def does_not_accept_internal_value_in_place_of_enum_literal(): - result = execute_query('{ colorEnum(fromEnum: 1) }') + result = execute_query("{ colorEnum(fromEnum: 1) }") - assert result == (None, [{ - 'message': "Expected type Color, found 1.", - 'locations': [(1, 23)]}]) + assert result == ( + None, + [{"message": "Expected type Color, found 1.", "locations": [(1, 23)]}], + ) def does_not_accept_internal_value_in_place_of_int(): - result = execute_query('{ colorEnum(fromInt: GREEN) }') + result = execute_query("{ colorEnum(fromInt: GREEN) }") - assert result == (None, [{ - 'message': "Expected type Int, found GREEN.", - 'locations': [(1, 22)]}]) + assert result == ( + None, + [{"message": "Expected type Int, found GREEN.", "locations": [(1, 22)]}], + ) def accepts_json_string_as_enum_variable(): - doc = 'query ($color: Color!) { colorEnum(fromEnum: $color) }' - result = execute_query(doc, {'color': 'BLUE'}) + doc = "query ($color: Color!) { colorEnum(fromEnum: $color) }" + result = execute_query(doc, {"color": "BLUE"}) - assert result == ({'colorEnum': 'BLUE'}, None) + assert result == ({"colorEnum": "BLUE"}, None) def accepts_enum_literals_as_input_arguments_to_mutations(): - doc = 'mutation ($color: Color!) { favoriteEnum(color: $color) }' - result = execute_query(doc, {'color': 'GREEN'}) + doc = "mutation ($color: Color!) { favoriteEnum(color: $color) }" + result = execute_query(doc, {"color": "GREEN"}) - assert result == ({'favoriteEnum': 'GREEN'}, None) + assert result == ({"favoriteEnum": "GREEN"}, None) def accepts_enum_literals_as_input_arguments_to_subscriptions(): - doc = ('subscription ($color: Color!) {' - ' subscribeToEnum(color: $color) }') - result = execute_query(doc, {'color': 'GREEN'}) + doc = "subscription ($color: Color!) {" " subscribeToEnum(color: $color) }" + result = execute_query(doc, {"color": "GREEN"}) - assert result == ({'subscribeToEnum': 'GREEN'}, None) + assert result == ({"subscribeToEnum": "GREEN"}, None) def does_not_accept_internal_value_as_enum_variable(): - doc = 'query ($color: Color!) { colorEnum(fromEnum: $color) }' - result = execute_query(doc, {'color': 2}) - - assert result == (None, [{ - 'message': "Variable '$color' got invalid value 2;" - ' Expected type Color.', - 'locations': [(1, 8)]}]) + doc = "query ($color: Color!) { colorEnum(fromEnum: $color) }" + result = execute_query(doc, {"color": 2}) + + assert result == ( + None, + [ + { + "message": "Variable '$color' got invalid value 2;" + " Expected type Color.", + "locations": [(1, 8)], + } + ], + ) def does_not_accept_string_variables_as_enum_input(): - doc = 'query ($color: String!) { colorEnum(fromEnum: $color) }' - result = execute_query(doc, {'color': 'BLUE'}) - - assert result == (None, [{ - 'message': "Variable '$color' of type 'String!'" - " used in position expecting type 'Color'.", - 'locations': [(1, 8), (1, 47)]}]) + doc = "query ($color: String!) { colorEnum(fromEnum: $color) }" + result = execute_query(doc, {"color": "BLUE"}) + + assert result == ( + None, + [ + { + "message": "Variable '$color' of type 'String!'" + " used in position expecting type 'Color'.", + "locations": [(1, 8), (1, 47)], + } + ], + ) def does_not_accept_internal_value_variable_as_enum_input(): - doc = 'query ($color: Int!) { colorEnum(fromEnum: $color) }' - result = execute_query(doc, {'color': 2}) - - assert result == (None, [{ - 'message': "Variable '$color' of type 'Int!'" - " used in position expecting type 'Color'.", - 'locations': [(1, 8), (1, 44)]}]) + doc = "query ($color: Int!) { colorEnum(fromEnum: $color) }" + result = execute_query(doc, {"color": 2}) + + assert result == ( + None, + [ + { + "message": "Variable '$color' of type 'Int!'" + " used in position expecting type 'Color'.", + "locations": [(1, 8), (1, 44)], + } + ], + ) def enum_value_may_have_an_internal_value_of_0(): - result = execute_query(""" + result = execute_query( + """ { colorEnum(fromEnum: RED) colorInt(fromEnum: RED) } - """) + """ + ) - assert result == ({'colorEnum': 'RED', 'colorInt': 0}, None) + assert result == ({"colorEnum": "RED", "colorInt": 0}, None) def enum_inputs_may_be_nullable(): - result = execute_query(""" + result = execute_query( + """ { colorEnum colorInt } - """) + """ + ) - assert result == ({'colorEnum': None, 'colorInt': None}, None) + assert result == ({"colorEnum": None, "colorInt": None}, None) def presents_a_values_property_for_complex_enums(): values = ComplexEnum.values assert len(values) == 2 assert isinstance(values, dict) - assert values['ONE'].value is complex1 - assert values['TWO'].value is complex2 + assert values["ONE"].value is complex1 + assert values["TWO"].value is complex2 def may_be_internally_represented_with_complex_values(): - result = execute_query(""" + result = execute_query( + """ { first: complexEnum second: complexEnum(fromEnum: TWO) good: complexEnum(provideGoodValue: true) bad: complexEnum(provideBadValue: true) } - """) - - assert result == ({ - 'first': 'ONE', 'second': 'TWO', 'good': 'TWO', 'bad': None}, - [{'message': - "Expected a value of type 'Complex' but received: Complex2", - 'locations': [(6, 15)], 'path': ['bad']}]) + """ + ) + + assert result == ( + {"first": "ONE", "second": "TWO", "good": "TWO", "bad": None}, + [ + { + "message": "Expected a value of type 'Complex' but received: Complex2", # noqa + "locations": [(6, 15)], + "path": ["bad"], + } + ], + ) def can_be_introspected_without_error(): introspection_from_schema(schema) diff --git a/tests/type/test_introspection.py b/tests/type/test_introspection.py index 4af9a930..89ca6181 100644 --- a/tests/type/test_introspection.py +++ b/tests/type/test_introspection.py @@ -1,773 +1,882 @@ from graphql import graphql_sync from graphql.type import ( - GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, - GraphQLInputField, GraphQLInputObjectType, GraphQLList, - GraphQLObjectType, GraphQLSchema, GraphQLString) + GraphQLArgument, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLList, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, +) from graphql.utilities import get_introspection_query from graphql.validation.rules.provided_required_arguments import ( - missing_field_arg_message) + missing_field_arg_message +) def describe_introspection(): - def executes_an_introspection_query(): - EmptySchema = GraphQLSchema(GraphQLObjectType('QueryRoot', { - 'onlyField': GraphQLField(GraphQLString)})) + EmptySchema = GraphQLSchema( + GraphQLObjectType("QueryRoot", {"onlyField": GraphQLField(GraphQLString)}) + ) query = get_introspection_query(descriptions=False) result = graphql_sync(EmptySchema, query) assert result.errors is None assert result.data == { - '__schema': { - 'mutationType': None, - 'subscriptionType': None, - 'queryType': { - 'name': 'QueryRoot' - }, - 'types': [{ - 'kind': 'OBJECT', - 'name': 'QueryRoot', - 'fields': [{ - 'name': 'onlyField', - 'args': [], - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None, - }, - 'isDeprecated': False, - 'deprecationReason': None - }], - 'inputFields': None, - 'interfaces': [], - 'enumValues': None, - 'possibleTypes': None - }, { - 'kind': 'SCALAR', - 'name': 'String', - 'fields': None, - 'inputFields': None, - 'interfaces': None, - 'enumValues': None, - 'possibleTypes': None - }, { - 'kind': 'OBJECT', - 'name': '__Schema', - 'fields': [{ - 'name': 'types', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None - } - } - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'queryType', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'mutationType', - 'args': [], - 'type': { - 'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'subscriptionType', - 'args': [], - 'type': { - 'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'directives', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__Directive', - 'ofType': None - } - } - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }], - 'inputFields': None, - 'interfaces': [], - 'enumValues': None, - 'possibleTypes': None - }, { - 'kind': 'OBJECT', - 'name': '__Type', - 'fields': [{ - 'name': 'kind', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'ENUM', - 'name': '__TypeKind', - 'ofType': None + "__schema": { + "mutationType": None, + "subscriptionType": None, + "queryType": {"name": "QueryRoot"}, + "types": [ + { + "kind": "OBJECT", + "name": "QueryRoot", + "fields": [ + { + "name": "onlyField", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'name', - 'args': [], - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'description', - 'args': [], - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'fields', - 'args': [{ - 'name': 'includeDeprecated', - 'type': { - 'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None + ], + "inputFields": None, + "interfaces": [], + "enumValues": None, + "possibleTypes": None, + }, + { + "kind": "SCALAR", + "name": "String", + "fields": None, + "inputFields": None, + "interfaces": None, + "enumValues": None, + "possibleTypes": None, + }, + { + "kind": "OBJECT", + "name": "__Schema", + "fields": [ + { + "name": "types", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": None, + }, + }, + }, + }, + "isDeprecated": False, + "deprecationReason": None, }, - 'defaultValue': 'false' - }], - 'type': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__Field', - 'ofType': None - } - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'interfaces', - 'args': [], - 'type': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None - } - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'possibleTypes', - 'args': [], - 'type': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None - } - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'enumValues', - 'args': [{ - 'name': 'includeDeprecated', - 'type': { - 'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None + { + "name": "queryType", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": None, + }, + }, + "isDeprecated": False, + "deprecationReason": None, }, - 'defaultValue': 'false' - }], - 'type': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__EnumValue', - 'ofType': None - } - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'inputFields', - 'args': [], - 'type': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__InputValue', - 'ofType': None - } - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'ofType', - 'args': [], - 'type': { - 'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }], - 'inputFields': None, - 'interfaces': [], - 'enumValues': None, - 'possibleTypes': None - }, { - 'kind': 'ENUM', - 'name': '__TypeKind', - 'fields': None, - 'inputFields': None, - 'interfaces': None, - 'enumValues': [{ - 'name': 'SCALAR', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'OBJECT', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'INTERFACE', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'UNION', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'ENUM', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'INPUT_OBJECT', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'LIST', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'NON_NULL', - 'isDeprecated': False, - 'deprecationReason': None - }], - 'possibleTypes': None - }, { - 'kind': 'SCALAR', - 'name': 'Boolean', - 'fields': None, - 'inputFields': None, - 'interfaces': None, - 'enumValues': None, - 'possibleTypes': None - }, { - 'kind': 'OBJECT', - 'name': '__Field', - 'fields': [{ - 'name': 'name', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'description', - 'args': [], - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'args', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__InputValue', - 'ofType': None - } - } - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'type', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'isDeprecated', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'deprecationReason', - 'args': [], - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }], - 'inputFields': None, - 'interfaces': [], - 'enumValues': None, - 'possibleTypes': None - }, { - 'kind': 'OBJECT', - 'name': '__InputValue', - 'fields': [{ - 'name': 'name', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'description', - 'args': [], - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'type', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__Type', - 'ofType': None - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'defaultValue', - 'args': [], - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }], - 'inputFields': None, - 'interfaces': [], - 'enumValues': None, - 'possibleTypes': None - }, { - 'kind': 'OBJECT', - 'name': '__EnumValue', - 'fields': [{ - 'name': 'name', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'description', - 'args': [], - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'isDeprecated', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'deprecationReason', - 'args': [], - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }], - 'inputFields': None, - 'interfaces': [], - 'enumValues': None, - 'possibleTypes': None - }, { - 'kind': 'OBJECT', - 'name': '__Directive', - 'fields': [{ - 'name': 'name', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'description', - 'args': [], - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'locations', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'ENUM', - 'name': '__DirectiveLocation', - 'ofType': None + { + "name": "mutationType", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "subscriptionType", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "directives", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__Directive", + "ofType": None, + }, + }, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + ], + "inputFields": None, + "interfaces": [], + "enumValues": None, + "possibleTypes": None, + }, + { + "kind": "OBJECT", + "name": "__Type", + "fields": [ + { + "name": "kind", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "ENUM", + "name": "__TypeKind", + "ofType": None, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "name", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "description", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "fields", + "args": [ + { + "name": "includeDeprecated", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": None, + }, + "defaultValue": "false", } - } - } - }, - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'args', - 'args': [], - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'OBJECT', - 'name': '__InputValue', - 'ofType': None + ], + "type": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__Field", + "ofType": None, + }, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "interfaces", + "args": [], + "type": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": None, + }, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "possibleTypes", + "args": [], + "type": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": None, + }, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "enumValues", + "args": [ + { + "name": "includeDeprecated", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": None, + }, + "defaultValue": "false", } - } + ], + "type": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__EnumValue", + "ofType": None, + }, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "inputFields", + "args": [], + "type": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": None, + }, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "ofType", + "args": [], + "type": { + "kind": "OBJECT", + "name": "__Type", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + ], + "inputFields": None, + "interfaces": [], + "enumValues": None, + "possibleTypes": None, + }, + { + "kind": "ENUM", + "name": "__TypeKind", + "fields": None, + "inputFields": None, + "interfaces": None, + "enumValues": [ + { + "name": "SCALAR", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "OBJECT", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "INTERFACE", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "UNION", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "ENUM", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "INPUT_OBJECT", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "LIST", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "NON_NULL", + "isDeprecated": False, + "deprecationReason": None, + }, + ], + "possibleTypes": None, + }, + { + "kind": "SCALAR", + "name": "Boolean", + "fields": None, + "inputFields": None, + "interfaces": None, + "enumValues": None, + "possibleTypes": None, + }, + { + "kind": "OBJECT", + "name": "__Field", + "fields": [ + { + "name": "name", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "description", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "args", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": None, + }, + }, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "type", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": None, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "isDeprecated", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": None, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "deprecationReason", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + ], + "inputFields": None, + "interfaces": [], + "enumValues": None, + "possibleTypes": None, + }, + { + "kind": "OBJECT", + "name": "__InputValue", + "fields": [ + { + "name": "name", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "description", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "type", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__Type", + "ofType": None, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "defaultValue", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + ], + "inputFields": None, + "interfaces": [], + "enumValues": None, + "possibleTypes": None, + }, + { + "kind": "OBJECT", + "name": "__EnumValue", + "fields": [ + { + "name": "name", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "description", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "isDeprecated", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": None, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "deprecationReason", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + ], + "inputFields": None, + "interfaces": [], + "enumValues": None, + "possibleTypes": None, + }, + { + "kind": "OBJECT", + "name": "__Directive", + "fields": [ + { + "name": "name", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "description", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "locations", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "ENUM", + "name": "__DirectiveLocation", + "ofType": None, + }, + }, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "args", + "args": [], + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "OBJECT", + "name": "__InputValue", + "ofType": None, + }, + }, + }, + }, + "isDeprecated": False, + "deprecationReason": None, + }, + ], + "inputFields": None, + "interfaces": [], + "enumValues": None, + "possibleTypes": None, + }, + { + "kind": "ENUM", + "name": "__DirectiveLocation", + "fields": None, + "inputFields": None, + "interfaces": None, + "enumValues": [ + { + "name": "QUERY", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "MUTATION", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "SUBSCRIPTION", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "FIELD", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "FRAGMENT_DEFINITION", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "FRAGMENT_SPREAD", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "INLINE_FRAGMENT", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "VARIABLE_DEFINITION", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "SCHEMA", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "SCALAR", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "OBJECT", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "FIELD_DEFINITION", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "ARGUMENT_DEFINITION", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "INTERFACE", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "UNION", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "ENUM", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "ENUM_VALUE", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "INPUT_OBJECT", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "INPUT_FIELD_DEFINITION", + "isDeprecated": False, + "deprecationReason": None, + }, + ], + "possibleTypes": None, + }, + ], + "directives": [ + { + "name": "include", + "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], + "args": [ + { + "defaultValue": None, + "name": "if", + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": None, + }, + }, } - }, - 'isDeprecated': False, - 'deprecationReason': None - }], - 'inputFields': None, - 'interfaces': [], - 'enumValues': None, - 'possibleTypes': None - }, { - 'kind': 'ENUM', - 'name': '__DirectiveLocation', - 'fields': None, - 'inputFields': None, - 'interfaces': None, - 'enumValues': [{ - 'name': 'QUERY', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'MUTATION', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'SUBSCRIPTION', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'FIELD', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'FRAGMENT_DEFINITION', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'FRAGMENT_SPREAD', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'INLINE_FRAGMENT', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'VARIABLE_DEFINITION', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'SCHEMA', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'SCALAR', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'OBJECT', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'FIELD_DEFINITION', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'ARGUMENT_DEFINITION', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'INTERFACE', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'UNION', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'ENUM', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'ENUM_VALUE', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'INPUT_OBJECT', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'INPUT_FIELD_DEFINITION', - 'isDeprecated': False, - 'deprecationReason': None - }], - 'possibleTypes': None - }], - 'directives': [{ - 'name': 'include', - 'locations': [ - 'FIELD', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT'], - 'args': [{ - 'defaultValue': None, - 'name': 'if', - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None + ], + }, + { + "name": "skip", + "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], + "args": [ + { + "defaultValue": None, + "name": "if", + "type": { + "kind": "NON_NULL", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": None, + }, + }, } - } - }] - }, { - 'name': 'skip', - 'locations': [ - 'FIELD', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT'], - 'args': [{ - 'defaultValue': None, - 'name': 'if', - 'type': { - 'kind': 'NON_NULL', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'Boolean', - 'ofType': None + ], + }, + { + "name": "deprecated", + "locations": ["FIELD_DEFINITION", "ENUM_VALUE"], + "args": [ + { + "defaultValue": '"No longer supported"', + "name": "reason", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, } - } - }] - }, { - 'name': 'deprecated', - 'locations': ['FIELD_DEFINITION', 'ENUM_VALUE'], - 'args': [{ - 'defaultValue': '"No longer supported"', - 'name': 'reason', - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - } - }] - }] + ], + }, + ], } } def introspects_on_input_object(): - TestInputObject = GraphQLInputObjectType('TestInputObject', { - 'a': GraphQLInputField(GraphQLString, - default_value='tes\t de\fault'), - 'b': GraphQLInputField(GraphQLList(GraphQLString)), - 'c': GraphQLInputField(GraphQLString, default_value=None)}) + TestInputObject = GraphQLInputObjectType( + "TestInputObject", + { + "a": GraphQLInputField(GraphQLString, default_value="tes\t de\fault"), + "b": GraphQLInputField(GraphQLList(GraphQLString)), + "c": GraphQLInputField(GraphQLString, default_value=None), + }, + ) - TestType = GraphQLObjectType('TestType', { - 'field': GraphQLField(GraphQLString, args={ - 'complex': GraphQLArgument(TestInputObject)}, - resolve=lambda obj, info, **args: repr(args.get('complex')))}) + TestType = GraphQLObjectType( + "TestType", + { + "field": GraphQLField( + GraphQLString, + args={"complex": GraphQLArgument(TestInputObject)}, + resolve=lambda obj, info, **args: repr(args.get("complex")), + ) + }, + ) schema = GraphQLSchema(TestType) request = """ @@ -801,45 +910,53 @@ def introspects_on_input_object(): } """ - assert graphql_sync(schema, request) == ({ - '__type': { - 'kind': 'INPUT_OBJECT', - 'name': 'TestInputObject', - 'inputFields': [{ - 'name': 'a', - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'defaultValue': '"tes\\t de\\fault"' - }, { - 'name': 'b', - 'type': { - 'kind': 'LIST', - 'name': None, - 'ofType': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None + assert graphql_sync(schema, request) == ( + { + "__type": { + "kind": "INPUT_OBJECT", + "name": "TestInputObject", + "inputFields": [ + { + "name": "a", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "defaultValue": '"tes\\t de\\fault"', }, - }, - 'defaultValue': None, - }, { - 'name': 'c', - 'type': { - 'kind': 'SCALAR', - 'name': 'String', - 'ofType': None - }, - 'defaultValue': 'null' - }] - } - }, None) + { + "name": "b", + "type": { + "kind": "LIST", + "name": None, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + }, + "defaultValue": None, + }, + { + "name": "c", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "defaultValue": "null", + }, + ], + } + }, + None, + ) def supports_the_type_root_field(): - TestType = GraphQLObjectType('TestType', { - 'testField': GraphQLField(GraphQLString)}) + TestType = GraphQLObjectType( + "TestType", {"testField": GraphQLField(GraphQLString)} + ) schema = GraphQLSchema(TestType) request = """ @@ -850,17 +967,18 @@ def supports_the_type_root_field(): } """ - assert graphql_sync(schema, request) == ({ - '__type': { - 'name': 'TestType', - } - }, None) + assert graphql_sync(schema, request) == ({"__type": {"name": "TestType"}}, None) def identifies_deprecated_fields(): - TestType = GraphQLObjectType('TestType', { - 'nonDeprecated': GraphQLField(GraphQLString), - 'deprecated': GraphQLField( - GraphQLString, deprecation_reason='Removed in 1.0')}) + TestType = GraphQLObjectType( + "TestType", + { + "nonDeprecated": GraphQLField(GraphQLString), + "deprecated": GraphQLField( + GraphQLString, deprecation_reason="Removed in 1.0" + ), + }, + ) schema = GraphQLSchema(TestType) request = """ @@ -876,26 +994,37 @@ def identifies_deprecated_fields(): } """ - assert graphql_sync(schema, request) == ({ - '__type': { - 'name': 'TestType', - 'fields': [{ - 'name': 'nonDeprecated', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'deprecated', - 'isDeprecated': True, - 'deprecationReason': 'Removed in 1.0' - }] - } - }, None) + assert graphql_sync(schema, request) == ( + { + "__type": { + "name": "TestType", + "fields": [ + { + "name": "nonDeprecated", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "deprecated", + "isDeprecated": True, + "deprecationReason": "Removed in 1.0", + }, + ], + } + }, + None, + ) def respects_the_include_deprecated_parameter_for_fields(): - TestType = GraphQLObjectType('TestType', { - 'nonDeprecated': GraphQLField(GraphQLString), - 'deprecated': GraphQLField( - GraphQLString, deprecation_reason='Removed in 1.0')}) + TestType = GraphQLObjectType( + "TestType", + { + "nonDeprecated": GraphQLField(GraphQLString), + "deprecated": GraphQLField( + GraphQLString, deprecation_reason="Removed in 1.0" + ), + }, + ) schema = GraphQLSchema(TestType) request = """ @@ -915,32 +1044,29 @@ def respects_the_include_deprecated_parameter_for_fields(): } """ - assert graphql_sync(schema, request) == ({ - '__type': { - 'name': 'TestType', - 'trueFields': [{ - 'name': 'nonDeprecated', - }, { - 'name': 'deprecated', - }], - 'falseFields': [{ - 'name': 'nonDeprecated', - }], - 'omittedFields': [{ - 'name': 'nonDeprecated', - }] - } - }, None) + assert graphql_sync(schema, request) == ( + { + "__type": { + "name": "TestType", + "trueFields": [{"name": "nonDeprecated"}, {"name": "deprecated"}], + "falseFields": [{"name": "nonDeprecated"}], + "omittedFields": [{"name": "nonDeprecated"}], + } + }, + None, + ) def identifies_deprecated_enum_values(): - TestEnum = GraphQLEnumType('TestEnum', { - 'NONDEPRECATED': GraphQLEnumValue(0), - 'DEPRECATED': GraphQLEnumValue( - 1, deprecation_reason='Removed in 1.0'), - 'ALSONONDEPRECATED': GraphQLEnumValue(2)}) + TestEnum = GraphQLEnumType( + "TestEnum", + { + "NONDEPRECATED": GraphQLEnumValue(0), + "DEPRECATED": GraphQLEnumValue(1, deprecation_reason="Removed in 1.0"), + "ALSONONDEPRECATED": GraphQLEnumValue(2), + }, + ) - TestType = GraphQLObjectType('TestType', { - 'testEnum': GraphQLField(TestEnum)}) + TestType = GraphQLObjectType("TestType", {"testEnum": GraphQLField(TestEnum)}) schema = GraphQLSchema(TestType) request = """ @@ -956,34 +1082,43 @@ def identifies_deprecated_enum_values(): } """ - assert graphql_sync(schema, request) == ({ - '__type': { - 'name': 'TestEnum', - 'enumValues': [{ - 'name': 'NONDEPRECATED', - 'isDeprecated': False, - 'deprecationReason': None - }, { - 'name': 'DEPRECATED', - 'isDeprecated': True, - 'deprecationReason': 'Removed in 1.0' - }, { - 'name': 'ALSONONDEPRECATED', - 'isDeprecated': False, - 'deprecationReason': None - }] - } - }, None) + assert graphql_sync(schema, request) == ( + { + "__type": { + "name": "TestEnum", + "enumValues": [ + { + "name": "NONDEPRECATED", + "isDeprecated": False, + "deprecationReason": None, + }, + { + "name": "DEPRECATED", + "isDeprecated": True, + "deprecationReason": "Removed in 1.0", + }, + { + "name": "ALSONONDEPRECATED", + "isDeprecated": False, + "deprecationReason": None, + }, + ], + } + }, + None, + ) def respects_the_include_deprecated_parameter_for_enum_values(): - TestEnum = GraphQLEnumType('TestEnum', { - 'NONDEPRECATED': GraphQLEnumValue(0), - 'DEPRECATED': GraphQLEnumValue( - 1, deprecation_reason='Removed in 1.0'), - 'ALSONONDEPRECATED': GraphQLEnumValue(2)}) + TestEnum = GraphQLEnumType( + "TestEnum", + { + "NONDEPRECATED": GraphQLEnumValue(0), + "DEPRECATED": GraphQLEnumValue(1, deprecation_reason="Removed in 1.0"), + "ALSONONDEPRECATED": GraphQLEnumValue(2), + }, + ) - TestType = GraphQLObjectType('TestType', { - 'testEnum': GraphQLField(TestEnum)}) + TestType = GraphQLObjectType("TestType", {"testEnum": GraphQLField(TestEnum)}) schema = GraphQLSchema(TestType) request = """ @@ -1003,32 +1138,32 @@ def respects_the_include_deprecated_parameter_for_enum_values(): } """ - assert graphql_sync(schema, request) == ({ - '__type': { - 'name': 'TestEnum', - 'trueValues': [{ - 'name': 'NONDEPRECATED' - }, { - 'name': 'DEPRECATED' - }, { - 'name': 'ALSONONDEPRECATED' - }], - 'falseValues': [{ - 'name': 'NONDEPRECATED' - }, { - 'name': 'ALSONONDEPRECATED' - }], - 'omittedValues': [{ - 'name': 'NONDEPRECATED' - }, { - 'name': 'ALSONONDEPRECATED' - }] - } - }, None) + assert graphql_sync(schema, request) == ( + { + "__type": { + "name": "TestEnum", + "trueValues": [ + {"name": "NONDEPRECATED"}, + {"name": "DEPRECATED"}, + {"name": "ALSONONDEPRECATED"}, + ], + "falseValues": [ + {"name": "NONDEPRECATED"}, + {"name": "ALSONONDEPRECATED"}, + ], + "omittedValues": [ + {"name": "NONDEPRECATED"}, + {"name": "ALSONONDEPRECATED"}, + ], + } + }, + None, + ) def fails_as_expected_on_the_type_root_field_without_an_arg(): - TestType = GraphQLObjectType('TestType', { - 'testField': GraphQLField(GraphQLString)}) + TestType = GraphQLObjectType( + "TestType", {"testField": GraphQLField(GraphQLString)} + ) schema = GraphQLSchema(TestType) request = """ @@ -1038,13 +1173,20 @@ def fails_as_expected_on_the_type_root_field_without_an_arg(): } } """ - assert graphql_sync(schema, request) == (None, [{ - 'message': missing_field_arg_message( - '__type', 'name', 'String!'), 'locations': [(3, 15)]}]) + assert graphql_sync(schema, request) == ( + None, + [ + { + "message": missing_field_arg_message("__type", "name", "String!"), + "locations": [(3, 15)], + } + ], + ) def exposes_descriptions_on_types_and_fields(): - QueryRoot = GraphQLObjectType('QueryRoot', { - 'onlyField': GraphQLField(GraphQLString)}) + QueryRoot = GraphQLObjectType( + "QueryRoot", {"onlyField": GraphQLField(GraphQLString)} + ) schema = GraphQLSchema(QueryRoot) @@ -1061,43 +1203,47 @@ def exposes_descriptions_on_types_and_fields(): } """ - assert graphql_sync(schema, request) == ({ - 'schemaType': { - 'name': '__Schema', - '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, mutation, and subscription operations.', - 'fields': [{ - 'name': 'types', - 'description': - 'A list of all types supported by this server.' - }, { - 'name': 'queryType', - 'description': - 'The type that query operations will be rooted at.' - }, { - 'name': 'mutationType', - 'description': - 'If this server supports mutation, the type that' - ' mutation operations will be rooted at.' - }, { - 'name': 'subscriptionType', - 'description': - 'If this server support subscription, the type' - ' that subscription operations will be rooted at.' - }, { - 'name': 'directives', - 'description': - 'A list of all directives supported by this server.' - }] - } - }, None) + assert graphql_sync(schema, request) == ( + { + "schemaType": { + "name": "__Schema", + "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, mutation, and subscription operations.", + "fields": [ + { + "name": "types", + "description": "A list of all types supported by this server.", # noqa + }, + { + "name": "queryType", + "description": "The type that query operations will be rooted at.", # noqa + }, + { + "name": "mutationType", + "description": "If this server supports mutation, the type that" # noqa + " mutation operations will be rooted at.", # noqa + }, + { + "name": "subscriptionType", + "description": "If this server support subscription, the type" # noqa + " that subscription operations will be rooted at.", # noqa + }, + { + "name": "directives", + "description": "A list of all directives supported by this server.", # noqa + }, + ], + } + }, + None, + ) def exposes_descriptions_on_enums(): - QueryRoot = GraphQLObjectType('QueryRoot', { - 'onlyField': GraphQLField(GraphQLString)}) + QueryRoot = GraphQLObjectType( + "QueryRoot", {"onlyField": GraphQLField(GraphQLString)} + ) schema = GraphQLSchema(QueryRoot) request = """ @@ -1113,57 +1259,62 @@ def exposes_descriptions_on_enums(): } """ - assert graphql_sync(schema, request) == ({ - 'typeKindType': { - 'name': '__TypeKind', - 'description': - 'An enum describing what kind of type' - ' a given `__Type` is.', - 'enumValues': [{ - 'description': 'Indicates this type is a scalar.', - 'name': 'SCALAR' - }, { - 'description': - 'Indicates this type is an object.' + - ' `fields` and `interfaces` are valid fields.', - 'name': 'OBJECT' - }, { - 'description': - 'Indicates this type is an interface.' - ' `fields` and `possibleTypes` are valid fields.', - 'name': 'INTERFACE' - }, { - 'description': - 'Indicates this type is a union.' - ' `possibleTypes` is a valid field.', - 'name': 'UNION' - }, { - 'description': - 'Indicates this type is an enum.' - ' `enumValues` is a valid field.', - 'name': 'ENUM' - }, { - 'description': - 'Indicates this type is an input object.' - ' `inputFields` is a valid field.', - 'name': 'INPUT_OBJECT' - }, { - 'description': - 'Indicates this type is a list.' - ' `ofType` is a valid field.', - 'name': 'LIST' - }, { - 'description': - 'Indicates this type is a non-null.' - ' `ofType` is a valid field.', - 'name': 'NON_NULL' - }] - } - }, None) + assert graphql_sync(schema, request) == ( + { + "typeKindType": { + "name": "__TypeKind", + "description": "An enum describing what kind of type" + " a given `__Type` is.", + "enumValues": [ + { + "description": "Indicates this type is a scalar.", + "name": "SCALAR", + }, + { + "description": "Indicates this type is an object." + + " `fields` and `interfaces` are valid fields.", + "name": "OBJECT", + }, + { + "description": "Indicates this type is an interface." + " `fields` and `possibleTypes` are valid fields.", + "name": "INTERFACE", + }, + { + "description": "Indicates this type is a union." + " `possibleTypes` is a valid field.", + "name": "UNION", + }, + { + "description": "Indicates this type is an enum." + " `enumValues` is a valid field.", + "name": "ENUM", + }, + { + "description": "Indicates this type is an input object." + " `inputFields` is a valid field.", + "name": "INPUT_OBJECT", + }, + { + "description": "Indicates this type is a list." + " `ofType` is a valid field.", + "name": "LIST", + }, + { + "description": "Indicates this type is a non-null." + " `ofType` is a valid field.", + "name": "NON_NULL", + }, + ], + } + }, + None, + ) def executes_introspection_query_without_calling_global_field_resolver(): - query_root = GraphQLObjectType('QueryRoot', { - 'onlyField': GraphQLField(GraphQLString)}) + query_root = GraphQLObjectType( + "QueryRoot", {"onlyField": GraphQLField(GraphQLString)} + ) schema = GraphQLSchema(query_root) source = get_introspection_query() @@ -1171,8 +1322,7 @@ def executes_introspection_query_without_calling_global_field_resolver(): called_for_fields = set() def field_resolver(value, info): - called_for_fields.add( - f'{info.parent_type.name}::{info.field_name}') + called_for_fields.add(f"{info.parent_type.name}::{info.field_name}") return value graphql_sync(schema, source, field_resolver=field_resolver) diff --git a/tests/type/test_predicate.py b/tests/type/test_predicate.py index 7472b799..3659ab6a 100644 --- a/tests/type/test_predicate.py +++ b/tests/type/test_predicate.py @@ -1,36 +1,69 @@ from pytest import raises from graphql.type import ( - GraphQLArgument, GraphQLEnumType, GraphQLInputField, - GraphQLInputObjectType, GraphQLInterfaceType, GraphQLList, - GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, - GraphQLString, GraphQLUnionType, - assert_abstract_type, assert_composite_type, assert_enum_type, - assert_input_object_type, assert_input_type, assert_interface_type, - assert_leaf_type, assert_list_type, assert_named_type, - assert_non_null_type, assert_nullable_type, assert_object_type, - assert_output_type, assert_scalar_type, assert_type, assert_union_type, - assert_wrapping_type, get_named_type, get_nullable_type, is_abstract_type, - is_composite_type, is_enum_type, is_input_object_type, is_input_type, - is_interface_type, is_leaf_type, is_list_type, is_named_type, - is_required_argument, is_required_input_field, - is_non_null_type, is_nullable_type, is_object_type, is_output_type, - is_scalar_type, is_type, is_union_type, is_wrapping_type) - -ObjectType = GraphQLObjectType('Object', {}) -InterfaceType = GraphQLInterfaceType('Interface') -UnionType = GraphQLUnionType('Union', types=[ObjectType]) -EnumType = GraphQLEnumType('Enum', values={'foo': {}}) -InputObjectType = GraphQLInputObjectType('InputObject', {}) + GraphQLArgument, + GraphQLEnumType, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLScalarType, + GraphQLString, + GraphQLUnionType, + assert_abstract_type, + assert_composite_type, + assert_enum_type, + assert_input_object_type, + assert_input_type, + assert_interface_type, + assert_leaf_type, + assert_list_type, + assert_named_type, + assert_non_null_type, + assert_nullable_type, + assert_object_type, + assert_output_type, + assert_scalar_type, + assert_type, + assert_union_type, + assert_wrapping_type, + get_named_type, + get_nullable_type, + is_abstract_type, + is_composite_type, + is_enum_type, + is_input_object_type, + is_input_type, + is_interface_type, + is_leaf_type, + is_list_type, + is_named_type, + is_required_argument, + is_required_input_field, + is_non_null_type, + is_nullable_type, + is_object_type, + is_output_type, + is_scalar_type, + is_type, + is_union_type, + is_wrapping_type, +) + +ObjectType = GraphQLObjectType("Object", {}) +InterfaceType = GraphQLInterfaceType("Interface") +UnionType = GraphQLUnionType("Union", types=[ObjectType]) +EnumType = GraphQLEnumType("Enum", values={"foo": {}}) +InputObjectType = GraphQLInputObjectType("InputObject", {}) ScalarType = GraphQLScalarType( - 'Scalar', - serialize=lambda: {}, parse_value=lambda: {}, parse_literal=lambda: {}) + "Scalar", serialize=lambda: {}, parse_value=lambda: {}, parse_literal=lambda: {} +) def describe_type_predicates(): - def describe_is_type(): - def returns_true_for_unwrapped_types(): assert is_type(GraphQLString) is True assert_type(GraphQLString) @@ -47,12 +80,11 @@ def returns_false_for_type_classes_rather_than_instance(): assert_type(GraphQLObjectType) def returns_false_for_random_garbage(): - assert is_type({'what': 'is this'}) is False + assert is_type({"what": "is this"}) is False with raises(TypeError): - assert_type({'what': 'is this'}) + assert_type({"what": "is this"}) def describe_is_scalar_type(): - def returns_true_for_spec_defined_scalar(): assert is_scalar_type(GraphQLString) is True assert_scalar_type(GraphQLString) @@ -67,7 +99,6 @@ def returns_false_for_non_scalar(): assert_scalar_type(EnumType) def describe_is_object_type(): - def returns_true_for_object_type(): assert is_object_type(ObjectType) is True assert_object_type(ObjectType) @@ -83,7 +114,6 @@ def returns_false_for_non_object_type(): assert_scalar_type(InterfaceType) def describe_is_interface_type(): - def returns_true_for_interface_type(): assert is_interface_type(InterfaceType) is True assert_interface_type(InterfaceType) @@ -99,7 +129,6 @@ def returns_false_for_non_interface_type(): assert_interface_type(ObjectType) def describe_is_union_type(): - def returns_true_for_union_type(): assert is_union_type(UnionType) is True assert_union_type(UnionType) @@ -115,7 +144,6 @@ def returns_false_for_non_union_type(): assert_union_type(ObjectType) def describe_is_enum_type(): - def returns_true_for_enum_type(): assert is_enum_type(EnumType) is True assert_enum_type(EnumType) @@ -131,7 +159,6 @@ def returns_false_for_non_enum_type(): assert_enum_type(ScalarType) def describe_is_input_object_type(): - def returns_true_for_input_object_type(): assert is_input_object_type(InputObjectType) is True assert_input_object_type(InputObjectType) @@ -147,7 +174,6 @@ def returns_false_for_non_input_object_type(): assert_input_object_type(ObjectType) def describe_is_list_type(): - def returns_true_for_a_list_wrapped_type(): assert is_list_type(GraphQLList(ObjectType)) is True assert_list_type(GraphQLList(ObjectType)) @@ -158,13 +184,11 @@ def returns_false_for_an_unwrapped_type(): assert_list_type(ObjectType) def returns_true_for_a_non_list_wrapped_type(): - assert is_list_type( - GraphQLNonNull(GraphQLList(ObjectType))) is False + assert is_list_type(GraphQLNonNull(GraphQLList(ObjectType))) is False with raises(TypeError): assert_list_type(GraphQLNonNull(GraphQLList(ObjectType))) def describe_is_non_null_type(): - def returns_true_for_a_non_null_wrapped_type(): assert is_non_null_type(GraphQLNonNull(ObjectType)) is True assert_non_null_type(GraphQLNonNull(ObjectType)) @@ -175,13 +199,11 @@ def returns_false_for_an_unwrapped_type(): assert_non_null_type(ObjectType) def returns_true_for_a_not_non_null_wrapped_type(): - assert is_non_null_type( - GraphQLList(GraphQLNonNull(ObjectType))) is False + assert is_non_null_type(GraphQLList(GraphQLNonNull(ObjectType))) is False with raises(TypeError): assert_non_null_type(GraphQLList(GraphQLNonNull(ObjectType))) def describe_is_input_type(): - def returns_true_for_an_input_type(): assert is_input_type(InputObjectType) is True assert_input_type(InputObjectType) @@ -206,7 +228,6 @@ def returns_false_for_a_wrapped_output_type(): assert_input_type(GraphQLNonNull(ObjectType)) def describe_is_output_type(): - def returns_true_for_an_output_type(): assert is_output_type(ObjectType) is True assert_output_type(ObjectType) @@ -231,7 +252,6 @@ def returns_false_for_a_wrapped_input_type(): assert_output_type(GraphQLNonNull(InputObjectType)) def describe_is_leaf_type(): - def returns_true_for_scalar_and_enum_types(): assert is_leaf_type(ScalarType) is True assert_leaf_type(ScalarType) @@ -254,7 +274,6 @@ def returns_false_for_wrapped_non_leaf_type(): assert_leaf_type(GraphQLList(ObjectType)) def describe_is_composite_type(): - def returns_true_for_object_interface_and_union_types(): assert is_composite_type(ObjectType) is True assert_composite_type(ObjectType) @@ -279,7 +298,6 @@ def returns_false_for_wrapped_non_composite_type(): assert_composite_type(GraphQLList(InputObjectType)) def describe_is_abstract_type(): - def returns_true_for_interface_and_union_types(): assert is_abstract_type(InterfaceType) is True assert_abstract_type(InterfaceType) @@ -302,7 +320,6 @@ def returns_false_for_wrapped_non_abstract_type(): assert_abstract_type(GraphQLList(ObjectType)) def describe_is_wrapping_type(): - def returns_true_for_list_and_non_null_types(): assert is_wrapping_type(GraphQLList(ObjectType)) is True assert_wrapping_type(GraphQLList(ObjectType)) @@ -315,14 +332,12 @@ def returns_false_for_unwrapped_types(): assert_wrapping_type(ObjectType) def describe_is_nullable_type(): - def returns_true_for_unwrapped_types(): assert is_nullable_type(ObjectType) is True assert_nullable_type(ObjectType) def returns_true_for_list_of_non_null_types(): - assert is_nullable_type( - GraphQLList(GraphQLNonNull(ObjectType))) is True + assert is_nullable_type(GraphQLList(GraphQLNonNull(ObjectType))) is True assert_nullable_type(GraphQLList(GraphQLNonNull(ObjectType))) def returns_false_for_non_null_types(): @@ -331,7 +346,6 @@ def returns_false_for_non_null_types(): assert_nullable_type(GraphQLNonNull(ObjectType)) def describe_get_nullable_type(): - def returns_none_for_no_type(): assert get_nullable_type(None) is None @@ -344,7 +358,6 @@ def unwraps_non_null_type(): assert get_nullable_type(GraphQLNonNull(ObjectType)) is ObjectType def describe_is_named_type(): - def returns_true_for_unwrapped_types(): assert is_named_type(ObjectType) is True assert_named_type(ObjectType) @@ -358,7 +371,6 @@ def returns_false_for_list_and_non_null_types(): assert_named_type(GraphQLNonNull(ObjectType)) def describe_get_named_type(): - def returns_none_for_no_type(): assert get_named_type(None) is None @@ -370,49 +382,47 @@ def unwraps_wrapper_types(): assert get_named_type(GraphQLList(ObjectType)) is ObjectType def unwraps_deeply_wrapper_types(): - assert get_named_type(GraphQLNonNull(GraphQLList(GraphQLNonNull( - ObjectType)))) is ObjectType + assert ( + get_named_type(GraphQLNonNull(GraphQLList(GraphQLNonNull(ObjectType)))) + is ObjectType + ) def describe_is_required_argument(): + def returns_true_for_required_arguments(): + required_arg = GraphQLArgument(GraphQLNonNull(GraphQLString)) + assert is_required_argument(required_arg) is True - def returns_true_for_required_arguments(): - required_arg = GraphQLArgument(GraphQLNonNull(GraphQLString)) - assert is_required_argument(required_arg) is True + def returns_false_for_optional_arguments(): + opt_arg1 = GraphQLArgument(GraphQLString) + assert is_required_argument(opt_arg1) is False - def returns_false_for_optional_arguments(): - opt_arg1 = GraphQLArgument(GraphQLString) - assert is_required_argument(opt_arg1) is False + opt_arg2 = GraphQLArgument(GraphQLString, default_value=None) + assert is_required_argument(opt_arg2) is False - opt_arg2 = GraphQLArgument(GraphQLString, default_value=None) - assert is_required_argument(opt_arg2) is False + opt_arg3 = GraphQLArgument(GraphQLList(GraphQLNonNull(GraphQLString))) + assert is_required_argument(opt_arg3) is False - opt_arg3 = GraphQLArgument( - GraphQLList(GraphQLNonNull(GraphQLString))) - assert is_required_argument(opt_arg3) is False - - opt_arg4 = GraphQLArgument( - GraphQLNonNull(GraphQLString), default_value='default') - assert is_required_argument(opt_arg4) is False + opt_arg4 = GraphQLArgument( + GraphQLNonNull(GraphQLString), default_value="default" + ) + assert is_required_argument(opt_arg4) is False def describe_is_required_input_field(): + def returns_true_for_required_input_field(): + required_field = GraphQLInputField(GraphQLNonNull(GraphQLString)) + assert is_required_input_field(required_field) is True - def returns_true_for_required_input_field(): - required_field = GraphQLInputField( - GraphQLNonNull(GraphQLString)) - assert is_required_input_field(required_field) is True - - def returns_false_for_optional_input_field(): - opt_field1 = GraphQLInputField(GraphQLString) - assert is_required_input_field(opt_field1) is False + def returns_false_for_optional_input_field(): + opt_field1 = GraphQLInputField(GraphQLString) + assert is_required_input_field(opt_field1) is False - opt_field2 = GraphQLInputField( - GraphQLString, default_value=None) - assert is_required_input_field(opt_field2) is False + opt_field2 = GraphQLInputField(GraphQLString, default_value=None) + assert is_required_input_field(opt_field2) is False - opt_field3 = GraphQLInputField( - GraphQLList(GraphQLNonNull(GraphQLString))) - assert is_required_input_field(opt_field3) is False + opt_field3 = GraphQLInputField(GraphQLList(GraphQLNonNull(GraphQLString))) + assert is_required_input_field(opt_field3) is False - opt_field4 = GraphQLInputField( - GraphQLNonNull(GraphQLString), default_value='default') - assert is_required_input_field(opt_field4) is False + opt_field4 = GraphQLInputField( + GraphQLNonNull(GraphQLString), default_value="default" + ) + assert is_required_input_field(opt_field4) is False diff --git a/tests/type/test_schema.py b/tests/type/test_schema.py index 7b7f41c7..632e6a48 100644 --- a/tests/type/test_schema.py +++ b/tests/type/test_schema.py @@ -2,46 +2,58 @@ from graphql.language import DirectiveLocation from graphql.type import ( - GraphQLField, GraphQLInterfaceType, - GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLInputObjectType, - GraphQLInputField, GraphQLDirective, GraphQLArgument, GraphQLList) + GraphQLField, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, + GraphQLInputObjectType, + GraphQLInputField, + GraphQLDirective, + GraphQLArgument, + GraphQLList, +) -InterfaceType = GraphQLInterfaceType('Interface', { - 'fieldName': GraphQLField(GraphQLString)}) +InterfaceType = GraphQLInterfaceType( + "Interface", {"fieldName": GraphQLField(GraphQLString)} +) -DirectiveInputType = GraphQLInputObjectType('DirInput', { - 'field': GraphQLInputField(GraphQLString)}) +DirectiveInputType = GraphQLInputObjectType( + "DirInput", {"field": GraphQLInputField(GraphQLString)} +) -WrappedDirectiveInputType = GraphQLInputObjectType('WrappedDirInput', { - 'field': GraphQLInputField(GraphQLString)}) +WrappedDirectiveInputType = GraphQLInputObjectType( + "WrappedDirInput", {"field": GraphQLInputField(GraphQLString)} +) Directive = GraphQLDirective( - name='dir', + name="dir", locations=[DirectiveLocation.OBJECT], - args={'arg': GraphQLArgument(DirectiveInputType), - 'argList': GraphQLArgument(GraphQLList(WrappedDirectiveInputType))}) + args={ + "arg": GraphQLArgument(DirectiveInputType), + "argList": GraphQLArgument(GraphQLList(WrappedDirectiveInputType)), + }, +) -Schema = GraphQLSchema(query=GraphQLObjectType('Query', { - 'getObject': GraphQLField(InterfaceType, resolve=lambda: {})}), - directives=[Directive]) +Schema = GraphQLSchema( + query=GraphQLObjectType( + "Query", {"getObject": GraphQLField(InterfaceType, resolve=lambda: {})} + ), + directives=[Directive], +) def describe_type_system_schema(): - def describe_type_map(): - def includes_input_types_only_used_in_directives(): - assert 'DirInput' in Schema.type_map - assert 'WrappedDirInput' in Schema.type_map + assert "DirInput" in Schema.type_map + assert "WrappedDirInput" in Schema.type_map def describe_validity(): - def describe_when_not_assumed_valid(): - def configures_the_schema_to_still_needing_validation(): # noinspection PyProtectedMember - assert GraphQLSchema( - assume_valid=False)._validation_errors is None + assert GraphQLSchema(assume_valid=False)._validation_errors is None def checks_the_configuration_for_mistakes(): with raises(Exception): @@ -55,5 +67,4 @@ def checks_the_configuration_for_mistakes(): def describe_when_assumed_valid(): def configures_the_schema_to_have_no_errors(): # noinspection PyProtectedMember - assert GraphQLSchema( - assume_valid=True)._validation_errors == [] + assert GraphQLSchema(assume_valid=True)._validation_errors == [] diff --git a/tests/type/test_serialization.py b/tests/type/test_serialization.py index d6360eee..d62012da 100644 --- a/tests/type/test_serialization.py +++ b/tests/type/test_serialization.py @@ -3,14 +3,18 @@ from pytest import raises from graphql.type import ( - GraphQLBoolean, GraphQLFloat, GraphQLID, GraphQLInt, GraphQLString) + GraphQLBoolean, + GraphQLFloat, + GraphQLID, + GraphQLInt, + GraphQLString, +) def describe_type_system_scalar_coercion(): - def serializes_output_as_int(): assert GraphQLInt.serialize(1) == 1 - assert GraphQLInt.serialize('123') == 123 + assert GraphQLInt.serialize("123") == 123 assert GraphQLInt.serialize(0) == 0 assert GraphQLInt.serialize(-1) == -1 assert GraphQLInt.serialize(1e5) == 100000 @@ -21,124 +25,110 @@ def serializes_output_as_int(): # values as Int to avoid accidental data loss. with raises(TypeError) as exc_info: GraphQLInt.serialize(0.1) - assert str(exc_info.value) == ( - 'Int cannot represent non-integer value: 0.1') + assert str(exc_info.value) == ("Int cannot represent non-integer value: 0.1") with raises(TypeError) as exc_info: GraphQLInt.serialize(1.1) - assert str(exc_info.value) == ( - 'Int cannot represent non-integer value: 1.1') + assert str(exc_info.value) == ("Int cannot represent non-integer value: 1.1") with raises(TypeError) as exc_info: GraphQLInt.serialize(-1.1) - assert str(exc_info.value) == ( - 'Int cannot represent non-integer value: -1.1') + assert str(exc_info.value) == ("Int cannot represent non-integer value: -1.1") with raises(TypeError) as exc_info: - GraphQLInt.serialize('-1.1') - assert str(exc_info.value) == ( - "Int cannot represent non-integer value: '-1.1'") + GraphQLInt.serialize("-1.1") + assert str(exc_info.value) == ("Int cannot represent non-integer value: '-1.1'") # Maybe a safe JavaScript int, but bigger than 2^32, so not # representable as a GraphQL Int with raises(Exception) as exc_info: GraphQLInt.serialize(9876504321) assert str(exc_info.value) == ( - 'Int cannot represent non 32-bit signed integer value:' - ' 9876504321') + "Int cannot represent non 32-bit signed integer value:" " 9876504321" + ) with raises(Exception) as exc_info: GraphQLInt.serialize(-9876504321) assert str(exc_info.value) == ( - 'Int cannot represent non 32-bit signed integer value:' - ' -9876504321') + "Int cannot represent non 32-bit signed integer value:" " -9876504321" + ) # Too big to represent as an Int in JavaScript or GraphQL with raises(Exception) as exc_info: GraphQLInt.serialize(1e100) assert str(exc_info.value) == ( - 'Int cannot represent non 32-bit signed integer value: 1e+100') + "Int cannot represent non 32-bit signed integer value: 1e+100" + ) with raises(Exception) as exc_info: GraphQLInt.serialize(-1e100) assert str(exc_info.value) == ( - 'Int cannot represent non 32-bit signed integer value: -1e+100') + "Int cannot represent non 32-bit signed integer value: -1e+100" + ) with raises(Exception) as exc_info: - GraphQLInt.serialize('one') - assert str(exc_info.value) == ( - "Int cannot represent non-integer value: 'one'") + GraphQLInt.serialize("one") + assert str(exc_info.value) == ("Int cannot represent non-integer value: 'one'") # Doesn't represent number with raises(Exception) as exc_info: - GraphQLInt.serialize('') - assert str(exc_info.value) == ( - "Int cannot represent non-integer value: ''") + GraphQLInt.serialize("") + assert str(exc_info.value) == ("Int cannot represent non-integer value: ''") with raises(Exception) as exc_info: GraphQLInt.serialize(nan) - assert str(exc_info.value) == ( - 'Int cannot represent non-integer value: nan') + assert str(exc_info.value) == ("Int cannot represent non-integer value: nan") with raises(Exception) as exc_info: GraphQLInt.serialize(inf) - assert str(exc_info.value) == ( - 'Int cannot represent non-integer value: inf') + assert str(exc_info.value) == ("Int cannot represent non-integer value: inf") with raises(Exception) as exc_info: GraphQLInt.serialize([5]) - assert str(exc_info.value) == ( - 'Int cannot represent non-integer value: [5]') + assert str(exc_info.value) == ("Int cannot represent non-integer value: [5]") def serializes_output_as_float(): assert GraphQLFloat.serialize(1) == 1.0 assert GraphQLFloat.serialize(0) == 0.0 - assert GraphQLFloat.serialize('123.5') == 123.5 + assert GraphQLFloat.serialize("123.5") == 123.5 assert GraphQLFloat.serialize(-1) == -1.0 assert GraphQLFloat.serialize(0.1) == 0.1 assert GraphQLFloat.serialize(1.1) == 1.1 assert GraphQLFloat.serialize(-1.1) == -1.1 - assert GraphQLFloat.serialize('-1.1') == -1.1 + assert GraphQLFloat.serialize("-1.1") == -1.1 assert GraphQLFloat.serialize(False) == 0 assert GraphQLFloat.serialize(True) == 1 with raises(Exception) as exc_info: GraphQLFloat.serialize(nan) - assert str(exc_info.value) == ( - 'Float cannot represent non numeric value: nan') + assert str(exc_info.value) == ("Float cannot represent non numeric value: nan") with raises(Exception) as exc_info: GraphQLFloat.serialize(inf) - assert str(exc_info.value) == ( - 'Float cannot represent non numeric value: inf') + assert str(exc_info.value) == ("Float cannot represent non numeric value: inf") with raises(Exception) as exc_info: - GraphQLFloat.serialize('one') + GraphQLFloat.serialize("one") assert str(exc_info.value) == ( - "Float cannot represent non numeric value: 'one'") + "Float cannot represent non numeric value: 'one'" + ) with raises(Exception) as exc_info: - GraphQLFloat.serialize('') - assert str(exc_info.value) == ( - "Float cannot represent non numeric value: ''") + GraphQLFloat.serialize("") + assert str(exc_info.value) == ("Float cannot represent non numeric value: ''") with raises(Exception) as exc_info: GraphQLFloat.serialize([5]) - assert str(exc_info.value) == ( - 'Float cannot represent non numeric value: [5]') + assert str(exc_info.value) == ("Float cannot represent non numeric value: [5]") def serializes_output_as_string(): - assert GraphQLString.serialize('string') == 'string' - assert GraphQLString.serialize(1) == '1' - assert GraphQLString.serialize(-1.1) == '-1.1' - assert GraphQLString.serialize(True) == 'true' - assert GraphQLString.serialize(False) == 'false' + assert GraphQLString.serialize("string") == "string" + assert GraphQLString.serialize(1) == "1" + assert GraphQLString.serialize(-1.1) == "-1.1" + assert GraphQLString.serialize(True) == "true" + assert GraphQLString.serialize(False) == "false" class StringableObjValue: def __str__(self): - return 'something useful' + return "something useful" - assert GraphQLString.serialize( - StringableObjValue()) == 'something useful' + assert GraphQLString.serialize(StringableObjValue()) == "something useful" with raises(Exception) as exc_info: GraphQLString.serialize(nan) - assert str(exc_info.value) == ( - 'String cannot represent value: nan') + assert str(exc_info.value) == ("String cannot represent value: nan") with raises(Exception) as exc_info: GraphQLString.serialize([1]) - assert str(exc_info.value) == ( - 'String cannot represent value: [1]') + assert str(exc_info.value) == ("String cannot represent value: [1]") with raises(Exception) as exc_info: GraphQLString.serialize({}) - assert str(exc_info.value) == ( - 'String cannot represent value: {}') + assert str(exc_info.value) == ("String cannot represent value: {}") def serializes_output_as_boolean(): assert GraphQLBoolean.serialize(1) is True @@ -149,35 +139,40 @@ def serializes_output_as_boolean(): with raises(Exception) as exc_info: GraphQLBoolean.serialize(nan) assert str(exc_info.value) == ( - 'Boolean cannot represent a non boolean value: nan') + "Boolean cannot represent a non boolean value: nan" + ) with raises(Exception) as exc_info: - GraphQLBoolean.serialize('') + GraphQLBoolean.serialize("") assert str(exc_info.value) == ( - "Boolean cannot represent a non boolean value: ''") + "Boolean cannot represent a non boolean value: ''" + ) with raises(Exception) as exc_info: - GraphQLBoolean.serialize('True') + GraphQLBoolean.serialize("True") assert str(exc_info.value) == ( - "Boolean cannot represent a non boolean value: 'True'") + "Boolean cannot represent a non boolean value: 'True'" + ) with raises(Exception) as exc_info: GraphQLBoolean.serialize([False]) assert str(exc_info.value) == ( - 'Boolean cannot represent a non boolean value: [False]') + "Boolean cannot represent a non boolean value: [False]" + ) with raises(Exception) as exc_info: GraphQLBoolean.serialize({}) assert str(exc_info.value) == ( - 'Boolean cannot represent a non boolean value: {}') + "Boolean cannot represent a non boolean value: {}" + ) def serializes_output_as_id(): - assert GraphQLID.serialize('string') == 'string' - assert GraphQLID.serialize('false') == 'false' - assert GraphQLID.serialize('') == '' - assert GraphQLID.serialize(123) == '123' - assert GraphQLID.serialize(0) == '0' - assert GraphQLID.serialize(-1) == '-1' + assert GraphQLID.serialize("string") == "string" + assert GraphQLID.serialize("false") == "false" + assert GraphQLID.serialize("") == "" + assert GraphQLID.serialize(123) == "123" + assert GraphQLID.serialize(0) == "0" + assert GraphQLID.serialize(-1) == "-1" class ObjValue: def __init__(self, value): @@ -187,24 +182,20 @@ def __str__(self): return str(self._id) obj_value = ObjValue(123) - assert GraphQLID.serialize(obj_value) == '123' + assert GraphQLID.serialize(obj_value) == "123" with raises(Exception) as exc_info: GraphQLID.serialize(True) - assert str(exc_info.value) == ( - "ID cannot represent value: True") + assert str(exc_info.value) == ("ID cannot represent value: True") with raises(Exception) as exc_info: GraphQLID.serialize(3.14) - assert str(exc_info.value) == ( - "ID cannot represent value: 3.14") + assert str(exc_info.value) == ("ID cannot represent value: 3.14") with raises(Exception) as exc_info: GraphQLID.serialize({}) - assert str(exc_info.value) == ( - "ID cannot represent value: {}") + assert str(exc_info.value) == ("ID cannot represent value: {}") with raises(Exception) as exc_info: - GraphQLID.serialize(['abc']) - assert str(exc_info.value) == ( - "ID cannot represent value: ['abc']") + GraphQLID.serialize(["abc"]) + assert str(exc_info.value) == ("ID cannot represent value: ['abc']") diff --git a/tests/type/test_validation.py b/tests/type/test_validation.py index 635904d3..6a9f2987 100644 --- a/tests/type/test_validation.py +++ b/tests/type/test_validation.py @@ -4,11 +4,23 @@ from graphql.language import parse from graphql.type import ( - GraphQLEnumType, GraphQLEnumValue, GraphQLField, - GraphQLInputField, GraphQLInputObjectType, GraphQLInterfaceType, - GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, - GraphQLSchema, GraphQLString, GraphQLUnionType, validate_schema, - GraphQLArgument, GraphQLDirective) + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLScalarType, + GraphQLSchema, + GraphQLString, + GraphQLUnionType, + validate_schema, + GraphQLArgument, + GraphQLDirective, +) from graphql.utilities import build_schema, extend_schema @@ -18,81 +30,81 @@ def _get(value): SomeScalarType = GraphQLScalarType( - name='SomeScalar', + name="SomeScalar", serialize=_get(None), parse_value=_get(None), - parse_literal=_get(None)) + parse_literal=_get(None), +) SomeInterfaceType = GraphQLInterfaceType( - name='SomeInterface', - fields=lambda: {'f': GraphQLField(SomeObjectType)}) + name="SomeInterface", fields=lambda: {"f": GraphQLField(SomeObjectType)} +) SomeObjectType = GraphQLObjectType( - name='SomeObject', - fields=lambda: {'f': GraphQLField(SomeObjectType)}, - interfaces=[SomeInterfaceType]) + name="SomeObject", + fields=lambda: {"f": GraphQLField(SomeObjectType)}, + interfaces=[SomeInterfaceType], +) -SomeUnionType = GraphQLUnionType( - name='SomeUnion', - types=[SomeObjectType]) +SomeUnionType = GraphQLUnionType(name="SomeUnion", types=[SomeObjectType]) -SomeEnumType = GraphQLEnumType( - name='SomeEnum', - values={'ONLY': GraphQLEnumValue()}) +SomeEnumType = GraphQLEnumType(name="SomeEnum", values={"ONLY": GraphQLEnumValue()}) SomeInputObjectType = GraphQLInputObjectType( - name='SomeInputObject', - fields={'val': GraphQLInputField(GraphQLString, default_value='hello')}) + name="SomeInputObject", + fields={"val": GraphQLInputField(GraphQLString, default_value="hello")}, +) def with_modifiers(types): - return types + [ - GraphQLList(t) for t in types] + [ - GraphQLNonNull(t) for t in types] + [ - GraphQLNonNull(GraphQLList(t)) for t in types] - - -output_types = with_modifiers([ - GraphQLString, - SomeScalarType, - SomeEnumType, - SomeObjectType, - SomeUnionType, - SomeInterfaceType]) + return ( + types + + [GraphQLList(t) for t in types] + + [GraphQLNonNull(t) for t in types] + + [GraphQLNonNull(GraphQLList(t)) for t in types] + ) + + +output_types = with_modifiers( + [ + GraphQLString, + SomeScalarType, + SomeEnumType, + SomeObjectType, + SomeUnionType, + SomeInterfaceType, + ] +) not_output_types = with_modifiers([SomeInputObjectType]) -input_types = with_modifiers([ - GraphQLString, - SomeScalarType, - SomeEnumType, - SomeInputObjectType]) +input_types = with_modifiers( + [GraphQLString, SomeScalarType, SomeEnumType, SomeInputObjectType] +) -not_input_types = with_modifiers([ - SomeObjectType, - SomeUnionType, - SomeInterfaceType]) +not_input_types = with_modifiers([SomeObjectType, SomeUnionType, SomeInterfaceType]) def schema_with_field_type(type_): return GraphQLSchema( - query=GraphQLObjectType( - name='Query', - fields={'f': GraphQLField(type_)}), - types=[type_]) + query=GraphQLObjectType(name="Query", fields={"f": GraphQLField(type_)}), + types=[type_], + ) def describe_type_system_a_schema_must_have_object_root_types(): - def accepts_a_schema_whose_query_type_is_an_object_type(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: String } - """) + """ + ) assert validate_schema(schema) == [] - schema_with_def = build_schema(""" + schema_with_def = build_schema( + """ schema { query: QueryRoot } @@ -100,12 +112,14 @@ def accepts_a_schema_whose_query_type_is_an_object_type(): type QueryRoot { test: String } - """) + """ + ) assert validate_schema(schema_with_def) == [] def accepts_a_schema_whose_query_and_mutation_types_are_object_types(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: String } @@ -113,10 +127,12 @@ def accepts_a_schema_whose_query_and_mutation_types_are_object_types(): type Mutation { test: String } - """) + """ + ) assert validate_schema(schema) == [] - schema_with_def = build_schema(""" + schema_with_def = build_schema( + """ schema { query: QueryRoot mutation: MutationRoot @@ -129,11 +145,13 @@ def accepts_a_schema_whose_query_and_mutation_types_are_object_types(): type MutationRoot { test: String } - """) + """ + ) assert validate_schema(schema_with_def) == [] def accepts_a_schema_whose_query_and_subscription_types_are_object_types(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: String } @@ -141,10 +159,12 @@ def accepts_a_schema_whose_query_and_subscription_types_are_object_types(): type Subscription { test: String } - """) + """ + ) assert validate_schema(schema) == [] - schema_with_def = build_schema(""" + schema_with_def = build_schema( + """ schema { query: QueryRoot subscription: SubscriptionRoot @@ -157,20 +177,24 @@ def accepts_a_schema_whose_query_and_subscription_types_are_object_types(): type SubscriptionRoot { test: String } - """) + """ + ) assert validate_schema(schema_with_def) == [] def rejects_a_schema_without_a_query_type(): - schema = build_schema(""" + schema = build_schema( + """ type Mutation { test: String } - """) - assert validate_schema(schema) == [{ - 'message': 'Query root type must be provided.', - 'locations': None}] - - schema_with_def = build_schema(""" + """ + ) + assert validate_schema(schema) == [ + {"message": "Query root type must be provided.", "locations": None} + ] + + schema_with_def = build_schema( + """ schema { mutation: MutationRoot } @@ -178,23 +202,30 @@ def rejects_a_schema_without_a_query_type(): type MutationRoot { test: String } - """) - assert validate_schema(schema_with_def) == [{ - 'message': 'Query root type must be provided.', - 'locations': [(2, 13)]}] + """ + ) + assert validate_schema(schema_with_def) == [ + {"message": "Query root type must be provided.", "locations": [(2, 13)]} + ] def rejects_a_schema_whose_query_root_type_is_not_an_object_type(): - schema = build_schema(""" + schema = build_schema( + """ input Query { test: String } - """) - assert validate_schema(schema) == [{ - 'message': 'Query root type must be Object type,' - ' it cannot be Query.', - 'locations': [(2, 13)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Query root type must be Object type," + " it cannot be Query.", + "locations": [(2, 13)], + } + ] - schema_with_def = build_schema(""" + schema_with_def = build_schema( + """ schema { query: SomeInputObject } @@ -202,14 +233,19 @@ def rejects_a_schema_whose_query_root_type_is_not_an_object_type(): input SomeInputObject { test: String } - """) - assert validate_schema(schema_with_def) == [{ - 'message': 'Query root type must be Object type,' - ' it cannot be SomeInputObject.', - 'locations': [(3, 22)]}] + """ + ) + assert validate_schema(schema_with_def) == [ + { + "message": "Query root type must be Object type," + " it cannot be SomeInputObject.", + "locations": [(3, 22)], + } + ] def rejects_a_schema_whose_mutation_type_is_an_input_type(): - schema = build_schema(""" + schema = build_schema( + """ type Query { field: String } @@ -217,13 +253,18 @@ def rejects_a_schema_whose_mutation_type_is_an_input_type(): input Mutation { test: String } - """) - assert validate_schema(schema) == [{ - 'message': 'Mutation root type must be Object type if provided,' - ' it cannot be Mutation.', - 'locations': [(6, 13)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Mutation root type must be Object type if provided," + " it cannot be Mutation.", + "locations": [(6, 13)], + } + ] - schema_with_def = build_schema(""" + schema_with_def = build_schema( + """ schema { query: Query mutation: SomeInputObject @@ -236,14 +277,19 @@ def rejects_a_schema_whose_mutation_type_is_an_input_type(): input SomeInputObject { test: String } - """) - assert validate_schema(schema_with_def) == [{ - 'message': 'Mutation root type must be Object type if provided,' - ' it cannot be SomeInputObject.', - 'locations': [(4, 25)]}] + """ + ) + assert validate_schema(schema_with_def) == [ + { + "message": "Mutation root type must be Object type if provided," + " it cannot be SomeInputObject.", + "locations": [(4, 25)], + } + ] def rejects_a_schema_whose_subscription_type_is_an_input_type(): - schema = build_schema(""" + schema = build_schema( + """ type Query { field: String } @@ -251,13 +297,18 @@ def rejects_a_schema_whose_subscription_type_is_an_input_type(): input Subscription { test: String } - """) - assert validate_schema(schema) == [{ - 'message': 'Subscription root type must be Object type if' - ' provided, it cannot be Subscription.', - 'locations': [(6, 13)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Subscription root type must be Object type if" + " provided, it cannot be Subscription.", + "locations": [(6, 13)], + } + ] - schema_with_def = build_schema(""" + schema_with_def = build_schema( + """ schema { query: Query subscription: SomeInputObject @@ -270,58 +321,84 @@ def rejects_a_schema_whose_subscription_type_is_an_input_type(): input SomeInputObject { test: String } - """) - assert validate_schema(schema_with_def) == [{ - 'message': 'Subscription root type must be Object type if' - ' provided, it cannot be SomeInputObject.', - 'locations': [(4, 29)]}] + """ + ) + assert validate_schema(schema_with_def) == [ + { + "message": "Subscription root type must be Object type if" + " provided, it cannot be SomeInputObject.", + "locations": [(4, 29)], + } + ] def rejects_a_schema_extended_with_invalid_root_types(): - schema = build_schema(""" + schema = build_schema( + """ input SomeInputObject { test: String } - """) - schema = extend_schema(schema, parse(""" + """ + ) + schema = extend_schema( + schema, + parse( + """ extend schema { query: SomeInputObject } - """)) - schema = extend_schema(schema, parse(""" + """ + ), + ) + schema = extend_schema( + schema, + parse( + """ extend schema { mutation: SomeInputObject } - """)) - schema = extend_schema(schema, parse(""" + """ + ), + ) + schema = extend_schema( + schema, + parse( + """ extend schema { subscription: SomeInputObject } - """)) - assert validate_schema(schema) == [{ - 'message': 'Query root type must be Object type,' - ' it cannot be SomeInputObject.', - 'locations': [(3, 22)] - }, { - 'message': 'Mutation root type must be Object type' - ' if provided, it cannot be SomeInputObject.', - 'locations': [(3, 25)] - }, { - 'message': 'Subscription root type must be Object type' - ' if provided, it cannot be SomeInputObject.', - 'locations': [(3, 29)] - }] + """ + ), + ) + assert validate_schema(schema) == [ + { + "message": "Query root type must be Object type," + " it cannot be SomeInputObject.", + "locations": [(3, 22)], + }, + { + "message": "Mutation root type must be Object type" + " if provided, it cannot be SomeInputObject.", + "locations": [(3, 25)], + }, + { + "message": "Subscription root type must be Object type" + " if provided, it cannot be SomeInputObject.", + "locations": [(3, 29)], + }, + ] def rejects_a_schema_whose_directives_are_incorrectly_typed(): - schema = GraphQLSchema(SomeObjectType, directives=[ - cast(GraphQLDirective, 'somedirective')]) + schema = GraphQLSchema( + SomeObjectType, directives=[cast(GraphQLDirective, "somedirective")] + ) msg = validate_schema(schema)[0].message assert msg == "Expected directive but got: 'somedirective'." def describe_type_system_objects_must_have_fields(): - def accepts_an_object_type_with_fields_object(): - schema = build_schema(""" + schema = build_schema( + """ type Query { field: SomeObject } @@ -329,63 +406,88 @@ def accepts_an_object_type_with_fields_object(): type SomeObject { field: String } - """) + """ + ) assert validate_schema(schema) == [] def rejects_an_object_type_with_missing_fields(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: IncompleteObject } type IncompleteObject - """) - assert validate_schema(schema) == [{ - 'message': 'Type IncompleteObject must define one or more fields.', - 'locations': [(6, 13)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Type IncompleteObject must define one or more fields.", + "locations": [(6, 13)], + } + ] manual_schema = schema_with_field_type( - GraphQLObjectType('IncompleteObject', {})) + GraphQLObjectType("IncompleteObject", {}) + ) msg = validate_schema(manual_schema)[0].message assert msg == "Type IncompleteObject must define one or more fields." manual_schema_2 = schema_with_field_type( - GraphQLObjectType('IncompleteObject', lambda: {})) + GraphQLObjectType("IncompleteObject", lambda: {}) + ) msg = validate_schema(manual_schema_2)[0].message assert msg == "Type IncompleteObject must define one or more fields." def rejects_an_object_type_with_incorrectly_named_fields(): - schema = schema_with_field_type(GraphQLObjectType('SomeObject', { - 'bad-name-with-dashes': GraphQLField(GraphQLString)})) + schema = schema_with_field_type( + GraphQLObjectType( + "SomeObject", {"bad-name-with-dashes": GraphQLField(GraphQLString)} + ) + ) msg = validate_schema(schema)[0].message assert msg == ( - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/' - " but 'bad-name-with-dashes' does not.") + "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/" + " but 'bad-name-with-dashes' does not." + ) def describe_type_system_field_args_must_be_properly_named(): - def accepts_field_args_with_valid_names(): - schema = schema_with_field_type(GraphQLObjectType('SomeObject', { - 'goodField': GraphQLField(GraphQLString, args={ - 'goodArg': GraphQLArgument(GraphQLString)})})) + schema = schema_with_field_type( + GraphQLObjectType( + "SomeObject", + { + "goodField": GraphQLField( + GraphQLString, args={"goodArg": GraphQLArgument(GraphQLString)} + ) + }, + ) + ) assert validate_schema(schema) == [] def reject_field_args_with_invalid_names(): - QueryType = GraphQLObjectType('SomeObject', { - 'badField': GraphQLField(GraphQLString, args={ - 'bad-name-with-dashes': GraphQLArgument(GraphQLString)})}) + QueryType = GraphQLObjectType( + "SomeObject", + { + "badField": GraphQLField( + GraphQLString, + args={"bad-name-with-dashes": GraphQLArgument(GraphQLString)}, + ) + }, + ) schema = GraphQLSchema(QueryType) msg = validate_schema(schema)[0].message assert msg == ( - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/' - " but 'bad-name-with-dashes' does not.") + "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/" + " but 'bad-name-with-dashes' does not." + ) def describe_type_system_union_types_must_be_valid(): - def accepts_a_union_type_with_member_types(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: GoodUnion } @@ -401,29 +503,41 @@ def accepts_a_union_type_with_member_types(): union GoodUnion = | TypeA | TypeB - """) + """ + ) assert validate_schema(schema) == [] def rejects_a_union_type_with_empty_types(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: BadUnion } union BadUnion - """) - schema = extend_schema(schema, parse(""" + """ + ) + schema = extend_schema( + schema, + parse( + """ directive @test on UNION extend union BadUnion @test - """)) - assert validate_schema(schema) == [{ - 'message': 'Union type BadUnion must define one or more' - ' member types.', - 'locations': [(6, 13), (4, 13)]}] + """ + ), + ) + assert validate_schema(schema) == [ + { + "message": "Union type BadUnion must define one or more" + " member types.", + "locations": [(6, 13), (4, 13)], + } + ] def rejects_a_union_type_with_duplicated_member_type(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: BadUnion } @@ -440,24 +554,34 @@ def rejects_a_union_type_with_duplicated_member_type(): | TypeA | TypeB | TypeA - """) + """ + ) - assert validate_schema(schema) == [{ - 'message': 'Union type BadUnion can only include type TypeA once.', - 'locations': [(15, 17), (17, 17)]}] + assert validate_schema(schema) == [ + { + "message": "Union type BadUnion can only include type TypeA once.", + "locations": [(15, 17), (17, 17)], + } + ] - schema = extend_schema(schema, parse('extend union BadUnion = TypeB')) + schema = extend_schema(schema, parse("extend union BadUnion = TypeB")) - assert validate_schema(schema) == [{ - 'message': 'Union type BadUnion can only include type TypeA once.', - 'locations': [(15, 17), (17, 17)]}, { - 'message': 'Union type BadUnion can only include type TypeB once.', - 'locations': [(16, 17), (1, 25)]}] + assert validate_schema(schema) == [ + { + "message": "Union type BadUnion can only include type TypeA once.", + "locations": [(15, 17), (17, 17)], + }, + { + "message": "Union type BadUnion can only include type TypeB once.", + "locations": [(16, 17), (1, 25)], + }, + ] def rejects_a_union_type_with_non_object_member_types(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: - build_schema(""" + build_schema( + """ type Query { test: BadUnion } @@ -474,10 +598,11 @@ def rejects_a_union_type_with_non_object_member_types(): | TypeA | String | TypeB - """) + """ + ) msg = str(exc_info.value) - assert msg == 'BadUnion types must be GraphQLObjectType objects.' + assert msg == "BadUnion types must be GraphQLObjectType objects." bad_union_member_types = [ GraphQLString, @@ -486,20 +611,22 @@ def rejects_a_union_type_with_non_object_member_types(): SomeInterfaceType, SomeUnionType, SomeEnumType, - SomeInputObjectType] + SomeInputObjectType, + ] for member_type in bad_union_member_types: # invalid schema cannot be built with Python with raises(TypeError) as exc_info: - schema_with_field_type(GraphQLUnionType( - 'BadUnion', types=[member_type])) + schema_with_field_type( + GraphQLUnionType("BadUnion", types=[member_type]) + ) msg = str(exc_info.value) - assert msg == 'BadUnion types must be GraphQLObjectType objects.' + assert msg == "BadUnion types must be GraphQLObjectType objects." def describe_type_system_input_objects_must_have_fields(): - def accepts_an_input_object_type_with_fields(): - schema = build_schema(""" + schema = build_schema( + """ type Query { field(arg: SomeInputObject): String } @@ -507,31 +634,43 @@ def accepts_an_input_object_type_with_fields(): input SomeInputObject { field: String } - """) + """ + ) assert validate_schema(schema) == [] def rejects_an_input_object_type_with_missing_fields(): - schema = build_schema(""" + schema = build_schema( + """ type Query { field(arg: SomeInputObject): String } input SomeInputObject - """) - schema = extend_schema(schema, parse(""" + """ + ) + schema = extend_schema( + schema, + parse( + """ directive @test on INPUT_OBJECT extend input SomeInputObject @test - """)) - assert validate_schema(schema) == [{ - 'message': 'Input Object type SomeInputObject' - ' must define one or more fields.', - 'locations': [(6, 13), (4, 13)]}] + """ + ), + ) + assert validate_schema(schema) == [ + { + "message": "Input Object type SomeInputObject" + " must define one or more fields.", + "locations": [(6, 13), (4, 13)], + } + ] def rejects_an_input_object_type_with_incorrectly_typed_fields(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: - build_schema(""" + build_schema( + """ type Query { field(arg: SomeInputObject): String } @@ -547,36 +686,48 @@ def rejects_an_input_object_type_with_incorrectly_typed_fields(): badUnion: SomeUnion goodInputObject: SomeInputObject } - """) + """ + ) msg = str(exc_info.value) assert msg == ( - 'SomeInputObject fields cannot be resolved:' - ' Input field type must be a GraphQL input type.') + "SomeInputObject fields cannot be resolved:" + " Input field type must be a GraphQL input type." + ) def describe_type_system_enum_types_must_be_well_defined(): - def rejects_an_enum_type_without_values(): - schema = build_schema(""" + schema = build_schema( + """ type Query { field: SomeEnum } enum SomeEnum - """) + """ + ) - schema = extend_schema(schema, parse(""" + schema = extend_schema( + schema, + parse( + """ directive @test on ENUM extend enum SomeEnum @test - """)) + """ + ), + ) - assert validate_schema(schema) == [{ - 'message': 'Enum type SomeEnum must define one or more values.', - 'locations': [(6, 13), (4, 13)]}] + assert validate_schema(schema) == [ + { + "message": "Enum type SomeEnum must define one or more values.", + "locations": [(6, 13), (4, 13)], + } + ] def rejects_an_enum_type_with_duplicate_values(): - schema = build_schema(""" + schema = build_schema( + """ type Query { field: SomeEnum } @@ -585,61 +736,65 @@ def rejects_an_enum_type_with_duplicate_values(): SOME_VALUE SOME_VALUE } - """) - assert validate_schema(schema) == [{ - 'message': 'Enum type SomeEnum can include value SOME_VALUE' - ' only once.', - 'locations': [(7, 15), (8, 15)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Enum type SomeEnum can include value SOME_VALUE" + " only once.", + "locations": [(7, 15), (8, 15)], + } + ] def rejects_an_enum_type_with_incorrectly_named_values(): def schema_with_enum(name): - return schema_with_field_type(GraphQLEnumType( - 'SomeEnum', {name: GraphQLEnumValue(1)})) + return schema_with_field_type( + GraphQLEnumType("SomeEnum", {name: GraphQLEnumValue(1)}) + ) - schema1 = schema_with_enum('#value') + schema1 = schema_with_enum("#value") msg = validate_schema(schema1)[0].message assert msg == ( - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/' - " but '#value' does not.") + "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/" " but '#value' does not." + ) - schema2 = schema_with_enum('1value') + schema2 = schema_with_enum("1value") msg = validate_schema(schema2)[0].message assert msg == ( - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/' - " but '1value' does not.") + "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/" " but '1value' does not." + ) - schema3 = schema_with_enum('KEBAB-CASE') + schema3 = schema_with_enum("KEBAB-CASE") msg = validate_schema(schema3)[0].message assert msg == ( - 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/' - " but 'KEBAB-CASE' does not.") + "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/" " but 'KEBAB-CASE' does not." + ) - schema4 = schema_with_enum('true') + schema4 = schema_with_enum("true") msg = validate_schema(schema4)[0].message - assert msg == ( - 'Enum type SomeEnum cannot include value: true.') + assert msg == ("Enum type SomeEnum cannot include value: true.") - schema5 = schema_with_enum('false') + schema5 = schema_with_enum("false") msg = validate_schema(schema5)[0].message - assert msg == ( - 'Enum type SomeEnum cannot include value: false.') + assert msg == ("Enum type SomeEnum cannot include value: false.") - schema6 = schema_with_enum('null') + schema6 = schema_with_enum("null") msg = validate_schema(schema6)[0].message - assert msg == ( - 'Enum type SomeEnum cannot include value: null.') + assert msg == ("Enum type SomeEnum cannot include value: null.") def describe_type_system_object_fields_must_have_output_types(): - @fixture def schema_with_object_field_of_type(field_type): - BadObjectType = GraphQLObjectType('BadObject', { - 'badField': GraphQLField(field_type)}) - return GraphQLSchema(GraphQLObjectType('Query', { - 'f': GraphQLField(BadObjectType)}), types=[SomeObjectType]) - - @mark.parametrize('type_', output_types) + BadObjectType = GraphQLObjectType( + "BadObject", {"badField": GraphQLField(field_type)} + ) + return GraphQLSchema( + GraphQLObjectType("Query", {"f": GraphQLField(BadObjectType)}), + types=[SomeObjectType], + ) + + @mark.parametrize("type_", output_types) def accepts_an_output_type_as_an_object_field_type(type_): schema = schema_with_object_field_of_type(type_) assert validate_schema(schema) == [] @@ -649,28 +804,29 @@ def rejects_an_empty_object_field_type(): with raises(TypeError) as exc_info: schema_with_object_field_of_type(None) msg = str(exc_info.value) - assert msg == 'Field type must be an output type.' + assert msg == "Field type must be an output type." - @mark.parametrize('type_', not_output_types) + @mark.parametrize("type_", not_output_types) def rejects_a_non_output_type_as_an_object_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: schema_with_object_field_of_type(type_) msg = str(exc_info.value) - assert msg == 'Field type must be an output type.' + assert msg == "Field type must be an output type." - @mark.parametrize('type_', [int, float, str]) + @mark.parametrize("type_", [int, float, str]) def rejects_a_non_type_value_as_an_object_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: schema_with_object_field_of_type(type_) msg = str(exc_info.value) - assert msg == 'Field type must be an output type.' + assert msg == "Field type must be an output type." def rejects_with_relevant_locations_for_a_non_output_type(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: - build_schema(""" + build_schema( + """ type Query { field: [SomeInputObject] } @@ -678,29 +834,35 @@ def rejects_with_relevant_locations_for_a_non_output_type(): input SomeInputObject { field: String } - """) + """ + ) msg = str(exc_info.value) assert msg == ( - 'Query fields cannot be resolved:' - ' Field type must be an output type.') + "Query fields cannot be resolved:" " Field type must be an output type." + ) def describe_type_system_objects_can_only_implement_unique_interfaces(): - def rejects_an_object_implementing_a_non_type_values(): schema = GraphQLSchema( - query=GraphQLObjectType('BadObject', { - 'f': GraphQLField(GraphQLString)}, interfaces=[])) + query=GraphQLObjectType( + "BadObject", {"f": GraphQLField(GraphQLString)}, interfaces=[] + ) + ) schema.query_type.interfaces.append(None) - assert validate_schema(schema) == [{ - 'message': 'Type BadObject must only implement Interface types,' - ' it cannot implement None.'}] + assert validate_schema(schema) == [ + { + "message": "Type BadObject must only implement Interface types," + " it cannot implement None." + } + ] def rejects_an_object_implementing_a_non_interface_type(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: - build_schema(""" + build_schema( + """ type Query { test: BadObject } @@ -712,13 +874,14 @@ def rejects_an_object_implementing_a_non_interface_type(): type BadObject implements SomeInputObject { field: String } - """) + """ + ) msg = str(exc_info.value) - assert msg == ( - 'BadObject interfaces must be GraphQLInterface objects.') + assert msg == ("BadObject interfaces must be GraphQLInterface objects.") def rejects_an_object_implementing_the_same_interface_twice(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -730,14 +893,19 @@ def rejects_an_object_implementing_the_same_interface_twice(): type AnotherObject implements AnotherInterface & AnotherInterface { field: String } - """) - assert validate_schema(schema) == [{ - 'message': 'Type AnotherObject can only implement' - ' AnotherInterface once.', - 'locations': [(10, 43), (10, 62)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Type AnotherObject can only implement" + " AnotherInterface once.", + "locations": [(10, 43), (10, 62)], + } + ] def rejects_an_object_implementing_same_interface_twice_due_to_extension(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -749,19 +917,24 @@ def rejects_an_object_implementing_same_interface_twice_due_to_extension(): type AnotherObject implements AnotherInterface { field: String } - """) - extended_schema = extend_schema(schema, parse( - 'extend type AnotherObject implements AnotherInterface')) - assert validate_schema(extended_schema) == [{ - 'message': 'Type AnotherObject can only implement' - ' AnotherInterface once.', - 'locations': [(10, 43), (1, 38)]}] + """ + ) + extended_schema = extend_schema( + schema, parse("extend type AnotherObject implements AnotherInterface") + ) + assert validate_schema(extended_schema) == [ + { + "message": "Type AnotherObject can only implement" + " AnotherInterface once.", + "locations": [(10, 43), (1, 38)], + } + ] def describe_type_system_interface_extensions_should_be_valid(): - def rejects_object_implementing_extended_interface_due_to_missing_field(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -773,8 +946,12 @@ def rejects_object_implementing_extended_interface_due_to_missing_field(): type AnotherObject implements AnotherInterface { field: String } - """) - extended_schema = extend_schema(schema, parse(""" + """ + ) + extended_schema = extend_schema( + schema, + parse( + """ extend interface AnotherInterface { newField: String } @@ -782,14 +959,20 @@ def rejects_object_implementing_extended_interface_due_to_missing_field(): extend type AnotherObject { differentNewField: String } - """)) - assert validate_schema(extended_schema) == [{ - 'message': 'Interface field AnotherInterface.newField expected' - ' but AnotherObject does not provide it.', - 'locations': [(3, 15), (10, 13), (6, 13)]}] + """ + ), + ) + assert validate_schema(extended_schema) == [ + { + "message": "Interface field AnotherInterface.newField expected" + " but AnotherObject does not provide it.", + "locations": [(3, 15), (10, 13), (6, 13)], + } + ] def rejects_object_implementing_extended_interface_due_to_missing_args(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -801,8 +984,12 @@ def rejects_object_implementing_extended_interface_due_to_missing_args(): type AnotherObject implements AnotherInterface { field: String } - """) - extended_schema = extend_schema(schema, parse(""" + """ + ) + extended_schema = extend_schema( + schema, + parse( + """ extend interface AnotherInterface { newField(test: Boolean): String } @@ -810,15 +997,21 @@ def rejects_object_implementing_extended_interface_due_to_missing_args(): extend type AnotherObject { newField: String } - """)) - assert validate_schema(extended_schema) == [{ - 'message': 'Interface field argument' - ' AnotherInterface.newField(test:) expected' - ' but AnotherObject.newField does not provide it.', - 'locations': [(3, 24), (7, 15)]}] + """ + ), + ) + assert validate_schema(extended_schema) == [ + { + "message": "Interface field argument" + " AnotherInterface.newField(test:) expected" + " but AnotherObject.newField does not provide it.", + "locations": [(3, 24), (7, 15)], + } + ] def rejects_object_implementing_extended_interface_due_to_type_mismatch(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -830,8 +1023,12 @@ def rejects_object_implementing_extended_interface_due_to_type_mismatch(): type AnotherObject implements AnotherInterface { field: String } - """) - extended_schema = extend_schema(schema, parse(""" + """ + ) + extended_schema = extend_schema( + schema, + parse( + """ extend interface AnotherInterface { newInterfaceField: NewInterface } @@ -852,29 +1049,37 @@ def rejects_object_implementing_extended_interface_due_to_type_mismatch(): type DummyObject implements NewInterface & MismatchingInterface { newField: String } - """)) - assert validate_schema(extended_schema) == [{ - 'message': 'Interface field AnotherInterface.newInterfaceField' - ' expects type NewInterface' - ' but AnotherObject.newInterfaceField' - ' is type MismatchingInterface.', - 'locations': [(3, 34), (15, 34)]}] + """ + ), + ) + assert validate_schema(extended_schema) == [ + { + "message": "Interface field AnotherInterface.newInterfaceField" + " expects type NewInterface" + " but AnotherObject.newInterfaceField" + " is type MismatchingInterface.", + "locations": [(3, 34), (15, 34)], + } + ] def describe_type_system_interface_fields_must_have_output_types(): - @fixture def schema_with_interface_field_of_type(field_type): - BadInterfaceType = GraphQLInterfaceType('BadInterface', { - 'badField': GraphQLField(field_type)}) - BadImplementingType = GraphQLObjectType('BadImplementing', { - 'badField': GraphQLField(field_type)}, - interfaces=[BadInterfaceType]) - return GraphQLSchema(GraphQLObjectType('Query', { - 'f': GraphQLField(BadInterfaceType)}), - types=[BadImplementingType, SomeObjectType]) - - @mark.parametrize('type_', output_types) + BadInterfaceType = GraphQLInterfaceType( + "BadInterface", {"badField": GraphQLField(field_type)} + ) + BadImplementingType = GraphQLObjectType( + "BadImplementing", + {"badField": GraphQLField(field_type)}, + interfaces=[BadInterfaceType], + ) + return GraphQLSchema( + GraphQLObjectType("Query", {"f": GraphQLField(BadInterfaceType)}), + types=[BadImplementingType, SomeObjectType], + ) + + @mark.parametrize("type_", output_types) def accepts_an_output_type_as_an_interface_field_type(type_): schema = schema_with_interface_field_of_type(type_) assert validate_schema(schema) == [] @@ -884,28 +1089,29 @@ def rejects_an_empty_interface_field_type(): with raises(TypeError) as exc_info: schema_with_interface_field_of_type(None) msg = str(exc_info.value) - assert msg == 'Field type must be an output type.' + assert msg == "Field type must be an output type." - @mark.parametrize('type_', not_output_types) + @mark.parametrize("type_", not_output_types) def rejects_a_non_output_type_as_an_interface_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: schema_with_interface_field_of_type(type_) msg = str(exc_info.value) - assert msg == 'Field type must be an output type.' + assert msg == "Field type must be an output type." - @mark.parametrize('type_', [int, float, str]) + @mark.parametrize("type_", [int, float, str]) def rejects_a_non_type_value_as_an_interface_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: schema_with_interface_field_of_type(type_) msg = str(exc_info.value) - assert msg == 'Field type must be an output type.' + assert msg == "Field type must be an output type." def rejects_a_non_output_type_as_an_interface_field_with_locations(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: - build_schema(""" + build_schema( + """ type Query { test: SomeInterface } @@ -921,14 +1127,17 @@ def rejects_a_non_output_type_as_an_interface_field_with_locations(): type SomeObject implements SomeInterface { field: SomeInputObject } - """) + """ + ) msg = str(exc_info.value) assert msg == ( - 'SomeInterface fields cannot be resolved:' - ' Field type must be an output type.') + "SomeInterface fields cannot be resolved:" + " Field type must be an output type." + ) def accepts_an_interface_not_implemented_by_at_least_one_object(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: SomeInterface } @@ -936,21 +1145,27 @@ def accepts_an_interface_not_implemented_by_at_least_one_object(): interface SomeInterface { foo: String } - """) + """ + ) assert validate_schema(schema) == [] def describe_type_system_field_arguments_must_have_input_types(): - @fixture def schema_with_arg_of_type(arg_type): - BadObjectType = GraphQLObjectType('BadObject', { - 'badField': GraphQLField(GraphQLString, args={ - 'badArg': GraphQLArgument(arg_type)})}) - return GraphQLSchema(GraphQLObjectType('Query', { - 'f': GraphQLField(BadObjectType)})) - - @mark.parametrize('type_', input_types) + BadObjectType = GraphQLObjectType( + "BadObject", + { + "badField": GraphQLField( + GraphQLString, args={"badArg": GraphQLArgument(arg_type)} + ) + }, + ) + return GraphQLSchema( + GraphQLObjectType("Query", {"f": GraphQLField(BadObjectType)}) + ) + + @mark.parametrize("type_", input_types) def accepts_an_input_type_as_a_field_arg_type(type_): schema = schema_with_arg_of_type(type_) assert validate_schema(schema) == [] @@ -960,28 +1175,29 @@ def rejects_an_empty_field_arg_type(): with raises(TypeError) as exc_info: schema_with_arg_of_type(None) msg = str(exc_info.value) - assert msg == 'Argument type must be a GraphQL input type.' + assert msg == "Argument type must be a GraphQL input type." - @mark.parametrize('type_', not_input_types) + @mark.parametrize("type_", not_input_types) def rejects_a_non_input_type_as_a_field_arg_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: schema_with_arg_of_type(type_) msg = str(exc_info.value) - assert msg == 'Argument type must be a GraphQL input type.' + assert msg == "Argument type must be a GraphQL input type." - @mark.parametrize('type_', [int, float, str]) + @mark.parametrize("type_", [int, float, str]) def rejects_a_non_type_value_as_a_field_arg_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: schema_with_arg_of_type(type_) msg = str(exc_info.value) - assert msg == 'Argument type must be a GraphQL input type.' + assert msg == "Argument type must be a GraphQL input type." def rejects_a_non_input_type_as_a_field_arg_with_locations(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: - build_schema(""" + build_schema( + """ type Query { test(arg: SomeObject): String } @@ -989,24 +1205,34 @@ def rejects_a_non_input_type_as_a_field_arg_with_locations(): type SomeObject { foo: String } - """) + """ + ) msg = str(exc_info.value) assert msg == ( - 'Query fields cannot be resolved:' - ' Argument type must be a GraphQL input type.') + "Query fields cannot be resolved:" + " Argument type must be a GraphQL input type." + ) def describe_type_system_input_object_fields_must_have_input_types(): - @fixture def schema_with_input_field_of_type(input_field_type): - BadInputObjectType = GraphQLInputObjectType('BadInputObject', { - 'badField': GraphQLInputField(input_field_type)}) - return GraphQLSchema(GraphQLObjectType('Query', { - 'f': GraphQLField(GraphQLString, args={ - 'badArg': GraphQLArgument(BadInputObjectType)})})) - - @mark.parametrize('type_', input_types) + BadInputObjectType = GraphQLInputObjectType( + "BadInputObject", {"badField": GraphQLInputField(input_field_type)} + ) + return GraphQLSchema( + GraphQLObjectType( + "Query", + { + "f": GraphQLField( + GraphQLString, + args={"badArg": GraphQLArgument(BadInputObjectType)}, + ) + }, + ) + ) + + @mark.parametrize("type_", input_types) def accepts_an_input_type_as_an_input_fieldtype(type_): schema = schema_with_input_field_of_type(type_) assert validate_schema(schema) == [] @@ -1016,28 +1242,29 @@ def rejects_an_empty_input_field_type(): with raises(TypeError) as exc_info: schema_with_input_field_of_type(None) msg = str(exc_info.value) - assert msg == 'Input field type must be a GraphQL input type.' + assert msg == "Input field type must be a GraphQL input type." - @mark.parametrize('type_', not_input_types) + @mark.parametrize("type_", not_input_types) def rejects_a_non_input_type_as_an_input_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: schema_with_input_field_of_type(type_) msg = str(exc_info.value) - assert msg == 'Input field type must be a GraphQL input type.' + assert msg == "Input field type must be a GraphQL input type." - @mark.parametrize('type_', [int, float, str]) + @mark.parametrize("type_", [int, float, str]) def rejects_a_non_type_value_as_an_input_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: schema_with_input_field_of_type(type_) msg = str(exc_info.value) - assert msg == 'Input field type must be a GraphQL input type.' + assert msg == "Input field type must be a GraphQL input type." def rejects_with_relevant_locations_for_a_non_input_type(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: - build_schema(""" + build_schema( + """ type Query { test(arg: SomeInputObject): String } @@ -1049,17 +1276,19 @@ def rejects_with_relevant_locations_for_a_non_input_type(): type SomeObject { bar: String } - """) + """ + ) msg = str(exc_info.value) assert msg == ( - 'SomeInputObject fields cannot be resolved:' - ' Input field type must be a GraphQL input type.') + "SomeInputObject fields cannot be resolved:" + " Input field type must be a GraphQL input type." + ) def describe_objects_must_adhere_to_interfaces_they_implement(): - def accepts_an_object_which_implements_an_interface(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1071,11 +1300,13 @@ def accepts_an_object_which_implements_an_interface(): type AnotherObject implements AnotherInterface { field(input: String): String } - """) + """ + ) assert validate_schema(schema) == [] def accepts_an_object_which_implements_an_interface_and_with_more_fields(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1088,11 +1319,13 @@ def accepts_an_object_which_implements_an_interface_and_with_more_fields(): field(input: String): String anotherField: String } - """) + """ + ) assert validate_schema(schema) == [] def accepts_an_object_which_implements_an_interface_field_with_more_args(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1104,11 +1337,13 @@ def accepts_an_object_which_implements_an_interface_field_with_more_args(): type AnotherObject implements AnotherInterface { field(input: String, anotherInput: String): String } - """) + """ + ) assert validate_schema(schema) == [] def rejects_an_object_missing_an_interface_field(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1120,14 +1355,19 @@ def rejects_an_object_missing_an_interface_field(): type AnotherObject implements AnotherInterface { anotherField: String } - """) - assert validate_schema(schema) == [{ - 'message': 'Interface field AnotherInterface.field expected but' - ' AnotherObject does not provide it.', - 'locations': [(7, 15), (10, 13)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Interface field AnotherInterface.field expected but" + " AnotherObject does not provide it.", + "locations": [(7, 15), (10, 13)], + } + ] def rejects_an_object_with_an_incorrectly_typed_interface_field(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1139,15 +1379,20 @@ def rejects_an_object_with_an_incorrectly_typed_interface_field(): type AnotherObject implements AnotherInterface { field(input: String): Int } - """) - assert validate_schema(schema) == [{ - 'message': 'Interface field AnotherInterface.field' - ' expects type String but' - ' AnotherObject.field is type Int.', - 'locations': [(7, 37), (11, 37)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Interface field AnotherInterface.field" + " expects type String but" + " AnotherObject.field is type Int.", + "locations": [(7, 37), (11, 37)], + } + ] def rejects_an_object_with_a_differently_typed_interface_field(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1162,14 +1407,19 @@ def rejects_an_object_with_a_differently_typed_interface_field(): type AnotherObject implements AnotherInterface { field: B } - """) - assert validate_schema(schema) == [{ - 'message': 'Interface field AnotherInterface.field' - ' expects type A but AnotherObject.field is type B.', - 'locations': [(10, 22), (14, 22)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Interface field AnotherInterface.field" + " expects type A but AnotherObject.field is type B.", + "locations": [(10, 22), (14, 22)], + } + ] def accepts_an_object_with_a_subtyped_interface_field_interface(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1181,11 +1431,13 @@ def accepts_an_object_with_a_subtyped_interface_field_interface(): type AnotherObject implements AnotherInterface { field: AnotherObject } - """) + """ + ) assert validate_schema(schema) == [] def accepts_an_object_with_a_subtyped_interface_field_union(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1203,11 +1455,13 @@ def accepts_an_object_with_a_subtyped_interface_field_union(): type AnotherObject implements AnotherInterface { field: SomeObject } - """) + """ + ) assert validate_schema(schema) == [] def rejects_an_object_missing_an_interface_argument(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1219,15 +1473,20 @@ def rejects_an_object_missing_an_interface_argument(): type AnotherObject implements AnotherInterface { field: String } - """) - assert validate_schema(schema) == [{ - 'message': 'Interface field argument' - ' AnotherInterface.field(input:) expected' - ' but AnotherObject.field does not provide it.', - 'locations': [(7, 21), (11, 15)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Interface field argument" + " AnotherInterface.field(input:) expected" + " but AnotherObject.field does not provide it.", + "locations": [(7, 21), (11, 15)], + } + ] def rejects_an_object_with_an_incorrectly_typed_interface_argument(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1239,15 +1498,20 @@ def rejects_an_object_with_an_incorrectly_typed_interface_argument(): type AnotherObject implements AnotherInterface { field(input: Int): String } - """) - assert validate_schema(schema) == [{ - 'message': 'Interface field argument' - ' AnotherInterface.field(input:) expects type String' - ' but AnotherObject.field(input:) is type Int.', - 'locations': [(7, 28), (11, 28)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Interface field argument" + " AnotherInterface.field(input:) expects type String" + " but AnotherObject.field(input:) is type Int.", + "locations": [(7, 28), (11, 28)], + } + ] def rejects_an_object_with_an_incorrectly_typed_field_and__argument(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1259,20 +1523,25 @@ def rejects_an_object_with_an_incorrectly_typed_field_and__argument(): type AnotherObject implements AnotherInterface { field(input: Int): Int } - """) - assert validate_schema(schema) == [{ - 'message': 'Interface field AnotherInterface.field expects' - ' type String but AnotherObject.field is type Int.', - 'locations': [(7, 37), (11, 34)] - }, { - 'message': 'Interface field argument' - ' AnotherInterface.field(input:) expects type String' - ' but AnotherObject.field(input:) is type Int.', - 'locations': [(7, 28), (11, 28)] - }] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Interface field AnotherInterface.field expects" + " type String but AnotherObject.field is type Int.", + "locations": [(7, 37), (11, 34)], + }, + { + "message": "Interface field argument" + " AnotherInterface.field(input:) expects type String" + " but AnotherObject.field(input:) is type Int.", + "locations": [(7, 28), (11, 28)], + }, + ] def rejects_object_implementing_an_interface_field_with_additional_args(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1289,15 +1558,20 @@ def rejects_object_implementing_an_interface_field_with_additional_args(): optionalArg2: String = "", ): String } - """) - assert validate_schema(schema) == [{ - 'message': 'Object field AnotherObject.field includes required' - ' argument requiredArg that is missing from the' - ' Interface field AnotherInterface.field.', - 'locations': [(13, 17), (7, 15)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Object field AnotherObject.field includes required" + " argument requiredArg that is missing from the" + " Interface field AnotherInterface.field.", + "locations": [(13, 17), (7, 15)], + } + ] def accepts_an_object_with_an_equivalently_wrapped_interface_field_type(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1309,11 +1583,13 @@ def accepts_an_object_with_an_equivalently_wrapped_interface_field_type(): type AnotherObject implements AnotherInterface { field: [String]! } - """) + """ + ) assert validate_schema(schema) == [] def rejects_an_object_with_a_non_list_interface_field_list_type(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1325,14 +1601,19 @@ def rejects_an_object_with_a_non_list_interface_field_list_type(): type AnotherObject implements AnotherInterface { field: String } - """) - assert validate_schema(schema) == [{ - 'message': 'Interface field AnotherInterface.field expects type' - ' [String] but AnotherObject.field is type String.', - 'locations': [(7, 22), (11, 22)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Interface field AnotherInterface.field expects type" + " [String] but AnotherObject.field is type String.", + "locations": [(7, 22), (11, 22)], + } + ] def rejects_a_object_with_a_list_interface_field_non_list_type(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1344,14 +1625,19 @@ def rejects_a_object_with_a_list_interface_field_non_list_type(): type AnotherObject implements AnotherInterface { field: [String] } - """) - assert validate_schema(schema) == [{ - 'message': 'Interface field AnotherInterface.field expects type' - ' String but AnotherObject.field is type [String].', - 'locations': [(7, 22), (11, 22)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Interface field AnotherInterface.field expects type" + " String but AnotherObject.field is type [String].", + "locations": [(7, 22), (11, 22)], + } + ] def accepts_an_object_with_a_subset_non_null_interface_field_type(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1363,11 +1649,13 @@ def accepts_an_object_with_a_subset_non_null_interface_field_type(): type AnotherObject implements AnotherInterface { field: String! } - """) + """ + ) assert validate_schema(schema) == [] def rejects_a_object_with_a_superset_nullable_interface_field_type(): - schema = build_schema(""" + schema = build_schema( + """ type Query { test: AnotherObject } @@ -1379,8 +1667,12 @@ def rejects_a_object_with_a_superset_nullable_interface_field_type(): type AnotherObject implements AnotherInterface { field: String } - """) - assert validate_schema(schema) == [{ - 'message': 'Interface field AnotherInterface.field expects type' - ' String! but AnotherObject.field is type String.', - 'locations': [(7, 22), (11, 22)]}] + """ + ) + assert validate_schema(schema) == [ + { + "message": "Interface field AnotherInterface.field expects type" + " String! but AnotherObject.field is type String.", + "locations": [(7, 22), (11, 22)], + } + ] diff --git a/tests/utilities/test_assert_valid_name.py b/tests/utilities/test_assert_valid_name.py index aa7fa739..bc48e857 100644 --- a/tests/utilities/test_assert_valid_name.py +++ b/tests/utilities/test_assert_valid_name.py @@ -5,24 +5,24 @@ def describe_assert_valid_name(): - def throws_for_use_of_leading_double_underscore(): with raises(GraphQLError) as exc_info: - assert assert_valid_name('__bad') + assert assert_valid_name("__bad") msg = exc_info.value.message assert msg == ( "Name '__bad' must not begin with '__'," - ' which is reserved by GraphQL introspection.') + " which is reserved by GraphQL introspection." + ) def throws_for_non_strings(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker assert_valid_name({}) msg = str(exc_info.value) - assert msg == 'Expected string' + assert msg == "Expected string" def throws_for_names_with_invalid_characters(): with raises(GraphQLError) as exc_info: - assert_valid_name('>--()-->') + assert_valid_name(">--()-->") msg = exc_info.value.message - assert 'Names must match' in msg + assert "Names must match" in msg diff --git a/tests/utilities/test_ast_from_value.py b/tests/utilities/test_ast_from_value.py index fae4dd45..8795e405 100644 --- a/tests/utilities/test_ast_from_value.py +++ b/tests/utilities/test_ast_from_value.py @@ -4,24 +4,37 @@ from graphql.error import INVALID from graphql.language import ( - BooleanValueNode, EnumValueNode, FloatValueNode, - IntValueNode, ListValueNode, NameNode, NullValueNode, ObjectFieldNode, - ObjectValueNode, StringValueNode) + BooleanValueNode, + EnumValueNode, + FloatValueNode, + IntValueNode, + ListValueNode, + NameNode, + NullValueNode, + ObjectFieldNode, + ObjectValueNode, + StringValueNode, +) from graphql.type import ( - GraphQLBoolean, GraphQLEnumType, GraphQLFloat, - GraphQLID, GraphQLInputField, GraphQLInputObjectType, GraphQLInt, - GraphQLList, GraphQLNonNull, GraphQLString) + GraphQLBoolean, + GraphQLEnumType, + GraphQLFloat, + GraphQLID, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInt, + GraphQLList, + GraphQLNonNull, + GraphQLString, +) from graphql.utilities import ast_from_value def describe_ast_from_value(): - def converts_boolean_values_to_asts(): - assert ast_from_value( - True, GraphQLBoolean) == BooleanValueNode(value=True) + assert ast_from_value(True, GraphQLBoolean) == BooleanValueNode(value=True) - assert ast_from_value( - False, GraphQLBoolean) == BooleanValueNode(value=False) + assert ast_from_value(False, GraphQLBoolean) == BooleanValueNode(value=False) assert ast_from_value(INVALID, GraphQLBoolean) is None @@ -29,96 +42,82 @@ def converts_boolean_values_to_asts(): assert ast_from_value(None, GraphQLBoolean) == NullValueNode() - assert ast_from_value( - 0, GraphQLBoolean) == BooleanValueNode(value=False) + assert ast_from_value(0, GraphQLBoolean) == BooleanValueNode(value=False) - assert ast_from_value( - 1, GraphQLBoolean) == BooleanValueNode(value=True) + assert ast_from_value(1, GraphQLBoolean) == BooleanValueNode(value=True) non_null_boolean = GraphQLNonNull(GraphQLBoolean) - assert ast_from_value( - 0, non_null_boolean) == BooleanValueNode(value=False) + assert ast_from_value(0, non_null_boolean) == BooleanValueNode(value=False) def converts_int_values_to_int_asts(): - assert ast_from_value(-1, GraphQLInt) == IntValueNode(value='-1') + assert ast_from_value(-1, GraphQLInt) == IntValueNode(value="-1") - assert ast_from_value(123.0, GraphQLInt) == IntValueNode(value='123') + assert ast_from_value(123.0, GraphQLInt) == IntValueNode(value="123") - assert ast_from_value(1e4, GraphQLInt) == IntValueNode(value='10000') + assert ast_from_value(1e4, GraphQLInt) == IntValueNode(value="10000") # GraphQL spec does not allow coercing non-integer values to Int to # avoid accidental data loss. with raises(TypeError) as exc_info: assert ast_from_value(123.5, GraphQLInt) msg = str(exc_info.value) - assert msg == 'Int cannot represent non-integer value: 123.5' + assert msg == "Int cannot represent non-integer value: 123.5" # Note: outside the bounds of 32bit signed int. with raises(TypeError) as exc_info: assert ast_from_value(1e40, GraphQLInt) msg = str(exc_info.value) - assert msg == ( - 'Int cannot represent non 32-bit signed integer value: 1e+40') + assert msg == ("Int cannot represent non 32-bit signed integer value: 1e+40") def converts_float_values_to_float_asts(): # luckily in Python we can discern between float and int - assert ast_from_value(-1, GraphQLFloat) == FloatValueNode(value='-1') + assert ast_from_value(-1, GraphQLFloat) == FloatValueNode(value="-1") - assert ast_from_value( - 123.0, GraphQLFloat) == FloatValueNode(value='123') + assert ast_from_value(123.0, GraphQLFloat) == FloatValueNode(value="123") - assert ast_from_value( - 123.5, GraphQLFloat) == FloatValueNode(value='123.5') + assert ast_from_value(123.5, GraphQLFloat) == FloatValueNode(value="123.5") - assert ast_from_value( - 1e4, GraphQLFloat) == FloatValueNode(value='10000') + assert ast_from_value(1e4, GraphQLFloat) == FloatValueNode(value="10000") - assert ast_from_value( - 1e40, GraphQLFloat) == FloatValueNode(value='1e+40') + assert ast_from_value(1e40, GraphQLFloat) == FloatValueNode(value="1e+40") def converts_string_values_to_string_asts(): - assert ast_from_value( - 'hello', GraphQLString) == StringValueNode(value='hello') + assert ast_from_value("hello", GraphQLString) == StringValueNode(value="hello") - assert ast_from_value( - 'VALUE', GraphQLString) == StringValueNode(value='VALUE') + assert ast_from_value("VALUE", GraphQLString) == StringValueNode(value="VALUE") - assert ast_from_value( - 'VA\nLUE', GraphQLString) == StringValueNode(value='VA\nLUE') + assert ast_from_value("VA\nLUE", GraphQLString) == StringValueNode( + value="VA\nLUE" + ) - assert ast_from_value( - 123, GraphQLString) == StringValueNode(value='123') + assert ast_from_value(123, GraphQLString) == StringValueNode(value="123") - assert ast_from_value( - False, GraphQLString) == StringValueNode(value='false') + assert ast_from_value(False, GraphQLString) == StringValueNode(value="false") assert ast_from_value(None, GraphQLString) == NullValueNode() assert ast_from_value(INVALID, GraphQLString) is None def converts_id_values_to_int_or_string_asts(): - assert ast_from_value( - 'hello', GraphQLID) == StringValueNode(value='hello') + assert ast_from_value("hello", GraphQLID) == StringValueNode(value="hello") - assert ast_from_value( - 'VALUE', GraphQLID) == StringValueNode(value='VALUE') + assert ast_from_value("VALUE", GraphQLID) == StringValueNode(value="VALUE") # Note: EnumValues cannot contain non-identifier characters - assert ast_from_value( - 'VA\nLUE', GraphQLID) == StringValueNode(value='VA\nLUE') + assert ast_from_value("VA\nLUE", GraphQLID) == StringValueNode(value="VA\nLUE") # Note: IntValues are used when possible. - assert ast_from_value(-1, GraphQLID) == IntValueNode(value='-1') + assert ast_from_value(-1, GraphQLID) == IntValueNode(value="-1") - assert ast_from_value(123, GraphQLID) == IntValueNode(value='123') + assert ast_from_value(123, GraphQLID) == IntValueNode(value="123") - assert ast_from_value('123', GraphQLID) == IntValueNode(value='123') + assert ast_from_value("123", GraphQLID) == IntValueNode(value="123") - assert ast_from_value('01', GraphQLID) == StringValueNode(value='01') + assert ast_from_value("01", GraphQLID) == StringValueNode(value="01") with raises(TypeError) as exc_info: assert ast_from_value(False, GraphQLID) - assert str(exc_info.value) == 'ID cannot represent value: False' + assert str(exc_info.value) == "ID cannot represent value: False" assert ast_from_value(None, GraphQLID) == NullValueNode() @@ -128,55 +127,64 @@ def does_not_convert_non_null_values_to_null_value(): non_null_boolean = GraphQLNonNull(GraphQLBoolean) assert ast_from_value(None, non_null_boolean) is None - complex_value = {'someArbitrary': 'complexValue'} + complex_value = {"someArbitrary": "complexValue"} - my_enum = GraphQLEnumType('MyEnum', { - 'HELLO': None, 'GOODBYE': None, 'COMPLEX': complex_value}) + my_enum = GraphQLEnumType( + "MyEnum", {"HELLO": None, "GOODBYE": None, "COMPLEX": complex_value} + ) def converts_string_values_to_enum_asts_if_possible(): - assert ast_from_value('HELLO', my_enum) == EnumValueNode(value='HELLO') + assert ast_from_value("HELLO", my_enum) == EnumValueNode(value="HELLO") - assert ast_from_value( - complex_value, my_enum) == EnumValueNode(value='COMPLEX') + assert ast_from_value(complex_value, my_enum) == EnumValueNode(value="COMPLEX") # Note: case sensitive - assert ast_from_value('hello', my_enum) is None + assert ast_from_value("hello", my_enum) is None # Note: not a valid enum value - assert ast_from_value('VALUE', my_enum) is None + assert ast_from_value("VALUE", my_enum) is None def converts_list_values_to_list_asts(): assert ast_from_value( - ['FOO', 'BAR'], GraphQLList(GraphQLString) - ) == ListValueNode(values=[ - StringValueNode(value='FOO'), StringValueNode(value='BAR')]) + ["FOO", "BAR"], GraphQLList(GraphQLString) + ) == ListValueNode( + values=[StringValueNode(value="FOO"), StringValueNode(value="BAR")] + ) assert ast_from_value( - ['HELLO', 'GOODBYE'], GraphQLList(my_enum) - ) == ListValueNode(values=[ - EnumValueNode(value='HELLO'), EnumValueNode(value='GOODBYE')]) + ["HELLO", "GOODBYE"], GraphQLList(my_enum) + ) == ListValueNode( + values=[EnumValueNode(value="HELLO"), EnumValueNode(value="GOODBYE")] + ) def converts_list_singletons(): - assert ast_from_value( - 'FOO', GraphQLList(GraphQLString)) == StringValueNode(value='FOO') + assert ast_from_value("FOO", GraphQLList(GraphQLString)) == StringValueNode( + value="FOO" + ) def converts_input_objects(): - input_obj = GraphQLInputObjectType('MyInputObj', { - 'foo': GraphQLInputField(GraphQLFloat), - 'bar': GraphQLInputField(my_enum)}) - - assert ast_from_value( - {'foo': 3, 'bar': 'HELLO'}, input_obj) == ObjectValueNode(fields=[ - ObjectFieldNode(name=NameNode(value='foo'), - value=FloatValueNode(value='3')), - ObjectFieldNode(name=NameNode(value='bar'), - value=EnumValueNode(value='HELLO'))]) + input_obj = GraphQLInputObjectType( + "MyInputObj", + {"foo": GraphQLInputField(GraphQLFloat), "bar": GraphQLInputField(my_enum)}, + ) + + assert ast_from_value({"foo": 3, "bar": "HELLO"}, input_obj) == ObjectValueNode( + fields=[ + ObjectFieldNode( + name=NameNode(value="foo"), value=FloatValueNode(value="3") + ), + ObjectFieldNode( + name=NameNode(value="bar"), value=EnumValueNode(value="HELLO") + ), + ] + ) def converts_input_objects_with_explicit_nulls(): - input_obj = GraphQLInputObjectType('MyInputObj', { - 'foo': GraphQLInputField(GraphQLFloat), - 'bar': GraphQLInputField(my_enum)}) - - assert ast_from_value({'foo': None}, input_obj) == ObjectValueNode( - fields=[ObjectFieldNode( - name=NameNode(value='foo'), value=NullValueNode())]) + input_obj = GraphQLInputObjectType( + "MyInputObj", + {"foo": GraphQLInputField(GraphQLFloat), "bar": GraphQLInputField(my_enum)}, + ) + + assert ast_from_value({"foo": None}, input_obj) == ObjectValueNode( + fields=[ObjectFieldNode(name=NameNode(value="foo"), value=NullValueNode())] + ) diff --git a/tests/utilities/test_build_ast_schema.py b/tests/utilities/test_build_ast_schema.py index e5f995fe..8aa77604 100644 --- a/tests/utilities/test_build_ast_schema.py +++ b/tests/utilities/test_build_ast_schema.py @@ -6,9 +6,15 @@ from graphql import graphql_sync from graphql.language import parse, print_ast, DocumentNode from graphql.type import ( - GraphQLDeprecatedDirective, GraphQLIncludeDirective, - GraphQLSkipDirective, GraphQLEnumType, GraphQLObjectType, - GraphQLInputObjectType, GraphQLInterfaceType, validate_schema) + GraphQLDeprecatedDirective, + GraphQLIncludeDirective, + GraphQLSkipDirective, + GraphQLEnumType, + GraphQLObjectType, + GraphQLInputObjectType, + GraphQLInterfaceType, + validate_schema, +) from graphql.pyutils import dedent from graphql.utilities import build_ast_schema, build_schema, print_schema @@ -26,36 +32,44 @@ def cycle_output(body: str) -> str: def describe_schema_builder(): - def can_use_built_schema_for_limited_execution(): - schema = build_ast_schema(parse(""" + schema = build_ast_schema( + parse( + """ type Query { str: String } - """)) + """ + ) + ) - data = namedtuple('Data', 'str')(123) + data = namedtuple("Data", "str")(123) - result = graphql_sync(schema, '{ str }', data) - assert result == ({'str': '123'}, None) + result = graphql_sync(schema, "{ str }", data) + assert result == ({"str": "123"}, None) def can_build_a_schema_directly_from_the_source(): - schema = build_schema(""" + schema = build_schema( + """ type Query { add(x: Int, y: Int): Int } - """) + """ + ) # noinspection PyMethodMayBeStatic class Root: def add(self, _info, x, y): return x + y - assert graphql_sync(schema, '{ add(x: 34, y: 55) }', Root()) == ( - {'add': 89}, None) + assert graphql_sync(schema, "{ add(x: 34, y: 55) }", Root()) == ( + {"add": 89}, + None, + ) def simple_type(): - body = dedent(""" + body = dedent( + """ type Query { str: String int: Int @@ -63,23 +77,27 @@ def simple_type(): id: ID bool: Boolean } - """) + """ + ) output = cycle_output(body) assert output == body def with_directives(): - body = dedent(""" + body = dedent( + """ directive @foo(arg: Int) on FIELD type Query { str: String } - """) + """ + ) output = cycle_output(body) assert output == body def supports_descriptions(): - body = dedent(''' + body = dedent( + ''' """This is a directive""" directive @foo( """It has an argument""" @@ -100,24 +118,28 @@ def supports_descriptions(): """And a field to boot""" str: String } - ''') + ''' + ) output = cycle_output(body) assert output == body def maintains_skip_and_include_directives(): - body = dedent(""" + body = dedent( + """ type Query { str: String } - """) + """ + ) schema = build_ast_schema(parse(body)) assert len(schema.directives) == 3 - assert schema.get_directive('skip') is GraphQLSkipDirective - assert schema.get_directive('include') is GraphQLIncludeDirective - assert schema.get_directive('deprecated') is GraphQLDeprecatedDirective + assert schema.get_directive("skip") is GraphQLSkipDirective + assert schema.get_directive("include") is GraphQLIncludeDirective + assert schema.get_directive("deprecated") is GraphQLDeprecatedDirective def overriding_directives_excludes_specified(): - body = dedent(""" + body = dedent( + """ directive @skip on FIELD directive @include on FIELD directive @deprecated on FIELD_DEFINITION @@ -125,49 +147,55 @@ def overriding_directives_excludes_specified(): type Query { str: String } - """) + """ + ) schema = build_ast_schema(parse(body)) assert len(schema.directives) == 3 get_directive = schema.get_directive - assert get_directive('skip') is not GraphQLSkipDirective - assert get_directive('skip') is not None - assert get_directive('include') is not GraphQLIncludeDirective - assert get_directive('include') is not None - assert get_directive('deprecated') is not GraphQLDeprecatedDirective - assert get_directive('deprecated') is not None + assert get_directive("skip") is not GraphQLSkipDirective + assert get_directive("skip") is not None + assert get_directive("include") is not GraphQLIncludeDirective + assert get_directive("include") is not None + assert get_directive("deprecated") is not GraphQLDeprecatedDirective + assert get_directive("deprecated") is not None def overriding_skip_directive_excludes_built_in_one(): - body = dedent(""" + body = dedent( + """ directive @skip on FIELD type Query { str: String } - """) + """ + ) schema = build_ast_schema(parse(body)) assert len(schema.directives) == 3 - assert schema.get_directive('skip') is not GraphQLSkipDirective - assert schema.get_directive('skip') is not None - assert schema.get_directive('include') is GraphQLIncludeDirective - assert schema.get_directive('deprecated') is GraphQLDeprecatedDirective + assert schema.get_directive("skip") is not GraphQLSkipDirective + assert schema.get_directive("skip") is not None + assert schema.get_directive("include") is GraphQLIncludeDirective + assert schema.get_directive("deprecated") is GraphQLDeprecatedDirective def adding_directives_maintains_skip_and_include_directives(): - body = dedent(""" + body = dedent( + """ directive @foo(arg: Int) on FIELD type Query { str: String } - """) + """ + ) schema = build_ast_schema(parse(body)) assert len(schema.directives) == 4 - assert schema.get_directive('skip') is GraphQLSkipDirective - assert schema.get_directive('include') is GraphQLIncludeDirective - assert schema.get_directive('deprecated') is GraphQLDeprecatedDirective - assert schema.get_directive('foo') is not None + assert schema.get_directive("skip") is GraphQLSkipDirective + assert schema.get_directive("include") is GraphQLIncludeDirective + assert schema.get_directive("deprecated") is GraphQLDeprecatedDirective + assert schema.get_directive("foo") is not None def type_modifiers(): - body = dedent(""" + body = dedent( + """ type Query { nonNullStr: String! listOfStrs: [String] @@ -175,22 +203,26 @@ def type_modifiers(): nonNullListOfStrs: [String]! nonNullListOfNonNullStrs: [String!]! } - """) + """ + ) output = cycle_output(body) assert output == body def recursive_type(): - body = dedent(""" + body = dedent( + """ type Query { str: String recurse: Query } - """) + """ + ) output = cycle_output(body) assert output == body def two_types_circular(): - body = dedent(""" + body = dedent( + """ schema { query: TypeOne } @@ -204,12 +236,14 @@ def two_types_circular(): str: String typeOne: TypeOne } - """) + """ + ) output = cycle_output(body) assert output == body def single_argument_field(): - body = dedent(""" + body = dedent( + """ type Query { str(int: Int): String floatToStr(float: Float): String @@ -217,21 +251,25 @@ def single_argument_field(): booleanToStr(bool: Boolean): String strToStr(bool: String): String } - """) + """ + ) output = cycle_output(body) assert output == body def simple_type_with_multiple_arguments(): - body = dedent(""" + body = dedent( + """ type Query { str(int: Int, bool: Boolean): String } - """) + """ + ) output = cycle_output(body) assert output == body def simple_type_with_interface(): - body = dedent(""" + body = dedent( + """ type Query implements WorldInterface { str: String } @@ -239,12 +277,14 @@ def simple_type_with_interface(): interface WorldInterface { str: String } - """) + """ + ) output = cycle_output(body) assert output == body def simple_output_enum(): - body = dedent(""" + body = dedent( + """ enum Hello { WORLD } @@ -252,12 +292,14 @@ def simple_output_enum(): type Query { hello: Hello } - """) + """ + ) output = cycle_output(body) assert output == body def simple_input_enum(): - body = dedent(""" + body = dedent( + """ enum Hello { WORLD } @@ -265,12 +307,14 @@ def simple_input_enum(): type Query { str(hello: Hello): String } - """) + """ + ) output = cycle_output(body) assert output == body def multiple_value_enum(): - body = dedent(""" + body = dedent( + """ enum Hello { WO RLD @@ -279,12 +323,14 @@ def multiple_value_enum(): type Query { hello: Hello } - """) + """ + ) output = cycle_output(body) assert output == body def simple_union(): - body = dedent(""" + body = dedent( + """ union Hello = World type Query { @@ -294,12 +340,14 @@ def simple_union(): type World { str: String } - """) + """ + ) output = cycle_output(body) assert output == body def multiple_union(): - body = dedent(""" + body = dedent( + """ union Hello = WorldOne | WorldTwo type Query { @@ -313,25 +361,29 @@ def multiple_union(): type WorldTwo { str: String } - """) + """ + ) output = cycle_output(body) assert output == body def can_build_recursive_union(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: - build_schema(""" + build_schema( + """ union Hello = Hello type Query { hello: Hello } - """) + """ + ) msg = str(exc_info.value) - assert msg == 'Hello types must be GraphQLObjectType objects.' + assert msg == "Hello types must be GraphQLObjectType objects." def specifying_union_type_using_typename(): - schema = build_schema(""" + schema = build_schema( + """ type Query { fruits: [Fruit] } @@ -345,7 +397,8 @@ def specifying_union_type_using_typename(): type Banana { length: Int } - """) + """ + ) query = """ { @@ -361,20 +414,20 @@ def specifying_union_type_using_typename(): """ root = { - 'fruits': [{ - 'color': 'green', - '__typename': 'Apple' - }, { - 'length': 5, - '__typename': 'Banana' - }] + "fruits": [ + {"color": "green", "__typename": "Apple"}, + {"length": 5, "__typename": "Banana"}, + ] } - assert graphql_sync(schema, query, root) == ({ - 'fruits': [{'color': 'green'}, {'length': 5}]}, None) + assert graphql_sync(schema, query, root) == ( + {"fruits": [{"color": "green"}, {"length": 5}]}, + None, + ) def specifying_interface_type_using_typename(): - schema = build_schema(""" + schema = build_schema( + """ type Query { characters: [Character] } @@ -392,7 +445,8 @@ def specifying_interface_type_using_typename(): name: String! primaryFunction: String } - """) + """ + ) query = """ { @@ -409,40 +463,42 @@ def specifying_interface_type_using_typename(): """ root = { - 'characters': [{ - 'name': 'Han Solo', - 'totalCredits': 10, - '__typename': 'Human' - }, { - 'name': 'R2-D2', - 'primaryFunction': 'Astromech', - '__typename': 'Droid' - }] + "characters": [ + {"name": "Han Solo", "totalCredits": 10, "__typename": "Human"}, + { + "name": "R2-D2", + "primaryFunction": "Astromech", + "__typename": "Droid", + }, + ] } - assert graphql_sync(schema, query, root) == ({ - 'characters': [{ - 'name': 'Han Solo', - 'totalCredits': 10 - }, { - 'name': 'R2-D2', - 'primaryFunction': 'Astromech' - }] - }, None) + assert graphql_sync(schema, query, root) == ( + { + "characters": [ + {"name": "Han Solo", "totalCredits": 10}, + {"name": "R2-D2", "primaryFunction": "Astromech"}, + ] + }, + None, + ) def custom_scalar(): - body = dedent(""" + body = dedent( + """ scalar CustomScalar type Query { customScalar: CustomScalar } - """) + """ + ) output = cycle_output(body) assert output == body def input_object(): - body = dedent(""" + body = dedent( + """ input Input { int: Int } @@ -450,32 +506,38 @@ def input_object(): type Query { field(in: Input): String } - """) + """ + ) output = cycle_output(body) assert output == body def simple_argument_field_with_default(): - body = dedent(""" + body = dedent( + """ type Query { str(int: Int = 2): String } - """) + """ + ) output = cycle_output(body) assert output == body def custom_scalar_argument_field_with_default(): - body = dedent(""" + body = dedent( + """ scalar CustomScalar type Query { str(int: CustomScalar = 2): String } - """) + """ + ) output = cycle_output(body) assert output == body def simple_type_with_mutation(): - body = dedent(""" + body = dedent( + """ schema { query: HelloScalars mutation: Mutation @@ -490,12 +552,14 @@ def simple_type_with_mutation(): type Mutation { addHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars } - """) # noqa + """ + ) # noqa output = cycle_output(body) assert output == body def simple_type_with_subscription(): - body = dedent(""" + body = dedent( + """ schema { query: HelloScalars subscription: Subscription @@ -510,12 +574,14 @@ def simple_type_with_subscription(): type Subscription { subscribeHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars } - """) # noqa + """ + ) # noqa output = cycle_output(body) assert output == body def unreferenced_type_implementing_referenced_interface(): - body = dedent(""" + body = dedent( + """ type Concrete implements Iface { key: String } @@ -527,12 +593,14 @@ def unreferenced_type_implementing_referenced_interface(): type Query { iface: Iface } - """) + """ + ) output = cycle_output(body) assert output == body def unreferenced_type_implementing_referenced_union(): - body = dedent(""" + body = dedent( + """ type Concrete { key: String } @@ -542,12 +610,14 @@ def unreferenced_type_implementing_referenced_union(): } union Union = Concrete - """) + """ + ) output = cycle_output(body) assert output == body def supports_deprecated_directive(): - body = dedent(""" + body = dedent( + """ enum MyEnum { VALUE OLD_VALUE @deprecated @@ -559,37 +629,40 @@ def supports_deprecated_directive(): field2: Int @deprecated(reason: "Because I said so") enum: MyEnum } - """) + """ + ) output = cycle_output(body) assert output == body ast = parse(body) schema = build_ast_schema(ast) - my_enum = schema.get_type('MyEnum') + my_enum = schema.get_type("MyEnum") my_enum = cast(GraphQLEnumType, my_enum) - value = my_enum.values['VALUE'] + value = my_enum.values["VALUE"] assert value.is_deprecated is False - old_value = my_enum.values['OLD_VALUE'] + old_value = my_enum.values["OLD_VALUE"] assert old_value.is_deprecated is True - assert old_value.deprecation_reason == 'No longer supported' + assert old_value.deprecation_reason == "No longer supported" - other_value = my_enum.values['OTHER_VALUE'] + other_value = my_enum.values["OTHER_VALUE"] assert other_value.is_deprecated is True - assert other_value.deprecation_reason == 'Terrible reasons' + assert other_value.deprecation_reason == "Terrible reasons" - root_fields = schema.get_type('Query').fields - field1 = root_fields['field1'] + root_fields = schema.get_type("Query").fields + field1 = root_fields["field1"] assert field1.is_deprecated is True - assert field1.deprecation_reason == 'No longer supported' - field2 = root_fields['field2'] + assert field1.deprecation_reason == "No longer supported" + field2 = root_fields["field2"] assert field2.is_deprecated is True - assert field2.deprecation_reason == 'Because I said so' + assert field2.deprecation_reason == "Because I said so" def correctly_assign_ast_nodes(): - schema_ast = parse(dedent(""" + schema_ast = parse( + dedent( + """ schema { query: Query } @@ -624,50 +697,56 @@ def correctly_assign_ast_nodes(): scalar TestScalar directive @test(arg: TestScalar) on FIELD - """)) + """ + ) + ) schema = build_ast_schema(schema_ast) - query = schema.get_type('Query') + query = schema.get_type("Query") query = cast(GraphQLObjectType, query) - test_input = schema.get_type('TestInput') + test_input = schema.get_type("TestInput") test_input = cast(GraphQLInputObjectType, test_input) - test_enum = schema.get_type('TestEnum') + test_enum = schema.get_type("TestEnum") test_enum = cast(GraphQLEnumType, test_enum) - test_union = schema.get_type('TestUnion') - test_interface = schema.get_type('TestInterface') + test_union = schema.get_type("TestUnion") + test_interface = schema.get_type("TestInterface") test_interface = cast(GraphQLInterfaceType, test_interface) - test_type = schema.get_type('TestType') - test_scalar = schema.get_type('TestScalar') - test_directive = schema.get_directive('test') - - restored_schema_ast = DocumentNode(definitions=[ - schema.ast_node, - query.ast_node, - test_input.ast_node, - test_enum.ast_node, - test_union.ast_node, - test_interface.ast_node, - test_type.ast_node, - test_scalar.ast_node, - test_directive.ast_node - ]) + test_type = schema.get_type("TestType") + test_scalar = schema.get_type("TestScalar") + test_directive = schema.get_directive("test") + + restored_schema_ast = DocumentNode( + definitions=[ + schema.ast_node, + query.ast_node, + test_input.ast_node, + test_enum.ast_node, + test_union.ast_node, + test_interface.ast_node, + test_type.ast_node, + test_scalar.ast_node, + test_directive.ast_node, + ] + ) assert print_ast(restored_schema_ast) == print_ast(schema_ast) - test_field = query.fields['testField'] + test_field = query.fields["testField"] assert print_ast(test_field.ast_node) == ( - 'testField(testArg: TestInput): TestUnion') - assert print_ast(test_field.args['testArg'].ast_node) == ( - 'testArg: TestInput') - assert print_ast(test_input.fields['testInputField'].ast_node) == ( - 'testInputField: TestEnum') - assert print_ast(test_enum.values['TEST_VALUE'].ast_node) == ( - 'TEST_VALUE') - assert print_ast(test_interface.fields['interfaceField'].ast_node) == ( - 'interfaceField: String') - assert print_ast(test_directive.args['arg'].ast_node) == ( - 'arg: TestScalar') + "testField(testArg: TestInput): TestUnion" + ) + assert print_ast(test_field.args["testArg"].ast_node) == ("testArg: TestInput") + assert print_ast(test_input.fields["testInputField"].ast_node) == ( + "testInputField: TestEnum" + ) + assert print_ast(test_enum.values["TEST_VALUE"].ast_node) == ("TEST_VALUE") + assert print_ast(test_interface.fields["interfaceField"].ast_node) == ( + "interfaceField: String" + ) + assert print_ast(test_directive.args["arg"].ast_node) == ("arg: TestScalar") def root_operation_type_with_custom_names(): - schema = build_schema(dedent(""" + schema = build_schema( + dedent( + """ schema { query: SomeQuery mutation: SomeMutation @@ -676,39 +755,51 @@ def root_operation_type_with_custom_names(): type SomeQuery { str: String } type SomeMutation { str: String } type SomeSubscription { str: String } - """)) + """ + ) + ) - assert schema.query_type.name == 'SomeQuery' - assert schema.mutation_type.name == 'SomeMutation' - assert schema.subscription_type.name == 'SomeSubscription' + assert schema.query_type.name == "SomeQuery" + assert schema.mutation_type.name == "SomeMutation" + assert schema.subscription_type.name == "SomeSubscription" def default_root_operation_type_names(): - schema = build_schema(dedent(""" + schema = build_schema( + dedent( + """ type Query { str: String } type Mutation { str: String } type Subscription { str: String } - """)) + """ + ) + ) - assert schema.query_type.name == 'Query' - assert schema.mutation_type.name == 'Mutation' - assert schema.subscription_type.name == 'Subscription' + assert schema.query_type.name == "Query" + assert schema.mutation_type.name == "Mutation" + assert schema.subscription_type.name == "Subscription" def can_build_invalid_schema(): - schema = build_schema(dedent(""" + schema = build_schema( + dedent( + """ # Invalid schema, because it is missing query root type type Mutation { str: String } - """)) + """ + ) + ) errors = validate_schema(schema) assert errors def rejects_invalid_sdl(): - doc = parse(""" + doc = parse( + """ type Query { foo: String @unknown } - """) + """ + ) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) @@ -725,9 +816,9 @@ def allows_to_disable_sdl_validation(): def describe_failures(): - def allows_only_a_single_query_type(): - body = dedent(""" + body = dedent( + """ schema { query: Hello query: Yellow @@ -740,15 +831,17 @@ def allows_only_a_single_query_type(): type Yellow { isColor: Boolean } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) - assert msg == 'Must provide only one query type in schema.' + assert msg == "Must provide only one query type in schema." def allows_only_a_single_mutation_type(): - body = dedent(""" + body = dedent( + """ schema { query: Hello mutation: Hello @@ -762,15 +855,17 @@ def allows_only_a_single_mutation_type(): type Yellow { isColor: Boolean } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) - assert msg == 'Must provide only one mutation type in schema.' + assert msg == "Must provide only one mutation type in schema." def allows_only_a_single_subscription_type(): - body = dedent(""" + body = dedent( + """ schema { query: Hello subscription: Hello @@ -783,15 +878,17 @@ def allows_only_a_single_subscription_type(): type Yellow { isColor: Boolean } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) - assert msg == 'Must provide only one subscription type in schema.' + assert msg == "Must provide only one subscription type in schema." def unknown_type_referenced(): - body = dedent(""" + body = dedent( + """ schema { query: Hello } @@ -799,7 +896,8 @@ def unknown_type_referenced(): type Hello { bar: Bar } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) @@ -807,11 +905,13 @@ def unknown_type_referenced(): assert "Type 'Bar' not found in document." in msg def unknown_type_in_interface_list(): - body = dedent(""" + body = dedent( + """ type Query implements Bar { field: String } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) @@ -819,10 +919,12 @@ def unknown_type_in_interface_list(): assert "Type 'Bar' not found in document." in msg def unknown_type_in_union_list(): - body = dedent(""" + body = dedent( + """ union TestUnion = Bar type Query { testUnion: TestUnion } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) @@ -830,7 +932,8 @@ def unknown_type_in_union_list(): assert "Type 'Bar' not found in document." in msg def unknown_query_type(): - body = dedent(""" + body = dedent( + """ schema { query: Wat } @@ -838,7 +941,8 @@ def unknown_query_type(): type Hello { str: String } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) @@ -846,7 +950,8 @@ def unknown_query_type(): assert msg == "Specified query type 'Wat' not found in document." def unknown_mutation_type(): - body = dedent(""" + body = dedent( + """ schema { query: Hello mutation: Wat @@ -855,7 +960,8 @@ def unknown_mutation_type(): type Hello { str: String } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) @@ -863,7 +969,8 @@ def unknown_mutation_type(): assert msg == "Specified mutation type 'Wat' not found in document." def unknown_subscription_type(): - body = dedent(""" + body = dedent( + """ schema { query: Hello mutation: Wat @@ -877,22 +984,24 @@ def unknown_subscription_type(): type Wat { str: String } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) msg = str(exc_info.value) - assert msg == ( - "Specified subscription type 'Awesome' not found in document.") + assert msg == ("Specified subscription type 'Awesome' not found in document.") def does_not_consider_directive_names(): - body = dedent(""" + body = dedent( + """ schema { query: Foo } directive @ Foo on QUERY - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) @@ -900,7 +1009,8 @@ def does_not_consider_directive_names(): assert msg == "Specified query type 'Foo' not found in document." def does_not_consider_operation_names(): - body = dedent(""" + body = dedent( + """ schema { query: Foo } @@ -908,7 +1018,8 @@ def does_not_consider_operation_names(): type Hello { str: String } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) @@ -916,13 +1027,15 @@ def does_not_consider_operation_names(): assert msg == "Specified query type 'Foo' not found in document." def does_not_consider_fragment_names(): - body = dedent(""" + body = dedent( + """ schema { query: Foo } fragment Foo on Type { field } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) @@ -930,7 +1043,8 @@ def does_not_consider_fragment_names(): assert msg == "Specified query type 'Foo' not found in document." def forbids_duplicate_type_definitions(): - body = dedent(""" + body = dedent( + """ schema { query: Repeated } @@ -942,7 +1056,8 @@ def forbids_duplicate_type_definitions(): type Repeated { id: String } - """) + """ + ) doc = parse(body) with raises(TypeError) as exc_info: build_ast_schema(doc) diff --git a/tests/utilities/test_build_client_schema.py b/tests/utilities/test_build_client_schema.py index 0074b94e..b20a837b 100644 --- a/tests/utilities/test_build_client_schema.py +++ b/tests/utilities/test_build_client_schema.py @@ -3,11 +3,26 @@ from graphql import graphql_sync from graphql.language import DirectiveLocation from graphql.type import ( - GraphQLArgument, GraphQLBoolean, GraphQLDirective, GraphQLEnumType, - GraphQLEnumValue, GraphQLField, GraphQLFloat, GraphQLID, - GraphQLInputField, GraphQLInputObjectType, GraphQLInt, - GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLScalarType, GraphQLSchema, GraphQLString, GraphQLUnionType) + GraphQLArgument, + GraphQLBoolean, + GraphQLDirective, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLFloat, + GraphQLID, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInt, + GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLScalarType, + GraphQLSchema, + GraphQLString, + GraphQLUnionType, +) from graphql.utilities import build_client_schema, introspection_from_schema @@ -27,45 +42,72 @@ def check_schema(server_schema): def describe_type_system_build_schema_from_introspection(): - def builds_a_simple_schema(): - schema = GraphQLSchema(GraphQLObjectType('Simple', { - 'string': GraphQLField( - GraphQLString, description='This is a string field')}, - description='This is a simple type')) + schema = GraphQLSchema( + GraphQLObjectType( + "Simple", + { + "string": GraphQLField( + GraphQLString, description="This is a string field" + ) + }, + description="This is a simple type", + ) + ) check_schema(schema) def builds_a_simple_schema_with_all_operation_types(): - query_type = GraphQLObjectType('QueryType', { - 'string': GraphQLField( - GraphQLString, description='This is a string field.')}, - description='This is a simple query type') - - mutation_type = GraphQLObjectType('MutationType', { - 'setString': GraphQLField( - GraphQLString, description='Set the string field', args={ - 'value': GraphQLArgument(GraphQLString)})}, - description='This is a simple mutation type') - - subscription_type = GraphQLObjectType('SubscriptionType', { - 'string': GraphQLField( - GraphQLString, description='This is a string field')}, - description='This is a simple subscription type') + query_type = GraphQLObjectType( + "QueryType", + { + "string": GraphQLField( + GraphQLString, description="This is a string field." + ) + }, + description="This is a simple query type", + ) + + mutation_type = GraphQLObjectType( + "MutationType", + { + "setString": GraphQLField( + GraphQLString, + description="Set the string field", + args={"value": GraphQLArgument(GraphQLString)}, + ) + }, + description="This is a simple mutation type", + ) + + subscription_type = GraphQLObjectType( + "SubscriptionType", + { + "string": GraphQLField( + GraphQLString, description="This is a string field" + ) + }, + description="This is a simple subscription type", + ) schema = GraphQLSchema(query_type, mutation_type, subscription_type) check_schema(schema) def uses_built_in_scalars_when_possible(): - custom_scalar = GraphQLScalarType( - 'CustomScalar', serialize=lambda: None) + custom_scalar = GraphQLScalarType("CustomScalar", serialize=lambda: None) - schema = GraphQLSchema(GraphQLObjectType('Scalars', { - 'int': GraphQLField(GraphQLInt), - 'float': GraphQLField(GraphQLFloat), - 'string': GraphQLField(GraphQLString), - 'boolean': GraphQLField(GraphQLBoolean), - 'id': GraphQLField(GraphQLID), - 'custom': GraphQLField(custom_scalar)})) + schema = GraphQLSchema( + GraphQLObjectType( + "Scalars", + { + "int": GraphQLField(GraphQLInt), + "float": GraphQLField(GraphQLFloat), + "string": GraphQLField(GraphQLString), + "boolean": GraphQLField(GraphQLBoolean), + "id": GraphQLField(GraphQLID), + "custom": GraphQLField(custom_scalar), + }, + ) + ) check_schema(schema) @@ -73,151 +115,227 @@ def uses_built_in_scalars_when_possible(): client_schema = build_client_schema(introspection) # Built-ins are used - assert client_schema.get_type('Int') is GraphQLInt - assert client_schema.get_type('Float') is GraphQLFloat - assert client_schema.get_type('String') is GraphQLString - assert client_schema.get_type('Boolean') is GraphQLBoolean - assert client_schema.get_type('ID') is GraphQLID + assert client_schema.get_type("Int") is GraphQLInt + assert client_schema.get_type("Float") is GraphQLFloat + assert client_schema.get_type("String") is GraphQLString + assert client_schema.get_type("Boolean") is GraphQLBoolean + assert client_schema.get_type("ID") is GraphQLID # Custom are built - assert client_schema.get_type('CustomScalar') is not custom_scalar + assert client_schema.get_type("CustomScalar") is not custom_scalar def builds_a_schema_with_a_recursive_type_reference(): recur_type = GraphQLObjectType( - 'Recur', lambda: {'recur': GraphQLField(recur_type)}) + "Recur", lambda: {"recur": GraphQLField(recur_type)} + ) schema = GraphQLSchema(recur_type) check_schema(schema) def builds_a_schema_with_a_circular_type_reference(): dog_type = GraphQLObjectType( - 'Dog', lambda: {'bestFriend': GraphQLField(human_type)}) + "Dog", lambda: {"bestFriend": GraphQLField(human_type)} + ) human_type = GraphQLObjectType( - 'Human', lambda: {'bestFriend': GraphQLField(dog_type)}) - schema = GraphQLSchema(GraphQLObjectType('Circular', { - 'dog': GraphQLField(dog_type), - 'human': GraphQLField(human_type)})) + "Human", lambda: {"bestFriend": GraphQLField(dog_type)} + ) + schema = GraphQLSchema( + GraphQLObjectType( + "Circular", + {"dog": GraphQLField(dog_type), "human": GraphQLField(human_type)}, + ) + ) check_schema(schema) def builds_a_schema_with_an_interface(): - friendly_type = GraphQLInterfaceType('Friendly', lambda: { - 'bestFriend': GraphQLField( - friendly_type, - description='The best friend of this friendly thing.')}) - dog_type = GraphQLObjectType('DogType', lambda: { - 'bestFriend': GraphQLField(friendly_type)}, interfaces=[ - friendly_type]) - human_type = GraphQLObjectType('Human', lambda: { - 'bestFriend': GraphQLField(friendly_type)}, interfaces=[ - friendly_type]) + friendly_type = GraphQLInterfaceType( + "Friendly", + lambda: { + "bestFriend": GraphQLField( + friendly_type, description="The best friend of this friendly thing." + ) + }, + ) + dog_type = GraphQLObjectType( + "DogType", + lambda: {"bestFriend": GraphQLField(friendly_type)}, + interfaces=[friendly_type], + ) + human_type = GraphQLObjectType( + "Human", + lambda: {"bestFriend": GraphQLField(friendly_type)}, + interfaces=[friendly_type], + ) schema = GraphQLSchema( - GraphQLObjectType('WithInterface', { - 'friendly': GraphQLField(friendly_type)}), - types=[dog_type, human_type]) + GraphQLObjectType( + "WithInterface", {"friendly": GraphQLField(friendly_type)} + ), + types=[dog_type, human_type], + ) check_schema(schema) def builds_a_schema_with_an_implicit_interface(): - friendly_type = GraphQLInterfaceType('Friendly', lambda: { - 'bestFriend': GraphQLField( - friendly_type, - description='The best friend of this friendly thing.')}) - dog_type = GraphQLObjectType('DogType', lambda: { - 'bestFriend': GraphQLField(dog_type)}, interfaces=[friendly_type]) - schema = GraphQLSchema(GraphQLObjectType('WithInterface', { - 'dog': GraphQLField(dog_type)})) + friendly_type = GraphQLInterfaceType( + "Friendly", + lambda: { + "bestFriend": GraphQLField( + friendly_type, description="The best friend of this friendly thing." + ) + }, + ) + dog_type = GraphQLObjectType( + "DogType", + lambda: {"bestFriend": GraphQLField(dog_type)}, + interfaces=[friendly_type], + ) + schema = GraphQLSchema( + GraphQLObjectType("WithInterface", {"dog": GraphQLField(dog_type)}) + ) check_schema(schema) def builds_a_schema_with_a_union(): dog_type = GraphQLObjectType( - 'Dog', lambda: {'bestFriend': GraphQLField(friendly_type)}) + "Dog", lambda: {"bestFriend": GraphQLField(friendly_type)} + ) human_type = GraphQLObjectType( - 'Human', lambda: {'bestFriend': GraphQLField(friendly_type)}) - friendly_type = GraphQLUnionType( - 'Friendly', types=[dog_type, human_type]) - schema = GraphQLSchema(GraphQLObjectType('WithUnion', { - 'friendly': GraphQLField(friendly_type)})) + "Human", lambda: {"bestFriend": GraphQLField(friendly_type)} + ) + friendly_type = GraphQLUnionType("Friendly", types=[dog_type, human_type]) + schema = GraphQLSchema( + GraphQLObjectType("WithUnion", {"friendly": GraphQLField(friendly_type)}) + ) check_schema(schema) def builds_a_schema_with_complex_field_values(): - schema = GraphQLSchema(GraphQLObjectType('ComplexFields', { - 'string': GraphQLField(GraphQLString), - 'listOfString': GraphQLField(GraphQLList(GraphQLString)), - 'nonNullString': GraphQLField(GraphQLNonNull(GraphQLString)), - 'nonNullListOfString': GraphQLField( - GraphQLNonNull(GraphQLList(GraphQLString))), - 'nonNullListOfNonNullString': GraphQLField( - GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString))))})) + schema = GraphQLSchema( + GraphQLObjectType( + "ComplexFields", + { + "string": GraphQLField(GraphQLString), + "listOfString": GraphQLField(GraphQLList(GraphQLString)), + "nonNullString": GraphQLField(GraphQLNonNull(GraphQLString)), + "nonNullListOfString": GraphQLField( + GraphQLNonNull(GraphQLList(GraphQLString)) + ), + "nonNullListOfNonNullString": GraphQLField( + GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString))) + ), + }, + ) + ) check_schema(schema) def builds_a_schema_with_field_arguments(): - schema = GraphQLSchema(GraphQLObjectType('ArgFields', { - 'one': GraphQLField( - GraphQLString, description='A field with a single arg', args={ - 'intArg': GraphQLArgument( - GraphQLInt, description='This is an int arg')}), - 'two': GraphQLField( - GraphQLString, description='A field with two args', args={ - 'listArg': GraphQLArgument( - GraphQLList(GraphQLInt), - description='This is a list of int arg'), - 'requiredArg': GraphQLArgument( - GraphQLNonNull(GraphQLBoolean), - description='This is a required arg')})})) + schema = GraphQLSchema( + GraphQLObjectType( + "ArgFields", + { + "one": GraphQLField( + GraphQLString, + description="A field with a single arg", + args={ + "intArg": GraphQLArgument( + GraphQLInt, description="This is an int arg" + ) + }, + ), + "two": GraphQLField( + GraphQLString, + description="A field with two args", + args={ + "listArg": GraphQLArgument( + GraphQLList(GraphQLInt), + description="This is a list of int arg", + ), + "requiredArg": GraphQLArgument( + GraphQLNonNull(GraphQLBoolean), + description="This is a required arg", + ), + }, + ), + }, + ) + ) check_schema(schema) def builds_a_schema_with_default_value_on_custom_scalar_field(): - schema = GraphQLSchema(GraphQLObjectType('ArgFields', { - 'testField': GraphQLField(GraphQLString, args={ - 'testArg': GraphQLArgument(GraphQLScalarType( - 'CustomScalar', serialize=lambda value: value), - default_value='default')})})) + schema = GraphQLSchema( + GraphQLObjectType( + "ArgFields", + { + "testField": GraphQLField( + GraphQLString, + args={ + "testArg": GraphQLArgument( + GraphQLScalarType( + "CustomScalar", serialize=lambda value: value + ), + default_value="default", + ) + }, + ) + }, + ) + ) check_schema(schema) def builds_a_schema_with_an_enum(): - food_enum = GraphQLEnumType('Food', { - 'VEGETABLES': GraphQLEnumValue( - 1, description='Foods that are vegetables.'), - 'FRUITS': GraphQLEnumValue( - 2, description='Foods that are fruits.'), - 'OILS': GraphQLEnumValue( - 3, description='Foods that are oils.'), - 'DAIRY': GraphQLEnumValue( - 4, description='Foods that are dairy.'), - 'MEAT': GraphQLEnumValue( - 5, description='Foods that are meat.')}, - description='Varieties of food stuffs') - - schema = GraphQLSchema(GraphQLObjectType('EnumFields', { - 'food': GraphQLField(food_enum, args={ - 'kind': GraphQLArgument( - food_enum, description='what kind of food?')}, - description='Repeats the arg you give it')})) + food_enum = GraphQLEnumType( + "Food", + { + "VEGETABLES": GraphQLEnumValue( + 1, description="Foods that are vegetables." + ), + "FRUITS": GraphQLEnumValue(2, description="Foods that are fruits."), + "OILS": GraphQLEnumValue(3, description="Foods that are oils."), + "DAIRY": GraphQLEnumValue(4, description="Foods that are dairy."), + "MEAT": GraphQLEnumValue(5, description="Foods that are meat."), + }, + description="Varieties of food stuffs", + ) + + schema = GraphQLSchema( + GraphQLObjectType( + "EnumFields", + { + "food": GraphQLField( + food_enum, + args={ + "kind": GraphQLArgument( + food_enum, description="what kind of food?" + ) + }, + description="Repeats the arg you give it", + ) + }, + ) + ) check_schema(schema) introspection = introspection_from_schema(schema) client_schema = build_client_schema(introspection) - client_food_enum = client_schema.get_type('Food') + client_food_enum = client_schema.get_type("Food") # It's also an Enum type on the client. assert isinstance(client_food_enum, GraphQLEnumType) values = client_food_enum.values - descriptions = { - name: value.description for name, value in values.items()} + descriptions = {name: value.description for name, value in values.items()} assert descriptions == { - 'VEGETABLES': 'Foods that are vegetables.', - 'FRUITS': 'Foods that are fruits.', - 'OILS': 'Foods that are oils.', - 'DAIRY': 'Foods that are dairy.', - 'MEAT': 'Foods that are meat.'} + "VEGETABLES": "Foods that are vegetables.", + "FRUITS": "Foods that are fruits.", + "OILS": "Foods that are oils.", + "DAIRY": "Foods that are dairy.", + "MEAT": "Foods that are meat.", + } values = values.values() assert all(value.value is None for value in values) assert all(value.is_deprecated is False for value in values) @@ -225,129 +343,204 @@ def builds_a_schema_with_an_enum(): assert all(value.ast_node is None for value in values) def builds_a_schema_with_an_input_object(): - address_type = GraphQLInputObjectType('Address', { - 'street': GraphQLInputField( - GraphQLNonNull(GraphQLString), - description='What street is this address?'), - 'city': GraphQLInputField( - GraphQLNonNull(GraphQLString), - description='The city the address is within?'), - 'country': GraphQLInputField( - GraphQLString, default_value='USA', - description='The country (blank will assume USA).')}, - description='An input address') - - schema = GraphQLSchema(GraphQLObjectType('HasInputObjectFields', { - 'geocode': GraphQLField(GraphQLString, args={ - 'address': GraphQLArgument( - address_type, description='The address to lookup')}, - description='Get a geocode from an address')})) + address_type = GraphQLInputObjectType( + "Address", + { + "street": GraphQLInputField( + GraphQLNonNull(GraphQLString), + description="What street is this address?", + ), + "city": GraphQLInputField( + GraphQLNonNull(GraphQLString), + description="The city the address is within?", + ), + "country": GraphQLInputField( + GraphQLString, + default_value="USA", + description="The country (blank will assume USA).", + ), + }, + description="An input address", + ) + + schema = GraphQLSchema( + GraphQLObjectType( + "HasInputObjectFields", + { + "geocode": GraphQLField( + GraphQLString, + args={ + "address": GraphQLArgument( + address_type, description="The address to lookup" + ) + }, + description="Get a geocode from an address", + ) + }, + ) + ) check_schema(schema) def builds_a_schema_with_field_arguments_with_default_values(): - geo_type = GraphQLInputObjectType('Geo', { - 'lat': GraphQLInputField(GraphQLFloat), - 'lon': GraphQLInputField(GraphQLFloat)}) - - schema = GraphQLSchema(GraphQLObjectType('ArgFields', { - 'defaultInt': GraphQLField(GraphQLString, args={ - 'intArg': GraphQLArgument(GraphQLInt, default_value=10)}), - 'defaultList': GraphQLField(GraphQLString, args={ - 'listArg': GraphQLArgument( - GraphQLList(GraphQLInt), default_value=[1, 2, 3])}), - 'defaultObject': GraphQLField(GraphQLString, args={ - 'objArg': GraphQLArgument( - geo_type, - default_value={'lat': 37.485, 'lon': -122.148})}), - 'defaultNull': GraphQLField(GraphQLString, args={ - 'intArg': GraphQLArgument(GraphQLInt, default_value=None)}), - 'noDefaults': GraphQLField(GraphQLString, args={ - 'intArg': GraphQLArgument(GraphQLInt)})})) + geo_type = GraphQLInputObjectType( + "Geo", + { + "lat": GraphQLInputField(GraphQLFloat), + "lon": GraphQLInputField(GraphQLFloat), + }, + ) + + schema = GraphQLSchema( + GraphQLObjectType( + "ArgFields", + { + "defaultInt": GraphQLField( + GraphQLString, + args={"intArg": GraphQLArgument(GraphQLInt, default_value=10)}, + ), + "defaultList": GraphQLField( + GraphQLString, + args={ + "listArg": GraphQLArgument( + GraphQLList(GraphQLInt), default_value=[1, 2, 3] + ) + }, + ), + "defaultObject": GraphQLField( + GraphQLString, + args={ + "objArg": GraphQLArgument( + geo_type, default_value={"lat": 37.485, "lon": -122.148} + ) + }, + ), + "defaultNull": GraphQLField( + GraphQLString, + args={ + "intArg": GraphQLArgument(GraphQLInt, default_value=None) + }, + ), + "noDefaults": GraphQLField( + GraphQLString, args={"intArg": GraphQLArgument(GraphQLInt)} + ), + }, + ) + ) check_schema(schema) def builds_a_schema_with_custom_directives(): schema = GraphQLSchema( - GraphQLObjectType('Simple', { - 'string': GraphQLField( - GraphQLString, description='This is a string field')}, - description='This is a simple type'), - directives=[GraphQLDirective( - 'customDirective', [DirectiveLocation.FIELD], - description='This is a custom directive')]) + GraphQLObjectType( + "Simple", + { + "string": GraphQLField( + GraphQLString, description="This is a string field" + ) + }, + description="This is a simple type", + ), + directives=[ + GraphQLDirective( + "customDirective", + [DirectiveLocation.FIELD], + description="This is a custom directive", + ) + ], + ) check_schema(schema) def builds_a_schema_aware_of_deprecation(): - schema = GraphQLSchema(GraphQLObjectType('Simple', { - 'shinyString': GraphQLField( - GraphQLString, description='This is a shiny string field'), - 'deprecatedString': GraphQLField( - GraphQLString, description='This is a deprecated string field', - deprecation_reason='Use shinyString'), - 'color': GraphQLField( - GraphQLEnumType('Color', { - 'RED': GraphQLEnumValue(description='So rosy'), - 'GREEN': GraphQLEnumValue(description='So grassy'), - 'BLUE': GraphQLEnumValue(description='So calming'), - 'MAUVE': GraphQLEnumValue( - description='So sickening', - deprecation_reason='No longer in fashion')}))}, - description='This is a simple type')) + schema = GraphQLSchema( + GraphQLObjectType( + "Simple", + { + "shinyString": GraphQLField( + GraphQLString, description="This is a shiny string field" + ), + "deprecatedString": GraphQLField( + GraphQLString, + description="This is a deprecated string field", + deprecation_reason="Use shinyString", + ), + "color": GraphQLField( + GraphQLEnumType( + "Color", + { + "RED": GraphQLEnumValue(description="So rosy"), + "GREEN": GraphQLEnumValue(description="So grassy"), + "BLUE": GraphQLEnumValue(description="So calming"), + "MAUVE": GraphQLEnumValue( + description="So sickening", + deprecation_reason="No longer in fashion", + ), + }, + ) + ), + }, + description="This is a simple type", + ) + ) check_schema(schema) def can_use_client_schema_for_limited_execution(): - custom_scalar = GraphQLScalarType( - 'CustomScalar', serialize=lambda: None) + custom_scalar = GraphQLScalarType("CustomScalar", serialize=lambda: None) - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'foo': GraphQLField(GraphQLString, args={ - 'custom1': GraphQLArgument(custom_scalar), - 'custom2': GraphQLArgument(custom_scalar)})})) + schema = GraphQLSchema( + GraphQLObjectType( + "Query", + { + "foo": GraphQLField( + GraphQLString, + args={ + "custom1": GraphQLArgument(custom_scalar), + "custom2": GraphQLArgument(custom_scalar), + }, + ) + }, + ) + ) introspection = introspection_from_schema(schema) client_schema = build_client_schema(introspection) class Data: - foo = 'bar' - unused = 'value' + foo = "bar" + unused = "value" result = graphql_sync( client_schema, - 'query Limited($v: CustomScalar) {' - ' foo(custom1: 123, custom2: $v) }', - Data(), variable_values={'v': 'baz'}) + "query Limited($v: CustomScalar) {" " foo(custom1: 123, custom2: $v) }", + Data(), + variable_values={"v": "baz"}, + ) - assert result.data == {'foo': 'bar'} + assert result.data == {"foo": "bar"} def describe_throws_when_given_incomplete_introspection(): - def throws_when_given_empty_types(): incomplete_introspection = { - '__schema': { - 'queryType': {'name': 'QueryType'}, - 'types': [] - } + "__schema": {"queryType": {"name": "QueryType"}, "types": []} } with raises(TypeError) as exc_info: build_client_schema(incomplete_introspection) assert str(exc_info.value) == ( - 'Invalid or incomplete schema, unknown type: QueryType.' - ' Ensure that a full introspection query is used' - ' in order to build a client schema.') + "Invalid or incomplete schema, unknown type: QueryType." + " Ensure that a full introspection query is used" + " in order to build a client schema." + ) def throws_when_missing_kind(): incomplete_introspection = { - '__schema': { - 'queryType': {'name': 'QueryType'}, - 'types': [{ - 'name': 'QueryType' - }] + "__schema": { + "queryType": {"name": "QueryType"}, + "types": [{"name": "QueryType"}], } } @@ -355,26 +548,33 @@ def throws_when_missing_kind(): build_client_schema(incomplete_introspection) assert str(exc_info.value) == ( - 'Invalid or incomplete introspection result.' - ' Ensure that a full introspection query is used' - " in order to build a client schema: {'name': 'QueryType'}") + "Invalid or incomplete introspection result." + " Ensure that a full introspection query is used" + " in order to build a client schema: {'name': 'QueryType'}" + ) def throws_when_missing_interfaces(): null_interface_introspection = { - '__schema': { - 'queryType': {'name': 'QueryType'}, - 'types': [{ - 'kind': 'OBJECT', - 'name': 'QueryType', - 'fields': [{ - 'name': 'aString', - 'args': [], - 'type': { - 'kind': 'SCALAR', 'name': 'String', - 'ofType': None}, - 'isDeprecated': False - }] - }] + "__schema": { + "queryType": {"name": "QueryType"}, + "types": [ + { + "kind": "OBJECT", + "name": "QueryType", + "fields": [ + { + "name": "aString", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": None, + }, + "isDeprecated": False, + } + ], + } + ], } } @@ -382,36 +582,51 @@ def throws_when_missing_interfaces(): build_client_schema(null_interface_introspection) assert str(exc_info.value) == ( - 'Introspection result missing interfaces:' + "Introspection result missing interfaces:" " {'kind': 'OBJECT', 'name': 'QueryType'," " 'fields': [{'name': 'aString', 'args': []," " 'type': {'kind': 'SCALAR', 'name': 'String', 'ofType': None}," - " 'isDeprecated': False}]}") + " 'isDeprecated': False}]}" + ) def throws_when_missing_directive_locations(): introspection = { - '__schema': { - 'types': [], - 'directives': [{'name': 'test', 'args': []}] - } + "__schema": {"types": [], "directives": [{"name": "test", "args": []}]} } with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value) == ( - 'Introspection result missing directive locations:' - " {'name': 'test', 'args': []}") + "Introspection result missing directive locations:" + " {'name': 'test', 'args': []}" + ) def describe_very_deep_decorators_are_not_supported(): - def fails_on_very_deep_lists_more_than_7_levels(): - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'foo': GraphQLField( - GraphQLList(GraphQLList(GraphQLList(GraphQLList( - GraphQLList(GraphQLList(GraphQLList(GraphQLList( - GraphQLString)))))))))})) + schema = GraphQLSchema( + GraphQLObjectType( + "Query", + { + "foo": GraphQLField( + GraphQLList( + GraphQLList( + GraphQLList( + GraphQLList( + GraphQLList( + GraphQLList( + GraphQLList(GraphQLList(GraphQLString)) + ) + ) + ) + ) + ) + ) + ) + }, + ) + ) introspection = introspection_from_schema(schema) @@ -419,15 +634,35 @@ def fails_on_very_deep_lists_more_than_7_levels(): build_client_schema(introspection) assert str(exc_info.value) == ( - 'Query fields cannot be resolved:' - ' Decorated type deeper than introspection query.') + "Query fields cannot be resolved:" + " Decorated type deeper than introspection query." + ) def fails_on_a_very_deep_non_null_more_than_7_levels(): - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'foo': GraphQLField( - GraphQLList(GraphQLNonNull(GraphQLList(GraphQLNonNull( - GraphQLList(GraphQLNonNull(GraphQLList(GraphQLNonNull( - GraphQLString)))))))))})) + schema = GraphQLSchema( + GraphQLObjectType( + "Query", + { + "foo": GraphQLField( + GraphQLList( + GraphQLNonNull( + GraphQLList( + GraphQLNonNull( + GraphQLList( + GraphQLNonNull( + GraphQLList( + GraphQLNonNull(GraphQLString) + ) + ) + ) + ) + ) + ) + ) + ) + }, + ) + ) introspection = introspection_from_schema(schema) @@ -435,51 +670,72 @@ def fails_on_a_very_deep_non_null_more_than_7_levels(): build_client_schema(introspection) assert str(exc_info.value) == ( - 'Query fields cannot be resolved:' - ' Decorated type deeper than introspection query.') + "Query fields cannot be resolved:" + " Decorated type deeper than introspection query." + ) def succeeds_on_deep_types_less_or_equal_7_levels(): - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'foo': GraphQLField( - # e.g., fully non-null 3D matrix - GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLList( - GraphQLNonNull(GraphQLList(GraphQLNonNull( - GraphQLString))))))))})) + schema = GraphQLSchema( + GraphQLObjectType( + "Query", + { + "foo": GraphQLField( + # e.g., fully non-null 3D matrix + GraphQLNonNull( + GraphQLList( + GraphQLNonNull( + GraphQLList( + GraphQLNonNull( + GraphQLList(GraphQLNonNull(GraphQLString)) + ) + ) + ) + ) + ) + ) + }, + ) + ) introspection = introspection_from_schema(schema) build_client_schema(introspection) def describe_prevents_infinite_recursion_on_invalid_introspection(): - def recursive_interfaces(): introspection = { - '__schema': { - 'types': [{ - 'name': 'Foo', - 'kind': 'OBJECT', - 'fields': [], - 'interfaces': [{'name': 'Foo'}], - }], - }, + "__schema": { + "types": [ + { + "name": "Foo", + "kind": "OBJECT", + "fields": [], + "interfaces": [{"name": "Foo"}], + } + ] + } } with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value) == ( - 'Foo interfaces cannot be resolved: ' - 'Expected Foo to be a GraphQL Interface type.') + "Foo interfaces cannot be resolved: " + "Expected Foo to be a GraphQL Interface type." + ) def recursive_union(): introspection = { - '__schema': { - 'types': [{ - 'name': 'Foo', - 'kind': 'UNION', - 'possibleTypes': [{'name': 'Foo'}], - }], - }, + "__schema": { + "types": [ + { + "name": "Foo", + "kind": "UNION", + "possibleTypes": [{"name": "Foo"}], + } + ] + } } with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value) == ( - 'Foo types cannot be resolved: ' - 'Expected Foo to be a GraphQL Object type.') + "Foo types cannot be resolved: " + "Expected Foo to be a GraphQL Object type." + ) diff --git a/tests/utilities/test_coerce_value.py b/tests/utilities/test_coerce_value.py index ddab6d4b..da9793bc 100644 --- a/tests/utilities/test_coerce_value.py +++ b/tests/utilities/test_coerce_value.py @@ -3,8 +3,15 @@ from graphql.error import INVALID from graphql.type import ( - GraphQLEnumType, GraphQLFloat, GraphQLID, GraphQLInputField, - GraphQLInputObjectType, GraphQLInt, GraphQLNonNull, GraphQLString) + GraphQLEnumType, + GraphQLFloat, + GraphQLID, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInt, + GraphQLNonNull, + GraphQLString, +) from graphql.utilities import coerce_value from graphql.utilities.coerce_value import CoercedValue @@ -22,34 +29,31 @@ def expect_error(result: CoercedValue) -> List[str]: def describe_coerce_value(): - def describe_for_graphql_string(): - def returns_error_for_array_input_as_string(): result = coerce_value([1, 2, 3], GraphQLString) assert expect_error(result) == [ - f'Expected type String;' - ' String cannot represent a non string value: [1, 2, 3]'] + f"Expected type String;" + " String cannot represent a non string value: [1, 2, 3]" + ] def describe_for_graphql_id(): - def returns_error_for_array_input_as_string(): result = coerce_value([1, 2, 3], GraphQLID) assert expect_error(result) == [ - f'Expected type ID;' - ' ID cannot represent value: [1, 2, 3]'] + f"Expected type ID;" " ID cannot represent value: [1, 2, 3]" + ] def describe_for_graphql_int(): - def returns_value_for_integer(): result = coerce_value(1, GraphQLInt) assert expect_value(result) == 1 def returns_no_error_for_numeric_looking_string(): - result = coerce_value('1', GraphQLInt) + result = coerce_value("1", GraphQLInt) assert expect_error(result) == [ - f'Expected type Int;' - " Int cannot represent non-integer value: '1'"] + f"Expected type Int;" " Int cannot represent non-integer value: '1'" + ] def returns_value_for_negative_int_input(): result = coerce_value(-1, GraphQLInt) @@ -64,49 +68,49 @@ def returns_null_for_null_value(): assert expect_value(result) is None def returns_a_single_error_for_empty_string_as_value(): - result = coerce_value('', GraphQLInt) + result = coerce_value("", GraphQLInt) assert expect_error(result) == [ - 'Expected type Int; Int cannot represent' - " non-integer value: ''"] + "Expected type Int; Int cannot represent" " non-integer value: ''" + ] def returns_a_single_error_for_2_32_input_as_int(): result = coerce_value(1 << 32, GraphQLInt) assert expect_error(result) == [ - 'Expected type Int; Int cannot represent' - ' non 32-bit signed integer value: 4294967296'] + "Expected type Int; Int cannot represent" + " non 32-bit signed integer value: 4294967296" + ] def returns_a_single_error_for_float_input_as_int(): result = coerce_value(1.5, GraphQLInt) assert expect_error(result) == [ - 'Expected type Int;' - " Int cannot represent non-integer value: 1.5"] + "Expected type Int;" " Int cannot represent non-integer value: 1.5" + ] def returns_a_single_error_for_nan_input_as_int(): result = coerce_value(nan, GraphQLInt) assert expect_error(result) == [ - 'Expected type Int;' - ' Int cannot represent non-integer value: nan'] + "Expected type Int;" " Int cannot represent non-integer value: nan" + ] def returns_a_single_error_for_infinity_input_as_int(): result = coerce_value(inf, GraphQLInt) assert expect_error(result) == [ - 'Expected type Int;' - ' Int cannot represent non-integer value: inf'] + "Expected type Int;" " Int cannot represent non-integer value: inf" + ] def returns_a_single_error_for_char_input(): - result = coerce_value('a', GraphQLInt) + result = coerce_value("a", GraphQLInt) assert expect_error(result) == [ - 'Expected type Int;' - " Int cannot represent non-integer value: 'a'"] + "Expected type Int;" " Int cannot represent non-integer value: 'a'" + ] def returns_a_single_error_for_string_input(): - result = coerce_value('meow', GraphQLInt) + result = coerce_value("meow", GraphQLInt) assert expect_error(result) == [ - 'Expected type Int;' - " Int cannot represent non-integer value: 'meow'"] + "Expected type Int;" " Int cannot represent non-integer value: 'meow'" + ] def describe_for_graphql_float(): - def returns_value_for_integer(): result = coerce_value(1, GraphQLFloat) assert expect_value(result) == 1 @@ -120,112 +124,117 @@ def returns_no_error_for_exponent_input(): assert expect_value(result) == 1000 def returns_error_for_numeric_looking_string(): - result = coerce_value('1', GraphQLFloat) + result = coerce_value("1", GraphQLFloat) assert expect_error(result) == [ - 'Expected type Float;' - " Float cannot represent non numeric value: '1'"] + "Expected type Float;" " Float cannot represent non numeric value: '1'" + ] def returns_null_for_null_value(): result = coerce_value(None, GraphQLFloat) assert expect_value(result) is None def returns_a_single_error_for_empty_string_input(): - result = coerce_value('', GraphQLFloat) + result = coerce_value("", GraphQLFloat) assert expect_error(result) == [ - 'Expected type Float;' - " Float cannot represent non numeric value: ''"] + "Expected type Float;" " Float cannot represent non numeric value: ''" + ] def returns_a_single_error_for_nan_input(): result = coerce_value(nan, GraphQLFloat) assert expect_error(result) == [ - 'Expected type Float;' - ' Float cannot represent non numeric value: nan'] + "Expected type Float;" " Float cannot represent non numeric value: nan" + ] def returns_a_single_error_for_infinity_input(): result = coerce_value(inf, GraphQLFloat) assert expect_error(result) == [ - 'Expected type Float;' - ' Float cannot represent non numeric value: inf'] + "Expected type Float;" " Float cannot represent non numeric value: inf" + ] def returns_a_single_error_for_char_input(): - result = coerce_value('a', GraphQLFloat) + result = coerce_value("a", GraphQLFloat) assert expect_error(result) == [ - 'Expected type Float;' - " Float cannot represent non numeric value: 'a'"] + "Expected type Float;" " Float cannot represent non numeric value: 'a'" + ] def returns_a_single_error_for_string_input(): - result = coerce_value('meow', GraphQLFloat) + result = coerce_value("meow", GraphQLFloat) assert expect_error(result) == [ - 'Expected type Float;' - " Float cannot represent non numeric value: 'meow'"] + "Expected type Float;" + " Float cannot represent non numeric value: 'meow'" + ] def describe_for_graphql_enum(): - TestEnum = GraphQLEnumType('TestEnum', { - 'FOO': 'InternalFoo', 'BAR': 123456789}) + TestEnum = GraphQLEnumType("TestEnum", {"FOO": "InternalFoo", "BAR": 123456789}) def returns_no_error_for_a_known_enum_name(): - foo_result = coerce_value('FOO', TestEnum) - assert expect_value(foo_result) == 'InternalFoo' + foo_result = coerce_value("FOO", TestEnum) + assert expect_value(foo_result) == "InternalFoo" - bar_result = coerce_value('BAR', TestEnum) + bar_result = coerce_value("BAR", TestEnum) assert expect_value(bar_result) == 123456789 def results_error_for_misspelled_enum_value(): - result = coerce_value('foo', TestEnum) - assert expect_error(result) == [ - 'Expected type TestEnum; did you mean FOO?'] + result = coerce_value("foo", TestEnum) + assert expect_error(result) == ["Expected type TestEnum; did you mean FOO?"] def results_error_for_incorrect_value_type(): result1 = coerce_value(123, TestEnum) - assert expect_error(result1) == ['Expected type TestEnum.'] + assert expect_error(result1) == ["Expected type TestEnum."] - result2 = coerce_value({'field': 'value'}, TestEnum) - assert expect_error(result2) == ['Expected type TestEnum.'] + result2 = coerce_value({"field": "value"}, TestEnum) + assert expect_error(result2) == ["Expected type TestEnum."] def describe_for_graphql_input_object(): - TestInputObject = GraphQLInputObjectType('TestInputObject', { - 'foo': GraphQLInputField(GraphQLNonNull(GraphQLInt)), - 'bar': GraphQLInputField(GraphQLInt)}) + TestInputObject = GraphQLInputObjectType( + "TestInputObject", + { + "foo": GraphQLInputField(GraphQLNonNull(GraphQLInt)), + "bar": GraphQLInputField(GraphQLInt), + }, + ) def returns_no_error_for_a_valid_input(): - result = coerce_value({'foo': 123}, TestInputObject) - assert expect_value(result) == {'foo': 123} + result = coerce_value({"foo": 123}, TestInputObject) + assert expect_value(result) == {"foo": 123} def returns_error_for_a_non_dict_value(): result = coerce_value(123, TestInputObject) assert expect_error(result) == [ - 'Expected type TestInputObject to be a dict.'] + "Expected type TestInputObject to be a dict." + ] def returns_error_for_an_invalid_field(): - result = coerce_value({'foo': 'abc'}, TestInputObject) + result = coerce_value({"foo": "abc"}, TestInputObject) assert expect_error(result) == [ - 'Expected type Int at value.foo;' - " Int cannot represent non-integer value: 'abc'"] + "Expected type Int at value.foo;" + " Int cannot represent non-integer value: 'abc'" + ] def returns_multiple_errors_for_multiple_invalid_fields(): - result = coerce_value( - {'foo': 'abc', 'bar': 'def'}, TestInputObject) + result = coerce_value({"foo": "abc", "bar": "def"}, TestInputObject) assert expect_error(result) == [ - 'Expected type Int at value.foo;' + "Expected type Int at value.foo;" " Int cannot represent non-integer value: 'abc'", - 'Expected type Int at value.bar;' - " Int cannot represent non-integer value: 'def'"] + "Expected type Int at value.bar;" + " Int cannot represent non-integer value: 'def'", + ] def returns_error_for_a_missing_required_field(): - result = coerce_value({'bar': 123}, TestInputObject) + result = coerce_value({"bar": 123}, TestInputObject) assert expect_error(result) == [ - 'Field value.foo' - ' of required type Int! was not provided.'] + "Field value.foo" " of required type Int! was not provided." + ] def returns_error_for_an_unknown_field(): - result = coerce_value( - {'foo': 123, 'unknownField': 123}, TestInputObject) + result = coerce_value({"foo": 123, "unknownField": 123}, TestInputObject) assert expect_error(result) == [ - "Field 'unknownField' is not defined" - ' by type TestInputObject.'] + "Field 'unknownField' is not defined" " by type TestInputObject." + ] def returns_error_for_a_misspelled_field(): - result = coerce_value({'foo': 123, 'bart': 123}, TestInputObject) + result = coerce_value({"foo": 123, "bart": 123}, TestInputObject) assert expect_error(result) == [ "Field 'bart' is not defined" - ' by type TestInputObject; did you mean bar?'] + " by type TestInputObject; did you mean bar?" + ] diff --git a/tests/utilities/test_concat_ast.py b/tests/utilities/test_concat_ast.py index 2e200c5e..f978b2f9 100644 --- a/tests/utilities/test_concat_ast.py +++ b/tests/utilities/test_concat_ast.py @@ -4,23 +4,27 @@ def describe_concat_ast(): - def concats_two_acts_together(): - source_a = Source(""" + source_a = Source( + """ { a, b, ... Frag } - """) + """ + ) - source_b = Source(""" + source_b = Source( + """ fragment Frag on T { c } - """) + """ + ) ast_a = parse(source_a) ast_b = parse(source_b) ast_c = concat_ast([ast_a, ast_b]) - assert print_ast(ast_c) == dedent(""" + assert print_ast(ast_c) == dedent( + """ { a b @@ -30,4 +34,5 @@ def concats_two_acts_together(): fragment Frag on T { c } - """) + """ + ) diff --git a/tests/utilities/test_extend_schema.py b/tests/utilities/test_extend_schema.py index 47f16d93..5dc2f0f6 100644 --- a/tests/utilities/test_extend_schema.py +++ b/tests/utilities/test_extend_schema.py @@ -2,66 +2,81 @@ from graphql import graphql_sync from graphql.error import GraphQLError -from graphql.language import ( - parse, print_ast, DirectiveLocation, DocumentNode) +from graphql.language import parse, print_ast, DirectiveLocation, DocumentNode from graphql.pyutils import dedent from graphql.type import ( - GraphQLArgument, GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, - GraphQLField, GraphQLID, GraphQLInputField, GraphQLInputObjectType, - GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLScalarType, GraphQLSchema, GraphQLString, GraphQLUnionType, - is_non_null_type, is_scalar_type, specified_directives, validate_schema) + GraphQLArgument, + GraphQLDirective, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLID, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLScalarType, + GraphQLSchema, + GraphQLString, + GraphQLUnionType, + is_non_null_type, + is_scalar_type, + specified_directives, + validate_schema, +) from graphql.utilities import extend_schema, print_schema # Test schema. -SomeScalarType = GraphQLScalarType( - name='SomeScalar', - serialize=lambda x: x) +SomeScalarType = GraphQLScalarType(name="SomeScalar", serialize=lambda x: x) SomeInterfaceType = GraphQLInterfaceType( - name='SomeInterface', + name="SomeInterface", fields=lambda: { - 'name': GraphQLField(GraphQLString), - 'some': GraphQLField(SomeInterfaceType)}) + "name": GraphQLField(GraphQLString), + "some": GraphQLField(SomeInterfaceType), + }, +) FooType = GraphQLObjectType( - name='Foo', + name="Foo", interfaces=[SomeInterfaceType], fields=lambda: { - 'name': GraphQLField(GraphQLString), - 'some': GraphQLField(SomeInterfaceType), - 'tree': GraphQLField(GraphQLNonNull(GraphQLList(FooType)))}) + "name": GraphQLField(GraphQLString), + "some": GraphQLField(SomeInterfaceType), + "tree": GraphQLField(GraphQLNonNull(GraphQLList(FooType))), + }, +) BarType = GraphQLObjectType( - name='Bar', + name="Bar", interfaces=[SomeInterfaceType], fields=lambda: { - 'name': GraphQLField(GraphQLString), - 'some': GraphQLField(SomeInterfaceType), - 'foo': GraphQLField(FooType)}) + "name": GraphQLField(GraphQLString), + "some": GraphQLField(SomeInterfaceType), + "foo": GraphQLField(FooType), + }, +) BizType = GraphQLObjectType( - name='Biz', - fields=lambda: { - 'fizz': GraphQLField(GraphQLString)}) + name="Biz", fields=lambda: {"fizz": GraphQLField(GraphQLString)} +) -SomeUnionType = GraphQLUnionType( - name='SomeUnion', - types=[FooType, BizType]) +SomeUnionType = GraphQLUnionType(name="SomeUnion", types=[FooType, BizType]) SomeEnumType = GraphQLEnumType( - name='SomeEnum', - values={ - 'ONE': GraphQLEnumValue(1), - 'TWO': GraphQLEnumValue(2)}) + name="SomeEnum", values={"ONE": GraphQLEnumValue(1), "TWO": GraphQLEnumValue(2)} +) -SomeInputType = GraphQLInputObjectType('SomeInput', lambda: { - 'fooArg': GraphQLInputField(GraphQLString)}) +SomeInputType = GraphQLInputObjectType( + "SomeInput", lambda: {"fooArg": GraphQLInputField(GraphQLString)} +) FooDirective = GraphQLDirective( - name='foo', - args={'input': GraphQLArgument(SomeInputType)}, + name="foo", + args={"input": GraphQLArgument(SomeInputType)}, locations=[ DirectiveLocation.SCHEMA, DirectiveLocation.SCALAR, @@ -73,24 +88,30 @@ DirectiveLocation.ENUM, DirectiveLocation.ENUM_VALUE, DirectiveLocation.INPUT_OBJECT, - DirectiveLocation.INPUT_FIELD_DEFINITION]) + DirectiveLocation.INPUT_FIELD_DEFINITION, + ], +) test_schema = GraphQLSchema( query=GraphQLObjectType( - name='Query', + name="Query", fields=lambda: { - 'foo': GraphQLField(FooType), - 'someScalar': GraphQLField(SomeScalarType), - 'someUnion': GraphQLField(SomeUnionType), - 'someEnum': GraphQLField(SomeEnumType), - 'someInterface': GraphQLField( + "foo": GraphQLField(FooType), + "someScalar": GraphQLField(SomeScalarType), + "someUnion": GraphQLField(SomeUnionType), + "someEnum": GraphQLField(SomeEnumType), + "someInterface": GraphQLField( SomeInterfaceType, - args={'id': GraphQLArgument(GraphQLNonNull(GraphQLID))}), - 'someInput': GraphQLField( - GraphQLString, - args={'input': GraphQLArgument(SomeInputType)})}), + args={"id": GraphQLArgument(GraphQLNonNull(GraphQLID))}, + ), + "someInput": GraphQLField( + GraphQLString, args={"input": GraphQLArgument(SomeInputType)} + ), + }, + ), types=[FooType, BarType], - directives=specified_directives + (FooDirective,)) + directives=specified_directives + (FooDirective,), +) def extend_test_schema(sdl, **options) -> GraphQLSchema: @@ -102,145 +123,175 @@ def extend_test_schema(sdl, **options) -> GraphQLSchema: test_schema_ast = parse(print_schema(test_schema)) -test_schema_definitions = [ - print_ast(node) for node in test_schema_ast.definitions] +test_schema_definitions = [print_ast(node) for node in test_schema_ast.definitions] def print_test_schema_changes(extended_schema): ast = parse(print_schema(extended_schema)) - ast.definitions = [node for node in ast.definitions - if print_ast(node) not in test_schema_definitions] + ast.definitions = [ + node + for node in ast.definitions + if print_ast(node) not in test_schema_definitions + ] return print_ast(ast) def describe_extend_schema(): - def returns_the_original_schema_when_there_are_no_type_definitions(): - extended_schema = extend_test_schema('{ field }') + extended_schema = extend_test_schema("{ field }") assert extended_schema == test_schema def extends_without_altering_original_schema(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Query { newField: String } - """) + """ + ) assert extend_schema != test_schema - assert 'newField' in print_schema(extended_schema) - assert 'newField' not in print_schema(test_schema) + assert "newField" in print_schema(extended_schema) + assert "newField" not in print_schema(test_schema) def can_be_used_for_limited_execution(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Query { newField: String } - """) + """ + ) - result = graphql_sync(extended_schema, - '{ newField }', {'newField': 123}) - assert result == ({'newField': '123'}, None) + result = graphql_sync(extended_schema, "{ newField }", {"newField": 123}) + assert result == ({"newField": "123"}, None) def can_describe_the_extended_fields(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Query { "New field description." newField: String } - """) + """ + ) - assert extended_schema.get_type( - 'Query').fields['newField'].description == 'New field description.' + assert ( + extended_schema.get_type("Query").fields["newField"].description + == "New field description." + ) def extends_objects_by_adding_new_fields(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Foo { newField: String } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ type Foo implements SomeInterface { name: String some: SomeInterface tree: [Foo]! newField: String } - """) + """ + ) - foo_type = extended_schema.get_type('Foo') - foo_field = extended_schema.get_type('Query').fields['foo'] + foo_type = extended_schema.get_type("Foo") + foo_field = extended_schema.get_type("Query").fields["foo"] assert foo_field.type == foo_type def extends_enums_by_adding_new_values(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend enum SomeEnum { NEW_ENUM } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ enum SomeEnum { ONE TWO NEW_ENUM } - """) + """ + ) - some_enum_type = extended_schema.get_type('SomeEnum') - enum_field = extended_schema.get_type('Query').fields['someEnum'] + some_enum_type = extended_schema.get_type("SomeEnum") + enum_field = extended_schema.get_type("Query").fields["someEnum"] assert enum_field.type == some_enum_type def extends_unions_by_adding_new_types(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend union SomeUnion = Bar - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ union SomeUnion = Foo | Biz | Bar - """) + """ + ) - some_union_type = extended_schema.get_type('SomeUnion') - union_field = extended_schema.get_type('Query').fields['someUnion'] + some_union_type = extended_schema.get_type("SomeUnion") + union_field = extended_schema.get_type("Query").fields["someUnion"] assert union_field.type == some_union_type def allows_extension_of_union_by_adding_itself(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: - extend_test_schema(""" + extend_test_schema( + """ extend union SomeUnion = SomeUnion - """) + """ + ) msg = str(exc_info.value) - assert msg == 'SomeUnion types must be GraphQLObjectType objects.' + assert msg == "SomeUnion types must be GraphQLObjectType objects." def extends_inputs_by_adding_new_fields(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend input SomeInput { newField: String } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ input SomeInput { fooArg: String newField: String } - """) + """ + ) - some_input_type = extended_schema.get_type('SomeInput') - input_field = extended_schema.get_type('Query').fields['someInput'] - assert input_field.args['input'].type == some_input_type + some_input_type = extended_schema.get_type("SomeInput") + input_field = extended_schema.get_type("Query").fields["someInput"] + assert input_field.args["input"].type == some_input_type - foo_directive = extended_schema.get_directive('foo') - assert foo_directive.args['input'].type == some_input_type + foo_directive = extended_schema.get_directive("foo") + assert foo_directive.args["input"].type == some_input_type def extends_scalars_by_adding_new_directives(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend scalar SomeScalar @foo - """) + """ + ) - some_scalar = extended_schema.get_type('SomeScalar') + some_scalar = extended_schema.get_type("SomeScalar") assert len(some_scalar.extension_ast_nodes) == 1 assert print_ast(some_scalar.extension_ast_nodes[0]) == ( - 'extend scalar SomeScalar @foo') + "extend scalar SomeScalar @foo" + ) def correctly_assigns_ast_nodes_to_new_and_extended_types(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Query { newField(testArg: TestInput): TestEnum } @@ -268,8 +319,10 @@ def correctly_assigns_ast_nodes_to_new_and_extended_types(): input TestInput { testInputField: TestEnum } - """) - ast = parse(""" + """ + ) + ast = parse( + """ extend type Query { oneMoreNewField: TestUnion } @@ -301,22 +354,23 @@ def correctly_assigns_ast_nodes_to_new_and_extended_types(): } directive @test(arg: Int) on FIELD | SCALAR - """) + """ + ) extended_twice_schema = extend_schema(extended_schema, ast) - query = extended_twice_schema.get_type('Query') - some_scalar = extended_twice_schema.get_type('SomeScalar') - some_enum = extended_twice_schema.get_type('SomeEnum') - some_union = extended_twice_schema.get_type('SomeUnion') - some_input = extended_twice_schema.get_type('SomeInput') - some_interface = extended_twice_schema.get_type('SomeInterface') + query = extended_twice_schema.get_type("Query") + some_scalar = extended_twice_schema.get_type("SomeScalar") + some_enum = extended_twice_schema.get_type("SomeEnum") + some_union = extended_twice_schema.get_type("SomeUnion") + some_input = extended_twice_schema.get_type("SomeInput") + some_interface = extended_twice_schema.get_type("SomeInterface") - test_input = extended_twice_schema.get_type('TestInput') - test_enum = extended_twice_schema.get_type('TestEnum') - test_union = extended_twice_schema.get_type('TestUnion') - test_interface = extended_twice_schema.get_type('TestInterface') - test_type = extended_twice_schema.get_type('TestType') - test_directive = extended_twice_schema.get_directive('test') + test_input = extended_twice_schema.get_type("TestInput") + test_enum = extended_twice_schema.get_type("TestEnum") + test_union = extended_twice_schema.get_type("TestUnion") + test_interface = extended_twice_schema.get_type("TestInterface") + test_type = extended_twice_schema.get_type("TestType") + test_directive = extended_twice_schema.get_directive("test") assert len(query.extension_ast_nodes) == 2 assert len(some_scalar.extension_ast_nodes) == 2 @@ -344,47 +398,57 @@ def correctly_assigns_ast_nodes_to_new_and_extended_types(): test_union.ast_node, test_interface.ast_node, test_type.ast_node, - test_directive.ast_node]) + test_directive.ast_node, + ] + ) assert print_schema( extend_schema(test_schema, restored_extension_ast) ) == print_schema(extended_twice_schema) - new_field = query.fields['newField'] - assert print_ast( - new_field.ast_node) == 'newField(testArg: TestInput): TestEnum' - assert print_ast( - new_field.args['testArg'].ast_node) == 'testArg: TestInput' - assert print_ast( - query.fields['oneMoreNewField'].ast_node - ) == 'oneMoreNewField: TestUnion' - assert print_ast(some_enum.values['NEW_VALUE'].ast_node) == 'NEW_VALUE' - assert print_ast(some_enum.values[ - 'ONE_MORE_NEW_VALUE'].ast_node) == 'ONE_MORE_NEW_VALUE' - assert print_ast(some_input.fields[ - 'newField'].ast_node) == 'newField: String' - assert print_ast(some_input.fields[ - 'oneMoreNewField'].ast_node) == 'oneMoreNewField: String' - assert print_ast(some_interface.fields[ - 'newField'].ast_node) == 'newField: String' - assert print_ast(some_interface.fields[ - 'oneMoreNewField'].ast_node) == 'oneMoreNewField: String' - - assert print_ast( - test_input.fields['testInputField'].ast_node - ) == 'testInputField: TestEnum' - assert print_ast( - test_enum.values['TEST_VALUE'].ast_node) == 'TEST_VALUE' - assert print_ast( - test_interface.fields['interfaceField'].ast_node - ) == 'interfaceField: String' - assert print_ast( - test_type.fields['interfaceField'].ast_node - ) == 'interfaceField: String' - assert print_ast(test_directive.args['arg'].ast_node) == 'arg: Int' + new_field = query.fields["newField"] + assert print_ast(new_field.ast_node) == "newField(testArg: TestInput): TestEnum" + assert print_ast(new_field.args["testArg"].ast_node) == "testArg: TestInput" + assert ( + print_ast(query.fields["oneMoreNewField"].ast_node) + == "oneMoreNewField: TestUnion" + ) + assert print_ast(some_enum.values["NEW_VALUE"].ast_node) == "NEW_VALUE" + assert ( + print_ast(some_enum.values["ONE_MORE_NEW_VALUE"].ast_node) + == "ONE_MORE_NEW_VALUE" + ) + assert print_ast(some_input.fields["newField"].ast_node) == "newField: String" + assert ( + print_ast(some_input.fields["oneMoreNewField"].ast_node) + == "oneMoreNewField: String" + ) + assert ( + print_ast(some_interface.fields["newField"].ast_node) == "newField: String" + ) + assert ( + print_ast(some_interface.fields["oneMoreNewField"].ast_node) + == "oneMoreNewField: String" + ) + + assert ( + print_ast(test_input.fields["testInputField"].ast_node) + == "testInputField: TestEnum" + ) + assert print_ast(test_enum.values["TEST_VALUE"].ast_node) == "TEST_VALUE" + assert ( + print_ast(test_interface.fields["interfaceField"].ast_node) + == "interfaceField: String" + ) + assert ( + print_ast(test_type.fields["interfaceField"].ast_node) + == "interfaceField: String" + ) + assert print_ast(test_directive.args["arg"].ast_node) == "arg: Int" def builds_types_with_deprecated_fields_and_values(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ type TypeWithDeprecatedField { newDeprecatedField: String @deprecated(reason: "not used anymore") } @@ -392,98 +456,120 @@ def builds_types_with_deprecated_fields_and_values(): enum EnumWithDeprecatedValue { DEPRECATED @deprecated(reason: "do not use") } - """) # noqa + """ + ) # noqa deprecated_field_def = extended_schema.get_type( - 'TypeWithDeprecatedField').fields['newDeprecatedField'] + "TypeWithDeprecatedField" + ).fields["newDeprecatedField"] assert deprecated_field_def.is_deprecated is True - assert deprecated_field_def.deprecation_reason == 'not used anymore' + assert deprecated_field_def.deprecation_reason == "not used anymore" deprecated_enum_def = extended_schema.get_type( - 'EnumWithDeprecatedValue').values['DEPRECATED'] + "EnumWithDeprecatedValue" + ).values["DEPRECATED"] assert deprecated_enum_def.is_deprecated is True - assert deprecated_enum_def.deprecation_reason == 'do not use' + assert deprecated_enum_def.deprecation_reason == "do not use" def extends_objects_with_deprecated_fields(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Foo { deprecatedField: String @deprecated(reason: "not used anymore") } - """) - deprecated_field_def = extended_schema.get_type( - 'Foo').fields['deprecatedField'] + """ + ) + deprecated_field_def = extended_schema.get_type("Foo").fields["deprecatedField"] assert deprecated_field_def.is_deprecated is True - assert deprecated_field_def.deprecation_reason == 'not used anymore' + assert deprecated_field_def.deprecation_reason == "not used anymore" def extend_enums_with_deprecated_values(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend enum SomeEnum { DEPRECATED @deprecated(reason: "do not use") } - """) + """ + ) - deprecated_enum_def = extended_schema.get_type( - 'SomeEnum').values['DEPRECATED'] + deprecated_enum_def = extended_schema.get_type("SomeEnum").values["DEPRECATED"] assert deprecated_enum_def.is_deprecated is True - assert deprecated_enum_def.deprecation_reason == 'do not use' + assert deprecated_enum_def.deprecation_reason == "do not use" def adds_new_unused_object_type(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ type Unused { someField: String } - """) + """ + ) assert extended_schema != test_schema - assert print_test_schema_changes(extended_schema) == dedent(""" + assert print_test_schema_changes(extended_schema) == dedent( + """ type Unused { someField: String } - """) + """ + ) def adds_new_unused_enum_type(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ enum UnusedEnum { SOME } - """) + """ + ) assert extended_schema != test_schema - assert print_test_schema_changes(extended_schema) == dedent(""" + assert print_test_schema_changes(extended_schema) == dedent( + """ enum UnusedEnum { SOME } - """) + """ + ) def adds_new_unused_input_object_type(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ input UnusedInput { someInput: String } - """) + """ + ) assert extended_schema != test_schema - assert print_test_schema_changes(extended_schema) == dedent(""" + assert print_test_schema_changes(extended_schema) == dedent( + """ input UnusedInput { someInput: String } - """) + """ + ) def adds_new_union_using_new_object_type(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ type DummyUnionMember { someField: String } union UnusedUnion = DummyUnionMember - """) + """ + ) assert extended_schema != test_schema - assert print_test_schema_changes(extended_schema) == dedent(""" + assert print_test_schema_changes(extended_schema) == dedent( + """ type DummyUnionMember { someField: String } union UnusedUnion = DummyUnionMember - """) + """ + ) def extends_objects_by_adding_new_fields_with_arguments(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Foo { newField(arg1: String, arg2: NewInputObj!): String } @@ -493,8 +579,10 @@ def extends_objects_by_adding_new_fields_with_arguments(): field2: [Float] field3: String! } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ type Foo implements SomeInterface { name: String some: SomeInterface @@ -507,40 +595,50 @@ def extends_objects_by_adding_new_fields_with_arguments(): field2: [Float] field3: String! } - """) + """ + ) def extends_objects_by_adding_new_fields_with_existing_types(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Foo { newField(arg1: SomeEnum!): SomeEnum } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ type Foo implements SomeInterface { name: String some: SomeInterface tree: [Foo]! newField(arg1: SomeEnum!): SomeEnum } - """) + """ + ) def extends_objects_by_adding_implemented_interfaces(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Biz implements SomeInterface { name: String some: SomeInterface } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ type Biz implements SomeInterface { fizz: String name: String some: SomeInterface } - """) + """ + ) def extends_objects_by_including_new_types(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Foo { newObject: NewObject newInterface: NewInterface @@ -570,8 +668,10 @@ def extends_objects_by_including_new_types(): OPTION_A OPTION_B } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ type Foo implements SomeInterface { name: String some: SomeInterface @@ -604,10 +704,12 @@ def extends_objects_by_including_new_types(): scalar NewScalar union NewUnion = NewObject | NewOtherObject - """) + """ + ) def extends_objects_by_adding_implemented_new_interfaces(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Foo implements NewInterface { baz: String } @@ -615,8 +717,10 @@ def extends_objects_by_adding_implemented_new_interfaces(): interface NewInterface { baz: String } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ type Foo implements SomeInterface & NewInterface { name: String some: SomeInterface @@ -627,10 +731,12 @@ def extends_objects_by_adding_implemented_new_interfaces(): interface NewInterface { baz: String } - """) + """ + ) def extends_different_types_multiple_times(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend type Biz implements NewInterface { buzz: String } @@ -677,8 +783,10 @@ def extends_different_types_multiple_times(): extend input SomeInput { fieldB: String } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ type Biz implements NewInterface & SomeInterface { fizz: String buzz: String @@ -714,10 +822,12 @@ def extends_different_types_multiple_times(): } union SomeUnion = Foo | Biz | Boo | Joo - """) + """ + ) def extends_interfaces_by_adding_new_fields(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend interface SomeInterface { newField: String } @@ -729,8 +839,10 @@ def extends_interfaces_by_adding_new_fields(): extend type Foo { newField: String } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ type Bar implements SomeInterface { name: String some: SomeInterface @@ -750,26 +862,32 @@ def extends_interfaces_by_adding_new_fields(): some: SomeInterface newField: String } - """) + """ + ) def allows_extension_of_interface_with_missing_object_fields(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend interface SomeInterface { newField: String } - """) + """ + ) errors = validate_schema(extended_schema) assert errors - assert print_test_schema_changes(extended_schema) == dedent(""" + assert print_test_schema_changes(extended_schema) == dedent( + """ interface SomeInterface { name: String some: SomeInterface newField: String } - """) + """ + ) def extends_interfaces_multiple_times(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ extend interface SomeInterface { newFieldA: Int } @@ -777,29 +895,36 @@ def extends_interfaces_multiple_times(): extend interface SomeInterface { newFieldB(test: Boolean): String } - """) - assert print_test_schema_changes(extended_schema) == dedent(""" + """ + ) + assert print_test_schema_changes(extended_schema) == dedent( + """ interface SomeInterface { name: String some: SomeInterface newFieldA: Int newFieldB(test: Boolean): String } - """) + """ + ) def may_extend_mutations_and_subscriptions(): mutationSchema = GraphQLSchema( query=GraphQLObjectType( - name='Query', fields=lambda: { - 'queryField': GraphQLField(GraphQLString)}), + name="Query", fields=lambda: {"queryField": GraphQLField(GraphQLString)} + ), mutation=GraphQLObjectType( - name='Mutation', fields=lambda: { - 'mutationField': GraphQLField(GraphQLString)}), + name="Mutation", + fields=lambda: {"mutationField": GraphQLField(GraphQLString)}, + ), subscription=GraphQLObjectType( - name='Subscription', fields=lambda: { - 'subscriptionField': GraphQLField(GraphQLString)})) + name="Subscription", + fields=lambda: {"subscriptionField": GraphQLField(GraphQLString)}, + ), + ) - ast = parse(""" + ast = parse( + """ extend type Query { newQueryField: Int } @@ -811,12 +936,14 @@ def may_extend_mutations_and_subscriptions(): extend type Subscription { newSubscriptionField: Int } - """) + """ + ) original_print = print_schema(mutationSchema) extended_schema = extend_schema(mutationSchema, ast) assert extended_schema != mutationSchema assert print_schema(mutationSchema) == original_print - assert print_schema(extended_schema) == dedent(""" + assert print_schema(extended_schema) == dedent( + """ type Mutation { mutationField: String newMutationField: Int @@ -831,40 +958,47 @@ def may_extend_mutations_and_subscriptions(): subscriptionField: String newSubscriptionField: Int } - """) + """ + ) def may_extend_directives_with_new_simple_directive(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ directive @neat on QUERY - """) + """ + ) - new_directive = extended_schema.get_directive('neat') - assert new_directive.name == 'neat' + new_directive = extended_schema.get_directive("neat") + assert new_directive.name == "neat" assert DirectiveLocation.QUERY in new_directive.locations def sets_correct_description_when_extending_with_a_new_directive(): - extended_schema = extend_test_schema(''' + extended_schema = extend_test_schema( + ''' """ new directive """ directive @new on QUERY - ''') + ''' + ) - new_directive = extended_schema.get_directive('new') - assert new_directive.description == 'new directive' + new_directive = extended_schema.get_directive("new") + assert new_directive.description == "new directive" def may_extend_directives_with_new_complex_directive(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ directive @profile(enable: Boolean! tag: String) on QUERY | FIELD - """) + """ + ) - extended_directive = extended_schema.get_directive('profile') - assert extended_directive.name == 'profile' + extended_directive = extended_schema.get_directive("profile") + assert extended_directive.name == "profile" assert DirectiveLocation.QUERY in extended_directive.locations assert DirectiveLocation.FIELD in extended_directive.locations args = extended_directive.args - assert list(args.keys()) == ['enable', 'tag'] + assert list(args.keys()) == ["enable", "tag"] arg0, arg1 = args.values() assert is_non_null_type(arg0.type) is True assert is_scalar_type(arg0.type.of_type) is True @@ -894,68 +1028,76 @@ def does_not_allow_replacing_a_default_directive(): extend_test_schema(sdl) assert str(exc_info.value).startswith( "Directive 'include' already exists in the schema." - ' It cannot be redefined.') + " It cannot be redefined." + ) def does_not_allow_replacing_a_custom_directive(): - extended_schema = extend_test_schema(""" + extended_schema = extend_test_schema( + """ directive @meow(if: Boolean!) on FIELD | FRAGMENT_SPREAD - """) + """ + ) - replacement_ast = parse(""" + replacement_ast = parse( + """ directive @meow(if: Boolean!) on FIELD | QUERY - """) + """ + ) with raises(GraphQLError) as exc_info: extend_schema(extended_schema, replacement_ast) assert str(exc_info.value).startswith( - "Directive 'meow' already exists in the schema." - ' It cannot be redefined.') + "Directive 'meow' already exists in the schema." " It cannot be redefined." + ) def does_not_allow_replacing_an_existing_type(): def existing_type_error(type_): - return (f"Type '{type_}' already exists in the schema." - ' It cannot also be defined in this type definition.') + return ( + f"Type '{type_}' already exists in the schema." + " It cannot also be defined in this type definition." + ) type_sdl = """ type Bar """ with raises(GraphQLError) as exc_info: assert extend_test_schema(type_sdl) - assert str(exc_info.value).startswith(existing_type_error('Bar')) + assert str(exc_info.value).startswith(existing_type_error("Bar")) scalar_sdl = """ scalar SomeScalar """ with raises(GraphQLError) as exc_info: assert extend_test_schema(scalar_sdl) - assert str(exc_info.value).startswith( - existing_type_error('SomeScalar')) + assert str(exc_info.value).startswith(existing_type_error("SomeScalar")) enum_sdl = """ enum SomeEnum """ with raises(GraphQLError) as exc_info: assert extend_test_schema(enum_sdl) - assert str(exc_info.value).startswith(existing_type_error('SomeEnum')) + assert str(exc_info.value).startswith(existing_type_error("SomeEnum")) union_sdl = """ union SomeUnion """ with raises(GraphQLError) as exc_info: assert extend_test_schema(union_sdl) - assert str(exc_info.value).startswith(existing_type_error('SomeUnion')) + assert str(exc_info.value).startswith(existing_type_error("SomeUnion")) input_sdl = """ input SomeInput """ with raises(GraphQLError) as exc_info: assert extend_test_schema(input_sdl) - assert str(exc_info.value).startswith(existing_type_error('SomeInput')) + assert str(exc_info.value).startswith(existing_type_error("SomeInput")) def does_not_allow_replacing_an_existing_field(): def existing_field_error(type_, field): - return (f"Field '{type_}.{field}' already exists in the schema." - ' It cannot also be defined in this type extension.') + return ( + f"Field '{type_}.{field}' already exists in the schema." + " It cannot also be defined in this type extension." + ) type_sdl = """ extend type Bar { @@ -964,8 +1106,7 @@ def existing_field_error(type_, field): """ with raises(GraphQLError) as exc_info: extend_test_schema(type_sdl) - assert str(exc_info.value).startswith( - existing_field_error('Bar', 'foo')) + assert str(exc_info.value).startswith(existing_field_error("Bar", "foo")) interface_sdl = """ extend interface SomeInterface { @@ -975,7 +1116,8 @@ def existing_field_error(type_, field): with raises(GraphQLError) as exc_info: extend_test_schema(interface_sdl) assert str(exc_info.value).startswith( - existing_field_error('SomeInterface', 'some')) + existing_field_error("SomeInterface", "some") + ) input_sdl = """ extend input SomeInput { @@ -985,7 +1127,8 @@ def existing_field_error(type_, field): with raises(GraphQLError) as exc_info: extend_test_schema(input_sdl) assert str(exc_info.value).startswith( - existing_field_error('SomeInput', 'fooArg')) + existing_field_error("SomeInput", "fooArg") + ) def does_not_allow_replacing_an_existing_enum_value(): sdl = """ @@ -997,12 +1140,14 @@ def does_not_allow_replacing_an_existing_enum_value(): extend_test_schema(sdl) assert str(exc_info.value).startswith( "Enum value 'SomeEnum.ONE' already exists in the schema." - ' It cannot also be defined in this type extension.') + " It cannot also be defined in this type extension." + ) def does_not_allow_referencing_an_unknown_type(): unknown_type_error = ( "Unknown type: 'Quix'. Ensure that this type exists either" - ' in the original schema, or is added in a type definition.') + " in the original schema, or is added in a type definition." + ) type_sdl = """ extend type Bar { @@ -1033,17 +1178,19 @@ def does_not_allow_referencing_an_unknown_type(): def does_not_allow_extending_an_unknown_type(): for sdl in [ - 'extend scalar UnknownType @foo', - 'extend type UnknownType @foo', - 'extend interface UnknownType @foo', - 'extend enum UnknownType @foo', - 'extend union UnknownType @foo', - 'extend input UnknownType @foo']: + "extend scalar UnknownType @foo", + "extend type UnknownType @foo", + "extend interface UnknownType @foo", + "extend enum UnknownType @foo", + "extend union UnknownType @foo", + "extend input UnknownType @foo", + ]: with raises(GraphQLError) as exc_info: extend_test_schema(sdl) assert str(exc_info.value).startswith( "Cannot extend type 'UnknownType'" - ' because it does not exist in the existing schema.') + " because it does not exist in the existing schema." + ) def it_does_not_allow_extending_a_mismatch_type(): type_sdl = """ @@ -1052,31 +1199,29 @@ def it_does_not_allow_extending_a_mismatch_type(): with raises(GraphQLError) as exc_info: extend_test_schema(type_sdl) assert str(exc_info.value).startswith( - "Cannot extend non-object type 'SomeInterface'.") + "Cannot extend non-object type 'SomeInterface'." + ) interface_sdl = """ extend interface Foo @foo """ with raises(GraphQLError) as exc_info: extend_test_schema(interface_sdl) - assert str(exc_info.value).startswith( - "Cannot extend non-interface type 'Foo'.") + assert str(exc_info.value).startswith("Cannot extend non-interface type 'Foo'.") enum_sdl = """ extend enum Foo @foo """ with raises(GraphQLError) as exc_info: extend_test_schema(enum_sdl) - assert str(exc_info.value).startswith( - "Cannot extend non-enum type 'Foo'.") + assert str(exc_info.value).startswith("Cannot extend non-enum type 'Foo'.") union_sdl = """ extend union Foo @foo """ with raises(GraphQLError) as exc_info: extend_test_schema(union_sdl) - assert str(exc_info.value).startswith( - "Cannot extend non-union type 'Foo'.") + assert str(exc_info.value).startswith("Cannot extend non-union type 'Foo'.") input_sdl = """ extend input Foo @foo @@ -1084,35 +1229,38 @@ def it_does_not_allow_extending_a_mismatch_type(): with raises(GraphQLError) as exc_info: extend_test_schema(input_sdl) assert str(exc_info.value).startswith( - "Cannot extend non-input object type 'Foo'.") + "Cannot extend non-input object type 'Foo'." + ) def describe_can_add_additional_root_operation_types(): - def does_not_automatically_include_common_root_type_names(): - schema = extend_test_schema(""" + schema = extend_test_schema( + """ type Mutation { doSomething: String } - """) + """ + ) assert schema.mutation_type is None def adds_schema_definition_missing_in_the_original_schema(): - schema = GraphQLSchema( - directives=[FooDirective], - types=[FooType]) + schema = GraphQLSchema(directives=[FooDirective], types=[FooType]) assert schema.query_type is None - ast = parse(""" + ast = parse( + """ schema @foo { query: Foo } - """) + """ + ) schema = extend_schema(schema, ast) query_type = schema.query_type - assert query_type.name == 'Foo' + assert query_type.name == "Foo" def adds_new_root_types_via_schema_extension(): - schema = extend_test_schema(""" + schema = extend_test_schema( + """ extend schema { mutation: Mutation } @@ -1120,12 +1268,14 @@ def adds_new_root_types_via_schema_extension(): type Mutation { doSomething: String } - """) + """ + ) mutation_type = schema.mutation_type - assert mutation_type.name == 'Mutation' + assert mutation_type.name == "Mutation" def adds_multiple_new_root_types_via_schema_extension(): - schema = extend_test_schema(""" + schema = extend_test_schema( + """ extend schema { mutation: Mutation subscription: Subscription @@ -1138,14 +1288,16 @@ def adds_multiple_new_root_types_via_schema_extension(): type Subscription { hearSomething: String } - """) + """ + ) mutation_type = schema.mutation_type subscription_type = schema.subscription_type - assert mutation_type.name == 'Mutation' - assert subscription_type.name == 'Subscription' + assert mutation_type.name == "Mutation" + assert subscription_type.name == "Subscription" def applies_multiple_schema_extensions(): - schema = extend_test_schema(""" + schema = extend_test_schema( + """ extend schema { mutation: Mutation } @@ -1161,14 +1313,16 @@ def applies_multiple_schema_extensions(): type Subscription { hearSomething: String } - """) + """ + ) mutation_type = schema.mutation_type subscription_type = schema.subscription_type - assert mutation_type.name == 'Mutation' - assert subscription_type.name == 'Subscription' + assert mutation_type.name == "Mutation" + assert subscription_type.name == "Subscription" def schema_extension_ast_are_available_from_schema_object(): - schema = extend_test_schema(""" + schema = extend_test_schema( + """ extend schema { mutation: Mutation } @@ -1184,16 +1338,19 @@ def schema_extension_ast_are_available_from_schema_object(): type Subscription { hearSomething: String } - """) + """ + ) - ast = parse(""" + ast = parse( + """ extend schema @foo - """) + """ + ) schema = extend_schema(schema, ast) nodes = schema.extension_ast_nodes - assert ''.join( - print_ast(node) + '\n' for node in nodes) == dedent(""" + assert "".join(print_ast(node) + "\n" for node in nodes) == dedent( + """ extend schema { mutation: Mutation } @@ -1201,7 +1358,8 @@ def schema_extension_ast_are_available_from_schema_object(): subscription: Subscription } extend schema @foo - """) + """ + ) def does_not_allow_redefining_an_existing_root_type(): sdl = """ @@ -1216,7 +1374,8 @@ def does_not_allow_redefining_an_existing_root_type(): with raises(TypeError) as exc_info: extend_test_schema(sdl) assert str(exc_info.value).startswith( - 'Must provide only one query type in schema.') + "Must provide only one query type in schema." + ) def does_not_allow_defining_a_root_operation_type_twice(): sdl = """ @@ -1235,7 +1394,8 @@ def does_not_allow_defining_a_root_operation_type_twice(): with raises(TypeError) as exc_info: extend_test_schema(sdl) assert str(exc_info.value).startswith( - 'Must provide only one mutation type in schema.') + "Must provide only one mutation type in schema." + ) def does_not_allow_defining_root_operation_type_with_different_types(): sdl = """ @@ -1258,4 +1418,5 @@ def does_not_allow_defining_root_operation_type_with_different_types(): with raises(TypeError) as exc_info: extend_test_schema(sdl) assert str(exc_info.value).startswith( - 'Must provide only one mutation type in schema.') + "Must provide only one mutation type in schema." + ) diff --git a/tests/utilities/test_find_breaking_changes.py b/tests/utilities/test_find_breaking_changes.py index 9b6469cb..97223185 100644 --- a/tests/utilities/test_find_breaking_changes.py +++ b/tests/utilities/test_find_breaking_changes.py @@ -1,26 +1,42 @@ from graphql.language import DirectiveLocation from graphql.type import ( - GraphQLSchema, GraphQLDirective, GraphQLDeprecatedDirective, - GraphQLIncludeDirective, GraphQLSkipDirective) + GraphQLSchema, + GraphQLDirective, + GraphQLDeprecatedDirective, + GraphQLIncludeDirective, + GraphQLSkipDirective, +) from graphql.utilities import ( - BreakingChangeType, DangerousChangeType, - build_schema, find_breaking_changes, find_dangerous_changes) + BreakingChangeType, + DangerousChangeType, + build_schema, + find_breaking_changes, + find_dangerous_changes, +) from graphql.utilities.find_breaking_changes import ( - find_removed_types, find_types_that_changed_kind, + find_removed_types, + find_types_that_changed_kind, find_fields_that_changed_type_on_object_or_interface_types, find_fields_that_changed_type_on_input_object_types, - find_types_removed_from_unions, find_values_removed_from_enums, - find_arg_changes, find_interfaces_removed_from_object_types, - find_removed_directives, find_removed_directive_args, - find_added_non_null_directive_args, find_removed_locations_for_directive, - find_removed_directive_locations, find_values_added_to_enums, - find_interfaces_added_to_object_types, find_types_added_to_unions) + find_types_removed_from_unions, + find_values_removed_from_enums, + find_arg_changes, + find_interfaces_removed_from_object_types, + find_removed_directives, + find_removed_directive_args, + find_added_non_null_directive_args, + find_removed_locations_for_directive, + find_removed_directive_locations, + find_values_added_to_enums, + find_interfaces_added_to_object_types, + find_types_added_to_unions, +) def describe_find_breaking_changes(): - def should_detect_if_a_type_was_removed_or_not(): - old_schema = build_schema(""" + old_schema = build_schema( + """ type Type1 { field1: String } @@ -32,9 +48,11 @@ def should_detect_if_a_type_was_removed_or_not(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type Type2 { field1: String } @@ -42,14 +60,17 @@ def should_detect_if_a_type_was_removed_or_not(): type Query { field1: String } - """) + """ + ) assert find_removed_types(old_schema, new_schema) == [ - (BreakingChangeType.TYPE_REMOVED, 'Type1 was removed.')] + (BreakingChangeType.TYPE_REMOVED, "Type1 was removed.") + ] assert find_removed_types(old_schema, old_schema) == [] def should_detect_if_a_type_changed_its_type(): - old_schema = build_schema(""" + old_schema = build_schema( + """ interface Type1 { field1: String } @@ -57,9 +78,11 @@ def should_detect_if_a_type_changed_its_type(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type ObjectType { field1: String } @@ -69,14 +92,19 @@ def should_detect_if_a_type_changed_its_type(): type Query { field1: String } - """) + """ + ) assert find_types_that_changed_kind(old_schema, new_schema) == [ - (BreakingChangeType.TYPE_CHANGED_KIND, - 'Type1 changed from an Interface type to a Union type.')] + ( + BreakingChangeType.TYPE_CHANGED_KIND, + "Type1 changed from an Interface type to a Union type.", + ) + ] def should_detect_if_a_field_on_type_was_deleted_or_changed_type(): - old_schema = build_schema(""" + old_schema = build_schema( + """ type TypeA { field1: String } @@ -104,9 +132,11 @@ def should_detect_if_a_field_on_type_was_deleted_or_changed_type(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type TypeA { field1: String } @@ -138,40 +168,71 @@ def should_detect_if_a_field_on_type_was_deleted_or_changed_type(): type Query { field1: String } - """) + """ + ) expected_field_changes = [ - (BreakingChangeType.FIELD_REMOVED, 'Type1.field2 was removed.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field3 changed type from String to Boolean.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field4 changed type from TypeA to TypeB.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field6 changed type from String to [String].'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field7 changed type from [String] to String.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field9 changed type from Int! to Int.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field10 changed type from [Int]! to [Int].'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field11 changed type from Int to [Int]!.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field13 changed type from [Int!] to [Int].'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field14 changed type from [Int] to [[Int]].'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field15 changed type from [[Int]] to [Int].'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field16 changed type from Int! to [Int]!.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'Type1.field18 changed type from [[Int!]!] to [[Int!]].')] - - assert find_fields_that_changed_type_on_object_or_interface_types( - old_schema, new_schema) == expected_field_changes + (BreakingChangeType.FIELD_REMOVED, "Type1.field2 was removed."), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field3 changed type from String to Boolean.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field4 changed type from TypeA to TypeB.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field6 changed type from String to [String].", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field7 changed type from [String] to String.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field9 changed type from Int! to Int.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field10 changed type from [Int]! to [Int].", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field11 changed type from Int to [Int]!.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field13 changed type from [Int!] to [Int].", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field14 changed type from [Int] to [[Int]].", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field15 changed type from [[Int]] to [Int].", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field16 changed type from Int! to [Int]!.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "Type1.field18 changed type from [[Int!]!] to [[Int!]].", + ), + ] + + assert ( + find_fields_that_changed_type_on_object_or_interface_types( + old_schema, new_schema + ) + == expected_field_changes + ) def should_detect_if_fields_on_input_types_changed_kind_or_were_removed(): - old_schema = build_schema(""" + old_schema = build_schema( + """ input InputType1 { field1: String field2: Boolean @@ -192,9 +253,11 @@ def should_detect_if_fields_on_input_types_changed_kind_or_were_removed(): type Query { field1: String - }""") + }""" + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ input InputType1 { field1: Int field3: String @@ -215,37 +278,63 @@ def should_detect_if_fields_on_input_types_changed_kind_or_were_removed(): type Query { field1: String } - """) + """ + ) expected_field_changes = [ - (BreakingChangeType.FIELD_CHANGED_KIND, - 'InputType1.field1 changed type from String to Int.'), - (BreakingChangeType.FIELD_REMOVED, - 'InputType1.field2 was removed.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'InputType1.field3 changed type from [String] to String.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'InputType1.field5 changed type from String to String!.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'InputType1.field6 changed type from [Int] to [Int]!.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'InputType1.field8 changed type from Int to [Int]!.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'InputType1.field9 changed type from [Int] to [Int!].'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'InputType1.field11 changed type from [Int] to [[Int]].'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'InputType1.field12 changed type from [[Int]] to [Int].'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'InputType1.field13 changed type from Int! to [Int]!.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'InputType1.field15 changed type from [[Int]!] to [[Int!]!].')] - - assert find_fields_that_changed_type_on_input_object_types( - old_schema, new_schema).breaking_changes == expected_field_changes + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "InputType1.field1 changed type from String to Int.", + ), + (BreakingChangeType.FIELD_REMOVED, "InputType1.field2 was removed."), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "InputType1.field3 changed type from [String] to String.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "InputType1.field5 changed type from String to String!.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "InputType1.field6 changed type from [Int] to [Int]!.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "InputType1.field8 changed type from Int to [Int]!.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "InputType1.field9 changed type from [Int] to [Int!].", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "InputType1.field11 changed type from [Int] to [[Int]].", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "InputType1.field12 changed type from [[Int]] to [Int].", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "InputType1.field13 changed type from Int! to [Int]!.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "InputType1.field15 changed type from [[Int]!] to [[Int!]!].", + ), + ] + + assert ( + find_fields_that_changed_type_on_input_object_types( + old_schema, new_schema + ).breaking_changes + == expected_field_changes + ) def should_detect_if_a_required_field_is_added_to_an_input_type(): - old_schema = build_schema(""" + old_schema = build_schema( + """ input InputType1 { field1: String } @@ -253,9 +342,11 @@ def should_detect_if_a_required_field_is_added_to_an_input_type(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ input InputType1 { field1: String requiredField: Int! @@ -266,18 +357,26 @@ def should_detect_if_a_required_field_is_added_to_an_input_type(): type Query { field1: String } - """) + """ + ) expected_field_changes = [ - (BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED, - 'A required field requiredField on input type' - ' InputType1 was added.')] - - assert find_fields_that_changed_type_on_input_object_types( - old_schema, new_schema).breaking_changes == expected_field_changes + ( + BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED, + "A required field requiredField on input type" " InputType1 was added.", + ) + ] + + assert ( + find_fields_that_changed_type_on_input_object_types( + old_schema, new_schema + ).breaking_changes + == expected_field_changes + ) def should_detect_if_a_type_was_removed_from_a_union_type(): - old_schema = build_schema(""" + old_schema = build_schema( + """ type Type1 { field1: String } @@ -291,9 +390,11 @@ def should_detect_if_a_type_was_removed_from_a_union_type(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type Type1 { field1: String } @@ -307,14 +408,19 @@ def should_detect_if_a_type_was_removed_from_a_union_type(): type Query { field1: String } - """) + """ + ) assert find_types_removed_from_unions(old_schema, new_schema) == [ - (BreakingChangeType.TYPE_REMOVED_FROM_UNION, - 'Type2 was removed from union type UnionType1.')] + ( + BreakingChangeType.TYPE_REMOVED_FROM_UNION, + "Type2 was removed from union type UnionType1.", + ) + ] def should_detect_if_a_value_was_removed_from_an_enum_type(): - old_schema = build_schema(""" + old_schema = build_schema( + """ enum EnumType1 { VALUE0 VALUE1 @@ -324,9 +430,11 @@ def should_detect_if_a_value_was_removed_from_an_enum_type(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ enum EnumType1 { VALUE0 VALUE2 @@ -336,14 +444,19 @@ def should_detect_if_a_value_was_removed_from_an_enum_type(): type Query { field1: String } - """) + """ + ) assert find_values_removed_from_enums(old_schema, new_schema) == [ - (BreakingChangeType.VALUE_REMOVED_FROM_ENUM, - 'VALUE1 was removed from enum type EnumType1.')] + ( + BreakingChangeType.VALUE_REMOVED_FROM_ENUM, + "VALUE1 was removed from enum type EnumType1.", + ) + ] def should_detect_if_a_field_argument_was_removed(): - old_schema = build_schema(""" + old_schema = build_schema( + """ input InputType1 { field1: String } @@ -359,9 +472,11 @@ def should_detect_if_a_field_argument_was_removed(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ interface Interface1 { field1: String } @@ -373,18 +488,21 @@ def should_detect_if_a_field_argument_was_removed(): type Query { field1: String } - """) + """ + ) assert find_arg_changes(old_schema, new_schema).breaking_changes == [ - (BreakingChangeType.ARG_REMOVED, - 'Interface1.field1 arg arg1 was removed'), - (BreakingChangeType.ARG_REMOVED, - 'Interface1.field1 arg objectArg was removed'), - (BreakingChangeType.ARG_REMOVED, - 'Type1.field1 arg name was removed')] + (BreakingChangeType.ARG_REMOVED, "Interface1.field1 arg arg1 was removed"), + ( + BreakingChangeType.ARG_REMOVED, + "Interface1.field1 arg objectArg was removed", + ), + (BreakingChangeType.ARG_REMOVED, "Type1.field1 arg name was removed"), + ] def should_detect_if_a_field_argument_has_changed_type(): - old_schema = build_schema(""" + old_schema = build_schema( + """ type Type1 { field1( arg1: String @@ -408,9 +526,11 @@ def should_detect_if_a_field_argument_has_changed_type(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type Type1 { field1( arg1: Int @@ -434,37 +554,63 @@ def should_detect_if_a_field_argument_has_changed_type(): type Query { field1: String } - """) + """ + ) assert find_arg_changes(old_schema, new_schema).breaking_changes == [ - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg1 has changed type from String to Int'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg2 has changed type from String to [String]'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg3 has changed type from [String] to String'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg4 has changed type from String to String!'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg5 has changed type from String! to Int'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg6 has changed type from String! to Int!'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg8 has changed type from Int to [Int]!'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg9 has changed type from [Int] to [Int!]'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg11 has changed type from [Int] to [[Int]]'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg12 has changed type from [[Int]] to [Int]'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg13 has changed type from Int! to [Int]!'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'Type1.field1 arg arg15 has changed type from [[Int]!]' - ' to [[Int!]!]')] + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg1 has changed type from String to Int", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg2 has changed type from String to [String]", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg3 has changed type from [String] to String", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg4 has changed type from String to String!", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg5 has changed type from String! to Int", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg6 has changed type from String! to Int!", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg8 has changed type from Int to [Int]!", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg9 has changed type from [Int] to [Int!]", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg11 has changed type from [Int] to [[Int]]", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg12 has changed type from [[Int]] to [Int]", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg13 has changed type from Int! to [Int]!", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "Type1.field1 arg arg15 has changed type from [[Int]!]" " to [[Int!]!]", + ), + ] def should_detect_if_a_required_field_argument_was_added(): - old_schema = build_schema(""" + old_schema = build_schema( + """ type Type1 { field1(arg1: String): String } @@ -472,9 +618,11 @@ def should_detect_if_a_required_field_argument_was_added(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type Type1 { field1( arg1: String, @@ -487,14 +635,19 @@ def should_detect_if_a_required_field_argument_was_added(): type Query { field1: String } - """) # noqa + """ + ) # noqa assert find_arg_changes(old_schema, new_schema).breaking_changes == [ - (BreakingChangeType.REQUIRED_ARG_ADDED, - 'A required arg newRequiredArg on Type1.field1 was added')] + ( + BreakingChangeType.REQUIRED_ARG_ADDED, + "A required arg newRequiredArg on Type1.field1 was added", + ) + ] def should_not_flag_args_with_the_same_type_signature_as_breaking(): - old_schema = build_schema(""" + old_schema = build_schema( + """ input InputType1 { field1: String } @@ -506,9 +659,11 @@ def should_not_flag_args_with_the_same_type_signature_as_breaking(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ input InputType1 { field1: String } @@ -520,12 +675,14 @@ def should_not_flag_args_with_the_same_type_signature_as_breaking(): type Query { field1: String } - """) + """ + ) assert find_arg_changes(old_schema, new_schema).breaking_changes == [] def should_consider_args_that_move_away_from_non_null_as_non_breaking(): - old_schema = build_schema(""" + old_schema = build_schema( + """ type Type1 { field1(name: String!): String } @@ -533,9 +690,11 @@ def should_consider_args_that_move_away_from_non_null_as_non_breaking(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type Type1 { field1(name: String): String } @@ -543,12 +702,14 @@ def should_consider_args_that_move_away_from_non_null_as_non_breaking(): type Query { field1: String } - """) + """ + ) assert find_arg_changes(old_schema, new_schema).breaking_changes == [] def should_detect_interfaces_removed_from_types(): - old_schema = build_schema(""" + old_schema = build_schema( + """ interface Interface1 { field1: String } @@ -560,9 +721,11 @@ def should_detect_interfaces_removed_from_types(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type Type1 { field1: String } @@ -570,15 +733,19 @@ def should_detect_interfaces_removed_from_types(): type Query { field1: String } - """) + """ + ) - assert find_interfaces_removed_from_object_types( - old_schema, new_schema) == [ - (BreakingChangeType.INTERFACE_REMOVED_FROM_OBJECT, - 'Type1 no longer implements interface Interface1.')] + assert find_interfaces_removed_from_object_types(old_schema, new_schema) == [ + ( + BreakingChangeType.INTERFACE_REMOVED_FROM_OBJECT, + "Type1 no longer implements interface Interface1.", + ) + ] def should_detect_all_breaking_changes(): - old_schema = build_schema(""" + old_schema = build_schema( + """ directive @DirectiveThatIsRemoved on FIELD_DEFINITION directive @DirectiveThatRemovesArg(arg1: String) on FIELD_DEFINITION @@ -631,9 +798,11 @@ def should_detect_all_breaking_changes(): type Query { field1: String } - """) # noqa + """ + ) # noqa - new_schema = build_schema(""" + new_schema = build_schema( + """ directive @DirectiveThatRemovesArg on FIELD_DEFINITION directive @NonNullDirectiveAdded(arg1: Boolean!) on FIELD_DEFINITION @@ -674,131 +843,179 @@ def should_detect_all_breaking_changes(): type Query { field1: String } - """) # noqa + """ + ) # noqa expected_breaking_changes = [ - (BreakingChangeType.TYPE_REMOVED, - 'Int was removed.'), - (BreakingChangeType.TYPE_REMOVED, - 'TypeInUnion2 was removed.'), - (BreakingChangeType.TYPE_REMOVED, - 'TypeThatGetsRemoved was removed.'), - (BreakingChangeType.TYPE_CHANGED_KIND, - 'TypeThatChangesType changed from an Object type to an' - ' Interface type.'), - (BreakingChangeType.FIELD_REMOVED, - 'TypeThatHasBreakingFieldChanges.field1 was removed.'), - (BreakingChangeType.FIELD_CHANGED_KIND, - 'TypeThatHasBreakingFieldChanges.field2 changed type' - ' from String to Boolean.'), - (BreakingChangeType.TYPE_REMOVED_FROM_UNION, - 'TypeInUnion2 was removed from union type' - ' UnionTypeThatLosesAType.'), - (BreakingChangeType.VALUE_REMOVED_FROM_ENUM, - 'VALUE0 was removed from enum type EnumTypeThatLosesAValue.'), - (BreakingChangeType.ARG_CHANGED_KIND, - 'ArgThatChanges.field1 arg id has changed' - ' type from Int to String'), - (BreakingChangeType.INTERFACE_REMOVED_FROM_OBJECT, - 'TypeThatGainsInterface1 no longer implements' - ' interface Interface1.'), - (BreakingChangeType.DIRECTIVE_REMOVED, - 'DirectiveThatIsRemoved was removed'), - (BreakingChangeType.DIRECTIVE_ARG_REMOVED, - 'arg1 was removed from DirectiveThatRemovesArg'), - (BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, - 'A required arg arg1 on directive' - ' NonNullDirectiveAdded was added'), - (BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, - 'QUERY was removed from DirectiveName')] - - assert find_breaking_changes( - old_schema, new_schema) == expected_breaking_changes + (BreakingChangeType.TYPE_REMOVED, "Int was removed."), + (BreakingChangeType.TYPE_REMOVED, "TypeInUnion2 was removed."), + (BreakingChangeType.TYPE_REMOVED, "TypeThatGetsRemoved was removed."), + ( + BreakingChangeType.TYPE_CHANGED_KIND, + "TypeThatChangesType changed from an Object type to an" + " Interface type.", + ), + ( + BreakingChangeType.FIELD_REMOVED, + "TypeThatHasBreakingFieldChanges.field1 was removed.", + ), + ( + BreakingChangeType.FIELD_CHANGED_KIND, + "TypeThatHasBreakingFieldChanges.field2 changed type" + " from String to Boolean.", + ), + ( + BreakingChangeType.TYPE_REMOVED_FROM_UNION, + "TypeInUnion2 was removed from union type" " UnionTypeThatLosesAType.", + ), + ( + BreakingChangeType.VALUE_REMOVED_FROM_ENUM, + "VALUE0 was removed from enum type EnumTypeThatLosesAValue.", + ), + ( + BreakingChangeType.ARG_CHANGED_KIND, + "ArgThatChanges.field1 arg id has changed" " type from Int to String", + ), + ( + BreakingChangeType.INTERFACE_REMOVED_FROM_OBJECT, + "TypeThatGainsInterface1 no longer implements" " interface Interface1.", + ), + ( + BreakingChangeType.DIRECTIVE_REMOVED, + "DirectiveThatIsRemoved was removed", + ), + ( + BreakingChangeType.DIRECTIVE_ARG_REMOVED, + "arg1 was removed from DirectiveThatRemovesArg", + ), + ( + BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, + "A required arg arg1 on directive" " NonNullDirectiveAdded was added", + ), + ( + BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, + "QUERY was removed from DirectiveName", + ), + ] + + assert ( + find_breaking_changes(old_schema, new_schema) == expected_breaking_changes + ) def should_detect_if_a_directive_was_explicitly_removed(): - old_schema = build_schema(""" + old_schema = build_schema( + """ directive @DirectiveThatIsRemoved on FIELD_DEFINITION directive @DirectiveThatStays on FIELD_DEFINITION - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ directive @DirectiveThatStays on FIELD_DEFINITION - """) + """ + ) assert find_removed_directives(old_schema, new_schema) == [ - (BreakingChangeType.DIRECTIVE_REMOVED, - 'DirectiveThatIsRemoved was removed')] + (BreakingChangeType.DIRECTIVE_REMOVED, "DirectiveThatIsRemoved was removed") + ] def should_detect_if_a_directive_was_implicitly_removed(): old_schema = GraphQLSchema() new_schema = GraphQLSchema( - directives=[GraphQLSkipDirective, GraphQLIncludeDirective]) + directives=[GraphQLSkipDirective, GraphQLIncludeDirective] + ) assert find_removed_directives(old_schema, new_schema) == [ - (BreakingChangeType.DIRECTIVE_REMOVED, - f'{GraphQLDeprecatedDirective.name} was removed')] + ( + BreakingChangeType.DIRECTIVE_REMOVED, + f"{GraphQLDeprecatedDirective.name} was removed", + ) + ] def should_detect_if_a_directive_argument_was_removed(): - old_schema = build_schema(""" + old_schema = build_schema( + """ directive @DirectiveWithArg(arg1: Int) on FIELD_DEFINITION - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ directive @DirectiveWithArg on FIELD_DEFINITION - """) + """ + ) assert find_removed_directive_args(old_schema, new_schema) == [ - (BreakingChangeType.DIRECTIVE_ARG_REMOVED, - 'arg1 was removed from DirectiveWithArg')] + ( + BreakingChangeType.DIRECTIVE_ARG_REMOVED, + "arg1 was removed from DirectiveWithArg", + ) + ] def should_detect_if_an_optional_directive_argument_was_added(): - old_schema = build_schema(""" + old_schema = build_schema( + """ directive @DirectiveName on FIELD_DEFINITION - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ directive @DirectiveName( newRequiredArg: String! newOptionalArg1: Int newOptionalArg2: Int! = 0 ) on FIELD_DEFINITION - """) + """ + ) assert find_added_non_null_directive_args(old_schema, new_schema) == [ - (BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, 'A required arg' - ' newRequiredArg on directive DirectiveName was added')] + ( + BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, + "A required arg" " newRequiredArg on directive DirectiveName was added", + ) + ] def should_detect_locations_removed_from_a_directive(): - d1 = GraphQLDirective('Directive Name', locations=[ - DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.QUERY]) + d1 = GraphQLDirective( + "Directive Name", + locations=[DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.QUERY], + ) - d2 = GraphQLDirective('Directive Name', locations=[ - DirectiveLocation.FIELD_DEFINITION]) + d2 = GraphQLDirective( + "Directive Name", locations=[DirectiveLocation.FIELD_DEFINITION] + ) - assert find_removed_locations_for_directive(d1, d2) == [ - DirectiveLocation.QUERY] + assert find_removed_locations_for_directive(d1, d2) == [DirectiveLocation.QUERY] def should_detect_locations_removed_directives_within_a_schema(): - old_schema = build_schema(""" + old_schema = build_schema( + """ directive @DirectiveName on FIELD_DEFINITION | QUERY - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ directive @DirectiveName on FIELD_DEFINITION - """) + """ + ) assert find_removed_directive_locations(old_schema, new_schema) == [ - (BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, - 'QUERY was removed from DirectiveName')] + ( + BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, + "QUERY was removed from DirectiveName", + ) + ] def describe_find_dangerous_changes(): - def describe_find_arg_changes(): - def should_detect_if_an_arguments_default_value_has_changed(): - old_schema = build_schema(""" + old_schema = build_schema( + """ type Type1 { field1(name: String = "test"): String } @@ -806,9 +1023,11 @@ def should_detect_if_an_arguments_default_value_has_changed(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type Type1 { field1(name: String = "Test"): String } @@ -816,15 +1035,19 @@ def should_detect_if_an_arguments_default_value_has_changed(): type Query { field1: String } - """) + """ + ) - assert find_arg_changes( - old_schema, new_schema).dangerous_changes == [ - (DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, - 'Type1.field1 arg name has changed defaultValue')] + assert find_arg_changes(old_schema, new_schema).dangerous_changes == [ + ( + DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, + "Type1.field1 arg name has changed defaultValue", + ) + ] def should_detect_if_a_value_was_added_to_an_enum_type(): - old_schema = build_schema(""" + old_schema = build_schema( + """ enum EnumType1 { VALUE0 VALUE1 @@ -833,9 +1056,11 @@ def should_detect_if_a_value_was_added_to_an_enum_type(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ enum EnumType1 { VALUE0 VALUE1 @@ -845,14 +1070,19 @@ def should_detect_if_a_value_was_added_to_an_enum_type(): type Query { field1: String } - """) + """ + ) assert find_values_added_to_enums(old_schema, new_schema) == [ - (DangerousChangeType.VALUE_ADDED_TO_ENUM, - 'VALUE2 was added to enum type EnumType1.')] + ( + DangerousChangeType.VALUE_ADDED_TO_ENUM, + "VALUE2 was added to enum type EnumType1.", + ) + ] def should_detect_interfaces_added_to_types(): - old_schema = build_schema(""" + old_schema = build_schema( + """ type Type1 { field1: String } @@ -860,9 +1090,11 @@ def should_detect_interfaces_added_to_types(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ interface Interface1 { field1: String } @@ -874,15 +1106,19 @@ def should_detect_interfaces_added_to_types(): type Query { field1: String } - """) + """ + ) - assert find_interfaces_added_to_object_types( - old_schema, new_schema) == [ - (DangerousChangeType.INTERFACE_ADDED_TO_OBJECT, - 'Interface1 added to interfaces implemented by Type1.')] + assert find_interfaces_added_to_object_types(old_schema, new_schema) == [ + ( + DangerousChangeType.INTERFACE_ADDED_TO_OBJECT, + "Interface1 added to interfaces implemented by Type1.", + ) + ] def should_detect_if_a_type_was_added_to_a_union_type(): - old_schema = build_schema(""" + old_schema = build_schema( + """ type Type1 { field1: String } @@ -892,9 +1128,11 @@ def should_detect_if_a_type_was_added_to_a_union_type(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type Type1 { field1: String } @@ -908,14 +1146,19 @@ def should_detect_if_a_type_was_added_to_a_union_type(): type Query { field1: String } - """) + """ + ) assert find_types_added_to_unions(old_schema, new_schema) == [ - (DangerousChangeType.TYPE_ADDED_TO_UNION, - 'Type2 was added to union type UnionType1.')] + ( + DangerousChangeType.TYPE_ADDED_TO_UNION, + "Type2 was added to union type UnionType1.", + ) + ] def should_detect_if_an_optional_field_was_added_to_an_input(): - old_schema = build_schema(""" + old_schema = build_schema( + """ input InputType1 { field1: String } @@ -923,9 +1166,11 @@ def should_detect_if_an_optional_field_was_added_to_an_input(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ input InputType1 { field1: String field2: Int @@ -934,17 +1179,26 @@ def should_detect_if_an_optional_field_was_added_to_an_input(): type Query { field1: String } - """) + """ + ) expected_field_changes = [ - (DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED, - 'An optional field field2 on input type InputType1 was added.')] - - assert find_fields_that_changed_type_on_input_object_types( - old_schema, new_schema).dangerous_changes == expected_field_changes + ( + DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED, + "An optional field field2 on input type InputType1 was added.", + ) + ] + + assert ( + find_fields_that_changed_type_on_input_object_types( + old_schema, new_schema + ).dangerous_changes + == expected_field_changes + ) def should_find_all_dangerous_changes(): - old_schema = build_schema(""" + old_schema = build_schema( + """ enum EnumType1 { VALUE0 VALUE1 @@ -967,9 +1221,11 @@ def should_find_all_dangerous_changes(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ enum EnumType1 { VALUE0 VALUE1 @@ -1001,24 +1257,36 @@ def should_find_all_dangerous_changes(): type Query { field1: String } - """) + """ + ) expected_dangerous_changes = [ - (DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, - 'Type1.field1 arg name has changed defaultValue'), - (DangerousChangeType.VALUE_ADDED_TO_ENUM, - 'VALUE2 was added to enum type EnumType1.'), - (DangerousChangeType.INTERFACE_ADDED_TO_OBJECT, - 'Interface1 added to interfaces implemented' - ' by TypeThatGainsInterface1.'), - (DangerousChangeType.TYPE_ADDED_TO_UNION, - 'TypeInUnion2 was added to union type UnionTypeThatGainsAType.')] - - assert find_dangerous_changes( - old_schema, new_schema) == expected_dangerous_changes + ( + DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, + "Type1.field1 arg name has changed defaultValue", + ), + ( + DangerousChangeType.VALUE_ADDED_TO_ENUM, + "VALUE2 was added to enum type EnumType1.", + ), + ( + DangerousChangeType.INTERFACE_ADDED_TO_OBJECT, + "Interface1 added to interfaces implemented" + " by TypeThatGainsInterface1.", + ), + ( + DangerousChangeType.TYPE_ADDED_TO_UNION, + "TypeInUnion2 was added to union type UnionTypeThatGainsAType.", + ), + ] + + assert ( + find_dangerous_changes(old_schema, new_schema) == expected_dangerous_changes + ) def should_detect_if_an_optional_field_argument_was_added(): - old_schema = build_schema(""" + old_schema = build_schema( + """ type Type1 { field1(arg1: String): String } @@ -1026,9 +1294,11 @@ def should_detect_if_an_optional_field_argument_was_added(): type Query { field1: String } - """) + """ + ) - new_schema = build_schema(""" + new_schema = build_schema( + """ type Type1 { field1(arg1: String, arg2: String): String } @@ -1036,8 +1306,12 @@ def should_detect_if_an_optional_field_argument_was_added(): type Query { field1: String } - """) + """ + ) assert find_arg_changes(old_schema, new_schema).dangerous_changes == [ - (DangerousChangeType.OPTIONAL_ARG_ADDED, - 'An optional arg arg2 on Type1.field1 was added')] + ( + DangerousChangeType.OPTIONAL_ARG_ADDED, + "An optional arg arg2 on Type1.field1 was added", + ) + ] diff --git a/tests/utilities/test_find_deprecated_usages.py b/tests/utilities/test_find_deprecated_usages.py index 8e203b34..9c2df14f 100644 --- a/tests/utilities/test_find_deprecated_usages.py +++ b/tests/utilities/test_find_deprecated_usages.py @@ -1,43 +1,61 @@ from graphql.language import parse from graphql.type import ( - GraphQLEnumType, GraphQLEnumValue, GraphQLSchema, GraphQLObjectType, - GraphQLField, GraphQLString, GraphQLArgument) + GraphQLEnumType, + GraphQLEnumValue, + GraphQLSchema, + GraphQLObjectType, + GraphQLField, + GraphQLString, + GraphQLArgument, +) from graphql.utilities import find_deprecated_usages def describe_find_deprecated_usages(): - enum_type = GraphQLEnumType('EnumType', { - 'ONE': GraphQLEnumValue(), - 'TWO': GraphQLEnumValue(deprecation_reason='Some enum reason.')}) - - schema = GraphQLSchema(GraphQLObjectType('Query', { - 'normalField': GraphQLField(GraphQLString, args={ - 'enumArg': GraphQLArgument(enum_type)}), - 'deprecatedField': GraphQLField( - GraphQLString, deprecation_reason='Some field reason.')})) + enum_type = GraphQLEnumType( + "EnumType", + { + "ONE": GraphQLEnumValue(), + "TWO": GraphQLEnumValue(deprecation_reason="Some enum reason."), + }, + ) + + schema = GraphQLSchema( + GraphQLObjectType( + "Query", + { + "normalField": GraphQLField( + GraphQLString, args={"enumArg": GraphQLArgument(enum_type)} + ), + "deprecatedField": GraphQLField( + GraphQLString, deprecation_reason="Some field reason." + ), + }, + ) + ) def should_report_empty_set_for_no_deprecated_usages(): - errors = find_deprecated_usages( - schema, parse('{ normalField(enumArg: ONE) }')) + errors = find_deprecated_usages(schema, parse("{ normalField(enumArg: ONE) }")) assert errors == [] def should_report_usage_of_deprecated_fields(): errors = find_deprecated_usages( - schema, parse('{ normalField, deprecatedField }')) + schema, parse("{ normalField, deprecatedField }") + ) error_messages = [err.message for err in errors] assert error_messages == [ - 'The field Query.deprecatedField is deprecated.' - ' Some field reason.'] + "The field Query.deprecatedField is deprecated." " Some field reason." + ] def should_report_usage_of_deprecated_enums(): - errors = find_deprecated_usages( - schema, parse('{ normalField(enumArg: TWO) }')) + errors = find_deprecated_usages(schema, parse("{ normalField(enumArg: TWO) }")) error_messages = [err.message for err in errors] assert error_messages == [ - 'The enum value EnumType.TWO is deprecated. Some enum reason.'] + "The enum value EnumType.TWO is deprecated. Some enum reason." + ] diff --git a/tests/utilities/test_get_operation_ast.py b/tests/utilities/test_get_operation_ast.py index 7c50db4c..c60ca1a2 100644 --- a/tests/utilities/test_get_operation_ast.py +++ b/tests/utilities/test_get_operation_ast.py @@ -3,53 +3,60 @@ def describe_get_operation_ast(): - def gets_an_operation_from_a_simple_document(): - doc = parse('{ field }') + doc = parse("{ field }") assert get_operation_ast(doc) == doc.definitions[0] def gets_an_operation_from_a_document_with_named_op_mutation(): - doc = parse('mutation Test { field }') + doc = parse("mutation Test { field }") assert get_operation_ast(doc) == doc.definitions[0] def gets_an_operation_from_a_document_with_named_op_subscription(): - doc = parse('subscription Test { field }') + doc = parse("subscription Test { field }") assert get_operation_ast(doc) == doc.definitions[0] def does_not_get_missing_operation(): - doc = parse('type Foo { field: String }') + doc = parse("type Foo { field: String }") assert get_operation_ast(doc) is None def does_not_get_ambiguous_unnamed_operation(): - doc = parse(""" + doc = parse( + """ { field } mutation Test { field } subscription TestSub { field } - """) + """ + ) assert get_operation_ast(doc) is None def does_not_get_ambiguous_named_operation(): - doc = parse(""" + doc = parse( + """ query TestQ { field } mutation TestM { field } subscription TestS { field } - """) + """ + ) assert get_operation_ast(doc) is None def does_not_get_misnamed_operation(): - doc = parse(""" + doc = parse( + """ query TestQ { field } mutation TestM { field } subscription TestS { field } - """) - assert get_operation_ast(doc, 'Unknown') is None + """ + ) + assert get_operation_ast(doc, "Unknown") is None def gets_named_operation(): - doc = parse(""" + doc = parse( + """ query TestQ { field } mutation TestM { field } subscription TestS { field } - """) - assert get_operation_ast(doc, 'TestQ') == doc.definitions[0] - assert get_operation_ast(doc, 'TestM') == doc.definitions[1] - assert get_operation_ast(doc, 'TestS') == doc.definitions[2] + """ + ) + assert get_operation_ast(doc, "TestQ") == doc.definitions[0] + assert get_operation_ast(doc, "TestM") == doc.definitions[1] + assert get_operation_ast(doc, "TestS") == doc.definitions[2] diff --git a/tests/utilities/test_get_operation_root_type.py b/tests/utilities/test_get_operation_root_type.py index 98e7b15f..50ddf81f 100644 --- a/tests/utilities/test_get_operation_root_type.py +++ b/tests/utilities/test_get_operation_root_type.py @@ -2,44 +2,45 @@ from graphql.error import GraphQLError from graphql.language import ( - parse, OperationDefinitionNode, OperationTypeDefinitionNode, - SchemaDefinitionNode) -from graphql.type import ( - GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString) + parse, + 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)}) +query_type = GraphQLObjectType("FooQuery", {"field": GraphQLField(GraphQLString)}) -mutation_type = GraphQLObjectType('FooMutation', { - 'field': GraphQLField(GraphQLString)}) +mutation_type = GraphQLObjectType("FooMutation", {"field": GraphQLField(GraphQLString)}) -subscription_type = GraphQLObjectType('FooSubscription', { - 'field': GraphQLField(GraphQLString)}) +subscription_type = GraphQLObjectType( + "FooSubscription", {"field": GraphQLField(GraphQLString)} +) def describe_get_operation_root_type(): - def gets_a_query_type_for_an_unnamed_operation_definition_node(): test_schema = GraphQLSchema(query_type) - doc = parse('{ field }') + doc = parse("{ field }") operation = doc.definitions[0] assert isinstance(operation, OperationDefinitionNode) assert get_operation_root_type(test_schema, operation) is query_type def gets_a_query_type_for_a_named_operation_definition_node(): test_schema = GraphQLSchema(query_type) - doc = parse('query Q { field }') + doc = parse("query Q { field }") operation = doc.definitions[0] assert isinstance(operation, OperationDefinitionNode) assert get_operation_root_type(test_schema, operation) is query_type def gets_a_type_for_operation_definition_nodes(): - test_schema = GraphQLSchema( - query_type, mutation_type, subscription_type) - doc = parse('schema { query: FooQuery' - ' mutation: FooMutation subscription: FooSubscription }') + test_schema = GraphQLSchema(query_type, mutation_type, subscription_type) + doc = parse( + "schema { query: FooQuery" + " mutation: FooMutation subscription: FooSubscription }" + ) schema = doc.definitions[0] assert isinstance(schema, SchemaDefinitionNode) operations = schema.operation_types @@ -51,61 +52,59 @@ def gets_a_type_for_operation_definition_nodes(): assert get_operation_root_type(test_schema, operation) is mutation_type operation = operations[2] assert isinstance(operation, OperationTypeDefinitionNode) - assert get_operation_root_type( - test_schema, operation) is subscription_type + assert get_operation_root_type(test_schema, operation) is subscription_type def gets_a_mutation_type_for_an_operation_definition_node(): test_schema = GraphQLSchema(mutation=mutation_type) - doc = parse('mutation { field }') + doc = parse("mutation { field }") operation = doc.definitions[0] assert isinstance(operation, OperationDefinitionNode) assert get_operation_root_type(test_schema, operation) is mutation_type def gets_a_subscription_type_for_an_operation_definition_node(): test_schema = GraphQLSchema(subscription=subscription_type) - doc = parse('subscription { field }') + doc = parse("subscription { field }") operation = doc.definitions[0] assert isinstance(operation, OperationDefinitionNode) - assert get_operation_root_type( - test_schema, operation) is subscription_type + assert get_operation_root_type(test_schema, operation) is subscription_type def throws_when_query_type_not_defined_in_schema(): test_schema = GraphQLSchema() - doc = parse('query { field }') + doc = parse("query { field }") operation = doc.definitions[0] assert isinstance(operation, OperationDefinitionNode) with raises(GraphQLError) as exc_info: get_operation_root_type(test_schema, operation) assert exc_info.value.message == ( - 'Schema does not define the required query root type.') + "Schema does not define the required query root type." + ) def throws_when_mutation_type_not_defined_in_schema(): test_schema = GraphQLSchema() - doc = parse('mutation { field }') + doc = parse("mutation { field }") operation = doc.definitions[0] assert isinstance(operation, OperationDefinitionNode) with raises(GraphQLError) as exc_info: get_operation_root_type(test_schema, operation) - assert exc_info.value.message == ( - 'Schema is not configured for mutations.') + assert exc_info.value.message == ("Schema is not configured for mutations.") def throws_when_subscription_type_not_defined_in_schema(): test_schema = GraphQLSchema() - doc = parse('subscription { field }') + doc = parse("subscription { field }") operation = doc.definitions[0] assert isinstance(operation, OperationDefinitionNode) with raises(GraphQLError) as exc_info: get_operation_root_type(test_schema, operation) - assert exc_info.value.message == ( - 'Schema is not configured for subscriptions.') + assert exc_info.value.message == ("Schema is not configured for subscriptions.") def throws_when_operation_not_a_valid_operation_kind(): test_schema = GraphQLSchema() - doc = parse('{ field }') + doc = parse("{ field }") operation = doc.definitions[0] assert isinstance(operation, OperationDefinitionNode) - operation.operation = 'non_existent_operation' + operation.operation = "non_existent_operation" with raises(GraphQLError) as exc_info: get_operation_root_type(test_schema, operation) assert exc_info.value.message == ( - 'Can only have query, mutation and subscription operations.') + "Can only have query, mutation and subscription operations." + ) diff --git a/tests/utilities/test_introspection_from_schema.py b/tests/utilities/test_introspection_from_schema.py index 6cfd0aa1..14668b14 100644 --- a/tests/utilities/test_introspection_from_schema.py +++ b/tests/utilities/test_introspection_from_schema.py @@ -1,8 +1,10 @@ from graphql.pyutils import dedent -from graphql.type import ( - GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString) +from graphql.type import GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString from graphql.utilities import ( - build_client_schema, print_schema, introspection_from_schema) + build_client_schema, + print_schema, + introspection_from_schema, +) def introspection_to_sdl(introspection): @@ -11,15 +13,23 @@ def introspection_to_sdl(introspection): def describe_introspection_from_schema(): - schema = GraphQLSchema(GraphQLObjectType('Simple', { - 'string': GraphQLField( - GraphQLString, description='This is a string field')}, - description='This is a simple type')) + schema = GraphQLSchema( + GraphQLObjectType( + "Simple", + { + "string": GraphQLField( + GraphQLString, description="This is a string field" + ) + }, + description="This is a simple type", + ) + ) def converts_a_simple_schema(): introspection = introspection_from_schema(schema) - assert introspection_to_sdl(introspection) == dedent(''' + assert introspection_to_sdl(introspection) == dedent( + ''' schema { query: Simple } @@ -29,12 +39,14 @@ def converts_a_simple_schema(): """This is a string field""" string: String } - ''') + ''' + ) def converts_a_simple_schema_without_description(): introspection = introspection_from_schema(schema, descriptions=False) - assert introspection_to_sdl(introspection) == dedent(""" + assert introspection_to_sdl(introspection) == dedent( + """ schema { query: Simple } @@ -42,4 +54,5 @@ def converts_a_simple_schema_without_description(): type Simple { string: String } - """) + """ + ) diff --git a/tests/utilities/test_lexicographic_sort_schema.py b/tests/utilities/test_lexicographic_sort_schema.py index d42d77b9..768c388b 100644 --- a/tests/utilities/test_lexicographic_sort_schema.py +++ b/tests/utilities/test_lexicographic_sort_schema.py @@ -1,6 +1,5 @@ from graphql.pyutils import dedent -from graphql.utilities import ( - build_schema, print_schema, lexicographic_sort_schema) +from graphql.utilities import build_schema, print_schema, lexicographic_sort_schema def sort_sdl(sdl): @@ -9,9 +8,10 @@ def sort_sdl(sdl): def describe_lexicographic_sort_schema(): - def sort_fields(): - sorted_sdl = sort_sdl(dedent(""" + sorted_sdl = sort_sdl( + dedent( + """ input Bar { barB: String barA: String @@ -33,9 +33,12 @@ def sort_fields(): type Query { dummy(arg: Bar): FooType } - """)) + """ + ) + ) - assert sorted_sdl == dedent(""" + assert sorted_sdl == dedent( + """ input Bar { barA: String barB: String @@ -57,10 +60,13 @@ def sort_fields(): type Query { dummy(arg: Bar): FooType } - """) + """ + ) def sort_implemented_interfaces(): - sorted_sdl = sort_sdl(dedent(""" + sorted_sdl = sort_sdl( + dedent( + """ interface FooA { dummy: String } @@ -76,9 +82,12 @@ def sort_implemented_interfaces(): type Query implements FooB & FooA & FooC { dummy: String } - """)) + """ + ) + ) - assert sorted_sdl == dedent(""" + assert sorted_sdl == dedent( + """ interface FooA { dummy: String } @@ -94,10 +103,13 @@ def sort_implemented_interfaces(): type Query implements FooA & FooB & FooC { dummy: String } - """) + """ + ) def sort_types_in_union(): - sorted_sdl = sort_sdl(dedent(""" + sorted_sdl = sort_sdl( + dedent( + """ type FooA { dummy: String } @@ -115,9 +127,12 @@ def sort_types_in_union(): type Query { dummy: FooUnion } - """)) + """ + ) + ) - assert sorted_sdl == dedent(""" + assert sorted_sdl == dedent( + """ type FooA { dummy: String } @@ -135,10 +150,13 @@ def sort_types_in_union(): type Query { dummy: FooUnion } - """) + """ + ) def sort_enum_types(): - sorted_sdl = sort_sdl(dedent(""" + sorted_sdl = sort_sdl( + dedent( + """ enum Foo { B C @@ -148,9 +166,12 @@ def sort_enum_types(): type Query { dummy: Foo } - """)) + """ + ) + ) - assert sorted_sdl == dedent(""" + assert sorted_sdl == dedent( + """ enum Foo { A B @@ -160,23 +181,32 @@ def sort_enum_types(): type Query { dummy: Foo } - """) + """ + ) def sort_field_arguments(): - sorted_sdl = sort_sdl(dedent(""" + sorted_sdl = sort_sdl( + dedent( + """ type Query { dummy(argB: Int, argA: String, argC: Float): ID } - """)) + """ + ) + ) - assert sorted_sdl == dedent(""" + assert sorted_sdl == dedent( + """ type Query { dummy(argA: String, argB: Int, argC: Float): ID } - """) + """ + ) def sort_types(): - sorted_sdl = sort_sdl(dedent(""" + sorted_sdl = sort_sdl( + dedent( + """ type Query { dummy(arg1: FooF, arg2: FooA, arg3: FooG): FooD } @@ -204,9 +234,12 @@ def sort_types(): type FooB { dummy: String } - """)) + """ + ) + ) - assert sorted_sdl == dedent(""" + assert sorted_sdl == dedent( + """ scalar FooA type FooB { @@ -234,44 +267,59 @@ def sort_types(): type Query { dummy(arg1: FooF, arg2: FooA, arg3: FooG): FooD } - """) + """ + ) def sort_directive_arguments(): - sorted_sdl = sort_sdl(dedent(""" + sorted_sdl = sort_sdl( + dedent( + """ directive @test(argC: Float, argA: String, argB: Int) on FIELD type Query { dummy: String } - """)) + """ + ) + ) - assert sorted_sdl == dedent(""" + assert sorted_sdl == dedent( + """ directive @test(argA: String, argB: Int, argC: Float) on FIELD type Query { dummy: String } - """) + """ + ) def sort_directive_locations(): - sorted_sdl = sort_sdl(dedent(""" + sorted_sdl = sort_sdl( + dedent( + """ directive @test(argC: Float, argA: String, argB: Int) on UNION | FIELD | ENUM type Query { dummy: String } - """)) # noqa + """ # noqa + ) + ) - assert sorted_sdl == dedent(""" + assert sorted_sdl == dedent( + """ directive @test(argA: String, argB: Int, argC: Float) on ENUM | FIELD | UNION type Query { dummy: String } - """) # noqa + """ # noqa + ) def sort_directives(): - sorted_sdl = sort_sdl(dedent(""" + sorted_sdl = sort_sdl( + dedent( + """ directive @fooC on FIELD directive @fooB on UNION @@ -281,9 +329,12 @@ def sort_directives(): type Query { dummy: String } - """)) + """ + ) + ) - assert sorted_sdl == dedent(""" + assert sorted_sdl == dedent( + """ directive @fooA on ENUM directive @fooB on UNION @@ -293,10 +344,13 @@ def sort_directives(): type Query { dummy: String } - """) + """ + ) def sort_recursive_types(): - sorted_sdl = sort_sdl(dedent(""" + sorted_sdl = sort_sdl( + dedent( + """ interface FooC { fooB: FooB fooA: FooA @@ -318,9 +372,12 @@ def sort_recursive_types(): fooB: FooB fooA: FooA } - """)) + """ + ) + ) - assert sorted_sdl == dedent(""" + assert sorted_sdl == dedent( + """ type FooA implements FooC { fooA: FooA fooB: FooB @@ -342,4 +399,5 @@ def sort_recursive_types(): fooB: FooB fooC: FooC } - """) + """ + ) diff --git a/tests/utilities/test_schema_printer.py b/tests/utilities/test_schema_printer.py index f9a3db25..7554f885 100644 --- a/tests/utilities/test_schema_printer.py +++ b/tests/utilities/test_schema_printer.py @@ -1,13 +1,27 @@ from graphql.language import DirectiveLocation from graphql.pyutils import dedent from graphql.type import ( - GraphQLArgument, GraphQLBoolean, GraphQLEnumType, GraphQLEnumValue, - GraphQLField, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, - GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, - GraphQLSchema, GraphQLString, GraphQLUnionType, GraphQLType, - GraphQLNullableType, GraphQLInputField, GraphQLDirective) -from graphql.utilities import ( - build_schema, print_schema, print_introspection_schema) + GraphQLArgument, + GraphQLBoolean, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLInputObjectType, + GraphQLInt, + GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLScalarType, + GraphQLSchema, + GraphQLString, + GraphQLUnionType, + GraphQLType, + GraphQLNullableType, + GraphQLInputField, + GraphQLDirective, +) +from graphql.utilities import build_schema, print_schema, print_introspection_schema def print_for_test(schema: GraphQLSchema) -> str: @@ -18,8 +32,7 @@ def print_for_test(schema: GraphQLSchema) -> str: def print_single_field_schema(field: GraphQLField): - Query = GraphQLObjectType( - name='Query', fields={'singleField': field}) + Query = GraphQLObjectType(name="Query", fields={"singleField": field}) return print_for_test(GraphQLSchema(query=Query)) @@ -32,70 +45,83 @@ def non_null(type_: GraphQLNullableType): def describe_type_system_printer(): - def prints_string_field(): output = print_single_field_schema(GraphQLField(GraphQLString)) - assert output == dedent(""" + assert output == dedent( + """ type Query { singleField: String } - """) + """ + ) def prints_list_of_string_field(): - output = print_single_field_schema( - GraphQLField(list_of(GraphQLString))) - assert output == dedent(""" + output = print_single_field_schema(GraphQLField(list_of(GraphQLString))) + assert output == dedent( + """ type Query { singleField: [String] } - """) + """ + ) def prints_non_null_string_field(): - output = print_single_field_schema( - GraphQLField(non_null(GraphQLString))) - assert output == dedent(""" + output = print_single_field_schema(GraphQLField(non_null(GraphQLString))) + assert output == dedent( + """ type Query { singleField: String! } - """) + """ + ) def prints_non_null_list_of_string_field(): output = print_single_field_schema( - GraphQLField(non_null(list_of(GraphQLString)))) - assert output == dedent(""" + GraphQLField(non_null(list_of(GraphQLString))) + ) + assert output == dedent( + """ type Query { singleField: [String]! } - """) + """ + ) def prints_list_of_non_null_string_field(): output = print_single_field_schema( - GraphQLField((list_of(non_null(GraphQLString))))) - assert output == dedent(""" + GraphQLField((list_of(non_null(GraphQLString)))) + ) + assert output == dedent( + """ type Query { singleField: [String!] } - """) + """ + ) def prints_non_null_list_of_non_null_string_field(): - output = print_single_field_schema(GraphQLField( - non_null(list_of(non_null(GraphQLString))))) - assert output == dedent(""" + output = print_single_field_schema( + GraphQLField(non_null(list_of(non_null(GraphQLString)))) + ) + assert output == dedent( + """ type Query { singleField: [String!]! } - """) + """ + ) def prints_object_field(): FooType = GraphQLObjectType( - name='Foo', fields={'str': GraphQLField(GraphQLString)}) + name="Foo", fields={"str": GraphQLField(GraphQLString)} + ) - Query = GraphQLObjectType( - name='Query', fields={'foo': GraphQLField(FooType)}) + Query = GraphQLObjectType(name="Query", fields={"foo": GraphQLField(FooType)}) Schema = GraphQLSchema(query=Query) output = print_for_test(Schema) - assert output == dedent(""" + assert output == dedent( + """ type Foo { str: String } @@ -103,119 +129,172 @@ def prints_object_field(): type Query { foo: Foo } - """) + """ + ) def prints_string_field_with_int_arg(): - output = print_single_field_schema(GraphQLField( - type_=GraphQLString, - args={'argOne': GraphQLArgument(GraphQLInt)})) - assert output == dedent(""" + output = print_single_field_schema( + GraphQLField( + type_=GraphQLString, args={"argOne": GraphQLArgument(GraphQLInt)} + ) + ) + assert output == dedent( + """ type Query { singleField(argOne: Int): String } - """) + """ + ) def 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 == dedent(""" + output = print_single_field_schema( + GraphQLField( + type_=GraphQLString, + args={"argOne": GraphQLArgument(GraphQLInt, default_value=2)}, + ) + ) + assert output == dedent( + """ type Query { singleField(argOne: Int = 2): String } - """) + """ + ) def prints_string_field_with_string_arg_with_default(): - output = print_single_field_schema(GraphQLField( - type_=GraphQLString, - args={'argOne': GraphQLArgument( - GraphQLString, default_value='tes\t de\fault')})) - assert output == dedent(r""" + output = print_single_field_schema( + GraphQLField( + type_=GraphQLString, + args={ + "argOne": GraphQLArgument( + GraphQLString, default_value="tes\t de\fault" + ) + }, + ) + ) + assert output == dedent( + r""" type Query { singleField(argOne: String = "tes\t de\fault"): String } - """) + """ + ) def prints_string_field_with_int_arg_with_default_null(): - output = print_single_field_schema(GraphQLField( - type_=GraphQLString, - args={'argOne': GraphQLArgument(GraphQLInt, default_value=None)})) - assert output == dedent(""" + output = print_single_field_schema( + GraphQLField( + type_=GraphQLString, + args={"argOne": GraphQLArgument(GraphQLInt, default_value=None)}, + ) + ) + assert output == dedent( + """ type Query { singleField(argOne: Int = null): String } - """) + """ + ) def prints_string_field_with_non_null_int_arg(): - output = print_single_field_schema(GraphQLField( - type_=GraphQLString, - args={'argOne': GraphQLArgument(non_null(GraphQLInt))})) - assert output == dedent(""" + output = print_single_field_schema( + GraphQLField( + type_=GraphQLString, + args={"argOne": GraphQLArgument(non_null(GraphQLInt))}, + ) + ) + assert output == dedent( + """ type Query { singleField(argOne: Int!): String } - """) + """ + ) def prints_string_field_with_multiple_args(): - output = print_single_field_schema(GraphQLField( - type_=GraphQLString, - args={ - 'argOne': GraphQLArgument(GraphQLInt), - 'argTwo': GraphQLArgument(GraphQLString)})) - assert output == dedent(""" + output = print_single_field_schema( + GraphQLField( + type_=GraphQLString, + args={ + "argOne": GraphQLArgument(GraphQLInt), + "argTwo": GraphQLArgument(GraphQLString), + }, + ) + ) + assert output == dedent( + """ type Query { singleField(argOne: Int, argTwo: String): String } - """) + """ + ) def prints_string_field_with_multiple_args_first_is_default(): - output = print_single_field_schema(GraphQLField( - type_=GraphQLString, - args={ - 'argOne': GraphQLArgument(GraphQLInt, default_value=1), - 'argTwo': GraphQLArgument(GraphQLString), - 'argThree': GraphQLArgument(GraphQLBoolean)})) - assert output == dedent(""" + output = print_single_field_schema( + GraphQLField( + type_=GraphQLString, + args={ + "argOne": GraphQLArgument(GraphQLInt, default_value=1), + "argTwo": GraphQLArgument(GraphQLString), + "argThree": GraphQLArgument(GraphQLBoolean), + }, + ) + ) + assert output == dedent( + """ type Query { singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String } - """) # noqa + """ # noqa + ) def prints_string_field_with_multiple_args_second_is_default(): - output = print_single_field_schema(GraphQLField( - type_=GraphQLString, - args={ - 'argOne': GraphQLArgument(GraphQLInt), - 'argTwo': GraphQLArgument(GraphQLString, default_value="foo"), - 'argThree': GraphQLArgument(GraphQLBoolean)})) - assert output == dedent(""" + output = print_single_field_schema( + GraphQLField( + type_=GraphQLString, + args={ + "argOne": GraphQLArgument(GraphQLInt), + "argTwo": GraphQLArgument(GraphQLString, default_value="foo"), + "argThree": GraphQLArgument(GraphQLBoolean), + }, + ) + ) + assert output == dedent( + """ type Query { singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String } - """) # noqa + """ # noqa + ) def prints_string_field_with_multiple_args_last_is_default(): - output = print_single_field_schema(GraphQLField( - type_=GraphQLString, - args={ - 'argOne': GraphQLArgument(GraphQLInt), - 'argTwo': GraphQLArgument(GraphQLString), - 'argThree': - GraphQLArgument(GraphQLBoolean, default_value=False)})) - assert output == dedent(""" + output = print_single_field_schema( + GraphQLField( + type_=GraphQLString, + args={ + "argOne": GraphQLArgument(GraphQLInt), + "argTwo": GraphQLArgument(GraphQLString), + "argThree": GraphQLArgument(GraphQLBoolean, default_value=False), + }, + ) + ) + assert output == dedent( + """ type Query { singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String } - """) # noqa + """ # noqa + ) def prints_custom_query_root_type(): CustomQueryType = GraphQLObjectType( - 'CustomQueryType', {'bar': GraphQLField(GraphQLString)}) + "CustomQueryType", {"bar": GraphQLField(GraphQLString)} + ) Schema = GraphQLSchema(CustomQueryType) output = print_for_test(Schema) - assert output == dedent(""" + assert output == dedent( + """ schema { query: CustomQueryType } @@ -223,25 +302,26 @@ def prints_custom_query_root_type(): type CustomQueryType { bar: String } - """) + """ + ) def prints_interface(): FooType = GraphQLInterfaceType( - name='Foo', - fields={'str': GraphQLField(GraphQLString)}) + name="Foo", fields={"str": GraphQLField(GraphQLString)} + ) BarType = GraphQLObjectType( - name='Bar', - fields={'str': GraphQLField(GraphQLString)}, - interfaces=[FooType]) + name="Bar", + fields={"str": GraphQLField(GraphQLString)}, + interfaces=[FooType], + ) - Root = GraphQLObjectType( - name='Root', - fields={'bar': GraphQLField(BarType)}) + Root = GraphQLObjectType(name="Root", fields={"bar": GraphQLField(BarType)}) Schema = GraphQLSchema(Root, types=[BarType]) output = print_for_test(Schema) - assert output == dedent(""" + assert output == dedent( + """ schema { query: Root } @@ -257,31 +337,33 @@ def prints_interface(): type Root { bar: Bar } - """) + """ + ) def prints_multiple_interfaces(): FooType = GraphQLInterfaceType( - name='Foo', - fields={'str': GraphQLField(GraphQLString)}) + name="Foo", fields={"str": GraphQLField(GraphQLString)} + ) BaazType = GraphQLInterfaceType( - name='Baaz', - fields={'int': GraphQLField(GraphQLInt)}) + name="Baaz", fields={"int": GraphQLField(GraphQLInt)} + ) BarType = GraphQLObjectType( - name='Bar', + name="Bar", fields={ - 'str': GraphQLField(GraphQLString), - 'int': GraphQLField(GraphQLInt)}, - interfaces=[FooType, BaazType]) + "str": GraphQLField(GraphQLString), + "int": GraphQLField(GraphQLInt), + }, + interfaces=[FooType, BaazType], + ) - Root = GraphQLObjectType( - name='Root', - fields={'bar': GraphQLField(BarType)}) + Root = GraphQLObjectType(name="Root", fields={"bar": GraphQLField(BarType)}) Schema = GraphQLSchema(Root, types=[BarType]) output = print_for_test(Schema) - assert output == dedent(""" + assert output == dedent( + """ schema { query: Root } @@ -302,34 +384,34 @@ def prints_multiple_interfaces(): type Root { bar: Bar } - """) + """ + ) def prints_unions(): FooType = GraphQLObjectType( - name='Foo', - fields={'bool': GraphQLField(GraphQLBoolean)}) + name="Foo", fields={"bool": GraphQLField(GraphQLBoolean)} + ) BarType = GraphQLObjectType( - name='Bar', - fields={'str': GraphQLField(GraphQLString)}) + name="Bar", fields={"str": GraphQLField(GraphQLString)} + ) - SingleUnion = GraphQLUnionType( - name='SingleUnion', - types=[FooType]) + SingleUnion = GraphQLUnionType(name="SingleUnion", types=[FooType]) - MultipleUnion = GraphQLUnionType( - name='MultipleUnion', - types=[FooType, BarType]) + MultipleUnion = GraphQLUnionType(name="MultipleUnion", types=[FooType, BarType]) Root = GraphQLObjectType( - name='Root', + name="Root", fields={ - 'single': GraphQLField(SingleUnion), - 'multiple': GraphQLField(MultipleUnion)}) + "single": GraphQLField(SingleUnion), + "multiple": GraphQLField(MultipleUnion), + }, + ) Schema = GraphQLSchema(Root) output = print_for_test(Schema) - assert output == dedent(""" + assert output == dedent( + """ schema { query: Root } @@ -350,21 +432,27 @@ def prints_unions(): } union SingleUnion = Foo - """) + """ + ) def prints_input_type(): InputType = GraphQLInputObjectType( - name='InputType', - fields={'int': GraphQLInputField(GraphQLInt)}) + name="InputType", fields={"int": GraphQLInputField(GraphQLInt)} + ) Root = GraphQLObjectType( - name='Root', - fields={'str': GraphQLField( - GraphQLString, args={'argOne': GraphQLArgument(InputType)})}) + name="Root", + fields={ + "str": GraphQLField( + GraphQLString, args={"argOne": GraphQLArgument(InputType)} + ) + }, + ) Schema = GraphQLSchema(Root) output = print_for_test(Schema) - assert output == dedent(""" + assert output == dedent( + """ schema { query: Root } @@ -376,20 +464,20 @@ def prints_input_type(): type Root { str(argOne: InputType): String } - """) + """ + ) def prints_custom_scalar(): OddType = GraphQLScalarType( - name='Odd', - serialize=lambda value: value if value % 2 else None) + name="Odd", serialize=lambda value: value if value % 2 else None + ) - Root = GraphQLObjectType( - name='Root', - fields={'odd': GraphQLField(OddType)}) + Root = GraphQLObjectType(name="Root", fields={"odd": GraphQLField(OddType)}) Schema = GraphQLSchema(Root) output = print_for_test(Schema) - assert output == dedent(""" + assert output == dedent( + """ schema { query: Root } @@ -399,23 +487,25 @@ def prints_custom_scalar(): type Root { odd: Odd } - """) + """ + ) def prints_enum(): RGBType = GraphQLEnumType( - name='RGB', + name="RGB", values={ - 'RED': GraphQLEnumValue(0), - 'GREEN': GraphQLEnumValue(1), - 'BLUE': GraphQLEnumValue(2)}) + "RED": GraphQLEnumValue(0), + "GREEN": GraphQLEnumValue(1), + "BLUE": GraphQLEnumValue(2), + }, + ) - Root = GraphQLObjectType( - name='Root', - fields={'rgb': GraphQLField(RGBType)}) + Root = GraphQLObjectType(name="Root", fields={"rgb": GraphQLField(RGBType)}) Schema = GraphQLSchema(Root) output = print_for_test(Schema) - assert output == dedent(""" + assert output == dedent( + """ schema { query: Root } @@ -429,82 +519,93 @@ def prints_enum(): type Root { rgb: RGB } - """) + """ + ) def prints_custom_directives(): Query = GraphQLObjectType( - name='Query', - fields={'field': GraphQLField(GraphQLString)}) + name="Query", fields={"field": GraphQLField(GraphQLString)} + ) CustomDirective = GraphQLDirective( - name='customDirective', - locations=[DirectiveLocation.FIELD]) + name="customDirective", locations=[DirectiveLocation.FIELD] + ) - Schema = GraphQLSchema( - query=Query, - directives=[CustomDirective]) + Schema = GraphQLSchema(query=Query, directives=[CustomDirective]) output = print_for_test(Schema) - assert output == dedent(""" + assert output == dedent( + """ directive @customDirective on FIELD type Query { field: String } - """) + """ + ) def one_line_prints_a_short_description(): - description = 'This field is awesome' - output = print_single_field_schema(GraphQLField( - GraphQLString, description=description)) - assert output == dedent(''' + description = "This field is awesome" + output = print_single_field_schema( + GraphQLField(GraphQLString, description=description) + ) + assert output == dedent( + ''' type Query { """This field is awesome""" singleField: String } - ''') - recreated_root = build_schema(output).type_map['Query'] - recreated_field = recreated_root.fields['singleField'] + ''' + ) + recreated_root = build_schema(output).type_map["Query"] + recreated_field = recreated_root.fields["singleField"] assert recreated_field.description == description def does_not_one_line_print_a_description_that_ends_with_a_quote(): description = 'This field is "awesome"' - output = print_single_field_schema(GraphQLField( - GraphQLString, description=description)) - assert output == dedent(''' + output = print_single_field_schema( + GraphQLField(GraphQLString, description=description) + ) + assert output == dedent( + ''' type Query { """ This field is "awesome" """ singleField: String } - ''') - recreated_root = build_schema(output).type_map['Query'] - recreated_field = recreated_root.fields['singleField'] + ''' + ) + recreated_root = build_schema(output).type_map["Query"] + recreated_field = recreated_root.fields["singleField"] assert recreated_field.description == description def preserves_leading_spaces_when_printing_a_description(): description = ' This field is "awesome"' - output = print_single_field_schema(GraphQLField( - GraphQLString, description=description)) - assert output == dedent(''' + output = print_single_field_schema( + GraphQLField(GraphQLString, description=description) + ) + assert output == dedent( + ''' type Query { """ This field is "awesome" """ singleField: String } - ''') - recreated_root = build_schema(output).type_map['Query'] - recreated_field = recreated_root.fields['singleField'] + ''' + ) + recreated_root = build_schema(output).type_map["Query"] + recreated_field = recreated_root.fields["singleField"] assert recreated_field.description == description def prints_introspection_schema(): Root = GraphQLObjectType( - name='Root', - fields={'onlyField': GraphQLField(GraphQLString)}) + name="Root", fields={"onlyField": GraphQLField(GraphQLString)} + ) Schema = GraphQLSchema(Root) output = print_introspection_schema(Schema) - assert output == dedent(''' + assert output == dedent( + ''' schema { query: Root } @@ -734,4 +835,5 @@ def prints_introspection_schema(): """Indicates this type is a non-null. `ofType` is a valid field.""" NON_NULL } - ''') # noqa + ''' # noqa + ) diff --git a/tests/utilities/test_separate_operations.py b/tests/utilities/test_separate_operations.py index dc0449a1..e0d6b161 100644 --- a/tests/utilities/test_separate_operations.py +++ b/tests/utilities/test_separate_operations.py @@ -4,9 +4,9 @@ def describe_separate_operations(): - def separates_one_ast_into_multiple_maintaining_document_order(): - ast = parse(""" + ast = parse( + """ { ...Y ...X @@ -42,13 +42,15 @@ def separates_one_ast_into_multiple_maintaining_document_order(): something } - """) + """ + ) separated_asts = separate_operations(ast) - assert list(separated_asts) == ['', 'One', 'Two'] + assert list(separated_asts) == ["", "One", "Two"] - assert print_ast(separated_asts['']) == dedent(""" + assert print_ast(separated_asts[""]) == dedent( + """ { ...Y ...X @@ -61,9 +63,11 @@ def separates_one_ast_into_multiple_maintaining_document_order(): fragment Y on T { fieldY } - """) + """ + ) - assert print_ast(separated_asts['One']) == dedent(""" + assert print_ast(separated_asts["One"]) == dedent( + """ query One { foo bar @@ -83,9 +87,11 @@ def separates_one_ast_into_multiple_maintaining_document_order(): fragment B on T { something } - """) + """ + ) - assert print_ast(separated_asts['Two']) == dedent(""" + assert print_ast(separated_asts["Two"]) == dedent( + """ fragment A on T { field ...B @@ -104,10 +110,12 @@ def separates_one_ast_into_multiple_maintaining_document_order(): fragment B on T { something } - """) + """ + ) def survives_circular_dependencies(): - ast = parse(""" + ast = parse( + """ query One { ...A } @@ -123,13 +131,15 @@ def survives_circular_dependencies(): query Two { ...B } - """) + """ + ) separated_asts = separate_operations(ast) - assert list(separated_asts) == ['One', 'Two'] + assert list(separated_asts) == ["One", "Two"] - assert print_ast(separated_asts['One']) == dedent(""" + assert print_ast(separated_asts["One"]) == dedent( + """ query One { ...A } @@ -141,9 +151,11 @@ def survives_circular_dependencies(): fragment B on T { ...A } - """) + """ + ) - assert print_ast(separated_asts['Two']) == dedent(""" + assert print_ast(separated_asts["Two"]) == dedent( + """ fragment A on T { ...B } @@ -155,4 +167,5 @@ def survives_circular_dependencies(): query Two { ...B } - """) + """ + ) diff --git a/tests/utilities/test_type_comparators.py b/tests/utilities/test_type_comparators.py index 608f6f19..19944a90 100644 --- a/tests/utilities/test_type_comparators.py +++ b/tests/utilities/test_type_comparators.py @@ -1,16 +1,23 @@ from pytest import fixture from graphql.type import ( - GraphQLField, GraphQLFloat, GraphQLInt, GraphQLInterfaceType, GraphQLList, - GraphQLNonNull, GraphQLObjectType, GraphQLOutputType, GraphQLSchema, - GraphQLString, GraphQLUnionType) + GraphQLField, + GraphQLFloat, + GraphQLInt, + GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLOutputType, + GraphQLSchema, + GraphQLString, + GraphQLUnionType, +) from graphql.utilities import is_equal_type, is_type_sub_type_of def describe_type_comparators(): - def describe_is_equal_type(): - def same_references_are_equal(): assert is_equal_type(GraphQLString, GraphQLString) is True @@ -18,65 +25,77 @@ def int_and_float_are_not_equal(): assert is_equal_type(GraphQLInt, GraphQLFloat) is False def lists_of_same_type_are_equal(): - assert is_equal_type( - GraphQLList(GraphQLInt), GraphQLList(GraphQLInt)) is True + assert ( + is_equal_type(GraphQLList(GraphQLInt), GraphQLList(GraphQLInt)) is True + ) def lists_is_not_equal_to_item(): assert is_equal_type(GraphQLList(GraphQLInt), GraphQLInt) is False def nonnull_of_same_type_are_equal(): - assert is_equal_type( - GraphQLNonNull(GraphQLInt), GraphQLNonNull(GraphQLInt)) is True + assert ( + is_equal_type(GraphQLNonNull(GraphQLInt), GraphQLNonNull(GraphQLInt)) + is True + ) def nonnull_is_not_equal_to_nullable(): - assert is_equal_type( - GraphQLNonNull(GraphQLInt), GraphQLInt) is False + assert is_equal_type(GraphQLNonNull(GraphQLInt), GraphQLInt) is False def describe_is_type_sub_type_of(): - @fixture - def test_schema(field_type: GraphQLOutputType=GraphQLString): + def test_schema(field_type: GraphQLOutputType = GraphQLString): return GraphQLSchema( - query=GraphQLObjectType('Query', { - 'field': GraphQLField(field_type)})) + query=GraphQLObjectType("Query", {"field": GraphQLField(field_type)}) + ) def same_reference_is_subtype(): - assert is_type_sub_type_of( - test_schema(), GraphQLString, GraphQLString) is True + assert ( + is_type_sub_type_of(test_schema(), GraphQLString, GraphQLString) is True + ) def int_is_not_subtype_of_float(): - assert is_type_sub_type_of( - test_schema(), GraphQLInt, GraphQLFloat) is False + assert is_type_sub_type_of(test_schema(), GraphQLInt, GraphQLFloat) is False def non_null_is_subtype_of_nullable(): - assert is_type_sub_type_of( - test_schema(), GraphQLNonNull(GraphQLInt), GraphQLInt) is True + assert ( + is_type_sub_type_of( + test_schema(), GraphQLNonNull(GraphQLInt), GraphQLInt + ) + is True + ) def nullable_is_not_subtype_of_non_null(): - assert is_type_sub_type_of( - test_schema(), GraphQLInt, GraphQLNonNull(GraphQLInt)) is False + assert ( + is_type_sub_type_of( + test_schema(), GraphQLInt, GraphQLNonNull(GraphQLInt) + ) + is False + ) def item_is_not_subtype_of_list(): assert not is_type_sub_type_of( - test_schema(), GraphQLInt, GraphQLList(GraphQLInt)) + test_schema(), GraphQLInt, GraphQLList(GraphQLInt) + ) def list_is_not_subtype_of_item(): assert not is_type_sub_type_of( - test_schema(), GraphQLList(GraphQLInt), GraphQLInt) + test_schema(), GraphQLList(GraphQLInt), GraphQLInt + ) def member_is_subtype_of_union(): - member = GraphQLObjectType('Object', { - 'field': GraphQLField(GraphQLString)}) - union = GraphQLUnionType('Union', [member]) + member = GraphQLObjectType("Object", {"field": GraphQLField(GraphQLString)}) + union = GraphQLUnionType("Union", [member]) schema = test_schema(union) assert is_type_sub_type_of(schema, member, union) def implementation_is_subtype_of_interface(): - iface = GraphQLInterfaceType('Interface', { - 'field': GraphQLField(GraphQLString)}) + iface = GraphQLInterfaceType( + "Interface", {"field": GraphQLField(GraphQLString)} + ) impl = GraphQLObjectType( - 'Object', - fields={'field': GraphQLField(GraphQLString)}, - interfaces=[iface]) + "Object", + fields={"field": GraphQLField(GraphQLString)}, + interfaces=[iface], + ) schema = test_schema(impl) assert is_type_sub_type_of(schema, impl, iface) diff --git a/tests/utilities/test_value_from_ast.py b/tests/utilities/test_value_from_ast.py index 6c3f3635..763c4da9 100644 --- a/tests/utilities/test_value_from_ast.py +++ b/tests/utilities/test_value_from_ast.py @@ -4,14 +4,21 @@ from graphql.error import INVALID from graphql.language import parse_value from graphql.type import ( - GraphQLBoolean, GraphQLEnumType, GraphQLFloat, - GraphQLID, GraphQLInputField, GraphQLInputObjectType, GraphQLInt, - GraphQLList, GraphQLNonNull, GraphQLString) + GraphQLBoolean, + GraphQLEnumType, + GraphQLFloat, + GraphQLID, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInt, + GraphQLList, + GraphQLNonNull, + GraphQLString, +) from graphql.utilities import value_from_ast def describe_value_from_ast(): - @fixture def test_case(type_, value_text, expected): value_node = parse_value(value_text) @@ -32,44 +39,41 @@ def rejects_empty_input(): assert value_from_ast(None, GraphQLBoolean) is INVALID def converts_according_to_input_coercion_rules(): - test_case(GraphQLBoolean, 'true', True) - test_case(GraphQLBoolean, 'false', False) - test_case(GraphQLInt, '123', 123) - test_case(GraphQLFloat, '123', 123) - test_case(GraphQLFloat, '123.456', 123.456) - test_case(GraphQLString, '"abc123"', 'abc123') - test_case(GraphQLID, '123456', '123456') - test_case(GraphQLID, '"123456"', '123456') + test_case(GraphQLBoolean, "true", True) + test_case(GraphQLBoolean, "false", False) + test_case(GraphQLInt, "123", 123) + test_case(GraphQLFloat, "123", 123) + test_case(GraphQLFloat, "123.456", 123.456) + test_case(GraphQLString, '"abc123"', "abc123") + test_case(GraphQLID, "123456", "123456") + test_case(GraphQLID, '"123456"', "123456") def does_not_convert_when_input_coercion_rules_reject_a_value(): - test_case(GraphQLBoolean, '123', INVALID) - test_case(GraphQLInt, '123.456', INVALID) - test_case(GraphQLInt, 'true', INVALID) + test_case(GraphQLBoolean, "123", INVALID) + test_case(GraphQLInt, "123.456", INVALID) + test_case(GraphQLInt, "true", INVALID) test_case(GraphQLInt, '"123"', INVALID) test_case(GraphQLFloat, '"123"', INVALID) - test_case(GraphQLString, '123', INVALID) - test_case(GraphQLString, 'true', INVALID) - test_case(GraphQLID, '123.456', INVALID) - - test_enum = GraphQLEnumType('TestColor', { - 'RED': 1, - 'GREEN': 2, - 'BLUE': 3, - 'NULL': None, - 'INVALID': INVALID, - 'NAN': nan}) + test_case(GraphQLString, "123", INVALID) + test_case(GraphQLString, "true", INVALID) + test_case(GraphQLID, "123.456", INVALID) + + test_enum = GraphQLEnumType( + "TestColor", + {"RED": 1, "GREEN": 2, "BLUE": 3, "NULL": None, "INVALID": INVALID, "NAN": nan}, + ) def converts_enum_values_according_to_input_coercion_rules(): - test_case(test_enum, 'RED', 1) - test_case(test_enum, 'BLUE', 3) - test_case(test_enum, 'YELLOW', INVALID) - test_case(test_enum, '3', INVALID) + test_case(test_enum, "RED", 1) + test_case(test_enum, "BLUE", 3) + test_case(test_enum, "YELLOW", INVALID) + test_case(test_enum, "3", INVALID) test_case(test_enum, '"BLUE"', INVALID) - test_case(test_enum, 'null', None) - test_case(test_enum, 'NULL', None) - test_case(test_enum, 'INVALID', INVALID) + test_case(test_enum, "null", None) + test_case(test_enum, "NULL", None) + test_case(test_enum, "INVALID", INVALID) # nan is not equal to itself, needs a special test case - test_case_expect_nan(test_enum, 'NAN') + test_case_expect_nan(test_enum, "NAN") # Boolean! non_null_bool = GraphQLNonNull(GraphQLBoolean) @@ -83,90 +87,94 @@ def converts_enum_values_according_to_input_coercion_rules(): non_null_list_of_non_mull_bool = GraphQLNonNull(list_of_non_null_bool) def coerces_to_null_unless_non_null(): - test_case(GraphQLBoolean, 'null', None) - test_case(non_null_bool, 'null', INVALID) + test_case(GraphQLBoolean, "null", None) + test_case(non_null_bool, "null", INVALID) def coerces_lists_of_values(): - test_case(list_of_bool, 'true', [True]) - test_case(list_of_bool, '123', INVALID) - test_case(list_of_bool, 'null', None) - test_case(list_of_bool, '[true, false]', [True, False]) - test_case(list_of_bool, '[true, 123]', INVALID) - test_case(list_of_bool, '[true, null]', [True, None]) - test_case(list_of_bool, '{ true: true }', INVALID) + test_case(list_of_bool, "true", [True]) + test_case(list_of_bool, "123", INVALID) + test_case(list_of_bool, "null", None) + test_case(list_of_bool, "[true, false]", [True, False]) + test_case(list_of_bool, "[true, 123]", INVALID) + test_case(list_of_bool, "[true, null]", [True, None]) + test_case(list_of_bool, "{ true: true }", INVALID) def coerces_non_null_lists_of_values(): - test_case(non_null_list_of_bool, 'true', [True]) - test_case(non_null_list_of_bool, '123', INVALID) - test_case(non_null_list_of_bool, 'null', INVALID) - test_case(non_null_list_of_bool, '[true, false]', [True, False]) - test_case(non_null_list_of_bool, '[true, 123]', INVALID) - test_case(non_null_list_of_bool, '[true, null]', [True, None]) + test_case(non_null_list_of_bool, "true", [True]) + test_case(non_null_list_of_bool, "123", INVALID) + test_case(non_null_list_of_bool, "null", INVALID) + test_case(non_null_list_of_bool, "[true, false]", [True, False]) + test_case(non_null_list_of_bool, "[true, 123]", INVALID) + test_case(non_null_list_of_bool, "[true, null]", [True, None]) def coerces_lists_of_non_null_values(): - test_case(list_of_non_null_bool, 'true', [True]) - test_case(list_of_non_null_bool, '123', INVALID) - test_case(list_of_non_null_bool, 'null', None) - test_case(list_of_non_null_bool, '[true, false]', [True, False]) - test_case(list_of_non_null_bool, '[true, 123]', INVALID) - test_case(list_of_non_null_bool, '[true, null]', INVALID) + test_case(list_of_non_null_bool, "true", [True]) + test_case(list_of_non_null_bool, "123", INVALID) + test_case(list_of_non_null_bool, "null", None) + test_case(list_of_non_null_bool, "[true, false]", [True, False]) + test_case(list_of_non_null_bool, "[true, 123]", INVALID) + test_case(list_of_non_null_bool, "[true, null]", INVALID) def coerces_non_null_lists_of_non_null_values(): - test_case(non_null_list_of_non_mull_bool, 'true', [True]) - test_case(non_null_list_of_non_mull_bool, '123', INVALID) - test_case(non_null_list_of_non_mull_bool, 'null', INVALID) - test_case(non_null_list_of_non_mull_bool, - '[true, false]', [True, False]) - test_case(non_null_list_of_non_mull_bool, '[true, 123]', INVALID) - test_case(non_null_list_of_non_mull_bool, '[true, null]', INVALID) - - test_input_obj = GraphQLInputObjectType('TestInput', { - 'int': GraphQLInputField(GraphQLInt, default_value=42), - 'bool': GraphQLInputField(GraphQLBoolean), - 'requiredBool': GraphQLInputField(non_null_bool)}) + test_case(non_null_list_of_non_mull_bool, "true", [True]) + test_case(non_null_list_of_non_mull_bool, "123", INVALID) + test_case(non_null_list_of_non_mull_bool, "null", INVALID) + test_case(non_null_list_of_non_mull_bool, "[true, false]", [True, False]) + test_case(non_null_list_of_non_mull_bool, "[true, 123]", INVALID) + test_case(non_null_list_of_non_mull_bool, "[true, null]", INVALID) + + test_input_obj = GraphQLInputObjectType( + "TestInput", + { + "int": GraphQLInputField(GraphQLInt, default_value=42), + "bool": GraphQLInputField(GraphQLBoolean), + "requiredBool": GraphQLInputField(non_null_bool), + }, + ) def coerces_input_objects_according_to_input_coercion_rules(): - test_case(test_input_obj, 'null', None) - test_case(test_input_obj, '123', INVALID) - test_case(test_input_obj, '[]', INVALID) - test_case(test_input_obj, '{ int: 123, requiredBool: false }', { - 'int': 123, - 'requiredBool': False, - }) - test_case(test_input_obj, '{ bool: true, requiredBool: false }', { - 'int': 42, - 'bool': True, - 'requiredBool': False, - }) - test_case(test_input_obj, - '{ int: true, requiredBool: true }', INVALID) - test_case(test_input_obj, '{ requiredBool: null }', INVALID) - test_case(test_input_obj, '{ bool: true }', INVALID) + test_case(test_input_obj, "null", None) + test_case(test_input_obj, "123", INVALID) + test_case(test_input_obj, "[]", INVALID) + test_case( + test_input_obj, + "{ int: 123, requiredBool: false }", + {"int": 123, "requiredBool": False}, + ) + test_case( + test_input_obj, + "{ bool: true, requiredBool: false }", + {"int": 42, "bool": True, "requiredBool": False}, + ) + test_case(test_input_obj, "{ int: true, requiredBool: true }", INVALID) + test_case(test_input_obj, "{ requiredBool: null }", INVALID) + test_case(test_input_obj, "{ bool: true }", INVALID) def accepts_variable_values_assuming_already_coerced(): - test_case_with_vars({}, GraphQLBoolean, '$var', INVALID) - test_case_with_vars({'var': True}, GraphQLBoolean, '$var', True) - test_case_with_vars({'var': None}, GraphQLBoolean, '$var', None) + test_case_with_vars({}, GraphQLBoolean, "$var", INVALID) + test_case_with_vars({"var": True}, GraphQLBoolean, "$var", True) + test_case_with_vars({"var": None}, GraphQLBoolean, "$var", None) def asserts_variables_are_provided_as_items_in_lists(): - test_case_with_vars({}, list_of_bool, '[ $foo ]', [None]) - test_case_with_vars({}, list_of_non_null_bool, '[ $foo ]', INVALID) - test_case_with_vars( - {'foo': True}, list_of_non_null_bool, '[ $foo ]', [True]) + test_case_with_vars({}, list_of_bool, "[ $foo ]", [None]) + test_case_with_vars({}, list_of_non_null_bool, "[ $foo ]", INVALID) + test_case_with_vars({"foo": True}, list_of_non_null_bool, "[ $foo ]", [True]) # Note: variables are expected to have already been coerced, so we # do not expect the singleton wrapping behavior for variables. - test_case_with_vars( - {'foo': True}, list_of_non_null_bool, '$foo', True) - test_case_with_vars( - {'foo': [True]}, list_of_non_null_bool, '$foo', [True]) + test_case_with_vars({"foo": True}, list_of_non_null_bool, "$foo", True) + test_case_with_vars({"foo": [True]}, list_of_non_null_bool, "$foo", [True]) def omits_input_object_fields_for_unprovided_variables(): test_case_with_vars( - {}, test_input_obj, - '{ int: $foo, bool: $foo, requiredBool: true }', - {'int': 42, 'requiredBool': True}) - test_case_with_vars( - {}, test_input_obj, '{ requiredBool: $foo }', INVALID) + {}, + test_input_obj, + "{ int: $foo, bool: $foo, requiredBool: true }", + {"int": 42, "requiredBool": True}, + ) + test_case_with_vars({}, test_input_obj, "{ requiredBool: $foo }", INVALID) test_case_with_vars( - {'foo': True}, test_input_obj, '{ requiredBool: $foo }', - {'int': 42, 'requiredBool': True}) + {"foo": True}, + test_input_obj, + "{ requiredBool: $foo }", + {"int": 42, "requiredBool": True}, + ) diff --git a/tests/utilities/test_value_from_ast_untyped.py b/tests/utilities/test_value_from_ast_untyped.py index e93dff0a..0cc0ac65 100644 --- a/tests/utilities/test_value_from_ast_untyped.py +++ b/tests/utilities/test_value_from_ast_untyped.py @@ -6,7 +6,6 @@ def describe_value_from_ast_untyped(): - @fixture def test_case(value_text, expected): value_node = parse_value(value_text) @@ -18,32 +17,32 @@ def test_case_with_vars(value_text, variables, expected): assert value_from_ast_untyped(value_node, variables) == expected def parses_simple_values(): - test_case('null', None) - test_case('true', True) - test_case('false', False) - test_case('123', 123) - test_case('123.456', 123.456) - test_case('"abc123"', 'abc123') + test_case("null", None) + test_case("true", True) + test_case("false", False) + test_case("123", 123) + test_case("123.456", 123.456) + test_case('"abc123"', "abc123") def parses_lists_of_values(): - test_case('[true, false]', [True, False]) - test_case('[true, 123.45]', [True, 123.45]) - test_case('[true, null]', [True, None]) - test_case('[true, ["foo", 1.2]]', [True, ['foo', 1.2]]) + test_case("[true, false]", [True, False]) + test_case("[true, 123.45]", [True, 123.45]) + test_case("[true, null]", [True, None]) + test_case('[true, ["foo", 1.2]]', [True, ["foo", 1.2]]) def parses_input_objects(): - test_case('{ int: 123, bool: false }', {'int': 123, 'bool': False}) - test_case('{ foo: [ { bar: "baz"} ] }', {'foo': [{'bar': 'baz'}]}) + test_case("{ int: 123, bool: false }", {"int": 123, "bool": False}) + test_case('{ foo: [ { bar: "baz"} ] }', {"foo": [{"bar": "baz"}]}) def parses_enum_values_as_plain_strings(): - test_case('TEST_ENUM_VALUE', 'TEST_ENUM_VALUE') - test_case('[TEST_ENUM_VALUE]', ['TEST_ENUM_VALUE']) + test_case("TEST_ENUM_VALUE", "TEST_ENUM_VALUE") + test_case("[TEST_ENUM_VALUE]", ["TEST_ENUM_VALUE"]) def parses_variables(): - test_case_with_vars('$testVariable', {'testVariable': 'foo'}, 'foo') - test_case_with_vars( - '[$testVariable]', {'testVariable': 'foo'}, ['foo']) + test_case_with_vars("$testVariable", {"testVariable": "foo"}, "foo") + test_case_with_vars("[$testVariable]", {"testVariable": "foo"}, ["foo"]) test_case_with_vars( - '{a:[$testVariable]}', {'testVariable': 'foo'}, {'a': ['foo']}) - test_case_with_vars('$testVariable', {'testVariable': None}, None) - test_case_with_vars('$testVariable', {}, INVALID) + "{a:[$testVariable]}", {"testVariable": "foo"}, {"a": ["foo"]} + ) + test_case_with_vars("$testVariable", {"testVariable": None}, None) + test_case_with_vars("$testVariable", {}, INVALID) diff --git a/tests/validation/harness.py b/tests/validation/harness.py index 3a8e8a4d..6ccbbb9e 100644 --- a/tests/validation/harness.py +++ b/tests/validation/harness.py @@ -1,141 +1,223 @@ from graphql.language.parser import parse from graphql.type import ( - GraphQLArgument, GraphQLBoolean, GraphQLEnumType, - GraphQLEnumValue, GraphQLField, GraphQLFloat, - GraphQLID, GraphQLInputField, - GraphQLInputObjectType, GraphQLInt, - GraphQLInterfaceType, GraphQLList, GraphQLNonNull, - GraphQLObjectType, GraphQLSchema, GraphQLString, - GraphQLUnionType, GraphQLScalarType) + GraphQLArgument, + GraphQLBoolean, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLFloat, + GraphQLID, + GraphQLInputField, + GraphQLInputObjectType, + GraphQLInt, + GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, + GraphQLUnionType, + GraphQLScalarType, +) from graphql.type.directives import ( - DirectiveLocation, GraphQLDirective, + DirectiveLocation, + GraphQLDirective, GraphQLIncludeDirective, - GraphQLSkipDirective) + GraphQLSkipDirective, +) from graphql.validation.validate import validate, validate_sdl -Being = GraphQLInterfaceType('Being', { - 'name': GraphQLField(GraphQLString, { - 'surname': GraphQLArgument(GraphQLBoolean)})}) - -Pet = GraphQLInterfaceType('Pet', { - 'name': GraphQLField(GraphQLString, { - 'surname': GraphQLArgument(GraphQLBoolean)})}) - -Canine = GraphQLInterfaceType('Canine', { - 'name': GraphQLField(GraphQLString, { - 'surname': GraphQLArgument(GraphQLBoolean)})}) - -DogCommand = GraphQLEnumType('DogCommand', { - 'SIT': GraphQLEnumValue(0), - 'HEEL': GraphQLEnumValue(1), - 'DOWN': GraphQLEnumValue(2)}) - -Dog = GraphQLObjectType('Dog', { - 'name': GraphQLField(GraphQLString, { - 'surname': GraphQLArgument(GraphQLBoolean)}), - 'nickname': GraphQLField(GraphQLString), - 'barkVolume': GraphQLField(GraphQLInt), - 'barks': GraphQLField(GraphQLBoolean), - 'doesKnowCommand': GraphQLField(GraphQLBoolean, { - 'dogCommand': GraphQLArgument(DogCommand)}), - 'isHousetrained': GraphQLField( - GraphQLBoolean, - args={'atOtherHomes': GraphQLArgument( - GraphQLBoolean, default_value=True)}), - 'isAtLocation': GraphQLField( - GraphQLBoolean, - args={'x': GraphQLArgument(GraphQLInt), - 'y': GraphQLArgument(GraphQLInt)})}, - interfaces=[Being, Pet, Canine], is_type_of=lambda: True) - -Cat = GraphQLObjectType('Cat', lambda: { - 'furColor': GraphQLField(FurColor), - 'name': GraphQLField(GraphQLString, { - 'surname': GraphQLArgument(GraphQLBoolean)}), - 'nickname': GraphQLField(GraphQLString)}, - interfaces=[Being, Pet], is_type_of=lambda: True) - -CatOrDog = GraphQLUnionType('CatOrDog', [Dog, Cat]) - -Intelligent = GraphQLInterfaceType('Intelligent', { - 'iq': GraphQLField(GraphQLInt)}) +Being = GraphQLInterfaceType( + "Being", + {"name": GraphQLField(GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)})}, +) + +Pet = GraphQLInterfaceType( + "Pet", + {"name": GraphQLField(GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)})}, +) + +Canine = GraphQLInterfaceType( + "Canine", + {"name": GraphQLField(GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)})}, +) + +DogCommand = GraphQLEnumType( + "DogCommand", + { + "SIT": GraphQLEnumValue(0), + "HEEL": GraphQLEnumValue(1), + "DOWN": GraphQLEnumValue(2), + }, +) + +Dog = GraphQLObjectType( + "Dog", + { + "name": GraphQLField( + GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)} + ), + "nickname": GraphQLField(GraphQLString), + "barkVolume": GraphQLField(GraphQLInt), + "barks": GraphQLField(GraphQLBoolean), + "doesKnowCommand": GraphQLField( + GraphQLBoolean, {"dogCommand": GraphQLArgument(DogCommand)} + ), + "isHousetrained": GraphQLField( + GraphQLBoolean, + args={"atOtherHomes": GraphQLArgument(GraphQLBoolean, default_value=True)}, + ), + "isAtLocation": GraphQLField( + GraphQLBoolean, + args={"x": GraphQLArgument(GraphQLInt), "y": GraphQLArgument(GraphQLInt)}, + ), + }, + interfaces=[Being, Pet, Canine], + is_type_of=lambda: True, +) + +Cat = GraphQLObjectType( + "Cat", + lambda: { + "furColor": GraphQLField(FurColor), + "name": GraphQLField( + GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)} + ), + "nickname": GraphQLField(GraphQLString), + }, + interfaces=[Being, Pet], + is_type_of=lambda: True, +) + +CatOrDog = GraphQLUnionType("CatOrDog", [Dog, Cat]) + +Intelligent = GraphQLInterfaceType("Intelligent", {"iq": GraphQLField(GraphQLInt)}) Human = GraphQLObjectType( - name='Human', + name="Human", interfaces=[Being, Intelligent], is_type_of=lambda: True, fields={ - 'name': GraphQLField(GraphQLString, { - 'surname': GraphQLArgument(GraphQLBoolean)}), - 'pets': GraphQLField(GraphQLList(Pet)), - 'iq': GraphQLField(GraphQLInt)}) + "name": GraphQLField( + GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)} + ), + "pets": GraphQLField(GraphQLList(Pet)), + "iq": GraphQLField(GraphQLInt), + }, +) Alien = GraphQLObjectType( - name='Alien', + name="Alien", is_type_of=lambda: True, interfaces=[Being, Intelligent], fields={ - 'iq': GraphQLField(GraphQLInt), - 'name': GraphQLField(GraphQLString, { - 'surname': GraphQLArgument(GraphQLBoolean)}), - 'numEyes': GraphQLField(GraphQLInt)}) - -DogOrHuman = GraphQLUnionType('DogOrHuman', [Dog, Human]) - -HumanOrAlien = GraphQLUnionType('HumanOrAlien', [Human, Alien]) - -FurColor = GraphQLEnumType('FurColor', { - 'BROWN': GraphQLEnumValue(0), - 'BLACK': GraphQLEnumValue(1), - 'TAN': GraphQLEnumValue(2), - 'SPOTTED': GraphQLEnumValue(3), - 'NO_FUR': GraphQLEnumValue(), - 'UNKNOWN': None}) - -ComplexInput = GraphQLInputObjectType('ComplexInput', { - 'requiredField': GraphQLInputField(GraphQLNonNull(GraphQLBoolean)), - 'nonNullField': GraphQLInputField( - GraphQLNonNull(GraphQLBoolean), default_value=False), - 'intField': GraphQLInputField(GraphQLInt), - 'stringField': GraphQLInputField(GraphQLString), - 'booleanField': GraphQLInputField(GraphQLBoolean), - 'stringListField': GraphQLInputField(GraphQLList(GraphQLString))}) - -ComplicatedArgs = GraphQLObjectType('ComplicatedArgs', { - 'intArgField': GraphQLField(GraphQLString, { - 'intArg': GraphQLArgument(GraphQLInt)}), - 'nonNullIntArgField': GraphQLField(GraphQLString, { - 'nonNullIntArg': GraphQLArgument(GraphQLNonNull(GraphQLInt))}), - 'stringArgField': GraphQLField(GraphQLString, { - 'stringArg': GraphQLArgument(GraphQLString)}), - 'booleanArgField': GraphQLField(GraphQLString, { - 'booleanArg': GraphQLArgument(GraphQLBoolean)}), - 'enumArgField': GraphQLField(GraphQLString, { - 'enumArg': GraphQLArgument(FurColor)}), - 'floatArgField': GraphQLField(GraphQLString, { - 'floatArg': GraphQLArgument(GraphQLFloat)}), - 'idArgField': GraphQLField(GraphQLString, { - 'idArg': GraphQLArgument(GraphQLID)}), - 'stringListArgField': GraphQLField(GraphQLString, { - 'stringListArg': GraphQLArgument(GraphQLList(GraphQLString))}), - 'stringListNonNullArgField': GraphQLField(GraphQLString, args={ - 'stringListNonNullArg': GraphQLArgument( - GraphQLList(GraphQLNonNull(GraphQLString)))}), - 'complexArgField': GraphQLField(GraphQLString, { - 'complexArg': GraphQLArgument(ComplexInput)}), - 'multipleReqs': GraphQLField(GraphQLString, { - 'req1': GraphQLArgument(GraphQLNonNull(GraphQLInt)), - 'req2': GraphQLArgument(GraphQLNonNull(GraphQLInt))}), - 'nonNullFieldWithDefault': GraphQLField(GraphQLString, { - 'arg': GraphQLArgument(GraphQLNonNull(GraphQLInt), default_value=0)}), - 'multipleOpts': GraphQLField(GraphQLString, { - 'opt1': GraphQLArgument(GraphQLInt, 0), - 'opt2': GraphQLArgument(GraphQLInt, 0)}), - 'multipleOptsAndReq': GraphQLField(GraphQLString, { - 'req1': GraphQLArgument(GraphQLNonNull(GraphQLInt)), - 'req2': GraphQLArgument(GraphQLNonNull(GraphQLInt)), - 'opt1': GraphQLArgument(GraphQLInt, 0), - 'opt2': GraphQLArgument(GraphQLInt, 0)})}) + "iq": GraphQLField(GraphQLInt), + "name": GraphQLField( + GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)} + ), + "numEyes": GraphQLField(GraphQLInt), + }, +) + +DogOrHuman = GraphQLUnionType("DogOrHuman", [Dog, Human]) + +HumanOrAlien = GraphQLUnionType("HumanOrAlien", [Human, Alien]) + +FurColor = GraphQLEnumType( + "FurColor", + { + "BROWN": GraphQLEnumValue(0), + "BLACK": GraphQLEnumValue(1), + "TAN": GraphQLEnumValue(2), + "SPOTTED": GraphQLEnumValue(3), + "NO_FUR": GraphQLEnumValue(), + "UNKNOWN": None, + }, +) + +ComplexInput = GraphQLInputObjectType( + "ComplexInput", + { + "requiredField": GraphQLInputField(GraphQLNonNull(GraphQLBoolean)), + "nonNullField": GraphQLInputField( + GraphQLNonNull(GraphQLBoolean), default_value=False + ), + "intField": GraphQLInputField(GraphQLInt), + "stringField": GraphQLInputField(GraphQLString), + "booleanField": GraphQLInputField(GraphQLBoolean), + "stringListField": GraphQLInputField(GraphQLList(GraphQLString)), + }, +) + +ComplicatedArgs = GraphQLObjectType( + "ComplicatedArgs", + { + "intArgField": GraphQLField( + GraphQLString, {"intArg": GraphQLArgument(GraphQLInt)} + ), + "nonNullIntArgField": GraphQLField( + GraphQLString, + {"nonNullIntArg": GraphQLArgument(GraphQLNonNull(GraphQLInt))}, + ), + "stringArgField": GraphQLField( + GraphQLString, {"stringArg": GraphQLArgument(GraphQLString)} + ), + "booleanArgField": GraphQLField( + GraphQLString, {"booleanArg": GraphQLArgument(GraphQLBoolean)} + ), + "enumArgField": GraphQLField( + GraphQLString, {"enumArg": GraphQLArgument(FurColor)} + ), + "floatArgField": GraphQLField( + GraphQLString, {"floatArg": GraphQLArgument(GraphQLFloat)} + ), + "idArgField": GraphQLField( + GraphQLString, {"idArg": GraphQLArgument(GraphQLID)} + ), + "stringListArgField": GraphQLField( + GraphQLString, + {"stringListArg": GraphQLArgument(GraphQLList(GraphQLString))}, + ), + "stringListNonNullArgField": GraphQLField( + GraphQLString, + args={ + "stringListNonNullArg": GraphQLArgument( + GraphQLList(GraphQLNonNull(GraphQLString)) + ) + }, + ), + "complexArgField": GraphQLField( + GraphQLString, {"complexArg": GraphQLArgument(ComplexInput)} + ), + "multipleReqs": GraphQLField( + GraphQLString, + { + "req1": GraphQLArgument(GraphQLNonNull(GraphQLInt)), + "req2": GraphQLArgument(GraphQLNonNull(GraphQLInt)), + }, + ), + "nonNullFieldWithDefault": GraphQLField( + GraphQLString, + {"arg": GraphQLArgument(GraphQLNonNull(GraphQLInt), default_value=0)}, + ), + "multipleOpts": GraphQLField( + GraphQLString, + { + "opt1": GraphQLArgument(GraphQLInt, 0), + "opt2": GraphQLArgument(GraphQLInt, 0), + }, + ), + "multipleOptsAndReq": GraphQLField( + GraphQLString, + { + "req1": GraphQLArgument(GraphQLNonNull(GraphQLInt)), + "req2": GraphQLArgument(GraphQLNonNull(GraphQLInt)), + "opt1": GraphQLArgument(GraphQLInt, 0), + "opt2": GraphQLArgument(GraphQLInt, 0), + }, + ), + }, +) def raise_type_error(message): @@ -143,74 +225,78 @@ def raise_type_error(message): InvalidScalar = GraphQLScalarType( - name='Invalid', + name="Invalid", serialize=lambda value: value, parse_literal=lambda node: raise_type_error( - f'Invalid scalar is always invalid: {node.value}'), + f"Invalid scalar is always invalid: {node.value}" + ), parse_value=lambda node: raise_type_error( - f'Invalid scalar is always invalid: {node}')) + f"Invalid scalar is always invalid: {node}" + ), +) AnyScalar = GraphQLScalarType( - name='Any', + name="Any", serialize=lambda value: value, parse_literal=lambda node: node, # Allows any value - parse_value=lambda value: value) # Allows any value - -QueryRoot = GraphQLObjectType('QueryRoot', { - 'human': GraphQLField(Human, { - 'id': GraphQLArgument(GraphQLID), - }), - 'dog': GraphQLField(Dog), - 'pet': GraphQLField(Pet), - 'alien': GraphQLField(Alien), - 'catOrDog': GraphQLField(CatOrDog), - 'humanOrAlien': GraphQLField(HumanOrAlien), - 'complicatedArgs': GraphQLField(ComplicatedArgs), - 'invalidArg': GraphQLField(GraphQLString, args={ - 'arg': GraphQLArgument(InvalidScalar)}), - 'anyArg': GraphQLField(GraphQLString, args={ - 'arg': GraphQLArgument(AnyScalar)})}) + parse_value=lambda value: value, +) # Allows any value + +QueryRoot = GraphQLObjectType( + "QueryRoot", + { + "human": GraphQLField(Human, {"id": GraphQLArgument(GraphQLID)}), + "dog": GraphQLField(Dog), + "pet": GraphQLField(Pet), + "alien": GraphQLField(Alien), + "catOrDog": GraphQLField(CatOrDog), + "humanOrAlien": GraphQLField(HumanOrAlien), + "complicatedArgs": GraphQLField(ComplicatedArgs), + "invalidArg": GraphQLField( + GraphQLString, args={"arg": GraphQLArgument(InvalidScalar)} + ), + "anyArg": GraphQLField(GraphQLString, args={"arg": GraphQLArgument(AnyScalar)}), + }, +) test_schema = GraphQLSchema( query=QueryRoot, directives=[ GraphQLIncludeDirective, GraphQLSkipDirective, + GraphQLDirective(name="onQuery", locations=[DirectiveLocation.QUERY]), + GraphQLDirective(name="onMutation", locations=[DirectiveLocation.MUTATION]), GraphQLDirective( - name='onQuery', - locations=[DirectiveLocation.QUERY]), - GraphQLDirective( - name='onMutation', - locations=[DirectiveLocation.MUTATION]), - GraphQLDirective( - name='onSubscription', - locations=[DirectiveLocation.SUBSCRIPTION]), - GraphQLDirective( - name='onField', - locations=[DirectiveLocation.FIELD]), + name="onSubscription", locations=[DirectiveLocation.SUBSCRIPTION] + ), + GraphQLDirective(name="onField", locations=[DirectiveLocation.FIELD]), GraphQLDirective( - name='onFragmentDefinition', - locations=[DirectiveLocation.FRAGMENT_DEFINITION]), + name="onFragmentDefinition", + locations=[DirectiveLocation.FRAGMENT_DEFINITION], + ), GraphQLDirective( - name='onFragmentSpread', - locations=[DirectiveLocation.FRAGMENT_SPREAD]), + name="onFragmentSpread", locations=[DirectiveLocation.FRAGMENT_SPREAD] + ), GraphQLDirective( - name='onInlineFragment', - locations=[DirectiveLocation.INLINE_FRAGMENT]), + name="onInlineFragment", locations=[DirectiveLocation.INLINE_FRAGMENT] + ), GraphQLDirective( - name='onVariableDefinition', - locations=[DirectiveLocation.VARIABLE_DEFINITION])], - types=[Cat, Dog, Human, Alien]) + name="onVariableDefinition", + locations=[DirectiveLocation.VARIABLE_DEFINITION], + ), + ], + types=[Cat, Dog, Human, Alien], +) def expect_valid(schema, rule, query_string, **options): errors = validate(schema, parse(query_string, **options), [rule]) - assert errors == [], 'Should validate' + assert errors == [], "Should validate" def expect_invalid(schema, rule, query_string, expected_errors, **options): errors = validate(schema, parse(query_string, **options), [rule]) - assert errors, 'Should not validate' + assert errors, "Should not validate" assert errors == expected_errors return errors diff --git a/tests/validation/test_executable_definitions.py b/tests/validation/test_executable_definitions.py index 3d495aa8..8618eb36 100644 --- a/tests/validation/test_executable_definitions.py +++ b/tests/validation/test_executable_definitions.py @@ -1,30 +1,35 @@ from graphql.validation import ExecutableDefinitionsRule from graphql.validation.rules.executable_definitions import ( - non_executable_definitions_message) + non_executable_definitions_message +) from .harness import expect_fails_rule, expect_passes_rule -def non_executable_definition( - def_name, line, column): +def non_executable_definition(def_name, line, column): return { - 'message': non_executable_definitions_message(def_name), - 'locations': [(line, column)]} + "message": non_executable_definitions_message(def_name), + "locations": [(line, column)], + } def describe_validate_executable_definitions(): - def with_only_operation(): - expect_passes_rule(ExecutableDefinitionsRule, """ + expect_passes_rule( + ExecutableDefinitionsRule, + """ query Foo { dog { name } } - """) + """, + ) def with_operation_and_fragment(): - expect_passes_rule(ExecutableDefinitionsRule, """ + expect_passes_rule( + ExecutableDefinitionsRule, + """ query Foo { dog { name @@ -35,10 +40,13 @@ def with_operation_and_fragment(): fragment Frag on Dog { name } - """) + """, + ) def with_type_definition(): - expect_fails_rule(ExecutableDefinitionsRule, """ + expect_fails_rule( + ExecutableDefinitionsRule, + """ query Foo { dog { name @@ -52,13 +60,17 @@ def with_type_definition(): extend type Dog { color: String } - """, [ - non_executable_definition('Cow', 8, 13), - non_executable_definition('Dog', 12, 13) - ]) + """, + [ + non_executable_definition("Cow", 8, 13), + non_executable_definition("Dog", 12, 13), + ], + ) def with_schema_definition(): - expect_fails_rule(ExecutableDefinitionsRule, """ + expect_fails_rule( + ExecutableDefinitionsRule, + """ schema { query: Query } @@ -68,8 +80,10 @@ def with_schema_definition(): } extend schema @directive - """, [ - non_executable_definition('schema', 2, 13), - non_executable_definition('Query', 6, 13), - non_executable_definition('schema', 10, 13), - ]) + """, + [ + non_executable_definition("schema", 2, 13), + non_executable_definition("Query", 6, 13), + non_executable_definition("schema", 10, 13), + ], + ) diff --git a/tests/validation/test_fields_on_correct_type.py b/tests/validation/test_fields_on_correct_type.py index 70fa124a..dbc4b18f 100644 --- a/tests/validation/test_fields_on_correct_type.py +++ b/tests/validation/test_fields_on_correct_type.py @@ -1,67 +1,86 @@ from graphql.validation import FieldsOnCorrectTypeRule -from graphql.validation.rules.fields_on_correct_type import ( - undefined_field_message) +from graphql.validation.rules.fields_on_correct_type import undefined_field_message from .harness import expect_fails_rule, expect_passes_rule -def undefined_field( - field, type_, suggested_types, suggested_fields, line, column): +def undefined_field(field, type_, suggested_types, suggested_fields, line, column): return { - 'message': undefined_field_message( - field, type_, suggested_types, suggested_fields), - 'locations': [(line, column)]} + "message": undefined_field_message( + field, type_, suggested_types, suggested_fields + ), + "locations": [(line, column)], + } def describe_validate_fields_on_correct_type(): - def object_field_selection(): - expect_passes_rule(FieldsOnCorrectTypeRule, """ + expect_passes_rule( + FieldsOnCorrectTypeRule, + """ fragment objectFieldSelection on Dog { __typename name } - """) + """, + ) def aliased_object_field_selection(): - expect_passes_rule(FieldsOnCorrectTypeRule, """ + expect_passes_rule( + FieldsOnCorrectTypeRule, + """ fragment aliasedObjectFieldSelection on Dog { tn : __typename otherName : name } - """) + """, + ) def interface_field_selection(): - expect_passes_rule(FieldsOnCorrectTypeRule, """ + expect_passes_rule( + FieldsOnCorrectTypeRule, + """ fragment interfaceFieldSelection on Pet { __typename name } - """) + """, + ) def aliased_interface_field_selection(): - expect_passes_rule(FieldsOnCorrectTypeRule, """ + expect_passes_rule( + FieldsOnCorrectTypeRule, + """ fragment interfaceFieldSelection on Pet { otherName : name } - """) + """, + ) def lying_alias_selection(): - expect_passes_rule(FieldsOnCorrectTypeRule, """ + expect_passes_rule( + FieldsOnCorrectTypeRule, + """ fragment lyingAliasSelection on Dog { name : nickname } - """) + """, + ) def ignores_fields_on_unknown_type(): - expect_passes_rule(FieldsOnCorrectTypeRule, """ + expect_passes_rule( + FieldsOnCorrectTypeRule, + """ fragment unknownSelection on UnknownType { unknownField } - """) + """, + ) def reports_errors_when_type_is_known_again(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment typeKnownAgain on Pet { unknown_pet_field { ... on Cat { @@ -69,118 +88,152 @@ def reports_errors_when_type_is_known_again(): } } }, - """, [ - undefined_field('unknown_pet_field', 'Pet', [], [], 3, 15), - undefined_field('unknown_cat_field', 'Cat', [], [], 5, 19) - ]) + """, + [ + undefined_field("unknown_pet_field", "Pet", [], [], 3, 15), + undefined_field("unknown_cat_field", "Cat", [], [], 5, 19), + ], + ) def field_not_defined_on_fragment(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment fieldNotDefined on Dog { meowVolume } - """, [ - undefined_field('meowVolume', 'Dog', [], ['barkVolume'], 3, 15) - ]) + """, + [undefined_field("meowVolume", "Dog", [], ["barkVolume"], 3, 15)], + ) def ignores_deeply_unknown_field(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment deepFieldNotDefined on Dog { unknown_field { deeper_unknown_field } } - """, [ - undefined_field('unknown_field', 'Dog', [], [], 3, 15) - ]) + """, + [undefined_field("unknown_field", "Dog", [], [], 3, 15)], + ) def sub_field_not_defined(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment subFieldNotDefined on Human { pets { unknown_field } } - """, [ - undefined_field('unknown_field', 'Pet', [], [], 4, 17) - ]) + """, + [undefined_field("unknown_field", "Pet", [], [], 4, 17)], + ) def field_not_defined_on_inline_fragment(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment fieldNotDefined on Pet { ... on Dog { meowVolume } } - """, [ - undefined_field('meowVolume', 'Dog', [], ['barkVolume'], 4, 17) - ]) + """, + [undefined_field("meowVolume", "Dog", [], ["barkVolume"], 4, 17)], + ) def aliased_field_target_not_defined(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment aliasedFieldTargetNotDefined on Dog { volume : mooVolume } - """, [ - undefined_field('mooVolume', 'Dog', [], ['barkVolume'], 3, 15) - ]) + """, + [undefined_field("mooVolume", "Dog", [], ["barkVolume"], 3, 15)], + ) def aliased_lying_field_target_not_defined(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment aliasedLyingFieldTargetNotDefined on Dog { barkVolume : kawVolume } - """, [ - undefined_field('kawVolume', 'Dog', [], ['barkVolume'], 3, 15) - ]) + """, + [undefined_field("kawVolume", "Dog", [], ["barkVolume"], 3, 15)], + ) def not_defined_on_interface(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment notDefinedOnInterface on Pet { tailLength } - """, [ - undefined_field('tailLength', 'Pet', [], [], 3, 15) - ]) + """, + [undefined_field("tailLength", "Pet", [], [], 3, 15)], + ) def defined_on_implementors_but_not_on_interface(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment definedOnImplementorsButNotInterface on Pet { nickname } - """, [ - undefined_field('nickname', 'Pet', ['Dog', 'Cat'], ['name'], 3, 15) - ]) + """, + [undefined_field("nickname", "Pet", ["Dog", "Cat"], ["name"], 3, 15)], + ) def meta_field_selection_on_union(): - expect_passes_rule(FieldsOnCorrectTypeRule, """ + expect_passes_rule( + FieldsOnCorrectTypeRule, + """ fragment directFieldSelectionOnUnion on CatOrDog { __typename } - """) + """, + ) def direct_field_selection_on_union(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment directFieldSelectionOnUnion on CatOrDog { directField } - """, [ - undefined_field('directField', 'CatOrDog', [], [], 3, 15) - ]) + """, + [undefined_field("directField", "CatOrDog", [], [], 3, 15)], + ) def defined_on_implementors_queried_on_union(): - expect_fails_rule(FieldsOnCorrectTypeRule, """ + expect_fails_rule( + FieldsOnCorrectTypeRule, + """ fragment definedOnImplementorsQueriedOnUnion on CatOrDog { name } - """, [ - undefined_field( - 'name', 'CatOrDog', - ['Being', 'Pet', 'Canine', 'Dog', 'Cat'], [], 3, 15) - ]) + """, + [ + undefined_field( + "name", + "CatOrDog", + ["Being", "Pet", "Canine", "Dog", "Cat"], + [], + 3, + 15, + ) + ], + ) def valid_field_in_inline_fragment(): - expect_passes_rule(FieldsOnCorrectTypeRule, """ + expect_passes_rule( + FieldsOnCorrectTypeRule, + """ fragment objectFieldSelection on Pet { ... on Dog { name @@ -189,38 +242,46 @@ def valid_field_in_inline_fragment(): name } } - """) + """, + ) def describe_fields_on_correct_type_error_message(): - def fields_correct_type_no_suggestion(): - assert undefined_field_message( - 'f', 'T', [], []) == "Cannot query field 'f' on type 'T'." + assert ( + undefined_field_message("f", "T", [], []) + == "Cannot query field 'f' on type 'T'." + ) def works_with_no_small_numbers_of_type_suggestion(): - assert undefined_field_message('f', 'T', ['A', 'B'], []) == ( + assert undefined_field_message("f", "T", ["A", "B"], []) == ( "Cannot query field 'f' on type 'T'." - " Did you mean to use an inline fragment on 'A' or 'B'?") + " Did you mean to use an inline fragment on 'A' or 'B'?" + ) def works_with_no_small_numbers_of_field_suggestion(): - assert undefined_field_message('f', 'T', [], ['z', 'y']) == ( - "Cannot query field 'f' on type 'T'." - " Did you mean 'z' or 'y'?") + assert undefined_field_message("f", "T", [], ["z", "y"]) == ( + "Cannot query field 'f' on type 'T'." " Did you mean 'z' or 'y'?" + ) def only_shows_one_set_of_suggestions_at_a_time_preferring_types(): - assert undefined_field_message('f', 'T', ['A', 'B'], ['z', 'y']) == ( + assert undefined_field_message("f", "T", ["A", "B"], ["z", "y"]) == ( "Cannot query field 'f' on type 'T'." - " Did you mean to use an inline fragment on 'A' or 'B'?") + " Did you mean to use an inline fragment on 'A' or 'B'?" + ) def limits_lots_of_type_suggestions(): assert undefined_field_message( - 'f', 'T', ['A', 'B', 'C', 'D', 'E', 'F'], []) == ( + "f", "T", ["A", "B", "C", "D", "E", "F"], [] + ) == ( "Cannot query field 'f' on type 'T'. Did you mean to use" - " an inline fragment on 'A', 'B', 'C', 'D' or 'E'?") + " an inline fragment on 'A', 'B', 'C', 'D' or 'E'?" + ) def limits_lots_of_field_suggestions(): assert undefined_field_message( - 'f', 'T', [], ['z', 'y', 'x', 'w', 'v', 'u']) == ( + "f", "T", [], ["z", "y", "x", "w", "v", "u"] + ) == ( "Cannot query field 'f' on type 'T'." - " Did you mean 'z', 'y', 'x', 'w' or 'v'?") + " Did you mean 'z', 'y', 'x', 'w' or 'v'?" + ) diff --git a/tests/validation/test_fragments_on_composite_types.py b/tests/validation/test_fragments_on_composite_types.py index 5a3ff6e0..c81ea62e 100644 --- a/tests/validation/test_fragments_on_composite_types.py +++ b/tests/validation/test_fragments_on_composite_types.py @@ -2,94 +2,123 @@ from graphql.validation import FragmentsOnCompositeTypesRule from graphql.validation.rules.fragments_on_composite_types import ( fragment_on_non_composite_error_message, - inline_fragment_on_non_composite_error_message) + inline_fragment_on_non_composite_error_message, +) from .harness import expect_fails_rule, expect_passes_rule def error(frag_name, type_name, line, column): return { - 'message': fragment_on_non_composite_error_message( - frag_name, type_name), - 'locations': [(line, column)]} + "message": fragment_on_non_composite_error_message(frag_name, type_name), + "locations": [(line, column)], + } def describe_validate_fragments_on_composite_types(): - def object_is_valid_fragment_type(): - expect_passes_rule(FragmentsOnCompositeTypesRule, """ + expect_passes_rule( + FragmentsOnCompositeTypesRule, + """ fragment validFragment on Dog { barks } - """) + """, + ) def interface_is_valid_fragment_type(): - expect_passes_rule(FragmentsOnCompositeTypesRule, """ + expect_passes_rule( + FragmentsOnCompositeTypesRule, + """ fragment validFragment on Pet { name } - """) + """, + ) def object_is_valid_inline_fragment_type(): - expect_passes_rule(FragmentsOnCompositeTypesRule, """ + expect_passes_rule( + FragmentsOnCompositeTypesRule, + """ fragment validFragment on Pet { ... on Dog { barks } } - """) + """, + ) def inline_fragment_without_type_is_valid(): - expect_passes_rule(FragmentsOnCompositeTypesRule, """ + expect_passes_rule( + FragmentsOnCompositeTypesRule, + """ fragment validFragment on Pet { ... { name } } - """) + """, + ) def union_is_valid_fragment_type(): - expect_passes_rule(FragmentsOnCompositeTypesRule, """ + expect_passes_rule( + FragmentsOnCompositeTypesRule, + """ fragment validFragment on CatOrDog { __typename } - """) + """, + ) def scalar_is_invalid_fragment_type(): - expect_fails_rule(FragmentsOnCompositeTypesRule, """ + expect_fails_rule( + FragmentsOnCompositeTypesRule, + """ fragment scalarFragment on Boolean { bad } - """, [ - error('scalarFragment', 'Boolean', 2, 40) - ]) + """, + [error("scalarFragment", "Boolean", 2, 40)], + ) def enum_is_invalid_fragment_type(): - expect_fails_rule(FragmentsOnCompositeTypesRule, """ + expect_fails_rule( + FragmentsOnCompositeTypesRule, + """ fragment scalarFragment on FurColor { bad } - """, [ - error('scalarFragment', 'FurColor', 2, 40) - ]) + """, + [error("scalarFragment", "FurColor", 2, 40)], + ) def input_object_is_invalid_fragment_type(): - expect_fails_rule(FragmentsOnCompositeTypesRule, """ + expect_fails_rule( + FragmentsOnCompositeTypesRule, + """ fragment inputFragment on ComplexInput { stringField } - """, [ - error('inputFragment', 'ComplexInput', 2, 39) - ]) + """, + [error("inputFragment", "ComplexInput", 2, 39)], + ) def scalar_is_invalid_inline_fragment_type(): - expect_fails_rule(FragmentsOnCompositeTypesRule, """ + expect_fails_rule( + FragmentsOnCompositeTypesRule, + """ fragment invalidFragment on Pet { ... on String { barks } } - """, [{ - 'message': inline_fragment_on_non_composite_error_message( - GraphQLString), 'locations': [(3, 22)] - }]) + """, + [ + { + "message": inline_fragment_on_non_composite_error_message( + GraphQLString + ), + "locations": [(3, 22)], + } + ], + ) diff --git a/tests/validation/test_known_argument_names.py b/tests/validation/test_known_argument_names.py index ecd367ff..27be93ec 100644 --- a/tests/validation/test_known_argument_names.py +++ b/tests/validation/test_known_argument_names.py @@ -4,69 +4,88 @@ from graphql.validation import KnownArgumentNamesRule from graphql.validation.rules.known_argument_names import ( KnownArgumentNamesOnDirectivesRule, - unknown_arg_message, unknown_directive_arg_message) + unknown_arg_message, + unknown_directive_arg_message, +) -from .harness import ( - expect_fails_rule, expect_passes_rule, expect_sdl_errors_from_rule) +from .harness import expect_fails_rule, expect_passes_rule, expect_sdl_errors_from_rule expect_sdl_errors = partial( - expect_sdl_errors_from_rule, KnownArgumentNamesOnDirectivesRule) + expect_sdl_errors_from_rule, KnownArgumentNamesOnDirectivesRule +) def unknown_arg(arg_name, field_name, type_name, suggested_args, line, column): return { - 'message': unknown_arg_message( - arg_name, field_name, type_name, suggested_args), - 'locations': [(line, column)]} + "message": unknown_arg_message(arg_name, field_name, type_name, suggested_args), + "locations": [(line, column)], + } -def unknown_directive_arg( - arg_name, directive_name, suggested_args, line, column): +def unknown_directive_arg(arg_name, directive_name, suggested_args, line, column): return { - 'message': unknown_directive_arg_message( - arg_name, directive_name, suggested_args), - 'locations': [(line, column)]} + "message": unknown_directive_arg_message( + arg_name, directive_name, suggested_args + ), + "locations": [(line, column)], + } def describe_validate_known_argument_names(): - def single_arg_is_known(): - expect_passes_rule(KnownArgumentNamesRule, """ + expect_passes_rule( + KnownArgumentNamesRule, + """ fragment argOnRequiredArg on Dog { doesKnowCommand(dogCommand: SIT) } - """) + """, + ) def multiple_args_are_known(): - expect_passes_rule(KnownArgumentNamesRule, """ + expect_passes_rule( + KnownArgumentNamesRule, + """ fragment multipleArgs on ComplicatedArgs { multipleReqs(req1: 1, req2: 2) } - """) + """, + ) def ignore_args_of_unknown_fields(): - expect_passes_rule(KnownArgumentNamesRule, """ + expect_passes_rule( + KnownArgumentNamesRule, + """ fragment argOnUnknownField on Dog { unknownField(unknownArg: SIT) } - """) + """, + ) def multiple_args_in_reverse_order_are_known(): - expect_passes_rule(KnownArgumentNamesRule, """ + expect_passes_rule( + KnownArgumentNamesRule, + """ fragment multipleArgsReverseOrder on ComplicatedArgs { multipleReqs(req2: 2, req1: 1) } - """) + """, + ) def no_args_on_optional_arg(): - expect_passes_rule(KnownArgumentNamesRule, """ + expect_passes_rule( + KnownArgumentNamesRule, + """ fragment noArgOnOptionalArg on Dog { isHousetrained } - """) + """, + ) def args_are_known_deeply(): - expect_passes_rule(KnownArgumentNamesRule, """ + expect_passes_rule( + KnownArgumentNamesRule, + """ { dog { doesKnowCommand(dogCommand: SIT) @@ -79,63 +98,85 @@ def args_are_known_deeply(): } } } - """) + """, + ) def directive_args_are_known(): - expect_passes_rule(KnownArgumentNamesRule, """ + expect_passes_rule( + KnownArgumentNamesRule, + """ { dog @skip(if: true) } - """) + """, + ) def field_args_are_invalid(): - expect_fails_rule(KnownArgumentNamesRule, """ + expect_fails_rule( + KnownArgumentNamesRule, + """ { dog @skip(unless: true) } - """, [ - unknown_directive_arg('unless', 'skip', [], 3, 25) - ]) + """, + [unknown_directive_arg("unless", "skip", [], 3, 25)], + ) def misspelled_directive_args_are_reported(): - expect_fails_rule(KnownArgumentNamesRule, """ + expect_fails_rule( + KnownArgumentNamesRule, + """ { dog @skip(iff: true) } - """, [ - unknown_directive_arg('iff', 'skip', ['if'], 3, 25) - ]) + """, + [unknown_directive_arg("iff", "skip", ["if"], 3, 25)], + ) def invalid_arg_name(): - expect_fails_rule(KnownArgumentNamesRule, """ + expect_fails_rule( + KnownArgumentNamesRule, + """ fragment invalidArgName on Dog { doesKnowCommand(unknown: true) } - """, [ - unknown_arg('unknown', 'doesKnowCommand', 'Dog', [], 3, 31) - ]) + """, + [unknown_arg("unknown", "doesKnowCommand", "Dog", [], 3, 31)], + ) def misspelled_args_name_is_reported(): - expect_fails_rule(KnownArgumentNamesRule, """ + expect_fails_rule( + KnownArgumentNamesRule, + """ fragment invalidArgName on Dog { doesKnowCommand(dogcommand: true) } - """, [unknown_arg( - 'dogcommand', 'doesKnowCommand', 'Dog', ['dogCommand'], 3, 31) - ]) + """, + [ + unknown_arg( + "dogcommand", "doesKnowCommand", "Dog", ["dogCommand"], 3, 31 + ) + ], + ) def unknown_args_amongst_known_args(): - expect_fails_rule(KnownArgumentNamesRule, """ + expect_fails_rule( + KnownArgumentNamesRule, + """ fragment oneGoodArgOneInvalidArg on Dog { doesKnowCommand(whoknows: 1, dogCommand: SIT, unknown: true) } - """, [ - unknown_arg('whoknows', 'doesKnowCommand', 'Dog', [], 3, 31), - unknown_arg('unknown', 'doesKnowCommand', 'Dog', [], 3, 61) - ]) + """, + [ + unknown_arg("whoknows", "doesKnowCommand", "Dog", [], 3, 31), + unknown_arg("unknown", "doesKnowCommand", "Dog", [], 3, 61), + ], + ) def unknown_args_deeply(): - expect_fails_rule(KnownArgumentNamesRule, """ + expect_fails_rule( + KnownArgumentNamesRule, + """ { dog { doesKnowCommand(unknown: true) @@ -148,81 +189,117 @@ def unknown_args_deeply(): } } } - """, [ - unknown_arg('unknown', 'doesKnowCommand', 'Dog', [], 4, 33), - unknown_arg('unknown', 'doesKnowCommand', 'Dog', [], 9, 37) - ]) + """, + [ + unknown_arg("unknown", "doesKnowCommand", "Dog", [], 4, 33), + unknown_arg("unknown", "doesKnowCommand", "Dog", [], 9, 37), + ], + ) def describe_within_sdl(): - def known_arg_on_directive_inside_sdl(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @test(arg: "") } directive @test(arg: String) on FIELD_DEFINITION - """) == [] + """ + ) + == [] + ) def unknown_arg_on_directive_defined_inside_sdl(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @test(unknown: "") } directive @test(arg: String) on FIELD_DEFINITION - """) == [ - unknown_directive_arg('unknown', 'test', [], 3, 37)] + """ + ) + == [unknown_directive_arg("unknown", "test", [], 3, 37)] + ) def misspelled_arg_name_is_reported_on_directive_defined_inside_sdl(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @test(agr: "") } directive @test(arg: String) on FIELD_DEFINITION - """) == [ - unknown_directive_arg('agr', 'test', ['arg'], 3, 37)] + """ + ) + == [unknown_directive_arg("agr", "test", ["arg"], 3, 37)] + ) def unknown_arg_on_standard_directive(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @deprecated(unknown: "") } - """) == [ - unknown_directive_arg('unknown', 'deprecated', [], 3, 43)] + """ + ) + == [unknown_directive_arg("unknown", "deprecated", [], 3, 43)] + ) def unknown_arg_on_overridden_standard_directive(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @deprecated(reason: "") } directive @deprecated(arg: String) on FIELD - """) == [ - unknown_directive_arg('reason', 'deprecated', [], 3, 43)] + """ + ) + == [unknown_directive_arg("reason", "deprecated", [], 3, 43)] + ) def unknown_arg_on_directive_defined_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ type Query { foo: String } - """) - assert expect_sdl_errors(""" + """ + ) + assert ( + expect_sdl_errors( + """ directive @test(arg: String) on OBJECT extend type Query @test(unknown: "") - """, schema) == [ - unknown_directive_arg('unknown', 'test', [], 4, 42)] + """, + schema, + ) + == [unknown_directive_arg("unknown", "test", [], 4, 42)] + ) def unknown_arg_on_directive_used_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ directive @test(arg: String) on OBJECT type Query { foo: String } - """) - assert expect_sdl_errors(""" + """ + ) + assert ( + expect_sdl_errors( + """ extend type Query @test(unknown: "") - """, schema) == [ - unknown_directive_arg('unknown', 'test', [], 2, 41)] + """, + schema, + ) + == [unknown_directive_arg("unknown", "test", [], 2, 41)] + ) diff --git a/tests/validation/test_known_directives.py b/tests/validation/test_known_directives.py index fefd00a8..9d97f82c 100644 --- a/tests/validation/test_known_directives.py +++ b/tests/validation/test_known_directives.py @@ -3,28 +3,31 @@ from graphql.utilities import build_schema from graphql.validation import KnownDirectivesRule from graphql.validation.rules.known_directives import ( - unknown_directive_message, misplaced_directive_message) + unknown_directive_message, + misplaced_directive_message, +) -from .harness import ( - expect_fails_rule, expect_passes_rule, expect_sdl_errors_from_rule) +from .harness import expect_fails_rule, expect_passes_rule, expect_sdl_errors_from_rule -expect_sdl_errors = partial( - expect_sdl_errors_from_rule, KnownDirectivesRule) +expect_sdl_errors = partial(expect_sdl_errors_from_rule, KnownDirectivesRule) def unknown_directive(directive_name, line, column): return { - 'message': unknown_directive_message(directive_name), - 'locations': [(line, column)]} + "message": unknown_directive_message(directive_name), + "locations": [(line, column)], + } def misplaced_directive(directive_name, placement, line, column): return { - 'message': misplaced_directive_message(directive_name, placement), - 'locations': [(line, column)]} + "message": misplaced_directive_message(directive_name, placement), + "locations": [(line, column)], + } -schema_with_sdl_directives = build_schema(""" +schema_with_sdl_directives = build_schema( + """ directive @onSchema on SCHEMA directive @onScalar on SCALAR directive @onObject on OBJECT @@ -36,13 +39,15 @@ def misplaced_directive(directive_name, placement, line, column): directive @onEnumValue on ENUM_VALUE directive @onInputObject on INPUT_OBJECT directive @onInputFieldDefinition on INPUT_FIELD_DEFINITION - """) + """ +) def describe_known_directives(): - def with_no_directives(): - expect_passes_rule(KnownDirectivesRule, """ + expect_passes_rule( + KnownDirectivesRule, + """ query Foo { name ...Frag @@ -51,10 +56,13 @@ def with_no_directives(): fragment Frag on Dog { name } - """) + """, + ) def with_known_directives(): - expect_passes_rule(KnownDirectivesRule, """ + expect_passes_rule( + KnownDirectivesRule, + """ { dog @include(if: true) { name @@ -63,21 +71,26 @@ def with_known_directives(): name } } - """) + """, + ) def with_unknown_directive(): - expect_fails_rule(KnownDirectivesRule, """ + expect_fails_rule( + KnownDirectivesRule, + """ { dog @unknown(directive: "value") { name } } - """, [ - unknown_directive('unknown', 3, 19) - ]) + """, + [unknown_directive("unknown", 3, 19)], + ) def with_many_unknown_directives(): - expect_fails_rule(KnownDirectivesRule, """ + expect_fails_rule( + KnownDirectivesRule, + """ { dog @unknown(directive: "value") { name @@ -89,14 +102,18 @@ def with_many_unknown_directives(): } } } - """, [ - unknown_directive('unknown', 3, 19), - unknown_directive('unknown', 6, 21), - unknown_directive('unknown', 8, 22) - ]) + """, + [ + unknown_directive("unknown", 3, 19), + unknown_directive("unknown", 6, 21), + unknown_directive("unknown", 8, 22), + ], + ) def with_well_placed_directives(): - expect_passes_rule(KnownDirectivesRule, """ + expect_passes_rule( + KnownDirectivesRule, + """ query Foo($var: Boolean) @onQuery { name @include(if: $var) ...Frag @include(if: true) @@ -107,17 +124,24 @@ def with_well_placed_directives(): mutation Bar @onMutation { someField } - """) + """, + ) def experimental_with_well_placed_variable_definition_directive(): - expect_passes_rule(KnownDirectivesRule, """ + expect_passes_rule( + KnownDirectivesRule, + """ query Foo($var: Boolean @onVariableDefinition) { name } - """, experimental_variable_definition_directives=True) + """, + experimental_variable_definition_directives=True, + ) def with_misplaced_directives(): - expect_fails_rule(KnownDirectivesRule, """ + expect_fails_rule( + KnownDirectivesRule, + """ query Foo($var: Boolean) @include(if: true) { name @onQuery @include(if: $var) ...Frag @onQuery @@ -126,84 +150,129 @@ def with_misplaced_directives(): mutation Bar @onQuery { someField } - """, [ - misplaced_directive('include', 'query', 2, 38), - misplaced_directive('onQuery', 'field', 3, 20), - misplaced_directive('onQuery', 'fragment spread', 4, 23), - misplaced_directive('onQuery', 'mutation', 7, 26), - ]) + """, + [ + misplaced_directive("include", "query", 2, 38), + misplaced_directive("onQuery", "field", 3, 20), + misplaced_directive("onQuery", "fragment spread", 4, 23), + misplaced_directive("onQuery", "mutation", 7, 26), + ], + ) def experimental_with_misplaced_variable_definition_directive(): - expect_fails_rule(KnownDirectivesRule, """ + expect_fails_rule( + KnownDirectivesRule, + """ query Foo($var: Boolean @onField) { name } - """, [ - misplaced_directive('onField', 'variable definition', 2, 37)], - experimental_variable_definition_directives=True) + """, + [misplaced_directive("onField", "variable definition", 2, 37)], + experimental_variable_definition_directives=True, + ) def describe_within_sdl(): - def with_directive_defined_inside_sdl(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @test } directive @test on FIELD_DEFINITION - """) == [] + """ + ) + == [] + ) def with_standard_directive(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @deprecated } - """) == [] + """ + ) + == [] + ) def with_overridden_standard_directive(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ schema @deprecated { query: Query } directive @deprecated on SCHEMA - """) == [] + """ + ) + == [] + ) def with_directive_defined_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ type Query { foo: String } - """) - assert expect_sdl_errors(""" + """ + ) + assert ( + expect_sdl_errors( + """ directive @test on OBJECT extend type Query @test - """, schema) == [] + """, + schema, + ) + == [] + ) def with_directive_used_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ directive @test on OBJECT type Query { foo: String } - """) - assert expect_sdl_errors(""" + """ + ) + assert ( + expect_sdl_errors( + """ extend type Query @test - """, schema) == [] + """, + schema, + ) + == [] + ) def with_unknown_directive_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ type Query { foo: String } - """) - assert expect_sdl_errors(""" + """ + ) + assert ( + expect_sdl_errors( + """ extend type Query @unknown - """, schema) == [unknown_directive('unknown', 2, 35)] + """, + schema, + ) + == [unknown_directive("unknown", 2, 35)] + ) def with_well_placed_directives(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type MyObj implements MyInterface @onObject { myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition } @@ -242,10 +311,15 @@ def with_well_placed_directives(): extend schema @onSchema """, # noqa - schema_with_sdl_directives) == [] + schema_with_sdl_directives, + ) + == [] + ) def with_misplaced_directives(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type MyObj implements MyInterface @onInterface { myField(myArg: Int @onInputFieldDefinition): String @onInputFieldDefinition } @@ -272,23 +346,32 @@ def with_misplaced_directives(): extend schema @onObject """, # noqa - schema_with_sdl_directives) == [ - misplaced_directive('onInterface', 'object', 2, 51), - misplaced_directive( - 'onInputFieldDefinition', 'argument definition', 3, 38), - misplaced_directive( - 'onInputFieldDefinition', 'field definition', 3, 71), - misplaced_directive('onEnum', 'scalar', 6, 33), - misplaced_directive('onObject', 'interface', 8, 39), - misplaced_directive( - 'onInputFieldDefinition', 'argument definition', 9, 38), - misplaced_directive( - 'onInputFieldDefinition', 'field definition', 9, 71), - misplaced_directive('onEnumValue', 'union', 12, 31), - misplaced_directive('onScalar', 'enum', 14, 29), - misplaced_directive('onUnion', 'enum value', 15, 28), - misplaced_directive('onEnum', 'input object', 18, 31), - misplaced_directive( - 'onArgumentDefinition', 'input field definition', 19, 32), - misplaced_directive('onObject', 'schema', 22, 24), - misplaced_directive('onObject', 'schema', 26, 31)] + schema_with_sdl_directives, + ) + == [ + misplaced_directive("onInterface", "object", 2, 51), + misplaced_directive( + "onInputFieldDefinition", "argument definition", 3, 38 + ), + misplaced_directive( + "onInputFieldDefinition", "field definition", 3, 71 + ), + misplaced_directive("onEnum", "scalar", 6, 33), + misplaced_directive("onObject", "interface", 8, 39), + misplaced_directive( + "onInputFieldDefinition", "argument definition", 9, 38 + ), + misplaced_directive( + "onInputFieldDefinition", "field definition", 9, 71 + ), + misplaced_directive("onEnumValue", "union", 12, 31), + misplaced_directive("onScalar", "enum", 14, 29), + misplaced_directive("onUnion", "enum value", 15, 28), + misplaced_directive("onEnum", "input object", 18, 31), + misplaced_directive( + "onArgumentDefinition", "input field definition", 19, 32 + ), + misplaced_directive("onObject", "schema", 22, 24), + misplaced_directive("onObject", "schema", 26, 31), + ] + ) diff --git a/tests/validation/test_known_fragment_names.py b/tests/validation/test_known_fragment_names.py index d8dd512a..4047d26f 100644 --- a/tests/validation/test_known_fragment_names.py +++ b/tests/validation/test_known_fragment_names.py @@ -1,20 +1,21 @@ from graphql.validation import KnownFragmentNamesRule -from graphql.validation.rules.known_fragment_names import ( - unknown_fragment_message) +from graphql.validation.rules.known_fragment_names import unknown_fragment_message from .harness import expect_fails_rule, expect_passes_rule def undef_fragment(fragment_name, line, column): return { - 'message': unknown_fragment_message(fragment_name), - 'locations': [(line, column)]} + "message": unknown_fragment_message(fragment_name), + "locations": [(line, column)], + } def describe_validate_known_fragment_names(): - def known_fragment_names_are_valid(): - expect_passes_rule(KnownFragmentNamesRule, """ + expect_passes_rule( + KnownFragmentNamesRule, + """ { human(id: 4) { ...HumanFields1 @@ -36,10 +37,13 @@ def known_fragment_names_are_valid(): fragment HumanFields3 on Human { name } - """) + """, + ) def unknown_fragment_names_are_invalid(): - expect_fails_rule(KnownFragmentNamesRule, """ + expect_fails_rule( + KnownFragmentNamesRule, + """ { human(id: 4) { ...UnknownFragment1 @@ -52,8 +56,10 @@ def unknown_fragment_names_are_invalid(): name ...UnknownFragment3 } - """, [ - undef_fragment('UnknownFragment1', 4, 20), - undef_fragment('UnknownFragment2', 6, 22), - undef_fragment('UnknownFragment3', 12, 18), - ]) + """, + [ + undef_fragment("UnknownFragment1", 4, 20), + undef_fragment("UnknownFragment2", 6, 22), + undef_fragment("UnknownFragment3", 12, 18), + ], + ) diff --git a/tests/validation/test_known_type_names.py b/tests/validation/test_known_type_names.py index 6b327a1b..90abe372 100644 --- a/tests/validation/test_known_type_names.py +++ b/tests/validation/test_known_type_names.py @@ -6,14 +6,16 @@ def unknown_type(type_name, suggested_types, line, column): return { - 'message': unknown_type_message(type_name, suggested_types), - 'locations': [(line, column)]} + "message": unknown_type_message(type_name, suggested_types), + "locations": [(line, column)], + } def describe_validate_known_type_names(): - def known_type_names_are_valid(): - expect_passes_rule(KnownTypeNamesRule, """ + expect_passes_rule( + KnownTypeNamesRule, + """ query Foo($var: String, $required: [String!]!) { user(id: 4) { pets { ... on Pet { name }, ...PetFields, ... { name } } @@ -22,10 +24,13 @@ def known_type_names_are_valid(): fragment PetFields on Pet { name } - """) + """, + ) def unknown_type_names_are_invalid(): - expect_fails_rule(KnownTypeNamesRule, """ + expect_fails_rule( + KnownTypeNamesRule, + """ query Foo($var: JumbledUpLetters) { user(id: 4) { name @@ -35,14 +40,18 @@ def unknown_type_names_are_invalid(): fragment PetFields on Peettt { name } - """, [ - unknown_type('JumbledUpLetters', [], 2, 29), - unknown_type('Badger', [], 5, 31), - unknown_type('Peettt', ['Pet'], 8, 35), - ]) + """, + [ + unknown_type("JumbledUpLetters", [], 2, 29), + unknown_type("Badger", [], 5, 31), + unknown_type("Peettt", ["Pet"], 8, 35), + ], + ) def ignores_type_definitions(): - expect_fails_rule(KnownTypeNamesRule, """ + expect_fails_rule( + KnownTypeNamesRule, + """ type NotInTheSchema { field: FooBar } @@ -58,6 +67,6 @@ def ignores_type_definitions(): id } } - """, [ - unknown_type('NotInTheSchema', [], 12, 29), - ]) + """, + [unknown_type("NotInTheSchema", [], 12, 29)], + ) diff --git a/tests/validation/test_lone_anonymous_operation.py b/tests/validation/test_lone_anonymous_operation.py index 3d3377ee..0f522271 100644 --- a/tests/validation/test_lone_anonymous_operation.py +++ b/tests/validation/test_lone_anonymous_operation.py @@ -1,34 +1,43 @@ from graphql.validation import LoneAnonymousOperationRule from graphql.validation.rules.lone_anonymous_operation import ( - anonymous_operation_not_alone_message) + anonymous_operation_not_alone_message +) from .harness import expect_fails_rule, expect_passes_rule def anon_not_alone(line, column): return { - 'message': anonymous_operation_not_alone_message(), - 'locations': [(line, column)]} + "message": anonymous_operation_not_alone_message(), + "locations": [(line, column)], + } def describe_validate_anonymous_operation_must_be_alone(): - def no_operations(): - expect_passes_rule(LoneAnonymousOperationRule, """ + expect_passes_rule( + LoneAnonymousOperationRule, + """ fragment fragA on Type { field } - """) + """, + ) def one_anon_operation(): - expect_passes_rule(LoneAnonymousOperationRule, """ + expect_passes_rule( + LoneAnonymousOperationRule, + """ { field } - """) + """, + ) def multiple_named_operation(): - expect_passes_rule(LoneAnonymousOperationRule, """ + expect_passes_rule( + LoneAnonymousOperationRule, + """ query Foo { field } @@ -36,51 +45,60 @@ def multiple_named_operation(): query Bar { field } - """) + """, + ) def anon_operation_with_fragment(): - expect_passes_rule(LoneAnonymousOperationRule, """ + expect_passes_rule( + LoneAnonymousOperationRule, + """ { ...Foo } fragment Foo on Type { field } - """) + """, + ) def multiple_anon_operations(): - expect_fails_rule(LoneAnonymousOperationRule, """ + expect_fails_rule( + LoneAnonymousOperationRule, + """ { fieldA } { fieldB } - """, [ - anon_not_alone(2, 13), - anon_not_alone(5, 13), - ]) + """, + [anon_not_alone(2, 13), anon_not_alone(5, 13)], + ) def anon_operation_with_a_mutation(): - expect_fails_rule(LoneAnonymousOperationRule, """ + expect_fails_rule( + LoneAnonymousOperationRule, + """ { fieldA } mutation Foo { fieldB } - """, [ - anon_not_alone(2, 13) - ]) + """, + [anon_not_alone(2, 13)], + ) def anon_operation_with_a_subscription(): - expect_fails_rule(LoneAnonymousOperationRule, """ + expect_fails_rule( + LoneAnonymousOperationRule, + """ { fieldA } subscription Foo { fieldB } - """, [ - anon_not_alone(2, 13) - ]) + """, + [anon_not_alone(2, 13)], + ) diff --git a/tests/validation/test_lone_schema_definition.py b/tests/validation/test_lone_schema_definition.py index df3f2d13..dbdc032b 100644 --- a/tests/validation/test_lone_schema_definition.py +++ b/tests/validation/test_lone_schema_definition.py @@ -2,38 +2,47 @@ from graphql.utilities import build_schema from graphql.validation.rules.lone_schema_definition import ( - LoneSchemaDefinitionRule, schema_definition_not_alone_message, - cannot_define_schema_within_extension_message) + LoneSchemaDefinitionRule, + schema_definition_not_alone_message, + cannot_define_schema_within_extension_message, +) from .harness import expect_sdl_errors_from_rule -expect_sdl_errors = partial( - expect_sdl_errors_from_rule, LoneSchemaDefinitionRule) +expect_sdl_errors = partial(expect_sdl_errors_from_rule, LoneSchemaDefinitionRule) def schema_definition_not_alone(line, column): return { - 'message': schema_definition_not_alone_message(), - 'locations': [(line, column)]} + "message": schema_definition_not_alone_message(), + "locations": [(line, column)], + } def cannot_define_schema_within_extension(line, column): return { - 'message': cannot_define_schema_within_extension_message(), - 'locations': [(line, column)]} + "message": cannot_define_schema_within_extension_message(), + "locations": [(line, column)], + } def describe_validate_schema_definition_should_be_alone(): - def no_schema(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String } - """) == [] + """ + ) + == [] + ) def one_schema_definition(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ schema { query: Foo } @@ -41,10 +50,15 @@ def one_schema_definition(): type Foo { foo: String } - """) == [] + """ + ) + == [] + ) def multiple_schema_definitions(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ schema { query: Foo } @@ -60,25 +74,38 @@ def multiple_schema_definitions(): schema { subscription: Foo } - """) == [ - schema_definition_not_alone(10, 13), - schema_definition_not_alone(14, 13)] + """ + ) + == [ + schema_definition_not_alone(10, 13), + schema_definition_not_alone(14, 13), + ] + ) def define_schema_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ type Foo { foo: String } - """) + """ + ) - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ schema { query: Foo } - """, schema) == [] + """, + schema, + ) + == [] + ) def redefine_schema_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ schema { query: Foo } @@ -86,17 +113,24 @@ def redefine_schema_in_schema_extension(): type Foo { foo: String } - """) + """ + ) - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ schema { mutation: Foo } - """, schema) == [ - cannot_define_schema_within_extension(2, 13)] + """, + schema, + ) + == [cannot_define_schema_within_extension(2, 13)] + ) def redefine_implicit_schema_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ type Query { fooField: Foo } @@ -104,17 +138,24 @@ def redefine_implicit_schema_in_schema_extension(): type Foo { foo: String } - """) + """ + ) - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ schema { mutation: Foo } - """, schema) == [ - cannot_define_schema_within_extension(2, 13)] + """, + schema, + ) + == [cannot_define_schema_within_extension(2, 13)] + ) def extend_schema_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ type Query { fooField: Foo } @@ -122,10 +163,17 @@ def extend_schema_in_schema_extension(): type Foo { foo: String } - """) + """ + ) - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ extend schema { mutation: Foo } - """, schema) == [] + """, + schema, + ) + == [] + ) diff --git a/tests/validation/test_no_fragment_cycles.py b/tests/validation/test_no_fragment_cycles.py index e8d16c2d..13ec7346 100644 --- a/tests/validation/test_no_fragment_cycles.py +++ b/tests/validation/test_no_fragment_cycles.py @@ -5,28 +5,38 @@ def describe_validate_no_circular_fragment_spreads(): - def single_reference_is_valid(): - expect_passes_rule(NoFragmentCyclesRule, """ + expect_passes_rule( + NoFragmentCyclesRule, + """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { name } - """) + """, + ) def spreading_twice_is_not_circular(): - expect_passes_rule(NoFragmentCyclesRule, """ + expect_passes_rule( + NoFragmentCyclesRule, + """ fragment fragA on Dog { ...fragB, ...fragB } fragment fragB on Dog { name } - """) + """, + ) def spreading_twice_indirectly_is_not_circular(): - expect_passes_rule(NoFragmentCyclesRule, """ + expect_passes_rule( + NoFragmentCyclesRule, + """ fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragC } fragment fragC on Dog { name } - """) + """, + ) def double_spread_within_abstract_types(): - expect_passes_rule(NoFragmentCyclesRule, """ + expect_passes_rule( + NoFragmentCyclesRule, + """ fragment nameFragment on Pet { ... on Dog { name } ... on Cat { name } @@ -35,63 +45,84 @@ def double_spread_within_abstract_types(): ... on Dog { ...nameFragment } ... on Cat { ...nameFragment } } - """) + """, + ) def does_not_raise_false_positive_on_unknown_fragment(): - expect_passes_rule(NoFragmentCyclesRule, """ + expect_passes_rule( + NoFragmentCyclesRule, + """ fragment nameFragment on Pet { ...UnknownFragment } - """) + """, + ) def spreading_recursively_within_field_fails(): - expect_fails_rule(NoFragmentCyclesRule, """ + expect_fails_rule( + NoFragmentCyclesRule, + """ fragment fragA on Human { relatives { ...fragA } }, - """, [{ - 'message': cycle_error_message('fragA', []), - 'locations': [(2, 51)] - }]) + """, + [{"message": cycle_error_message("fragA", []), "locations": [(2, 51)]}], + ) def no_spreading_itself_directly(): - expect_fails_rule(NoFragmentCyclesRule, """ + expect_fails_rule( + NoFragmentCyclesRule, + """ fragment fragA on Dog { ...fragA } - """, [{ - 'message': cycle_error_message('fragA', []), - 'locations': [(2, 37)] - }]) + """, + [{"message": cycle_error_message("fragA", []), "locations": [(2, 37)]}], + ) def no_spreading_itself_directly_within_inline_fragment(): - expect_fails_rule(NoFragmentCyclesRule, """ + expect_fails_rule( + NoFragmentCyclesRule, + """ fragment fragA on Pet { ... on Dog { ...fragA } } - """, [{ - 'message': cycle_error_message('fragA', []), - 'locations': [(4, 17)] - }]) + """, + [{"message": cycle_error_message("fragA", []), "locations": [(4, 17)]}], + ) def no_spreading_itself_indirectly(): - expect_fails_rule(NoFragmentCyclesRule, """ + expect_fails_rule( + NoFragmentCyclesRule, + """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragA } - """, [{ - 'message': cycle_error_message('fragA', ['fragB']), - 'locations': [(2, 37), (3, 37)] - }]) + """, + [ + { + "message": cycle_error_message("fragA", ["fragB"]), + "locations": [(2, 37), (3, 37)], + } + ], + ) def no_spreading_itself_indirectly_reports_opposite_order(): - expect_fails_rule(NoFragmentCyclesRule, """ + expect_fails_rule( + NoFragmentCyclesRule, + """ fragment fragB on Dog { ...fragA } fragment fragA on Dog { ...fragB } - """, [{ - 'message': cycle_error_message('fragB', ['fragA']), - 'locations': [(2, 37), (3, 37)] - }]) + """, + [ + { + "message": cycle_error_message("fragB", ["fragA"]), + "locations": [(2, 37), (3, 37)], + } + ], + ) def no_spreading_itself_indirectly_within_inline_fragment(): - expect_fails_rule(NoFragmentCyclesRule, """ + expect_fails_rule( + NoFragmentCyclesRule, + """ fragment fragA on Pet { ... on Dog { ...fragB @@ -102,13 +133,19 @@ def no_spreading_itself_indirectly_within_inline_fragment(): ...fragA } } - """, [{ - 'message': cycle_error_message('fragA', ['fragB']), - 'locations': [(4, 17), (9, 17)] - }]) + """, + [ + { + "message": cycle_error_message("fragA", ["fragB"]), + "locations": [(4, 17), (9, 17)], + } + ], + ) def no_spreading_itself_deeply(): - expect_fails_rule(NoFragmentCyclesRule, """ + expect_fails_rule( + NoFragmentCyclesRule, + """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragC } fragment fragC on Dog { ...fragO } @@ -117,56 +154,82 @@ def no_spreading_itself_deeply(): fragment fragZ on Dog { ...fragO } fragment fragO on Dog { ...fragP } fragment fragP on Dog { ...fragA, ...fragX } - """, [{ - 'message': cycle_error_message( - 'fragA', ['fragB', 'fragC', 'fragO', 'fragP']), - 'locations': [(2, 37), (3, 37), (4, 37), (8, 37), (9, 37)], - 'path': None - }, { - 'message': cycle_error_message( - 'fragO', ['fragP', 'fragX', 'fragY', 'fragZ']), - 'locations': [(8, 37), (9, 47), (5, 37), (6, 37), (7, 37)], - 'path': None - }]) + """, + [ + { + "message": cycle_error_message( + "fragA", ["fragB", "fragC", "fragO", "fragP"] + ), + "locations": [(2, 37), (3, 37), (4, 37), (8, 37), (9, 37)], + "path": None, + }, + { + "message": cycle_error_message( + "fragO", ["fragP", "fragX", "fragY", "fragZ"] + ), + "locations": [(8, 37), (9, 47), (5, 37), (6, 37), (7, 37)], + "path": None, + }, + ], + ) def no_spreading_itself_deeply_two_paths(): - expect_fails_rule(NoFragmentCyclesRule, """ + expect_fails_rule( + NoFragmentCyclesRule, + """ fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragA } fragment fragC on Dog { ...fragA } - """, [{ - 'message': cycle_error_message('fragA', ['fragB']), - 'locations': [(2, 37), (3, 37)] - }, { - 'message': cycle_error_message('fragA', ['fragC']), - 'locations': [(2, 47), (4, 37)] - }]) + """, + [ + { + "message": cycle_error_message("fragA", ["fragB"]), + "locations": [(2, 37), (3, 37)], + }, + { + "message": cycle_error_message("fragA", ["fragC"]), + "locations": [(2, 47), (4, 37)], + }, + ], + ) def no_spreading_itself_deeply_two_paths_alt_traverse_order(): - expect_fails_rule(NoFragmentCyclesRule, """ + expect_fails_rule( + NoFragmentCyclesRule, + """ fragment fragA on Dog { ...fragC } fragment fragB on Dog { ...fragC } fragment fragC on Dog { ...fragA, ...fragB } - """, [{ - 'message': cycle_error_message('fragA', ['fragC']), - 'locations': [(2, 37), (4, 37)] - }, { - 'message': cycle_error_message('fragC', ['fragB']), - 'locations': [(4, 47), (3, 37)] - }]) + """, + [ + { + "message": cycle_error_message("fragA", ["fragC"]), + "locations": [(2, 37), (4, 37)], + }, + { + "message": cycle_error_message("fragC", ["fragB"]), + "locations": [(4, 47), (3, 37)], + }, + ], + ) def no_spreading_itself_deeply_and_immediately(): - expect_fails_rule(NoFragmentCyclesRule, """ + expect_fails_rule( + NoFragmentCyclesRule, + """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragB, ...fragC } fragment fragC on Dog { ...fragA, ...fragB } - """, [{ - 'message': cycle_error_message('fragB', []), - 'locations': [(3, 37)] - }, { - 'message': cycle_error_message('fragA', ['fragB', 'fragC']), - 'locations': [(2, 37), (3, 47), (4, 37)] - }, { - 'message': cycle_error_message('fragB', ['fragC']), - 'locations': [(3, 47), (4, 47)] - }]) + """, + [ + {"message": cycle_error_message("fragB", []), "locations": [(3, 37)]}, + { + "message": cycle_error_message("fragA", ["fragB", "fragC"]), + "locations": [(2, 37), (3, 47), (4, 37)], + }, + { + "message": cycle_error_message("fragB", ["fragC"]), + "locations": [(3, 47), (4, 47)], + }, + ], + ) diff --git a/tests/validation/test_no_undefined_variables.py b/tests/validation/test_no_undefined_variables.py index b688994b..6802525e 100644 --- a/tests/validation/test_no_undefined_variables.py +++ b/tests/validation/test_no_undefined_variables.py @@ -1,27 +1,31 @@ from graphql.validation import NoUndefinedVariablesRule -from graphql.validation.rules.no_undefined_variables import ( - undefined_var_message) +from graphql.validation.rules.no_undefined_variables import undefined_var_message from .harness import expect_fails_rule, expect_passes_rule def undef_var(var_name, l1, c1, op_name, l2, c2): return { - 'message': undefined_var_message(var_name, op_name), - 'locations': [(l1, c1), (l2, c2)]} + "message": undefined_var_message(var_name, op_name), + "locations": [(l1, c1), (l2, c2)], + } def describe_validate_no_undefined_variables(): - def all_variables_defined(): - expect_passes_rule(NoUndefinedVariablesRule, """ + expect_passes_rule( + NoUndefinedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c) } - """) + """, + ) def all_variables_deeply_defined(): - expect_passes_rule(NoUndefinedVariablesRule, """ + expect_passes_rule( + NoUndefinedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { field(a: $a) { field(b: $b) { @@ -29,10 +33,13 @@ def all_variables_deeply_defined(): } } } - """) + """, + ) def all_variables_deeply_in_inline_fragments_defined(): - expect_passes_rule(NoUndefinedVariablesRule, """ + expect_passes_rule( + NoUndefinedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { ... on Type { field(a: $a) { @@ -44,10 +51,13 @@ def all_variables_deeply_in_inline_fragments_defined(): } } } - """) + """, + ) def all_variables_in_fragments_deeply_defined(): - expect_passes_rule(NoUndefinedVariablesRule, """ + expect_passes_rule( + NoUndefinedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -64,10 +74,13 @@ def all_variables_in_fragments_deeply_defined(): fragment FragC on Type { field(c: $c) } - """) + """, + ) def variable_within_single_fragment_defined_in_multiple_operations(): - expect_passes_rule(NoUndefinedVariablesRule, """ + expect_passes_rule( + NoUndefinedVariablesRule, + """ query Foo($a: String) { ...FragA } @@ -77,10 +90,13 @@ def variable_within_single_fragment_defined_in_multiple_operations(): fragment FragA on Type { field(a: $a) } - """) + """, + ) def variable_within_fragments_defined_in_operations(): - expect_passes_rule(NoUndefinedVariablesRule, """ + expect_passes_rule( + NoUndefinedVariablesRule, + """ query Foo($a: String) { ...FragA } @@ -93,10 +109,13 @@ def variable_within_fragments_defined_in_operations(): fragment FragB on Type { field(b: $b) } - """) + """, + ) def variable_within_recursive_fragment_defined(): - expect_passes_rule(NoUndefinedVariablesRule, """ + expect_passes_rule( + NoUndefinedVariablesRule, + """ query Foo($a: String) { ...FragA } @@ -105,50 +124,60 @@ def variable_within_recursive_fragment_defined(): ...FragA } } - """) + """, + ) def variable_not_defined(): - expect_fails_rule(NoUndefinedVariablesRule, """ + expect_fails_rule( + NoUndefinedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c, d: $d) } - """, [ - undef_var('d', 3, 45, 'Foo', 2, 13) - ]) + """, + [undef_var("d", 3, 45, "Foo", 2, 13)], + ) def variable_not_defined_by_unnamed_query(): - expect_fails_rule(NoUndefinedVariablesRule, """ + expect_fails_rule( + NoUndefinedVariablesRule, + """ { field(a: $a) } - """, [ - undef_var('a', 3, 24, '', 2, 13) - ]) + """, + [undef_var("a", 3, 24, "", 2, 13)], + ) def multiple_variables_not_defined(): - expect_fails_rule(NoUndefinedVariablesRule, """ + expect_fails_rule( + NoUndefinedVariablesRule, + """ query Foo($b: String) { field(a: $a, b: $b, c: $c) } - """, [ - undef_var('a', 3, 24, 'Foo', 2, 13), - undef_var('c', 3, 38, 'Foo', 2, 13) - ]) + """, + [undef_var("a", 3, 24, "Foo", 2, 13), undef_var("c", 3, 38, "Foo", 2, 13)], + ) def variable_in_fragment_not_defined_by_unnamed_query(): - expect_fails_rule(NoUndefinedVariablesRule, """ + expect_fails_rule( + NoUndefinedVariablesRule, + """ { ...FragA } fragment FragA on Type { field(a: $a) } - """, [ - undef_var('a', 6, 24, '', 2, 13) - ]) + """, + [undef_var("a", 6, 24, "", 2, 13)], + ) def variable_in_fragment_not_defined_by_operation(): - expect_fails_rule(NoUndefinedVariablesRule, """ + expect_fails_rule( + NoUndefinedVariablesRule, + """ query Foo($a: String, $b: String) { ...FragA } @@ -165,12 +194,14 @@ def variable_in_fragment_not_defined_by_operation(): fragment FragC on Type { field(c: $c) } - """, [ - undef_var('c', 16, 24, 'Foo', 2, 13) - ]) + """, + [undef_var("c", 16, 24, "Foo", 2, 13)], + ) def multiple_variables_in_fragments_not_defined(): - expect_fails_rule(NoUndefinedVariablesRule, """ + expect_fails_rule( + NoUndefinedVariablesRule, + """ query Foo($b: String) { ...FragA } @@ -187,13 +218,14 @@ def multiple_variables_in_fragments_not_defined(): fragment FragC on Type { field(c: $c) } - """, [ - undef_var('a', 6, 24, 'Foo', 2, 13), - undef_var('c', 16, 24, 'Foo', 2, 13) - ]) + """, + [undef_var("a", 6, 24, "Foo", 2, 13), undef_var("c", 16, 24, "Foo", 2, 13)], + ) def single_variable_in_fragment_not_defined_by_multiple_operations(): - expect_fails_rule(NoUndefinedVariablesRule, """ + expect_fails_rule( + NoUndefinedVariablesRule, + """ query Foo($a: String) { ...FragAB } @@ -203,13 +235,14 @@ def single_variable_in_fragment_not_defined_by_multiple_operations(): fragment FragAB on Type { field(a: $a, b: $b) } - """, [ - undef_var('b', 9, 31, 'Foo', 2, 13), - undef_var('b', 9, 31, 'Bar', 5, 13) - ]) + """, + [undef_var("b", 9, 31, "Foo", 2, 13), undef_var("b", 9, 31, "Bar", 5, 13)], + ) def variables_in_fragment_not_defined_by_multiple_operations(): - expect_fails_rule(NoUndefinedVariablesRule, """ + expect_fails_rule( + NoUndefinedVariablesRule, + """ query Foo($b: String) { ...FragAB } @@ -219,13 +252,14 @@ def variables_in_fragment_not_defined_by_multiple_operations(): fragment FragAB on Type { field(a: $a, b: $b) } - """, [ - undef_var('a', 9, 24, 'Foo', 2, 13), - undef_var('b', 9, 31, 'Bar', 5, 13) - ]) + """, + [undef_var("a", 9, 24, "Foo", 2, 13), undef_var("b", 9, 31, "Bar", 5, 13)], + ) def variable_in_fragment_used_by_other_operation(): - expect_fails_rule(NoUndefinedVariablesRule, """ + expect_fails_rule( + NoUndefinedVariablesRule, + """ query Foo($b: String) { ...FragA } @@ -238,13 +272,14 @@ def variable_in_fragment_used_by_other_operation(): fragment FragB on Type { field(b: $b) } - """, [ - undef_var('a', 9, 24, 'Foo', 2, 13), - undef_var('b', 12, 24, 'Bar', 5, 13) - ]) + """, + [undef_var("a", 9, 24, "Foo", 2, 13), undef_var("b", 12, 24, "Bar", 5, 13)], + ) def multiple_undefined_variables_produce_multiple_errors(): - expect_fails_rule(NoUndefinedVariablesRule, """ + expect_fails_rule( + NoUndefinedVariablesRule, + """ query Foo($b: String) { ...FragAB } @@ -259,11 +294,13 @@ def multiple_undefined_variables_produce_multiple_errors(): fragment FragC on Type { field2(c: $c) } - """, [ - undef_var('a', 9, 25, 'Foo', 2, 13), - undef_var('a', 11, 25, 'Foo', 2, 13), - undef_var('c', 14, 25, 'Foo', 2, 13), - undef_var('b', 9, 32, 'Bar', 5, 13), - undef_var('b', 11, 32, 'Bar', 5, 13), - undef_var('c', 14, 25, 'Bar', 5, 13), - ]) + """, + [ + undef_var("a", 9, 25, "Foo", 2, 13), + undef_var("a", 11, 25, "Foo", 2, 13), + undef_var("c", 14, 25, "Foo", 2, 13), + undef_var("b", 9, 32, "Bar", 5, 13), + undef_var("b", 11, 32, "Bar", 5, 13), + undef_var("c", 14, 25, "Bar", 5, 13), + ], + ) diff --git a/tests/validation/test_no_unused_fragments.py b/tests/validation/test_no_unused_fragments.py index 255028aa..0ac4018a 100644 --- a/tests/validation/test_no_unused_fragments.py +++ b/tests/validation/test_no_unused_fragments.py @@ -1,20 +1,21 @@ from graphql.validation import NoUnusedFragmentsRule -from graphql.validation.rules.no_unused_fragments import ( - unused_fragment_message) +from graphql.validation.rules.no_unused_fragments import unused_fragment_message from .harness import expect_fails_rule, expect_passes_rule def unused_frag(frag_name, line, column): return { - 'message': unused_fragment_message(frag_name), - 'locations': [(line, column)]} + "message": unused_fragment_message(frag_name), + "locations": [(line, column)], + } def describe_validate_no_unused_fragments(): - def all_fragment_names_are_used(): - expect_passes_rule(NoUnusedFragmentsRule, """ + expect_passes_rule( + NoUnusedFragmentsRule, + """ { human(id: 4) { ...HumanFields1 @@ -33,10 +34,13 @@ def all_fragment_names_are_used(): fragment HumanFields3 on Human { name } - """) + """, + ) def all_fragment_names_are_used_by_multiple_operations(): - expect_passes_rule(NoUnusedFragmentsRule, """ + expect_passes_rule( + NoUnusedFragmentsRule, + """ query Foo { human(id: 4) { ...HumanFields1 @@ -57,10 +61,13 @@ def all_fragment_names_are_used_by_multiple_operations(): fragment HumanFields3 on Human { name } - """) + """, + ) def contains_unknown_fragments(): - expect_fails_rule(NoUnusedFragmentsRule, """ + expect_fails_rule( + NoUnusedFragmentsRule, + """ query Foo { human(id: 4) { ...HumanFields1 @@ -87,13 +94,14 @@ def contains_unknown_fragments(): fragment Unused2 on Human { name } - """, [ - unused_frag('Unused1', 22, 13), - unused_frag('Unused2', 25, 13), - ]) + """, + [unused_frag("Unused1", 22, 13), unused_frag("Unused2", 25, 13)], + ) def contains_unknown_fragments_with_ref_cycle(): - expect_fails_rule(NoUnusedFragmentsRule, """ + expect_fails_rule( + NoUnusedFragmentsRule, + """ query Foo { human(id: 4) { ...HumanFields1 @@ -122,13 +130,14 @@ def contains_unknown_fragments_with_ref_cycle(): name ...Unused1 } - """, [ - unused_frag('Unused1', 22, 13), - unused_frag('Unused2', 26, 13), - ]) + """, + [unused_frag("Unused1", 22, 13), unused_frag("Unused2", 26, 13)], + ) def contains_unknown_and_undefined_fragments(): - expect_fails_rule(NoUnusedFragmentsRule, """ + expect_fails_rule( + NoUnusedFragmentsRule, + """ query Foo { human(id: 4) { ...bar @@ -137,6 +146,6 @@ def contains_unknown_and_undefined_fragments(): fragment foo on Human { name } - """, [ - unused_frag('foo', 7, 13) - ]) + """, + [unused_frag("foo", 7, 13)], + ) diff --git a/tests/validation/test_no_unused_variables.py b/tests/validation/test_no_unused_variables.py index 0654f29b..4cc66416 100644 --- a/tests/validation/test_no_unused_variables.py +++ b/tests/validation/test_no_unused_variables.py @@ -1,27 +1,31 @@ from graphql.validation import NoUnusedVariablesRule -from graphql.validation.rules.no_unused_variables import ( - unused_variable_message) +from graphql.validation.rules.no_unused_variables import unused_variable_message from .harness import expect_fails_rule, expect_passes_rule def unused_var(var_name, op_name, line, column): return { - 'message': unused_variable_message(var_name, op_name), - 'locations': [(line, column)]} + "message": unused_variable_message(var_name, op_name), + "locations": [(line, column)], + } def describe_validate_no_unused_variables(): - def uses_all_variables(): - expect_passes_rule(NoUnusedVariablesRule, """ + expect_passes_rule( + NoUnusedVariablesRule, + """ query ($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c) } - """) + """, + ) def uses_all_variables_deeply(): - expect_passes_rule(NoUnusedVariablesRule, """ + expect_passes_rule( + NoUnusedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { field(a: $a) { field(b: $b) { @@ -29,10 +33,13 @@ def uses_all_variables_deeply(): } } } - """) + """, + ) def uses_all_variables_deeply_in_inline_fragments(): - expect_passes_rule(NoUnusedVariablesRule, """ + expect_passes_rule( + NoUnusedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { ... on Type { field(a: $a) { @@ -44,10 +51,13 @@ def uses_all_variables_deeply_in_inline_fragments(): } } } - """) + """, + ) def uses_all_variables_in_fragment(): - expect_passes_rule(NoUnusedVariablesRule, """ + expect_passes_rule( + NoUnusedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -64,10 +74,13 @@ def uses_all_variables_in_fragment(): fragment FragC on Type { field(c: $c) } - """) + """, + ) def variable_used_by_fragment_in_multiple_operations(): - expect_passes_rule(NoUnusedVariablesRule, """ + expect_passes_rule( + NoUnusedVariablesRule, + """ query Foo($a: String) { ...FragA } @@ -80,10 +93,13 @@ def variable_used_by_fragment_in_multiple_operations(): fragment FragB on Type { field(b: $b) } - """) + """, + ) def variable_used_by_recursive_fragment(): - expect_passes_rule(NoUnusedVariablesRule, """ + expect_passes_rule( + NoUnusedVariablesRule, + """ query Foo($a: String) { ...FragA } @@ -92,29 +108,35 @@ def variable_used_by_recursive_fragment(): ...FragA } } - """) + """, + ) def variable_not_used(): - expect_fails_rule(NoUnusedVariablesRule, """ + expect_fails_rule( + NoUnusedVariablesRule, + """ query ($a: String, $b: String, $c: String) { field(a: $a, b: $b) } - """, [ - unused_var('c', None, 2, 44) - ]) + """, + [unused_var("c", None, 2, 44)], + ) def multiple_variables_not_used(): - expect_fails_rule(NoUnusedVariablesRule, """ + expect_fails_rule( + NoUnusedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { field(b: $b) } - """, [ - unused_var('a', 'Foo', 2, 23), - unused_var('c', 'Foo', 2, 47) - ]) + """, + [unused_var("a", "Foo", 2, 23), unused_var("c", "Foo", 2, 47)], + ) def variable_not_used_in_fragments(): - expect_fails_rule(NoUnusedVariablesRule, """ + expect_fails_rule( + NoUnusedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -131,12 +153,14 @@ def variable_not_used_in_fragments(): fragment FragC on Type { field } - """, [ - unused_var('c', 'Foo', 2, 47) - ]) + """, + [unused_var("c", "Foo", 2, 47)], + ) def multiple_variables_not_used_in_fragments(): - expect_fails_rule(NoUnusedVariablesRule, """ + expect_fails_rule( + NoUnusedVariablesRule, + """ query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -153,13 +177,14 @@ def multiple_variables_not_used_in_fragments(): fragment FragC on Type { field } - """, [ - unused_var('a', 'Foo', 2, 23), - unused_var('c', 'Foo', 2, 47) - ]) + """, + [unused_var("a", "Foo", 2, 23), unused_var("c", "Foo", 2, 47)], + ) def variable_not_used_by_unreferenced_fragment(): - expect_fails_rule(NoUnusedVariablesRule, """ + expect_fails_rule( + NoUnusedVariablesRule, + """ query Foo($b: String) { ...FragA } @@ -169,12 +194,14 @@ def variable_not_used_by_unreferenced_fragment(): fragment FragB on Type { field(b: $b) } - """, [ - unused_var('b', 'Foo', 2, 23), - ]) + """, + [unused_var("b", "Foo", 2, 23)], + ) def variable_not_used_by_fragment_used_by_other_operation(): - expect_fails_rule(NoUnusedVariablesRule, """ + expect_fails_rule( + NoUnusedVariablesRule, + """ query Foo($b: String) { ...FragA } @@ -187,7 +214,6 @@ def variable_not_used_by_fragment_used_by_other_operation(): fragment FragB on Type { field(b: $b) } - """, [ - unused_var('b', 'Foo', 2, 23), - unused_var('a', 'Bar', 5, 23), - ]) + """, + [unused_var("b", "Foo", 2, 23), unused_var("a", "Bar", 5, 23)], + ) diff --git a/tests/validation/test_overlapping_fields_can_be_merged.py b/tests/validation/test_overlapping_fields_can_be_merged.py index 02f2792d..f8a7a71b 100644 --- a/tests/validation/test_overlapping_fields_can_be_merged.py +++ b/tests/validation/test_overlapping_fields_can_be_merged.py @@ -1,91 +1,132 @@ from graphql.type import ( - GraphQLField, GraphQLID, GraphQLInt, - GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, - GraphQLSchema, GraphQLString) + GraphQLField, + GraphQLID, + GraphQLInt, + GraphQLInterfaceType, + GraphQLList, + GraphQLNonNull, + GraphQLObjectType, + GraphQLSchema, + GraphQLString, +) from graphql.validation import OverlappingFieldsCanBeMergedRule from graphql.validation.rules.overlapping_fields_can_be_merged import ( - fields_conflict_message) + fields_conflict_message +) from .harness import ( - expect_fails_rule, expect_fails_rule_with_schema, - expect_passes_rule, expect_passes_rule_with_schema) + expect_fails_rule, + expect_fails_rule_with_schema, + expect_passes_rule, + expect_passes_rule_with_schema, +) def describe_validate_overlapping_fields_can_be_merged(): - def unique_fields(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment uniqueFields on Dog { name nickname } - """) + """, + ) def identical_fields(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment mergeIdenticalFields on Dog { name name } - """) + """, + ) def identical_fields_with_identical_args(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment mergeIdenticalFieldsWithIdenticalArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: SIT) } - """) + """, + ) def identical_fields_with_identical_directives(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment mergeSameFieldsWithSameDirectives on Dog { name @include(if: true) name @include(if: true) } - """) + """, + ) def different_args_with_different_aliases(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment differentArgsWithDifferentAliases on Dog { knowsSit: doesKnowCommand(dogCommand: SIT) knowsDown: doesKnowCommand(dogCommand: DOWN) } - """) + """, + ) def different_directives_with_different_aliases(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment differentDirectivesWithDifferentAliases on Dog { nameIfTrue: name @include(if: true) nameIfFalse: name @include(if: false) } - """) + """, + ) def different_skip_or_include_directives_accepted(): # Note: Differing skip/include directives don't create an ambiguous # return value and are acceptable in conditions where differing runtime # values may have the same desired effect of including/skipping a field - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment differentDirectivesWithDifferentAliases on Dog { name @include(if: true) name @include(if: false) } - """) + """, + ) def same_aliases_with_different_field_targets(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment sameAliasesWithDifferentFieldTargets on Dog { fido: name fido: nickname } - """, [{ - 'message': fields_conflict_message( - 'fido', 'name and nickname are different fields'), - 'locations': [(3, 15), (4, 15)], 'path': None - }]) + """, + [ + { + "message": fields_conflict_message( + "fido", "name and nickname are different fields" + ), + "locations": [(3, 15), (4, 15)], + "path": None, + } + ], + ) def same_aliases_allowed_on_non_overlapping_fields(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment sameAliasesWithDifferentFieldTargets on Pet { ... on Dog { name @@ -94,60 +135,91 @@ def same_aliases_allowed_on_non_overlapping_fields(): name: nickname } } - """) + """, + ) def alias_masking_direct_field_access(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment aliasMaskingDirectFieldAccess on Dog { name: nickname name } - """, [{ - 'message': fields_conflict_message( - 'name', 'nickname and name are different fields'), - 'locations': [(3, 15), (4, 15)] - }]) + """, + [ + { + "message": fields_conflict_message( + "name", "nickname and name are different fields" + ), + "locations": [(3, 15), (4, 15)], + } + ], + ) def different_args_second_adds_an_argument(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment conflictingArgs on Dog { doesKnowCommand doesKnowCommand(dogCommand: HEEL) } - """, [{ - 'message': fields_conflict_message( - 'doesKnowCommand', 'they have differing arguments'), - 'locations': [(3, 15), (4, 15)] - }]) + """, + [ + { + "message": fields_conflict_message( + "doesKnowCommand", "they have differing arguments" + ), + "locations": [(3, 15), (4, 15)], + } + ], + ) def different_args_second_missing_an_argument(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment conflictingArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand } - """, [{ - 'message': fields_conflict_message( - 'doesKnowCommand', 'they have differing arguments'), - 'locations': [(3, 15), (4, 15)] - }]) + """, + [ + { + "message": fields_conflict_message( + "doesKnowCommand", "they have differing arguments" + ), + "locations": [(3, 15), (4, 15)], + } + ], + ) def conflicting_args(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment conflictingArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: HEEL) } - """, [{ - 'message': fields_conflict_message( - 'doesKnowCommand', 'they have differing arguments'), - 'locations': [(3, 15), (4, 15)] - }]) + """, + [ + { + "message": fields_conflict_message( + "doesKnowCommand", "they have differing arguments" + ), + "locations": [(3, 15), (4, 15)], + } + ], + ) def allows_different_args_where_no_conflict_is_possible(): # This is valid since no object can be both a "Dog" and a "Cat", thus # these fields can never overlap. - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment conflictingArgs on Pet { ... on Dog { name(surname: true) @@ -156,10 +228,13 @@ def allows_different_args_where_no_conflict_is_possible(): name } } - """) + """, + ) def encounters_conflict_in_fragments(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ { ...A ...B @@ -170,14 +245,21 @@ def encounters_conflict_in_fragments(): fragment B on Type { x: b } - """, [{ - 'message': fields_conflict_message( - 'x', 'a and b are different fields'), - 'locations': [(7, 15), (10, 15)] - }]) + """, + [ + { + "message": fields_conflict_message( + "x", "a and b are different fields" + ), + "locations": [(7, 15), (10, 15)], + } + ], + ) def reports_each_conflict_once(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ { f1 { ...A @@ -199,22 +281,33 @@ def reports_each_conflict_once(): fragment B on Type { x: b } - """, [{ - 'message': fields_conflict_message( - 'x', 'a and b are different fields'), - 'locations': [(18, 15), (21, 15)] - }, { - 'message': fields_conflict_message( - 'x', 'c and a are different fields'), - 'locations': [(14, 17), (18, 15)] - }, { - 'message': fields_conflict_message( - 'x', 'c and b are different fields'), - 'locations': [(14, 17), (21, 15)] - }]) + """, + [ + { + "message": fields_conflict_message( + "x", "a and b are different fields" + ), + "locations": [(18, 15), (21, 15)], + }, + { + "message": fields_conflict_message( + "x", "c and a are different fields" + ), + "locations": [(14, 17), (18, 15)], + }, + { + "message": fields_conflict_message( + "x", "c and b are different fields" + ), + "locations": [(14, 17), (21, 15)], + }, + ], + ) def deep_conflict(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ { field { x: a @@ -223,14 +316,21 @@ def deep_conflict(): x: b } } - """, [{ - 'message': fields_conflict_message('field', [ - ('x', 'a and b are different fields')]), - 'locations': [(3, 15), (4, 17), (6, 15), (7, 17)] - }]) + """, + [ + { + "message": fields_conflict_message( + "field", [("x", "a and b are different fields")] + ), + "locations": [(3, 15), (4, 17), (6, 15), (7, 17)], + } + ], + ) def deep_conflict_with_multiple_issues(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ { field { x: a @@ -241,17 +341,26 @@ def deep_conflict_with_multiple_issues(): y: d } } - """, [{ - 'message': fields_conflict_message('field', [ - ('x', 'a and b are different fields'), - ('y', 'c and d are different fields')]), - 'locations': [ - (3, 15), (4, 17), (5, 17), (7, 15), (8, 17), (9, 17)], - 'path': None - }]) + """, + [ + { + "message": fields_conflict_message( + "field", + [ + ("x", "a and b are different fields"), + ("y", "c and d are different fields"), + ], + ), + "locations": [(3, 15), (4, 17), (5, 17), (7, 15), (8, 17), (9, 17)], + "path": None, + } + ], + ) def very_deep_conflict(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ { field { deepField { @@ -264,16 +373,30 @@ def very_deep_conflict(): } } } - """, [{ - 'message': fields_conflict_message('field', [ - ('deepField', [('x', 'a and b are different fields')])]), - 'locations': [ - (3, 15), (4, 17), (5, 19), (8, 15), (9, 17), (10, 19)], - 'path': None - }]) + """, + [ + { + "message": fields_conflict_message( + "field", + [("deepField", [("x", "a and b are different fields")])], + ), + "locations": [ + (3, 15), + (4, 17), + (5, 19), + (8, 15), + (9, 17), + (10, 19), + ], + "path": None, + } + ], + ) def reports_deep_conflict_to_nearest_common_ancestor(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ { field { deepField { @@ -289,14 +412,21 @@ def reports_deep_conflict_to_nearest_common_ancestor(): } } } - """, [{ - 'message': fields_conflict_message('deepField', [ - ('x', 'a and b are different fields')]), - 'locations': [(4, 17), (5, 19), (7, 17), (8, 19)] - }]) + """, + [ + { + "message": fields_conflict_message( + "deepField", [("x", "a and b are different fields")] + ), + "locations": [(4, 17), (5, 19), (7, 17), (8, 19)], + } + ], + ) def reports_deep_conflict_to_nearest_common_ancestor_in_fragments(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ { field { ...F @@ -320,15 +450,21 @@ def reports_deep_conflict_to_nearest_common_ancestor_in_fragments(): } } } - """, [{ - 'message': fields_conflict_message('deeperField', [ - ('x', 'a and b are different fields')]), - 'locations': [ - (12, 17), (13, 19), (15, 17), (16, 19)] - }]) + """, + [ + { + "message": fields_conflict_message( + "deeperField", [("x", "a and b are different fields")] + ), + "locations": [(12, 17), (13, 19), (15, 17), (16, 19)], + } + ], + ) def reports_deep_conflict_in_nested_fragments(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ { field { ...F @@ -351,17 +487,33 @@ def reports_deep_conflict_in_nested_fragments(): fragment J on T { x: b } - """, [{ - 'message': fields_conflict_message('field', [ - ('x', 'a and b are different fields'), - ('y', 'c and d are different fields')]), - 'locations': [ - (3, 15), (11, 15), (15, 15), (6, 15), (22, 15), (18, 15)], - 'path': None - }]) + """, + [ + { + "message": fields_conflict_message( + "field", + [ + ("x", "a and b are different fields"), + ("y", "c and d are different fields"), + ], + ), + "locations": [ + (3, 15), + (11, 15), + (15, 15), + (6, 15), + (22, 15), + (18, 15), + ], + "path": None, + } + ], + ) def ignores_unknown_fragments(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ { field ...Unknown @@ -372,62 +524,107 @@ def ignores_unknown_fragments(): field ...OtherUnknown } - """) + """, + ) def describe_return_types_must_be_unambiguous(): - SomeBox = GraphQLInterfaceType('SomeBox', lambda: { - 'deepBox': GraphQLField(SomeBox), - 'unrelatedField': GraphQLField(GraphQLString)}) - - StringBox = GraphQLObjectType('StringBox', lambda: { - 'scalar': GraphQLField(GraphQLString), - 'deepBox': GraphQLField(StringBox), - 'unrelatedField': GraphQLField(GraphQLString), - 'listStringBox': GraphQLField(GraphQLList(StringBox)), - 'stringBox': GraphQLField(StringBox), - 'intBox': GraphQLField(IntBox)}, - interfaces=[SomeBox]) - - IntBox = GraphQLObjectType('IntBox', lambda: { - 'scalar': GraphQLField(GraphQLInt), - 'deepBox': GraphQLField(IntBox), - 'unrelatedField': GraphQLField(GraphQLString), - 'listStringBox': GraphQLField(GraphQLList(StringBox)), - 'stringBox': GraphQLField(StringBox), - 'intBox': GraphQLField(IntBox)}, - interfaces=[SomeBox]) - - NonNullStringBox1 = GraphQLInterfaceType('NonNullStringBox1', { - 'scalar': GraphQLField(GraphQLNonNull(GraphQLString))}) - - NonNullStringBox1Impl = GraphQLObjectType('NonNullStringBox1Impl', { - 'scalar': GraphQLField(GraphQLNonNull(GraphQLString)), - 'deepBox': GraphQLField(StringBox), - 'unrelatedField': GraphQLField(GraphQLString)}, - interfaces=[SomeBox, NonNullStringBox1]) - - NonNullStringBox2 = GraphQLInterfaceType('NonNullStringBox2', { - 'scalar': GraphQLField(GraphQLNonNull(GraphQLString))}) - - NonNullStringBox2Impl = GraphQLObjectType('NonNullStringBox2Impl', { - 'scalar': GraphQLField(GraphQLNonNull(GraphQLString)), - 'unrelatedField': GraphQLField(GraphQLString), - 'deepBox': GraphQLField(StringBox), - }, interfaces=[SomeBox, NonNullStringBox2]) - - Connection = GraphQLObjectType('Connection', { - 'edges': GraphQLField(GraphQLList(GraphQLObjectType('Edge', { - 'node': GraphQLField(GraphQLObjectType('Node', { - 'id': GraphQLField(GraphQLID), - 'name': GraphQLField(GraphQLString)}))})))}) + SomeBox = GraphQLInterfaceType( + "SomeBox", + lambda: { + "deepBox": GraphQLField(SomeBox), + "unrelatedField": GraphQLField(GraphQLString), + }, + ) + + StringBox = GraphQLObjectType( + "StringBox", + lambda: { + "scalar": GraphQLField(GraphQLString), + "deepBox": GraphQLField(StringBox), + "unrelatedField": GraphQLField(GraphQLString), + "listStringBox": GraphQLField(GraphQLList(StringBox)), + "stringBox": GraphQLField(StringBox), + "intBox": GraphQLField(IntBox), + }, + interfaces=[SomeBox], + ) + + IntBox = GraphQLObjectType( + "IntBox", + lambda: { + "scalar": GraphQLField(GraphQLInt), + "deepBox": GraphQLField(IntBox), + "unrelatedField": GraphQLField(GraphQLString), + "listStringBox": GraphQLField(GraphQLList(StringBox)), + "stringBox": GraphQLField(StringBox), + "intBox": GraphQLField(IntBox), + }, + interfaces=[SomeBox], + ) + + NonNullStringBox1 = GraphQLInterfaceType( + "NonNullStringBox1", {"scalar": GraphQLField(GraphQLNonNull(GraphQLString))} + ) + + NonNullStringBox1Impl = GraphQLObjectType( + "NonNullStringBox1Impl", + { + "scalar": GraphQLField(GraphQLNonNull(GraphQLString)), + "deepBox": GraphQLField(StringBox), + "unrelatedField": GraphQLField(GraphQLString), + }, + interfaces=[SomeBox, NonNullStringBox1], + ) + + NonNullStringBox2 = GraphQLInterfaceType( + "NonNullStringBox2", {"scalar": GraphQLField(GraphQLNonNull(GraphQLString))} + ) + + NonNullStringBox2Impl = GraphQLObjectType( + "NonNullStringBox2Impl", + { + "scalar": GraphQLField(GraphQLNonNull(GraphQLString)), + "unrelatedField": GraphQLField(GraphQLString), + "deepBox": GraphQLField(StringBox), + }, + interfaces=[SomeBox, NonNullStringBox2], + ) + + Connection = GraphQLObjectType( + "Connection", + { + "edges": GraphQLField( + GraphQLList( + GraphQLObjectType( + "Edge", + { + "node": GraphQLField( + GraphQLObjectType( + "Node", + { + "id": GraphQLField(GraphQLID), + "name": GraphQLField(GraphQLString), + }, + ) + ) + }, + ) + ) + ) + }, + ) schema = GraphQLSchema( - GraphQLObjectType('QueryRoot', { - 'someBox': GraphQLField(SomeBox), - 'connection': GraphQLField(Connection)}), - types=[IntBox, StringBox, - NonNullStringBox1Impl, NonNullStringBox2Impl]) + GraphQLObjectType( + "QueryRoot", + { + "someBox": GraphQLField(SomeBox), + "connection": GraphQLField(Connection), + }, + ), + types=[IntBox, StringBox, NonNullStringBox1Impl, NonNullStringBox2Impl], + ) def conflicting_return_types_which_potentially_overlap(): # This is invalid since an object could potentially be both the @@ -435,7 +632,9 @@ def conflicting_return_types_which_potentially_overlap(): # While that condition does not exist in the current schema, the # schema could expand in the future to allow this. expect_fails_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ...on IntBox { @@ -446,19 +645,25 @@ def conflicting_return_types_which_potentially_overlap(): } } } - """, [{ - 'message': fields_conflict_message( - 'scalar', - 'they return conflicting types Int and String!'), - 'locations': [(5, 27), (8, 27)] - }]) + """, + [ + { + "message": fields_conflict_message( + "scalar", "they return conflicting types Int and String!" + ), + "locations": [(5, 27), (8, 27)], + } + ], + ) def compatible_return_shapes_on_different_return_types(): # In this case `deepBox` returns `SomeBox` in the first usage, and # `StringBox` in the second usage. These types are not the same! # However this is valid because the return *shapes* are compatible. expect_passes_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ... on SomeBox { @@ -473,11 +678,14 @@ def compatible_return_shapes_on_different_return_types(): } } } - """) + """, + ) def disallows_differing_return_types_despite_no_overlap(): expect_fails_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ... on IntBox { @@ -488,16 +696,22 @@ def disallows_differing_return_types_despite_no_overlap(): } } } - """, [{ - 'message': fields_conflict_message( - 'scalar', - 'they return conflicting types Int and String'), - 'locations': [(5, 27), (8, 27)] - }]) + """, + [ + { + "message": fields_conflict_message( + "scalar", "they return conflicting types Int and String" + ), + "locations": [(5, 27), (8, 27)], + } + ], + ) def reports_correctly_when_a_non_exclusive_follows_an_exclusive(): expect_fails_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ... on IntBox { @@ -540,17 +754,29 @@ def reports_correctly_when_a_non_exclusive_follows_an_exclusive(): fragment Y on SomeBox { scalar: unrelatedField } - """, [{ - 'message': fields_conflict_message('other', [ - ('scalar', - 'scalar and unrelatedField are different fields')]), - 'locations': [(31, 23), (39, 23), (34, 23), (42, 23)], - 'path': None - }]) + """, + [ + { + "message": fields_conflict_message( + "other", + [ + ( + "scalar", + "scalar and unrelatedField are different fields", + ) + ], + ), + "locations": [(31, 23), (39, 23), (34, 23), (42, 23)], + "path": None, + } + ], + ) def disallows_differing_return_type_nullability_despite_no_overlap(): expect_fails_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ... on NonNullStringBox1 { @@ -561,16 +787,22 @@ def disallows_differing_return_type_nullability_despite_no_overlap(): } } } - """, [{ - 'message': fields_conflict_message( - 'scalar', - 'they return conflicting types String! and String'), - 'locations': [(5, 27), (8, 27)] - }]) + """, + [ + { + "message": fields_conflict_message( + "scalar", "they return conflicting types String! and String" + ), + "locations": [(5, 27), (8, 27)], + } + ], + ) def disallows_differing_return_type_list_despite_no_overlap_1(): expect_fails_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ... on IntBox { @@ -585,15 +817,23 @@ def disallows_differing_return_type_list_despite_no_overlap_1(): } } } - """, [{ - 'message': fields_conflict_message( - 'box', 'they return conflicting types' - ' [StringBox] and StringBox'), - 'locations': [(5, 27), (10, 27)] - }]) + """, + [ + { + "message": fields_conflict_message( + "box", + "they return conflicting types" + " [StringBox] and StringBox", + ), + "locations": [(5, 27), (10, 27)], + } + ], + ) expect_fails_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ... on IntBox { @@ -608,16 +848,24 @@ def disallows_differing_return_type_list_despite_no_overlap_1(): } } } - """, [{ - 'message': fields_conflict_message( - 'box', 'they return conflicting types' - ' StringBox and [StringBox]'), - 'locations': [(5, 27), (10, 27)] - }]) + """, + [ + { + "message": fields_conflict_message( + "box", + "they return conflicting types" + " StringBox and [StringBox]", + ), + "locations": [(5, 27), (10, 27)], + } + ], + ) def disallows_differing_subfields(): expect_fails_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ... on IntBox { @@ -633,16 +881,22 @@ def disallows_differing_subfields(): } } } - """, [{ - 'message': fields_conflict_message( - 'val', - 'scalar and unrelatedField are different fields'), - 'locations': [(6, 29), (7, 29)] - }]) + """, + [ + { + "message": fields_conflict_message( + "val", "scalar and unrelatedField are different fields" + ), + "locations": [(6, 29), (7, 29)], + } + ], + ) def disallows_differing_deep_return_types_despite_no_overlap(): expect_fails_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ... on IntBox { @@ -657,17 +911,29 @@ def disallows_differing_deep_return_types_despite_no_overlap(): } } } - """, [{ - 'message': fields_conflict_message('box', [ - ('scalar', - 'they return conflicting types String and Int')]), - 'locations': [(5, 27), (6, 29), (10, 27), (11, 29)], - 'path': None - }]) + """, + [ + { + "message": fields_conflict_message( + "box", + [ + ( + "scalar", + "they return conflicting types String and Int", + ) + ], + ), + "locations": [(5, 27), (6, 29), (10, 27), (11, 29)], + "path": None, + } + ], + ) def allows_non_conflicting_overlapping_types(): expect_passes_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ... on IntBox { @@ -678,11 +944,14 @@ def allows_non_conflicting_overlapping_types(): } } } - """) + """, + ) def same_wrapped_scalar_return_types(): expect_passes_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ...on NonNullStringBox1 { @@ -693,22 +962,28 @@ def same_wrapped_scalar_return_types(): } } } - """) + """, + ) def allows_inline_typeless_fragments(): expect_passes_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { a ... { a } } - """) + """, + ) def compares_deep_types_including_list(): expect_fails_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { connection { ...edgeID @@ -727,19 +1002,31 @@ def compares_deep_types_including_list(): } } } - """, [{ - 'message': fields_conflict_message('edges', [ - ('node', [ - ('id', 'name and id are different fields')])]), - 'locations': [ - (5, 25), (6, 27), (7, 29), - (14, 23), (15, 25), (16, 27)], - 'path': None - }]) + """, + [ + { + "message": fields_conflict_message( + "edges", + [("node", [("id", "name and id are different fields")])], + ), + "locations": [ + (5, 25), + (6, 27), + (7, 29), + (14, 23), + (15, 25), + (16, 27), + ], + "path": None, + } + ], + ) def ignores_unknown_types(): expect_passes_rule_with_schema( - schema, OverlappingFieldsCanBeMergedRule, """ + schema, + OverlappingFieldsCanBeMergedRule, + """ { someBox { ...on UnknownType { @@ -750,78 +1037,101 @@ def ignores_unknown_types(): } } } - """) + """, + ) def error_message_contains_hint_for_alias_conflict(): # The error template should end with a hint for the user to try # using different aliases. - error = fields_conflict_message( - 'x', 'a and b are different fields') + error = fields_conflict_message("x", "a and b are different fields") assert error == ( "Fields 'x' conflict because a and b are different fields." - ' Use different aliases on the fields to fetch both' - ' if this was intentional.') + " Use different aliases on the fields to fetch both" + " if this was intentional." + ) def works_for_field_names_that_are_js_keywords(): - FooType = GraphQLObjectType('Foo', { - 'constructor': GraphQLField(GraphQLString)}) + FooType = GraphQLObjectType( + "Foo", {"constructor": GraphQLField(GraphQLString)} + ) schema_with_keywords = GraphQLSchema( - GraphQLObjectType('query', lambda: { - 'foo': GraphQLField(FooType)})) + GraphQLObjectType("query", lambda: {"foo": GraphQLField(FooType)}) + ) expect_passes_rule_with_schema( - schema_with_keywords, OverlappingFieldsCanBeMergedRule, """ + schema_with_keywords, + OverlappingFieldsCanBeMergedRule, + """ { foo { constructor } } - """) + """, + ) def works_for_field_names_that_are_python_keywords(): - FooType = GraphQLObjectType('Foo', { - 'class': GraphQLField(GraphQLString)}) + FooType = GraphQLObjectType("Foo", {"class": GraphQLField(GraphQLString)}) schema_with_keywords = GraphQLSchema( - GraphQLObjectType('query', lambda: { - 'foo': GraphQLField(FooType)})) + GraphQLObjectType("query", lambda: {"foo": GraphQLField(FooType)}) + ) expect_passes_rule_with_schema( - schema_with_keywords, OverlappingFieldsCanBeMergedRule, """ + schema_with_keywords, + OverlappingFieldsCanBeMergedRule, + """ { foo { class } } - """) + """, + ) def does_not_infinite_loop_on_recursive_fragments(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment fragA on Human { name, relatives { name, ...fragA } } - """) + """, + ) def does_not_infinite_loop_on_immediately_recursive_fragments(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment fragA on Human { name, ...fragA } - """) + """, + ) def does_not_infinite_loop_on_transitively_recursive_fragments(): - expect_passes_rule(OverlappingFieldsCanBeMergedRule, """ + expect_passes_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment fragA on Human { name, ...fragB } fragment fragB on Human { name, ...fragC } fragment fragC on Human { name, ...fragA } - """) + """, + ) def finds_invalid_case_even_with_immediately_recursive_fragment(): - expect_fails_rule(OverlappingFieldsCanBeMergedRule, """ + expect_fails_rule( + OverlappingFieldsCanBeMergedRule, + """ fragment sameAliasesWithDifferentFieldTargets on Dog { ...sameAliasesWithDifferentFieldTargets fido: name fido: nickname } - """, [{ - 'message': fields_conflict_message( - 'fido', 'name and nickname are different fields'), - 'locations': [(4, 15), (5, 15)] - }]) + """, + [ + { + "message": fields_conflict_message( + "fido", "name and nickname are different fields" + ), + "locations": [(4, 15), (5, 15)], + } + ], + ) diff --git a/tests/validation/test_possible_fragment_spreads.py b/tests/validation/test_possible_fragment_spreads.py index 274742a9..5fbedf5f 100644 --- a/tests/validation/test_possible_fragment_spreads.py +++ b/tests/validation/test_possible_fragment_spreads.py @@ -1,182 +1,243 @@ from graphql.validation import PossibleFragmentSpreadsRule from graphql.validation.rules.possible_fragment_spreads import ( type_incompatible_spread_message, - type_incompatible_anon_spread_message) + type_incompatible_anon_spread_message, +) from .harness import expect_fails_rule, expect_passes_rule def error(frag_name, parent_type, frag_type, line, column): return { - 'message': type_incompatible_spread_message( - frag_name, parent_type, frag_type), - 'locations': [(line, column)]} + "message": type_incompatible_spread_message(frag_name, parent_type, frag_type), + "locations": [(line, column)], + } def error_anon(parent_type, frag_type, line, column): return { - 'message': type_incompatible_anon_spread_message( - parent_type, frag_type), - 'locations': [(line, column)]} + "message": type_incompatible_anon_spread_message(parent_type, frag_type), + "locations": [(line, column)], + } def describe_validate_possible_fragment_spreads(): - def of_the_same_object(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment objectWithinObject on Dog { ...dogFragment } fragment dogFragment on Dog { barkVolume } - """) + """, + ) def of_the_same_object_inline_fragment(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment objectWithinObjectAnon on Dog { ... on Dog { barkVolume } } - """) # noqa + """, + ) # noqa def object_into_implemented_interface(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment objectWithinInterface on Pet { ...dogFragment } fragment dogFragment on Dog { barkVolume } - """) + """, + ) def object_into_containing_union(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment objectWithinUnion on CatOrDog { ...dogFragment } fragment dogFragment on Dog { barkVolume } - """) + """, + ) def union_into_contained_object(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment unionWithinObject on Dog { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } - """) + """, + ) def union_into_overlapping_interface(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment unionWithinInterface on Pet { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } - """) + """, + ) def union_into_overlapping_union(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment unionWithinUnion on DogOrHuman { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } - """) + """, + ) def interface_into_implemented_object(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment interfaceWithinObject on Dog { ...petFragment } fragment petFragment on Pet { name } - """) + """, + ) def interface_into_overlapping_interface(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment interfaceWithinInterface on Pet { ...beingFragment } fragment beingFragment on Being { name } - """) + """, + ) def interface_into_overlapping_interface_in_inline_fragment(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment interfaceWithinInterface on Pet { ... on Being { name } } - """) + """, + ) def interface_into_overlapping_union(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment interfaceWithinUnion on CatOrDog { ...petFragment } fragment petFragment on Pet { name } - """) + """, + ) def ignores_incorrect_type_caught_by_fragments_on_composite_types(): - expect_passes_rule(PossibleFragmentSpreadsRule, """ + expect_passes_rule( + PossibleFragmentSpreadsRule, + """ fragment petFragment on Pet { ...badInADifferentWay } fragment badInADifferentWay on String { name } - """) + """, + ) def different_object_into_object(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidObjectWithinObject on Cat { ...dogFragment } fragment dogFragment on Dog { barkVolume } - """, [ - error('dogFragment', 'Cat', 'Dog', 2, 57) - ]) + """, + [error("dogFragment", "Cat", "Dog", 2, 57)], + ) def different_object_into_object_in_inline_fragment(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidObjectWithinObjectAnon on Cat { ... on Dog { barkVolume } } - """, [ - error_anon('Cat', 'Dog', 3, 15) - ]) + """, + [error_anon("Cat", "Dog", 3, 15)], + ) def object_into_not_implementing_interface(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidObjectWithinInterface on Pet { ...humanFragment } fragment humanFragment on Human { pets { name } } - """, [ - error('humanFragment', 'Pet', 'Human', 2, 60) - ]) + """, + [error("humanFragment", "Pet", "Human", 2, 60)], + ) def object_into_not_containing_union(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } fragment humanFragment on Human { pets { name } } - """, [error('humanFragment', 'CatOrDog', 'Human', 2, 61)]) + """, + [error("humanFragment", "CatOrDog", "Human", 2, 61)], + ) def union_into_not_contained_object(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidUnionWithinObject on Human { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } - """, [ - error('catOrDogFragment', 'Human', 'CatOrDog', 2, 58)]) + """, + [error("catOrDogFragment", "Human", "CatOrDog", 2, 58)], + ) def union_into_non_overlapping_interface(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } - """, [ # noqa - error('humanOrAlienFragment', 'Pet', 'HumanOrAlien', 2, 59) - ]) + """, + [error("humanOrAlienFragment", "Pet", "HumanOrAlien", 2, 59)], # noqa + ) def union_into_non_overlapping_union(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } - """, [ # noqa - error('humanOrAlienFragment', 'CatOrDog', 'HumanOrAlien', 2, 60) - ]) + """, + [error("humanOrAlienFragment", "CatOrDog", "HumanOrAlien", 2, 60)], # noqa + ) def interface_into_non_implementing_object(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } - """, [ # noqa - error('intelligentFragment', 'Cat', 'Intelligent', 2, 60) - ]) + """, + [error("intelligentFragment", "Cat", "Intelligent", 2, 60)], # noqa + ) def interface_into_non_overlapping_interface(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidInterfaceWithinInterface on Pet { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } - """, [ - error('intelligentFragment', 'Pet', 'Intelligent', 3, 15) - ]) + """, + [error("intelligentFragment", "Pet", "Intelligent", 3, 15)], + ) def interface_into_non_overlapping_interface_in_inline_fragment(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidInterfaceWithinInterfaceAnon on Pet { ...on Intelligent { iq } } - """, [ - error_anon('Pet', 'Intelligent', 3, 15) - ]) + """, + [error_anon("Pet", "Intelligent", 3, 15)], + ) def interface_into_non_overlapping_union(): - expect_fails_rule(PossibleFragmentSpreadsRule, """ + expect_fails_rule( + PossibleFragmentSpreadsRule, + """ fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } fragment petFragment on Pet { name } - """, [ # noqa - error('petFragment', 'HumanOrAlien', 'Pet', 2, 68) - ]) + """, + [error("petFragment", "HumanOrAlien", "Pet", 2, 68)], # noqa + ) diff --git a/tests/validation/test_provided_required_arguments.py b/tests/validation/test_provided_required_arguments.py index d233a113..e48552d5 100644 --- a/tests/validation/test_provided_required_arguments.py +++ b/tests/validation/test_provided_required_arguments.py @@ -4,183 +4,231 @@ from graphql.validation import ProvidedRequiredArgumentsRule from graphql.validation.rules.provided_required_arguments import ( ProvidedRequiredArgumentsOnDirectivesRule, - missing_field_arg_message, missing_directive_arg_message) + missing_field_arg_message, + missing_directive_arg_message, +) -from .harness import ( - expect_fails_rule, expect_passes_rule, expect_sdl_errors_from_rule) +from .harness import expect_fails_rule, expect_passes_rule, expect_sdl_errors_from_rule expect_sdl_errors = partial( - expect_sdl_errors_from_rule, ProvidedRequiredArgumentsOnDirectivesRule) + expect_sdl_errors_from_rule, ProvidedRequiredArgumentsOnDirectivesRule +) def missing_field_arg(field_name, arg_name, type_name, line, column): return { - 'message': missing_field_arg_message(field_name, arg_name, type_name), - 'locations': [(line, column)]} + "message": missing_field_arg_message(field_name, arg_name, type_name), + "locations": [(line, column)], + } def missing_directive_arg(directive_name, arg_name, type_name, line, column): return { - 'message': missing_directive_arg_message( - directive_name, arg_name, type_name), - 'locations': [(line, column)]} + "message": missing_directive_arg_message(directive_name, arg_name, type_name), + "locations": [(line, column)], + } def describe_validate_provided_required_arguments(): - def ignores_unknown_arguments(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { dog { isHousetrained(unknownArgument: true) } - }""") + }""", + ) def describe_valid_non_nullable_value(): - def arg_on_optional_arg(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { dog { isHousetrained(atOtherHomes: true) } - }""") + }""", + ) def no_arg_on_optional_arg(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { dog { isHousetrained } - }""") + }""", + ) def no_arg_on_non_null_field_with_default(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { nonNullFieldWithDefault } - }""") + }""", + ) def multiple_args(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleReqs(req1: 1, req2: 2) } } - """) + """, + ) def multiple_args_reverse_order(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleReqs(req2: 2, req1: 1) } } - """) + """, + ) def no_args_on_multiple_optional(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleOpts } } - """) + """, + ) def one_arg_on_multiple_optional(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleOpts(opt1: 1) } } - """) + """, + ) def second_arg_on_multiple_optional(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleOpts(opt2: 1) } } - """) + """, + ) def multiple_reqs_on_mixed_list(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4) } } - """) + """, + ) def multiple_reqs_and_one_opt_on_mixed_list(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) } } - """) + """, + ) def all_reqs_and_opts_on_mixed_list(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) } } - """) + """, + ) def describe_invalid_non_nullable_value(): - def missing_one_non_nullable_argument(): - expect_fails_rule(ProvidedRequiredArgumentsRule, """ + expect_fails_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleReqs(req2: 2) } } - """, [ - missing_field_arg('multipleReqs', 'req1', 'Int!', 4, 21) - ]) + """, + [missing_field_arg("multipleReqs", "req1", "Int!", 4, 21)], + ) def missing_multiple_non_nullable_arguments(): - expect_fails_rule(ProvidedRequiredArgumentsRule, """ + expect_fails_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleReqs } } - """, [ - missing_field_arg('multipleReqs', 'req1', 'Int!', 4, 21), - missing_field_arg('multipleReqs', 'req2', 'Int!', 4, 21) - ]) + """, + [ + missing_field_arg("multipleReqs", "req1", "Int!", 4, 21), + missing_field_arg("multipleReqs", "req2", "Int!", 4, 21), + ], + ) def incorrect_value_and_missing_argument(): - expect_fails_rule(ProvidedRequiredArgumentsRule, """ + expect_fails_rule( + ProvidedRequiredArgumentsRule, + """ { complicatedArgs { multipleReqs(req1: "one") } } - """, [ - missing_field_arg('multipleReqs', 'req2', 'Int!', 4, 21) - ]) + """, + [missing_field_arg("multipleReqs", "req2", "Int!", 4, 21)], + ) def describe_directive_arguments(): - def ignores_unknown_directives(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { dog @unknown } - """) + """, + ) def with_directives_of_valid_type(): - expect_passes_rule(ProvidedRequiredArgumentsRule, """ + expect_passes_rule( + ProvidedRequiredArgumentsRule, + """ { dog @include(if: true) { name @@ -189,81 +237,115 @@ def with_directives_of_valid_type(): name } } - """) + """, + ) def with_directive_with_missing_types(): - expect_fails_rule(ProvidedRequiredArgumentsRule, """ + expect_fails_rule( + ProvidedRequiredArgumentsRule, + """ { dog @include { name @skip } } - """, [ - missing_directive_arg('include', 'if', 'Boolean!', 3, 23), - missing_directive_arg('skip', 'if', 'Boolean!', 4, 26), - ]) + """, + [ + missing_directive_arg("include", "if", "Boolean!", 3, 23), + missing_directive_arg("skip", "if", "Boolean!", 4, 26), + ], + ) def describe_within_sdl(): - def missing_optional_args_on_directive_defined_inside_sdl(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @test } directive @test(arg1: String, arg2: String! = "") on FIELD_DEFINITION - """) == [] # noqa + """ + ) + == [] + ) # noqa def missing_arg_on_directive_defined_inside_sdl(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @test } directive @test(arg: String!) on FIELD_DEFINITION - """) == [ - missing_directive_arg('test', 'arg', 'String!', 3, 31)] + """ + ) + == [missing_directive_arg("test", "arg", "String!", 3, 31)] + ) def missing_arg_on_standard_directive(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @include } - """) == [ - missing_directive_arg('include', 'if', 'Boolean!', 3, 31)] + """ + ) + == [missing_directive_arg("include", "if", "Boolean!", 3, 31)] + ) def missing_arg_on_overridden_standard_directive(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ type Query { foo: String @deprecated } directive @deprecated(reason: String!) on FIELD - """) == [ - missing_directive_arg( - 'deprecated', 'reason', 'String!', 3, 31)] + """ + ) + == [missing_directive_arg("deprecated", "reason", "String!", 3, 31)] + ) def missing_arg_on_directive_defined_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ type Query { foo: String } - """) - assert expect_sdl_errors(""" + """ + ) + assert ( + expect_sdl_errors( + """ directive @test(arg: String!) on OBJECT extend type Query @test - """, schema) == [ - missing_directive_arg('test', 'arg', 'String!', 4, 36)] + """, + schema, + ) + == [missing_directive_arg("test", "arg", "String!", 4, 36)] + ) def missing_arg_on_directive_used_in_schema_extension(): - schema = build_schema(""" + schema = build_schema( + """ directive @test(arg: String!) on OBJECT type Query { foo: String } - """) - assert expect_sdl_errors(""" + """ + ) + assert ( + expect_sdl_errors( + """ extend type Query @test - """, schema) == [ - missing_directive_arg('test', 'arg', 'String!', 2, 36)] + """, + schema, + ) + == [missing_directive_arg("test", "arg", "String!", 2, 36)] + ) diff --git a/tests/validation/test_scalar_leafs.py b/tests/validation/test_scalar_leafs.py index 6168c9c9..ccb107a5 100644 --- a/tests/validation/test_scalar_leafs.py +++ b/tests/validation/test_scalar_leafs.py @@ -1,97 +1,120 @@ from graphql.validation import ScalarLeafsRule from graphql.validation.rules.scalar_leafs import ( - no_subselection_allowed_message, required_subselection_message) + no_subselection_allowed_message, + required_subselection_message, +) from .harness import expect_fails_rule, expect_passes_rule def no_scalar_subselection(field, type_, line, column): return { - 'message': no_subselection_allowed_message(field, type_), - 'locations': [(line, column)]} + "message": no_subselection_allowed_message(field, type_), + "locations": [(line, column)], + } def missing_obj_subselection(field, type_, line, column): return { - 'message': required_subselection_message(field, type_), - 'locations': [(line, column)]} + "message": required_subselection_message(field, type_), + "locations": [(line, column)], + } def describe_validate_scalar_leafs(): - def valid_scalar_selection(): - expect_passes_rule(ScalarLeafsRule, """ + expect_passes_rule( + ScalarLeafsRule, + """ fragment scalarSelection on Dog { barks } - """) + """, + ) def object_type_missing_selection(): - expect_fails_rule(ScalarLeafsRule, """ + expect_fails_rule( + ScalarLeafsRule, + """ query directQueryOnObjectWithoutSubFields { human } - """, [ - missing_obj_subselection('human', 'Human', 3, 15) - ]) + """, + [missing_obj_subselection("human", "Human", 3, 15)], + ) def interface_type_missing_selection(): - expect_fails_rule(ScalarLeafsRule, """ + expect_fails_rule( + ScalarLeafsRule, + """ { human { pets } } - """, [ - missing_obj_subselection('pets', '[Pet]', 3, 23) - ]) + """, + [missing_obj_subselection("pets", "[Pet]", 3, 23)], + ) def valid_scalar_selection_with_args(): - expect_passes_rule(ScalarLeafsRule, """ + expect_passes_rule( + ScalarLeafsRule, + """ fragment scalarSelectionWithArgs on Dog { doesKnowCommand(dogCommand: SIT) } - """) + """, + ) def scalar_selection_not_allowed_on_boolean(): - expect_fails_rule(ScalarLeafsRule, """ + expect_fails_rule( + ScalarLeafsRule, + """ fragment scalarSelectionsNotAllowedOnBoolean on Dog { barks { sinceWhen } } - """, [ - no_scalar_subselection('barks', 'Boolean', 3, 21) - ]) + """, + [no_scalar_subselection("barks", "Boolean", 3, 21)], + ) def scalar_selection_not_allowed_on_enum(): - expect_fails_rule(ScalarLeafsRule, """ + expect_fails_rule( + ScalarLeafsRule, + """ fragment scalarSelectionsNotAllowedOnEnum on Cat { furColor { inHexdec } } - """, [ - no_scalar_subselection('furColor', 'FurColor', 3, 24) - ]) + """, + [no_scalar_subselection("furColor", "FurColor", 3, 24)], + ) def scalar_selection_not_allowed_with_args(): - expect_fails_rule(ScalarLeafsRule, """ + expect_fails_rule( + ScalarLeafsRule, + """ fragment scalarSelectionsNotAllowedWithArgs on Dog { doesKnowCommand(dogCommand: SIT) { sinceWhen } } - """, [ - no_scalar_subselection('doesKnowCommand', 'Boolean', 3, 48) - ]) + """, + [no_scalar_subselection("doesKnowCommand", "Boolean", 3, 48)], + ) def scalar_selection_not_allowed_with_directives(): - expect_fails_rule(ScalarLeafsRule, """ + expect_fails_rule( + ScalarLeafsRule, + """ fragment scalarSelectionsNotAllowedWithDirectives on Dog { name @include(if: true) { isAlsoHumanName } } - """, [ - no_scalar_subselection('name', 'String', 3, 39) - ]) + """, + [no_scalar_subselection("name", "String", 3, 39)], + ) def scalar_selection_not_allowed_with_directives_and_args(): - expect_fails_rule(ScalarLeafsRule, """ + expect_fails_rule( + ScalarLeafsRule, + """ fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog { doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen } } - """, [ - no_scalar_subselection('doesKnowCommand', 'Boolean', 3, 67) - ]) + """, + [no_scalar_subselection("doesKnowCommand", "Boolean", 3, 67)], + ) diff --git a/tests/validation/test_single_field_subscriptions.py b/tests/validation/test_single_field_subscriptions.py index 69641461..a08ac632 100644 --- a/tests/validation/test_single_field_subscriptions.py +++ b/tests/validation/test_single_field_subscriptions.py @@ -1,60 +1,82 @@ from graphql.validation import SingleFieldSubscriptionsRule from graphql.validation.rules.single_field_subscriptions import ( - single_field_only_message) + single_field_only_message +) from .harness import expect_fails_rule, expect_passes_rule def describe_validate_subscriptions_with_single_field(): - def valid_subscription(): - expect_passes_rule(SingleFieldSubscriptionsRule, """ + expect_passes_rule( + SingleFieldSubscriptionsRule, + """ subscription ImportantEmails { importantEmails } - """) + """, + ) def fails_with_more_than_one_root_field(): - expect_fails_rule(SingleFieldSubscriptionsRule, """ + expect_fails_rule( + SingleFieldSubscriptionsRule, + """ subscription ImportantEmails { importantEmails notImportantEmails } - """, [{ - 'message': single_field_only_message('ImportantEmails'), - 'locations': [(4, 15)] - }]) + """, + [ + { + "message": single_field_only_message("ImportantEmails"), + "locations": [(4, 15)], + } + ], + ) def fails_with_more_than_one_root_field_including_introspection(): - expect_fails_rule(SingleFieldSubscriptionsRule, """ + expect_fails_rule( + SingleFieldSubscriptionsRule, + """ subscription ImportantEmails { importantEmails __typename } - """, [{ - 'message': single_field_only_message('ImportantEmails'), - 'locations': [(4, 15)] - }]) + """, + [ + { + "message": single_field_only_message("ImportantEmails"), + "locations": [(4, 15)], + } + ], + ) def fails_with_many_more_than_one_root_field(): - expect_fails_rule(SingleFieldSubscriptionsRule, """ + expect_fails_rule( + SingleFieldSubscriptionsRule, + """ subscription ImportantEmails { importantEmails notImportantEmails spamEmails } - """, [{ - 'message': single_field_only_message('ImportantEmails'), - 'locations': [(4, 15), (5, 15)] - }]) + """, + [ + { + "message": single_field_only_message("ImportantEmails"), + "locations": [(4, 15), (5, 15)], + } + ], + ) def fails_with_more_than_one_root_field_in_anonymous_subscriptions(): - expect_fails_rule(SingleFieldSubscriptionsRule, """ + expect_fails_rule( + SingleFieldSubscriptionsRule, + """ subscription { importantEmails notImportantEmails } - """, [{ - 'message': single_field_only_message(None), - 'locations': [(4, 15)] - }]) + """, + [{"message": single_field_only_message(None), "locations": [(4, 15)]}], + ) diff --git a/tests/validation/test_unique_argument_names.py b/tests/validation/test_unique_argument_names.py index 951ed5fc..1e9b00f4 100644 --- a/tests/validation/test_unique_argument_names.py +++ b/tests/validation/test_unique_argument_names.py @@ -1,116 +1,148 @@ from graphql.validation import UniqueArgumentNamesRule -from graphql.validation.rules.unique_argument_names import ( - duplicate_arg_message) +from graphql.validation.rules.unique_argument_names import duplicate_arg_message from .harness import expect_fails_rule, expect_passes_rule def duplicate_arg(arg_name, l1, c1, l2, c2): return { - 'message': duplicate_arg_message(arg_name), - 'locations': [(l1, c1), (l2, c2)]} + "message": duplicate_arg_message(arg_name), + "locations": [(l1, c1), (l2, c2)], + } def describe_validate_unique_argument_names(): - def no_arguments_on_field(): - expect_passes_rule(UniqueArgumentNamesRule, """ + expect_passes_rule( + UniqueArgumentNamesRule, + """ { field } - """) + """, + ) def no_arguments_on_directive(): - expect_passes_rule(UniqueArgumentNamesRule, """ + expect_passes_rule( + UniqueArgumentNamesRule, + """ { field } - """) + """, + ) def argument_on_field(): - expect_passes_rule(UniqueArgumentNamesRule, """ + expect_passes_rule( + UniqueArgumentNamesRule, + """ { field(arg: "value") } - """) + """, + ) def argument_on_directive(): - expect_passes_rule(UniqueArgumentNamesRule, """ + expect_passes_rule( + UniqueArgumentNamesRule, + """ { field @directive(arg: "value") } - """) + """, + ) def same_argument_on_two_fields(): - expect_passes_rule(UniqueArgumentNamesRule, """ + expect_passes_rule( + UniqueArgumentNamesRule, + """ { one: field(arg: "value") two: field(arg: "value") } - """) + """, + ) def same_argument_on_field_and_directive(): - expect_passes_rule(UniqueArgumentNamesRule, """ + expect_passes_rule( + UniqueArgumentNamesRule, + """ { field(arg: "value") @directive(arg: "value") } - """) + """, + ) def same_argument_on_two_directives(): - expect_passes_rule(UniqueArgumentNamesRule, """ + expect_passes_rule( + UniqueArgumentNamesRule, + """ { field @directive1(arg: "value") @directive2(arg: "value") } - """) + """, + ) def multiple_field_arguments(): - expect_passes_rule(UniqueArgumentNamesRule, """ + expect_passes_rule( + UniqueArgumentNamesRule, + """ { field(arg1: "value", arg2: "value", arg3: "value") } - """) + """, + ) def multiple_directive_arguments(): - expect_passes_rule(UniqueArgumentNamesRule, """ + expect_passes_rule( + UniqueArgumentNamesRule, + """ { field @directive(arg1: "value", arg2: "value", arg3: "value") } - """) + """, + ) def duplicate_field_arguments(): - expect_fails_rule(UniqueArgumentNamesRule, """ + expect_fails_rule( + UniqueArgumentNamesRule, + """ { field(arg1: "value", arg1: "value") } - """, [ - duplicate_arg('arg1', 3, 21, 3, 36) - ]) + """, + [duplicate_arg("arg1", 3, 21, 3, 36)], + ) def many_duplicate_field_arguments(): - expect_fails_rule(UniqueArgumentNamesRule, """ + expect_fails_rule( + UniqueArgumentNamesRule, + """ { field(arg1: "value", arg1: "value", arg1: "value") } - """, [ - duplicate_arg('arg1', 3, 21, 3, 36), - duplicate_arg('arg1', 3, 21, 3, 51) - ]) + """, + [duplicate_arg("arg1", 3, 21, 3, 36), duplicate_arg("arg1", 3, 21, 3, 51)], + ) def duplicate_directive_arguments(): - expect_fails_rule(UniqueArgumentNamesRule, """ + expect_fails_rule( + UniqueArgumentNamesRule, + """ { field @directive(arg1: "value", arg1: "value") } - """, [ - duplicate_arg('arg1', 3, 32, 3, 47) - ]) + """, + [duplicate_arg("arg1", 3, 32, 3, 47)], + ) def many_duplicate_directive_arguments(): - expect_fails_rule(UniqueArgumentNamesRule, """ + expect_fails_rule( + UniqueArgumentNamesRule, + """ { field @directive(arg1: "value", arg1: "value", arg1: "value") } - """, [ - duplicate_arg('arg1', 3, 32, 3, 47), - duplicate_arg('arg1', 3, 32, 3, 62) - ]) + """, + [duplicate_arg("arg1", 3, 32, 3, 47), duplicate_arg("arg1", 3, 32, 3, 62)], + ) diff --git a/tests/validation/test_unique_directives_per_location.py b/tests/validation/test_unique_directives_per_location.py index 836e35ec..efe6df55 100644 --- a/tests/validation/test_unique_directives_per_location.py +++ b/tests/validation/test_unique_directives_per_location.py @@ -2,91 +2,121 @@ from graphql.validation import UniqueDirectivesPerLocationRule from graphql.validation.rules.unique_directives_per_location import ( - duplicate_directive_message) + duplicate_directive_message +) -from .harness import ( - expect_fails_rule, expect_passes_rule, expect_sdl_errors_from_rule) +from .harness import expect_fails_rule, expect_passes_rule, expect_sdl_errors_from_rule expect_sdl_errors = partial( - expect_sdl_errors_from_rule, UniqueDirectivesPerLocationRule) + expect_sdl_errors_from_rule, UniqueDirectivesPerLocationRule +) def duplicate_directive(directive_name, l1, c1, l2, c2): return { - 'message': duplicate_directive_message(directive_name), - 'locations': [(l1, c1), (l2, c2)]} + "message": duplicate_directive_message(directive_name), + "locations": [(l1, c1), (l2, c2)], + } def describe_validate_directives_are_unique_per_location(): - def no_directives(): - expect_passes_rule(UniqueDirectivesPerLocationRule, """ + expect_passes_rule( + UniqueDirectivesPerLocationRule, + """ { field } - """) + """, + ) def unique_directives_in_different_locations(): - expect_passes_rule(UniqueDirectivesPerLocationRule, """ + expect_passes_rule( + UniqueDirectivesPerLocationRule, + """ fragment Test on Type @directiveA { field @directiveB } - """) + """, + ) def unique_directives_in_same_locations(): - expect_passes_rule(UniqueDirectivesPerLocationRule, """ + expect_passes_rule( + UniqueDirectivesPerLocationRule, + """ fragment Test on Type @directiveA @directiveB { field @directiveA @directiveB } - """) + """, + ) def same_directives_in_different_locations(): - expect_passes_rule(UniqueDirectivesPerLocationRule, """ + expect_passes_rule( + UniqueDirectivesPerLocationRule, + """ fragment Test on Type @directiveA { field @directiveA } - """) + """, + ) def same_directives_in_similar_locations(): - expect_passes_rule(UniqueDirectivesPerLocationRule, """ + expect_passes_rule( + UniqueDirectivesPerLocationRule, + """ fragment Test on Type { field @directive field @directive } - """) + """, + ) def duplicate_directives_in_one_location(): - expect_fails_rule(UniqueDirectivesPerLocationRule, """ + expect_fails_rule( + UniqueDirectivesPerLocationRule, + """ fragment Test on Type { field @directive @directive @directive } - """, [ - duplicate_directive('directive', 3, 21, 3, 32), - duplicate_directive('directive', 3, 21, 3, 43), - ]) + """, + [ + duplicate_directive("directive", 3, 21, 3, 32), + duplicate_directive("directive", 3, 21, 3, 43), + ], + ) def different_duplicate_directives_in_one_location(): - expect_fails_rule(UniqueDirectivesPerLocationRule, """ + expect_fails_rule( + UniqueDirectivesPerLocationRule, + """ fragment Test on Type { field @directiveA @directiveB @directiveA @directiveB } - """, [ - duplicate_directive('directiveA', 3, 21, 3, 45), - duplicate_directive('directiveB', 3, 33, 3, 57), - ]) + """, + [ + duplicate_directive("directiveA", 3, 21, 3, 45), + duplicate_directive("directiveB", 3, 33, 3, 57), + ], + ) def different_duplicate_directives_in_many_locations(): - expect_fails_rule(UniqueDirectivesPerLocationRule, """ + expect_fails_rule( + UniqueDirectivesPerLocationRule, + """ fragment Test on Type @directive @directive { field @directive @directive } - """, [ - duplicate_directive('directive', 2, 35, 2, 46), - duplicate_directive('directive', 3, 21, 3, 32), - ]) + """, + [ + duplicate_directive("directive", 2, 35, 2, 46), + duplicate_directive("directive", 3, 21, 3, 32), + ], + ) def duplicate_directives_on_sdl_definitions(): - assert expect_sdl_errors(""" + assert ( + expect_sdl_errors( + """ schema @directive @directive { query: Dummy } extend schema @directive @directive @@ -104,16 +134,20 @@ def duplicate_directives_on_sdl_definitions(): input TestInput @directive @directive extend input TestInput @directive @directive - """) == [ - duplicate_directive('directive', 2, 20, 2, 31), - duplicate_directive('directive', 3, 27, 3, 38), - duplicate_directive('directive', 5, 31, 5, 42), - duplicate_directive('directive', 6, 38, 6, 49), - duplicate_directive('directive', 8, 29, 8, 40), - duplicate_directive('directive', 9, 36, 9, 47), - duplicate_directive('directive', 11, 37, 11, 48), - duplicate_directive('directive', 12, 44, 12, 55), - duplicate_directive('directive', 14, 29, 14, 40), - duplicate_directive('directive', 15, 36, 15, 47), - duplicate_directive('directive', 17, 29, 17, 40), - duplicate_directive('directive', 18, 36, 18, 47)] + """ + ) + == [ + duplicate_directive("directive", 2, 20, 2, 31), + duplicate_directive("directive", 3, 27, 3, 38), + duplicate_directive("directive", 5, 31, 5, 42), + duplicate_directive("directive", 6, 38, 6, 49), + duplicate_directive("directive", 8, 29, 8, 40), + duplicate_directive("directive", 9, 36, 9, 47), + duplicate_directive("directive", 11, 37, 11, 48), + duplicate_directive("directive", 12, 44, 12, 55), + duplicate_directive("directive", 14, 29, 14, 40), + duplicate_directive("directive", 15, 36, 15, 47), + duplicate_directive("directive", 17, 29, 17, 40), + duplicate_directive("directive", 18, 36, 18, 47), + ] + ) diff --git a/tests/validation/test_unique_fragment_names.py b/tests/validation/test_unique_fragment_names.py index f6536720..3e2e3642 100644 --- a/tests/validation/test_unique_fragment_names.py +++ b/tests/validation/test_unique_fragment_names.py @@ -1,37 +1,46 @@ from graphql.validation import UniqueFragmentNamesRule from graphql.validation.rules.unique_fragment_names import ( - duplicate_fragment_name_message) + duplicate_fragment_name_message +) from .harness import expect_fails_rule, expect_passes_rule def duplicate_fragment(frag_name, l1, c1, l2, c2): return { - 'message': duplicate_fragment_name_message(frag_name), - 'locations': [(l1, c1), (l2, c2)]} + "message": duplicate_fragment_name_message(frag_name), + "locations": [(l1, c1), (l2, c2)], + } def describe_validate_unique_fragment_names(): - def no_fragments(): - expect_passes_rule(UniqueFragmentNamesRule, """ + expect_passes_rule( + UniqueFragmentNamesRule, + """ { field } - """) + """, + ) def one_fragment(): - expect_passes_rule(UniqueFragmentNamesRule, """ + expect_passes_rule( + UniqueFragmentNamesRule, + """ { ...fragA } fragment fragA on Type { field } - """) + """, + ) def many_fragments(): - expect_passes_rule(UniqueFragmentNamesRule, """ + expect_passes_rule( + UniqueFragmentNamesRule, + """ { ...fragA ...fragB @@ -46,10 +55,13 @@ def many_fragments(): fragment fragC on Type { fieldC } - """) + """, + ) def inline_fragments_are_always_unique(): - expect_passes_rule(UniqueFragmentNamesRule, """ + expect_passes_rule( + UniqueFragmentNamesRule, + """ { ...on Type { fieldA @@ -58,20 +70,26 @@ def inline_fragments_are_always_unique(): fieldB } } - """) + """, + ) def fragment_and_operation_named_the_same(): - expect_passes_rule(UniqueFragmentNamesRule, """ + expect_passes_rule( + UniqueFragmentNamesRule, + """ query Foo { ...Foo } fragment Foo on Type { field } - """) + """, + ) def fragments_named_the_same(): - expect_fails_rule(UniqueFragmentNamesRule, """ + expect_fails_rule( + UniqueFragmentNamesRule, + """ { ...fragA } @@ -81,18 +99,20 @@ def fragments_named_the_same(): fragment fragA on Type { fieldB } - """, [ - duplicate_fragment('fragA', 5, 24, 8, 24) - ]) + """, + [duplicate_fragment("fragA", 5, 24, 8, 24)], + ) def fragments_named_the_same_without_being_referenced(): - expect_fails_rule(UniqueFragmentNamesRule, """ + expect_fails_rule( + UniqueFragmentNamesRule, + """ fragment fragA on Type { fieldA } fragment fragA on Type { fieldB } - """, [ - duplicate_fragment('fragA', 2, 22, 5, 22) - ]) + """, + [duplicate_fragment("fragA", 2, 22, 5, 22)], + ) diff --git a/tests/validation/test_unique_input_field_names.py b/tests/validation/test_unique_input_field_names.py index 504299d6..ca744f53 100644 --- a/tests/validation/test_unique_input_field_names.py +++ b/tests/validation/test_unique_input_field_names.py @@ -1,41 +1,53 @@ from graphql.validation import UniqueInputFieldNamesRule from graphql.validation.rules.unique_input_field_names import ( - duplicate_input_field_message) + duplicate_input_field_message +) from .harness import expect_fails_rule, expect_passes_rule def duplicate_field(name, l1, c1, l2, c2): return { - 'message': duplicate_input_field_message(name), - 'locations': [(l1, c1), (l2, c2)]} + "message": duplicate_input_field_message(name), + "locations": [(l1, c1), (l2, c2)], + } def describe_validate_unique_input_field_names(): - def input_object_with_fields(): - expect_passes_rule(UniqueInputFieldNamesRule, """ + expect_passes_rule( + UniqueInputFieldNamesRule, + """ { field(arg: { f: true }) } - """) + """, + ) def same_input_object_within_two_args(): - expect_passes_rule(UniqueInputFieldNamesRule, """ + expect_passes_rule( + UniqueInputFieldNamesRule, + """ { field(arg1: { f: true }, arg2: { f: true }) } - """) + """, + ) def multiple_input_object_fields(): - expect_passes_rule(UniqueInputFieldNamesRule, """ + expect_passes_rule( + UniqueInputFieldNamesRule, + """ { field(arg: { f1: "value", f2: "value", f3: "value" }) } - """) + """, + ) def allows_for_nested_input_objects_with_similar_fields(): - expect_passes_rule(UniqueInputFieldNamesRule, """ + expect_passes_rule( + UniqueInputFieldNamesRule, + """ { field(arg: { deep: { @@ -47,23 +59,27 @@ def allows_for_nested_input_objects_with_similar_fields(): id: 1 }) } - """) + """, + ) def duplicate_input_object_fields(): - expect_fails_rule(UniqueInputFieldNamesRule, """ + expect_fails_rule( + UniqueInputFieldNamesRule, + """ { field(arg: { f1: "value", f1: "value" }) } - """, [ - duplicate_field('f1', 3, 28, 3, 41) - ]) + """, + [duplicate_field("f1", 3, 28, 3, 41)], + ) def many_duplicate_input_object_fields(): - expect_fails_rule(UniqueInputFieldNamesRule, """ + expect_fails_rule( + UniqueInputFieldNamesRule, + """ { field(arg: { f1: "value", f1: "value", f1: "value" }) } - """, [ - duplicate_field('f1', 3, 28, 3, 41), - duplicate_field('f1', 3, 28, 3, 54) - ]) + """, + [duplicate_field("f1", 3, 28, 3, 41), duplicate_field("f1", 3, 28, 3, 54)], + ) diff --git a/tests/validation/test_unique_operation_names.py b/tests/validation/test_unique_operation_names.py index 2e88046a..bbf29515 100644 --- a/tests/validation/test_unique_operation_names.py +++ b/tests/validation/test_unique_operation_names.py @@ -1,41 +1,53 @@ from graphql.validation import UniqueOperationNamesRule from graphql.validation.rules.unique_operation_names import ( - duplicate_operation_name_message) + duplicate_operation_name_message +) from .harness import expect_fails_rule, expect_passes_rule def duplicate_op(op_name, l1, c1, l2, c2): return { - 'message': duplicate_operation_name_message(op_name), - 'locations': [(l1, c1), (l2, c2)]} + "message": duplicate_operation_name_message(op_name), + "locations": [(l1, c1), (l2, c2)], + } def describe_validate_unique_operation_names(): - def no_operations(): - expect_passes_rule(UniqueOperationNamesRule, """ + expect_passes_rule( + UniqueOperationNamesRule, + """ fragment fragA on Type { field } - """) + """, + ) def one_anon_operation(): - expect_passes_rule(UniqueOperationNamesRule, """ + expect_passes_rule( + UniqueOperationNamesRule, + """ { field } - """) + """, + ) def one_named_operation(): - expect_passes_rule(UniqueOperationNamesRule, """ + expect_passes_rule( + UniqueOperationNamesRule, + """ query Foo { field } - """) + """, + ) def multiple_operations(): - expect_passes_rule(UniqueOperationNamesRule, """ + expect_passes_rule( + UniqueOperationNamesRule, + """ query Foo { field } @@ -43,10 +55,13 @@ def multiple_operations(): query Bar { field } - """) + """, + ) def multiple_operations_of_different_types(): - expect_passes_rule(UniqueOperationNamesRule, """ + expect_passes_rule( + UniqueOperationNamesRule, + """ query Foo { field } @@ -58,50 +73,60 @@ def multiple_operations_of_different_types(): subscription Baz { field } - """) + """, + ) def fragment_and_operation_named_the_same(): - expect_passes_rule(UniqueOperationNamesRule, """ + expect_passes_rule( + UniqueOperationNamesRule, + """ query Foo { ...Foo } fragment Foo on Type { field } - """) + """, + ) def multiple_operations_of_same_name(): - expect_fails_rule(UniqueOperationNamesRule, """ + expect_fails_rule( + UniqueOperationNamesRule, + """ query Foo { fieldA } query Foo { fieldB } - """, [ - duplicate_op('Foo', 2, 19, 5, 19), - ]) + """, + [duplicate_op("Foo", 2, 19, 5, 19)], + ) def multiple_ops_of_same_name_of_different_types_mutation(): - expect_fails_rule(UniqueOperationNamesRule, """ + expect_fails_rule( + UniqueOperationNamesRule, + """ query Foo { fieldA } mutation Foo { fieldB } - """, [ - duplicate_op('Foo', 2, 19, 5, 22), - ]) + """, + [duplicate_op("Foo", 2, 19, 5, 22)], + ) def multiple_ops_of_same_name_of_different_types_subscription(): - expect_fails_rule(UniqueOperationNamesRule, """ + expect_fails_rule( + UniqueOperationNamesRule, + """ query Foo { fieldA } subscription Foo { fieldB } - """, [ - duplicate_op('Foo', 2, 19, 5, 26), - ]) + """, + [duplicate_op("Foo", 2, 19, 5, 26)], + ) diff --git a/tests/validation/test_unique_variable_names.py b/tests/validation/test_unique_variable_names.py index b0da79de..d955c3c1 100644 --- a/tests/validation/test_unique_variable_names.py +++ b/tests/validation/test_unique_variable_names.py @@ -1,32 +1,38 @@ from graphql.validation import UniqueVariableNamesRule -from graphql.validation.rules.unique_variable_names import ( - duplicate_variable_message) +from graphql.validation.rules.unique_variable_names import duplicate_variable_message from .harness import expect_fails_rule, expect_passes_rule def duplicate_variable(name, l1, c1, l2, c2): return { - 'message': duplicate_variable_message(name), - 'locations': [(l1, c1), (l2, c2)]} + "message": duplicate_variable_message(name), + "locations": [(l1, c1), (l2, c2)], + } def describe_validate_unique_variable_names(): - def unique_variable_names(): - expect_passes_rule(UniqueVariableNamesRule, """ + expect_passes_rule( + UniqueVariableNamesRule, + """ query A($x: Int, $y: String) { __typename } query B($x: String, $y: Int) { __typename } - """) + """, + ) def duplicate_variable_names(): - expect_fails_rule(UniqueVariableNamesRule, """ + expect_fails_rule( + UniqueVariableNamesRule, + """ query A($x: Int, $x: Int, $x: String) { __typename } query B($x: String, $x: Int) { __typename } query C($x: Int, $x: Int) { __typename } - """, [ - duplicate_variable('x', 2, 22, 2, 31), - duplicate_variable('x', 2, 22, 2, 40), - duplicate_variable('x', 3, 22, 3, 34), - duplicate_variable('x', 4, 22, 4, 31), - ]) + """, + [ + duplicate_variable("x", 2, 22, 2, 31), + duplicate_variable("x", 2, 22, 2, 40), + duplicate_variable("x", 3, 22, 3, 34), + duplicate_variable("x", 4, 22, 4, 31), + ], + ) diff --git a/tests/validation/test_validation.py b/tests/validation/test_validation.py index eb23fcf2..de21d6cf 100644 --- a/tests/validation/test_validation.py +++ b/tests/validation/test_validation.py @@ -7,13 +7,14 @@ def expect_valid(schema, query_string): errors = validate(schema, parse(query_string)) - assert not errors, 'Should validate' + assert not errors, "Should validate" def describe_validate_supports_full_validation(): - def validates_queries(): - expect_valid(test_schema, """ + expect_valid( + test_schema, + """ query { catOrDog { ... on Cat { @@ -24,7 +25,8 @@ def validates_queries(): } } } - """) + """, + ) def detects_bad_scalar_parse(): doc = """ @@ -34,17 +36,21 @@ def detects_bad_scalar_parse(): """ errors = validate(test_schema, parse(doc)) - assert errors == [{ - 'message': 'Expected type Invalid, found "bad value";' - ' Invalid scalar is always invalid: bad value', - 'locations': [(3, 31)]}] + assert errors == [ + { + "message": 'Expected type Invalid, found "bad value";' + " Invalid scalar is always invalid: bad value", + "locations": [(3, 31)], + } + ] # NOTE: experimental def validates_using_a_custom_type_info(): # This TypeInfo will never return a valid field. type_info = TypeInfo(test_schema, lambda *args: None) - ast = parse(""" + ast = parse( + """ query { catOrDog { ... on Cat { @@ -55,14 +61,15 @@ def validates_using_a_custom_type_info(): } } } - """) + """ + ) errors = validate(test_schema, ast, specified_rules, type_info) assert [error.message for error in errors] == [ "Cannot query field 'catOrDog' on type 'QueryRoot'." " Did you mean 'catOrDog'?", - "Cannot query field 'furColor' on type 'Cat'." - " Did you mean 'furColor'?", + "Cannot query field 'furColor' on type 'Cat'." " Did you mean 'furColor'?", "Cannot query field 'isHousetrained' on type 'Dog'." - " Did you mean 'isHousetrained'?"] + " Did you mean 'isHousetrained'?", + ] diff --git a/tests/validation/test_values_of_correct_type.py b/tests/validation/test_values_of_correct_type.py index 7ac17889..d2709471 100644 --- a/tests/validation/test_values_of_correct_type.py +++ b/tests/validation/test_values_of_correct_type.py @@ -1,668 +1,820 @@ from graphql.validation import ValuesOfCorrectTypeRule from graphql.validation.rules.values_of_correct_type import ( - bad_value_message, required_field_message, unknown_field_message) + bad_value_message, + required_field_message, + unknown_field_message, +) from .harness import expect_fails_rule, expect_passes_rule def bad_value(type_name, value, line, column, message=None): return { - 'message': bad_value_message(type_name, value, message), - 'locations': [(line, column)]} + "message": bad_value_message(type_name, value, message), + "locations": [(line, column)], + } def required_field(type_name, field_name, field_type_name, line, column): return { - 'message': required_field_message( - type_name, field_name, field_type_name), - 'locations': [(line, column)]} + "message": required_field_message(type_name, field_name, field_type_name), + "locations": [(line, column)], + } def unknown_field(type_name, field_name, line, column, message=None): return { - 'message': unknown_field_message(type_name, field_name, message), - 'locations': [(line, column)]} + "message": unknown_field_message(type_name, field_name, message), + "locations": [(line, column)], + } def describe_validate_values_of_correct_type(): - def describe_valid_values(): - def good_int_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { intArgField(intArg: 2) } } - """) + """, + ) def good_negative_int_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { intArgField(intArg: -2) } } - """) + """, + ) def good_boolean_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { booleanArgField(intArg: true) } } - """) + """, + ) def good_string_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringArgField(intArg: "foo") } } - """) + """, + ) def good_float_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { floatArgField(intArg: 1.1) } } - """) + """, + ) def good_negative_float_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { floatArgField(intArg: -1.1) } } - """) + """, + ) def int_into_id(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { idArgField(idArg: 1) } } - """) + """, + ) def string_into_id(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { idArgField(idArg: "someIdString") } } - """) + """, + ) def good_enum_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { dog { doesKnowCommand(dogCommand: SIT) } } - """) + """, + ) def enum_with_undefined_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { enumArgField(enumArg: UNKNOWN) } } - """) + """, + ) def enum_with_null_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { enumArgField(enumArg: NO_FUR) } } - """) + """, + ) def null_into_nullable_type(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { intArgField(intArg: null) } } - """) + """, + ) - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { dog(a: null, b: null, c:{ requiredField: true, intField: null }) { name } } - """) # noqa + """, + ) # noqa def describe_invalid_string_values(): - def int_into_string(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringArgField(stringArg: 1) } } - """, [ - bad_value('String', '1', 4, 47) - ]) + """, + [bad_value("String", "1", 4, 47)], + ) def float_into_string(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringArgField(stringArg: 1.0) } } - """, [ - bad_value('String', '1.0', 4, 47) - ]) + """, + [bad_value("String", "1.0", 4, 47)], + ) def boolean_into_string(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringArgField(stringArg: true) } } - """, [ - bad_value('String', 'true', 4, 47) - ]) + """, + [bad_value("String", "true", 4, 47)], + ) def unquoted_string_into_string(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringArgField(stringArg: BAR) } } - """, [ - bad_value('String', 'BAR', 4, 47) - ]) + """, + [bad_value("String", "BAR", 4, 47)], + ) def describe_invalid_int_values(): - def string_into_int(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { intArgField(intArg: "3") } } - """, [ - bad_value('Int', '"3"', 4, 41) - ]) + """, + [bad_value("Int", '"3"', 4, 41)], + ) def big_int_into_int(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { intArgField(intArg: 829384293849283498239482938) } } - """, [ - bad_value('Int', '829384293849283498239482938', 4, 41) - ]) + """, + [bad_value("Int", "829384293849283498239482938", 4, 41)], + ) def unquoted_string_into_int(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { intArgField(intArg: FOO) } } - """, [ - bad_value('Int', 'FOO', 4, 41) - ]) + """, + [bad_value("Int", "FOO", 4, 41)], + ) def simple_float_into_int(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { intArgField(intArg: 3.0) } } - """, [ - bad_value('Int', '3.0', 4, 41) - ]) + """, + [bad_value("Int", "3.0", 4, 41)], + ) def float_into_int(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { intArgField(intArg: 3.333) } } - """, [ - bad_value('Int', '3.333', 4, 41) - ]) + """, + [bad_value("Int", "3.333", 4, 41)], + ) def describe_invalid_float_values(): - def string_into_float(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { floatArgField(floatArg: "3.333") } } - """, [ - bad_value('Float', '"3.333"', 4, 45) - ]) + """, + [bad_value("Float", '"3.333"', 4, 45)], + ) def boolean_into_float(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { floatArgField(floatArg: true) } } - """, [ - bad_value('Float', 'true', 4, 45) - ]) + """, + [bad_value("Float", "true", 4, 45)], + ) def unquoted_into_float(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { floatArgField(floatArg: FOO) } } - """, [ - bad_value('Float', 'FOO', 4, 45) - ]) + """, + [bad_value("Float", "FOO", 4, 45)], + ) def describe_invalid_boolean_value(): - def int_into_boolean(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { booleanArgField(booleanArg: 2) } } - """, [ - bad_value('Boolean', '2', 4, 49) - ]) + """, + [bad_value("Boolean", "2", 4, 49)], + ) def float_into_boolean(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { booleanArgField(booleanArg: 1.0) } } - """, [ - bad_value('Boolean', '1.0', 4, 49) - ]) + """, + [bad_value("Boolean", "1.0", 4, 49)], + ) def string_into_boolean(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { booleanArgField(booleanArg: "true") } } - """, [ - bad_value('Boolean', '"true"', 4, 49) - ]) + """, + [bad_value("Boolean", '"true"', 4, 49)], + ) def unquoted_into_boolean(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { booleanArgField(booleanArg: TRUE) } } - """, [ - bad_value('Boolean', 'TRUE', 4, 49) - ]) + """, + [bad_value("Boolean", "TRUE", 4, 49)], + ) def describe_invalid_id_value(): - def float_into_id(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { idArgField(idArg: 1.0) } } - """, [ - bad_value('ID', '1.0', 4, 39) - ]) + """, + [bad_value("ID", "1.0", 4, 39)], + ) def boolean_into_id(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { idArgField(idArg: true) } } - """, [ - bad_value('ID', 'true', 4, 39) - ]) + """, + [bad_value("ID", "true", 4, 39)], + ) def unquoted_into_id(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { idArgField(idArg: SOMETHING) } } - """, [ - bad_value('ID', 'SOMETHING', 4, 39) - ]) + """, + [bad_value("ID", "SOMETHING", 4, 39)], + ) def describe_invalid_enum_value(): - def int_into_enum(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { dog { doesKnowCommand(dogCommand: 2) } } - """, [ - bad_value('DogCommand', '2', 4, 49) - ]) + """, + [bad_value("DogCommand", "2", 4, 49)], + ) def float_into_enum(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { dog { doesKnowCommand(dogCommand: 1.0) } } - """, [ - bad_value('DogCommand', '1.0', 4, 49) - ]) + """, + [bad_value("DogCommand", "1.0", 4, 49)], + ) def string_into_enum(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { dog { doesKnowCommand(dogCommand: "SIT") } } - """, [ - bad_value('DogCommand', '"SIT"', 4, 49, - 'Did you mean the enum value SIT?') - ]) + """, + [ + bad_value( + "DogCommand", '"SIT"', 4, 49, "Did you mean the enum value SIT?" + ) + ], + ) def boolean_into_enum(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { dog { doesKnowCommand(dogCommand: true) } } - """, [ - bad_value('DogCommand', 'true', 4, 49) - ]) + """, + [bad_value("DogCommand", "true", 4, 49)], + ) def unknown_enum_value_into_enum(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { dog { doesKnowCommand(dogCommand: JUGGLE) } } - """, [ - bad_value('DogCommand', 'JUGGLE', 4, 49) - ]) + """, + [bad_value("DogCommand", "JUGGLE", 4, 49)], + ) def different_case_enum_value_into_enum(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { dog { doesKnowCommand(dogCommand: sit) } } - """, [ - bad_value('DogCommand', 'sit', 4, 49, - 'Did you mean the enum value SIT?') - ]) + """, + [ + bad_value( + "DogCommand", "sit", 4, 49, "Did you mean the enum value SIT?" + ) + ], + ) def describe_valid_list_value(): - def good_list_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringListArgField(stringListArg: ["one", null, "two"]) } } - """) + """, + ) def empty_list_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringListArgField(stringListArg: []) } } - """) + """, + ) def null_value(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringListArgField(stringListArg: null) } } - """) + """, + ) def single_value_into_list(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringListArgField(stringListArg: "one") } } - """) + """, + ) def describe_invalid_list_value(): - def incorrect_item_type(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringListArgField(stringListArg: ["one", 2]) } } - """, [ - bad_value('String', '2', 4, 63) - ]) + """, + [bad_value("String", "2", 4, 63)], + ) def single_value_of_incorrect_type(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { stringListArgField(stringListArg: 1) } } - """, [ - bad_value('[String]', '1', 4, 55) - ]) + """, + [bad_value("[String]", "1", 4, 55)], + ) def describe_valid_non_nullable_value(): - def arg_on_optional_arg(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { dog { isHousetrained(atOtherHomes: true) } } - """) + """, + ) def no_arg_on_optional_arg(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { dog { isHousetrained } } - """) + """, + ) def multiple_args(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleReqs(req1: 1, req2: 2) } } - """) + """, + ) def multiple_args_reverse_order(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleReqs(req2: 2, req1: 1) } } - """) + """, + ) def no_args_on_multiple_optional(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleOpts } } - """) + """, + ) def one_arg_on_multiple_optional(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleOpts(opt1: 1) } } - """) + """, + ) def second_arg_on_multiple_optional(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleOpts(opt2: 1) } } - """) + """, + ) def multiple_reqs_on_mixed_list(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4) } } - """) + """, + ) def multiple_reqs_and_one_opt_on_mixed_list(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) } } - """) + """, + ) def all_reqs_and_and_opts_on_mixed_list(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) } } - """) + """, + ) def describe_invalid_non_nullable_value(): - def incorrect_value_type(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleReqs(req2: "two", req1: "one") } } - """, [ - bad_value('Int!', '"two"', 4, 40), - bad_value('Int!', '"one"', 4, 53), - ]) + """, + [bad_value("Int!", '"two"', 4, 40), bad_value("Int!", '"one"', 4, 53)], + ) def incorrect_value_and_missing_argument_provided_required_arguments(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleReqs(req1: "one") } } - """, [ - bad_value('Int!', '"one"', 4, 40), - ]) + """, + [bad_value("Int!", '"one"', 4, 40)], + ) def null_value(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { multipleReqs(req1: null) } } - """, [ - bad_value('Int!', 'null', 4, 40), - ]) + """, + [bad_value("Int!", "null", 4, 40)], + ) def describe_valid_input_object_value(): - def optional_arg_despite_required_field_in_type(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { complexArgField } } - """) + """, + ) def partial_object_only_required(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { complexArgField(complexArg: { requiredField: true }) } } - """) + """, + ) def partial_object_required_field_can_be_falsey(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { complexArgField(complexArg: { requiredField: false }) } } - """) + """, + ) def partial_object_including_required(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { complexArgField(complexArg: { requiredField: true, intField: 4 }) } } - """) # noqa + """, + ) # noqa def full_object(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { complexArgField(complexArg: { @@ -674,10 +826,13 @@ def full_object(): }) } } - """) + """, + ) def full_object_with_fields_in_different_order(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { complexArgField(complexArg: { @@ -689,24 +844,27 @@ def full_object_with_fields_in_different_order(): }) } } - """) + """, + ) def describe_invalid_input_object_value(): - def partial_object_missing_required(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { complexArgField(complexArg: { intField: 4 }) } } - """, [ - required_field( - 'ComplexInput', 'requiredField', 'Boolean!', 4, 49), - ]) + """, + [required_field("ComplexInput", "requiredField", "Boolean!", 4, 49)], + ) def partial_object_invalid_field_type(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { complexArgField(complexArg: { @@ -715,12 +873,14 @@ def partial_object_invalid_field_type(): }) } } - """, [ - bad_value('String', '2', 5, 48), - ]) + """, + [bad_value("String", "2", 5, 48)], + ) def partial_object_null_to_non_null_field(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { complexArgField(complexArg: { @@ -729,12 +889,14 @@ def partial_object_null_to_non_null_field(): }) } } - """, [ - bad_value('Boolean!', 'null', 6, 37), - ]) + """, + [bad_value("Boolean!", "null", 6, 37)], + ) def partial_object_unknown_field_arg(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { complicatedArgs { complexArgField(complexArg: { @@ -743,38 +905,54 @@ def partial_object_unknown_field_arg(): }) } } - """, [ - unknown_field( - 'ComplexInput', 'unknownField', 6, 23, - 'Did you mean nonNullField, intField or booleanField?') - ]) + """, + [ + unknown_field( + "ComplexInput", + "unknownField", + 6, + 23, + "Did you mean nonNullField, intField or booleanField?", + ) + ], + ) def reports_original_error_for_custom_scalar_which_throws(): - errors = expect_fails_rule(ValuesOfCorrectTypeRule, """ + errors = expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { invalidArg(arg: 123) } - """, [ - bad_value('Invalid', '123', 3, 35, - 'Invalid scalar is always invalid: 123') - ]) + """, + [ + bad_value( + "Invalid", "123", 3, 35, "Invalid scalar is always invalid: 123" + ) + ], + ) assert str(errors[0].original_error) == ( - 'Invalid scalar is always invalid: 123') + "Invalid scalar is always invalid: 123" + ) def allows_custom_scalar_to_accept_complex_literals(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { test1: anyArg(arg: 123) test2: anyArg(arg: "abc") test3: anyArg(arg: [123, "abc"]) test4: anyArg(arg: {deep: [123, "abc"]}) } - """) + """, + ) def describe_directive_arguments(): - def with_directives_of_valid_types(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ { dog @include(if: true) { name @@ -783,24 +961,30 @@ def with_directives_of_valid_types(): name } } - """) + """, + ) def with_directives_with_incorrect_types(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ { dog @include(if: "yes") { name @skip(if: ENUM) } } - """, [ - bad_value('Boolean!', '"yes"', 3, 36), - bad_value('Boolean!', 'ENUM', 4, 36), - ]) + """, + [ + bad_value("Boolean!", '"yes"', 3, 36), + bad_value("Boolean!", "ENUM", 4, 36), + ], + ) def describe_variable_default_values(): - def variables_with_valid_default_values(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ query WithDefaultValues( $a: Int = 1, $b: String = "ok", @@ -809,10 +993,13 @@ def variables_with_valid_default_values(): ) { dog { name } } - """) + """, + ) def variables_with_valid_default_null_values(): - expect_passes_rule(ValuesOfCorrectTypeRule, """ + expect_passes_rule( + ValuesOfCorrectTypeRule, + """ query WithDefaultValues( $a: Int = null, $b: String = null, @@ -820,10 +1007,13 @@ def variables_with_valid_default_null_values(): ) { dog { name } } - """) + """, + ) def variables_with_invalid_default_null_values(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ query WithDefaultValues( $a: Int! = null, $b: String! = null, @@ -831,14 +1021,18 @@ def variables_with_invalid_default_null_values(): ) { dog { name } } - """, [ - bad_value('Int!', 'null', 3, 30), - bad_value('String!', 'null', 4, 33), - bad_value('Boolean!', 'null', 5, 55), - ]) + """, + [ + bad_value("Int!", "null", 3, 30), + bad_value("String!", "null", 4, 33), + bad_value("Boolean!", "null", 5, 55), + ], + ) def variables_with_invalid_default_values(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ query InvalidDefaultValues( $a: Int = "one", $b: String = 4, @@ -846,39 +1040,45 @@ def variables_with_invalid_default_values(): ) { dog { name } } - """, [ - bad_value('Int', '"one"', 3, 29), - bad_value('String', '4', 4, 32), - bad_value('ComplexInput', '"notverycomplex"', 5, 38), - ]) + """, + [ + bad_value("Int", '"one"', 3, 29), + bad_value("String", "4", 4, 32), + bad_value("ComplexInput", '"notverycomplex"', 5, 38), + ], + ) def variables_with_complex_invalid_default_values(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ query WithDefaultValues( $a: ComplexInput = { requiredField: 123, intField: "abc" } ) { dog { name } } - """, [ - bad_value('Boolean!', '123', 3, 55), - bad_value('Int', '"abc"', 3, 70), - ]) + """, + [bad_value("Boolean!", "123", 3, 55), bad_value("Int", '"abc"', 3, 70)], + ) def complex_variables_missing_required_fields(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ query MissingRequiredField($a: ComplexInput = {intField: 3}) { dog { name } } - """, [ - required_field( - 'ComplexInput', 'requiredField', 'Boolean!', 2, 63) - ]) + """, + [required_field("ComplexInput", "requiredField", "Boolean!", 2, 63)], + ) def list_variables_with_invalid_item(): - expect_fails_rule(ValuesOfCorrectTypeRule, """ + expect_fails_rule( + ValuesOfCorrectTypeRule, + """ query InvalidItem($a: [String] = ["one", 2]) { dog { name } } - """, [ - bad_value('String', '2', 2, 58) - ]) + """, + [bad_value("String", "2", 2, 58)], + ) diff --git a/tests/validation/test_variables_are_input_types.py b/tests/validation/test_variables_are_input_types.py index cff23234..d3347a7e 100644 --- a/tests/validation/test_variables_are_input_types.py +++ b/tests/validation/test_variables_are_input_types.py @@ -1,31 +1,42 @@ from graphql.validation import VariablesAreInputTypesRule from graphql.validation.rules.variables_are_input_types import ( - non_input_type_on_var_message) + non_input_type_on_var_message +) from .harness import expect_fails_rule, expect_passes_rule def describe_validate_variables_are_input_types(): - def input_types_are_valid(): - expect_passes_rule(VariablesAreInputTypesRule, """ + expect_passes_rule( + VariablesAreInputTypesRule, + """ query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) { field(a: $a, b: $b, c: $c) } - """) + """, + ) def output_types_are_invalid(): - expect_fails_rule(VariablesAreInputTypesRule, """ + expect_fails_rule( + VariablesAreInputTypesRule, + """ query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { field(a: $a, b: $b, c: $c) } - """, [{ - 'locations': [(2, 27)], - 'message': non_input_type_on_var_message('a', 'Dog') - }, { - 'locations': [(2, 36)], - 'message': non_input_type_on_var_message('b', '[[CatOrDog!]]!') - }, { - 'locations': [(2, 56)], - 'message': non_input_type_on_var_message('c', 'Pet') - }]) + """, + [ + { + "locations": [(2, 27)], + "message": non_input_type_on_var_message("a", "Dog"), + }, + { + "locations": [(2, 36)], + "message": non_input_type_on_var_message("b", "[[CatOrDog!]]!"), + }, + { + "locations": [(2, 56)], + "message": non_input_type_on_var_message("c", "Pet"), + }, + ], + ) diff --git a/tests/validation/test_variables_in_allowed_position.py b/tests/validation/test_variables_in_allowed_position.py index 2807240e..dd1453f9 100644 --- a/tests/validation/test_variables_in_allowed_position.py +++ b/tests/validation/test_variables_in_allowed_position.py @@ -1,24 +1,27 @@ from graphql.validation import VariablesInAllowedPositionRule -from graphql.validation.rules.variables_in_allowed_position import ( - bad_var_pos_message) +from graphql.validation.rules.variables_in_allowed_position import bad_var_pos_message from .harness import expect_fails_rule, expect_passes_rule def describe_validate_variables_are_in_allowed_positions(): - def boolean_to_boolean(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($booleanArg: Boolean) { complicatedArgs { booleanArgField(booleanArg: $booleanArg) } } - """) + """, + ) def boolean_to_boolean_in_fragment(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $booleanArg) } @@ -28,9 +31,12 @@ def boolean_to_boolean_in_fragment(): ...booleanArgFrag } } - """) + """, + ) - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($booleanArg: Boolean) { complicatedArgs { @@ -40,20 +46,26 @@ def boolean_to_boolean_in_fragment(): fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $booleanArg) } - """) + """, + ) def non_null_boolean_to_boolean(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($nonNullBooleanArg: Boolean!) { complicatedArgs { booleanArgField(booleanArg: $nonNullBooleanArg) } } - """) + """, + ) def non_null_boolean_to_boolean_within_fragment(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $nonNullBooleanArg) } @@ -64,90 +76,120 @@ def non_null_boolean_to_boolean_within_fragment(): ...booleanArgFrag } } - """) + """, + ) def array_of_string_to_array_of_string(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($stringListVar: [String]) { complicatedArgs { stringListArgField(stringListArg: $stringListVar) } } - """) + """, + ) def array_of_non_null_string_to_array_of_string(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($stringListVar: [String!]) { complicatedArgs { stringListArgField(stringListArg: $stringListVar) } } - """) + """, + ) def string_to_array_of_string_in_item_position(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($stringVar: String) { complicatedArgs { stringListArgField(stringListArg: [$stringVar]) } } - """) + """, + ) def non_null_string_to_array_of_string_in_item_position(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($stringVar: String!) { complicatedArgs { stringListArgField(stringListArg: [$stringVar]) } } - """) + """, + ) def complex_input_to_complex_input(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($complexVar: ComplexInput) { complicatedArgs { complexArgField(complexArg: $complexVar) } } - """) + """, + ) def complex_input_to_complex_input_in_field_position(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($boolVar: Boolean = false) { complicatedArgs { complexArgField(complexArg: {requiredArg: $boolVar}) } } - """) + """, + ) def non_null_boolean_to_non_null_boolean_in_directive(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($boolVar: Boolean!) { dog @include(if: $boolVar) } - """) + """, + ) def int_to_non_null_int(): - expect_fails_rule(VariablesInAllowedPositionRule, """ + expect_fails_rule( + VariablesInAllowedPositionRule, + """ query Query($intArg: Int) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } } - """, [{ - 'message': bad_var_pos_message('intArg', 'Int', 'Int!'), - 'locations': [(2, 25), (4, 51)] - }]) + """, + [ + { + "message": bad_var_pos_message("intArg", "Int", "Int!"), + "locations": [(2, 25), (4, 51)], + } + ], + ) def int_to_non_null_int_within_fragment(): - expect_fails_rule(VariablesInAllowedPositionRule, """ + expect_fails_rule( + VariablesInAllowedPositionRule, + """ fragment nonNullIntArgFieldFrag on ComplicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } @@ -157,13 +199,19 @@ def int_to_non_null_int_within_fragment(): ...nonNullIntArgFieldFrag } } - """, [{ - 'message': bad_var_pos_message('intArg', 'Int', 'Int!'), - 'locations': [(6, 25), (3, 49)] - }]) + """, + [ + { + "message": bad_var_pos_message("intArg", "Int", "Int!"), + "locations": [(6, 25), (3, 49)], + } + ], + ) def int_to_non_null_int_within_nested_fragment(): - expect_fails_rule(VariablesInAllowedPositionRule, """ + expect_fails_rule( + VariablesInAllowedPositionRule, + """ fragment outerFrag on ComplicatedArgs { ...nonNullIntArgFieldFrag } @@ -177,104 +225,153 @@ def int_to_non_null_int_within_nested_fragment(): ...outerFrag } } - """, [{ - 'message': bad_var_pos_message('intArg', 'Int', 'Int!'), - 'locations': [(10, 25), (7, 49)] - }]) + """, + [ + { + "message": bad_var_pos_message("intArg", "Int", "Int!"), + "locations": [(10, 25), (7, 49)], + } + ], + ) def string_to_boolean(): - expect_fails_rule(VariablesInAllowedPositionRule, """ + expect_fails_rule( + VariablesInAllowedPositionRule, + """ query Query($stringVar: String) { complicatedArgs { booleanArgField(booleanArg: $stringVar) } } - """, [{ - 'message': bad_var_pos_message('stringVar', 'String', 'Boolean'), - 'locations': [(2, 25), (4, 45)] - }]) + """, + [ + { + "message": bad_var_pos_message("stringVar", "String", "Boolean"), + "locations": [(2, 25), (4, 45)], + } + ], + ) def string_to_array_of_string(): - expect_fails_rule(VariablesInAllowedPositionRule, """ + expect_fails_rule( + VariablesInAllowedPositionRule, + """ query Query($stringVar: String) { complicatedArgs { stringListArgField(stringListArg: $stringVar) } } - """, [{ - 'message': bad_var_pos_message('stringVar', 'String', '[String]'), - 'locations': [(2, 25), (4, 51)] - }]) + """, + [ + { + "message": bad_var_pos_message("stringVar", "String", "[String]"), + "locations": [(2, 25), (4, 51)], + } + ], + ) def boolean_to_non_null_boolean_in_directive(): - expect_fails_rule(VariablesInAllowedPositionRule, """ + expect_fails_rule( + VariablesInAllowedPositionRule, + """ query Query($boolVar: Boolean) { dog @include(if: $boolVar) } - """, [{ - 'message': bad_var_pos_message('boolVar', 'Boolean', 'Boolean!'), - 'locations': [(2, 25), (3, 32)] - }]) + """, + [ + { + "message": bad_var_pos_message("boolVar", "Boolean", "Boolean!"), + "locations": [(2, 25), (3, 32)], + } + ], + ) def string_to_non_null_boolean_in_directive(): - expect_fails_rule(VariablesInAllowedPositionRule, """ + expect_fails_rule( + VariablesInAllowedPositionRule, + """ query Query($stringVar: String) { dog @include(if: $stringVar) } - """, [{ - 'message': bad_var_pos_message('stringVar', 'String', 'Boolean!'), - 'locations': [(2, 25), (3, 32)] - }]) + """, + [ + { + "message": bad_var_pos_message("stringVar", "String", "Boolean!"), + "locations": [(2, 25), (3, 32)], + } + ], + ) def array_of_string_to_array_of_non_null_string(): - expect_fails_rule(VariablesInAllowedPositionRule, """ + expect_fails_rule( + VariablesInAllowedPositionRule, + """ query Query($stringListVar: [String]) { complicatedArgs { stringListNonNullArgField(stringListNonNullArg: $stringListVar) } } - """, [{ - 'message': bad_var_pos_message( - 'stringListVar', '[String]', '[String!]'), - 'locations': [(2, 25), (5, 65)] - }]) + """, + [ + { + "message": bad_var_pos_message( + "stringListVar", "[String]", "[String!]" + ), + "locations": [(2, 25), (5, 65)], + } + ], + ) def describe_allows_optional_nullable_variables_with_default_values(): - def int_to_non_null_int_fails_when_var_provides_null_default_value(): - expect_fails_rule(VariablesInAllowedPositionRule, """ + expect_fails_rule( + VariablesInAllowedPositionRule, + """ query Query($intVar: Int = null) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intVar) } } - """, [{ - 'message': bad_var_pos_message('intVar', 'Int', 'Int!'), - 'locations': [(2, 29), (4, 55)] - }]) + """, + [ + { + "message": bad_var_pos_message("intVar", "Int", "Int!"), + "locations": [(2, 29), (4, 55)], + } + ], + ) def int_to_non_null_int_when_var_provides_non_null_default_value(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($intVar: Int = 1) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intVar) } } - """) + """, + ) def int_to_non_null_int_when_optional_arg_provides_default_value(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($intVar: Int) { complicatedArgs { nonNullFieldWithDefault(nonNullIntArg: $intVar) } } - """) + """, + ) def bool_to_non_null_bool_in_directive_with_default_value_with_option(): - expect_passes_rule(VariablesInAllowedPositionRule, """ + expect_passes_rule( + VariablesInAllowedPositionRule, + """ query Query($boolVar: Boolean = false) { dog @include(if: $boolVar) } - """) + """, + )