async def introspection_directives_executor( element: Any, ctx: Optional[Any], info: "ResolveInfo", context_coercer: Optional[Any] = None, ) -> Any: """ Applies introspection directives on the element or a list of elements. :param element: element to treat :param ctx: context passed to the query execution :param info: information related to the execution and the resolved field :param context_coercer: context passed to the query execution to use on argument coercion process :type element: Any :type ctx: Optional[Any] :type info: ResolveInfo :type context_coercer: Optional[Any] :return: the coerced element :rtype: Any """ if not isinstance(element, list): computed_element = await execute_introspection_directive( element, ctx, info, context_coercer=context_coercer) if not is_invalid_value(computed_element): return computed_element return None results = await asyncio.gather(*[ execute_introspection_directive( item, ctx, info, context_coercer=context_coercer) for item in element ]) return [result for result in results if not is_invalid_value(result)]
async def scalar_coercer( result: Any, info: "ResolveInfo", execution_context: "ExecutionContext", field_nodes: List["FieldNode"], path: "Path", scalar_type: "GraphQLScalar", ) -> Any: """ Computes the value of a scalar type. :param result: resolved value :param info: information related to the execution and the resolved field :param execution_context: instance of the query execution context :param field_nodes: AST nodes related to the resolved field :param path: the path traveled until this resolver :param scalar_type: the GraphQLType instance of the scalar :type result: Any :type info: ResolveInfo :type execution_context: ExecutionContext :type field_nodes: List[FieldNode] :type path: Path :type scalar_type: GraphQLScalar :return: the computed value :rtype: Any """ # pylint: disable=unused-argument coerced_result = scalar_type.coerce_output(result) if is_invalid_value(coerced_result): raise ValueError( f"Expected value of type {scalar_type} but received {type(result)}." ) return coerced_result
async def scalar_coercer( parent_node: Union["VariableDefinitionNode", "InputValueDefinitionNode"], node: Union["ValueNode", "VariableNode"], ctx: Optional[Any], scalar_type: "GraphQLScalarType", variables: Optional[Dict[str, Any]] = None, path: Optional["Path"] = None, ) -> "CoercionResult": """ Computes the value of a scalar. :param parent_node: the root parent AST node :param node: the AST node to treat :param ctx: context passed to the query execution :param scalar_type: the GraphQLScalarType instance of the scalar :param variables: the variables provided in the GraphQL request :param path: the path traveled until this coercer :type parent_node: Union[VariableDefinitionNode, InputValueDefinitionNode] :type node: Union[ValueNode, VariableNode] :type ctx: Optional[Any] :type scalar_type: GraphQLScalarType :type variables: Optional[Dict[str, Any]] :type path: Optional[Path] :return: the computed value :rtype: CoercionResult """ # pylint: disable=unused-argument try: value = scalar_type.parse_literal(node) if not is_invalid_value(value): return CoercionResult(value=value) except Exception: # pylint: disable=broad-except pass return CoercionResult(value=UNDEFINED_VALUE)
async def execute_fields_serially( execution_context: "ExecutionContext", parent_type: "GraphQLObjectType", source_value: Any, path: Optional["Path"], fields: Dict[str, List["FieldNode"]], ) -> Dict[str, Any]: """ Implements the "Evaluating selection sets" section of the spec for "write" mode. :param execution_context: instance of the query execution context :param parent_type: GraphQLObjectType of the field's parent :param source_value: default root value or field parent value :param path: the path traveled until this resolver :param fields: dictionary of collected fields :type execution_context: ExecutionContext :type parent_type: GraphQLObjectType :type source_value: Any :type path: Optional[Path] :type fields: Dict[str, List[FieldNode]] :return: the computed fields value :rtype: Dict[str, Any] """ results = {} for entry_key, field_nodes in fields.items(): result = await resolve_field( execution_context, parent_type, source_value, field_nodes, Path(path, entry_key), ) if not is_invalid_value(result): results[entry_key] = result return results
async def execute_fields( execution_context: "ExecutionContext", parent_type: "GraphQLObjectType", source_value: Any, path: Optional["Path"], fields: Dict[str, List["FieldNode"]], is_introspection_context: bool = False, ) -> Dict[str, Any]: """ Implements the "Evaluating selection sets" section of the spec for "read" mode. :param execution_context: instance of the query execution context :param parent_type: GraphQLObjectType of the field's parent :param source_value: default root value or field parent value :param path: the path traveled until this resolver :param fields: dictionary of collected fields :param is_introspection_context: determines whether or not the resolved field is in a context of an introspection query :type execution_context: ExecutionContext :type parent_type: GraphQLObjectType :type source_value: Any :type path: Optional[Path] :type fields: Dict[str, List[FieldNode]] :type is_introspection_context: bool :return: the computed fields value :rtype: Dict[str, Any] """ results = await asyncio.gather( *[ resolve_field( execution_context, parent_type, source_value, field_nodes, Path(path, entry_key), is_introspection_context, ) for entry_key, field_nodes in fields.items() ], return_exceptions=True, ) exceptions = extract_exceptions_from_results(results) if exceptions: raise exceptions return { entry_key: result for entry_key, result in zip(fields, results) if not is_invalid_value(result) }
async def input_field_value_coercer( parent_node: Union["VariableDefinitionNode", "InputValueDefinitionNode"], node: "Node", value: Any, ctx: Optional[Any], input_field: "GraphQLInputField", path: "Path", ) -> Union["CoercionResult", "UNDEFINED_VALUE"]: """ Computes the value of an input field object. :param parent_node: the root parent AST node :param node: the AST node to treat :param value: the raw value to compute :param ctx: context passed to the query execution :param input_field: the input field to compute :param path: the path traveled until this coercer :type parent_node: Union[VariableDefinitionNode, InputValueDefinitionNode] :type node: Node :type value: Any :type ctx: Optional[Any] :type input_field: GraphQLInputField :type path: Path :return: the coercion result :rtype: Union[CoercionResult, UNDEFINED_VALUE] """ if is_invalid_value(value): if input_field.default_value is not None: return await input_field.literal_coercer(parent_node, input_field.default_value, ctx) if input_field.graphql_type.is_non_null_type: return CoercionResult(errors=[ coercion_error( f"Field < {path} > of required type " f"< {input_field.gql_type} > was not provided", node, ) ]) return UNDEFINED_VALUE return await input_field.input_coercer(parent_node, node, value, ctx, path=path)
async def wrapper( parent_node: Union["VariableDefinitionNode", "InputValueDefinitionNode"], node: "Node", ctx: Optional[Any], variables: Optional[Dict[str, Any]] = None, is_non_null_type: bool = False, **kwargs, ) -> "CoercionResult": """ Computes the value if null or variable. :param parent_node: the root parent AST node :param node: the AST node to treat :param ctx: context passed to the query execution :param variables: the variables provided in the GraphQL request :param is_non_null_type: determines whether or not the value is nullable :type parent_node: Union[VariableDefinitionNode, InputValueDefinitionNode] :type node: Union[ValueNode, VariableNode] :type ctx: Optional[Any] :type variables: Optional[Dict[str, Any]] :type is_non_null_type: bool :return: the computed value :rtype: CoercionResult """ if not node: return CoercionResult(value=UNDEFINED_VALUE) if isinstance(node, NullValueNode): return CoercionResult(value=None) if isinstance(node, VariableNode): if not variables: return CoercionResult(value=UNDEFINED_VALUE) value = variables.get(node.name.value, UNDEFINED_VALUE) if is_invalid_value(value) or (value is None and is_non_null_type): return CoercionResult(value=UNDEFINED_VALUE) return CoercionResult(value=value) return await coercer(parent_node, node, ctx, variables=variables, **kwargs)
async def scalar_coercer( parent_node: Union["VariableDefinitionNode", "InputValueDefinitionNode"], node: "Node", value: Any, ctx: Optional[Any], scalar_type: "GraphQLScalarType", path: Optional["Path"] = None, ) -> "CoercionResult": """ Computes the value of a scalar. :param parent_node: the root parent AST node :param node: the AST node to treat :param value: the raw value to compute :param ctx: context passed to the query execution :param scalar_type: the GraphQLScalarType instance of the scalar :param path: the path traveled until this coercer :type parent_node: Union[VariableDefinitionNode, InputValueDefinitionNode] :type node: Node :type value: Any :type ctx: Optional[Any] :type scalar_type: GraphQLScalarType :type path: Optional[Path] :return: the coercion result :rtype: CoercionResult """ # pylint: disable=unused-argument try: coerced_value = scalar_type.coerce_input(value) if is_invalid_value(coerced_value): return CoercionResult(errors=[ coercion_error(f"Expected type < {scalar_type.name} >", node, path) ]) except Exception as e: # pylint: disable=broad-except return CoercionResult(errors=[ coercion_error( f"Expected type < {scalar_type.name} >", node, path, sub_message=str(e), original_error=e, ) ]) return CoercionResult(value=coerced_value)
def is_missing_variable( value_node: Union["ValueNode", "VariableNode"], variables: Dict[str, Any] ) -> bool: """ Determines whether or not the value node is a VariableNode without defined value. :param value_node: the AST node to treat :param variables: the variables provided in the GraphQL request :type value_node: Union[ValueNode, VariableNode] :type variables: Dict[str, Any] :return: whether or not the value node is a VariableNode without defined value :rtype: bool """ return isinstance(value_node, VariableNode) and ( not variables or value_node.name.value not in variables or is_invalid_value(variables[value_node.name.value]) )
async def enum_coercer( result: Any, info: "ResolveInfo", execution_context: "ExecutionContext", field_nodes: List["FieldNode"], path: "Path", enum_type: "GraphQLEnumType", ) -> Any: """ Computes the value of an enum type. :param result: resolved value :param info: information related to the execution and the resolved field :param execution_context: instance of the query execution context :param field_nodes: AST nodes related to the resolved field :param path: the path traveled until this resolver :param enum_type: the GraphQLType instance of the enum :type result: Any :type info: ResolveInfo :type execution_context: ExecutionContext :type field_nodes: List[FieldNode] :type path: Path :type enum_type: GraphQLEnumType :return: the computed value :rtype: Any """ # pylint: disable=unused-argument try: enum_value = enum_type.get_value(result) coerced_result = await enum_value.output_coercer( result, execution_context.context, info, context_coercer=execution_context.context, ) except KeyError: coerced_result = UNDEFINED_VALUE if is_invalid_value(coerced_result): raise ValueError( f"Expected value of type {enum_type} but received {type(result)}.") return coerced_result
async def input_field_value_coercer( input_field: "GraphQLInputField", parent_node: Union["VariableDefinitionNode", "InputValueDefinitionNode"], value_node: Union["ValueNode", "VariableNode", "UNDEFINED_VALUE"], ctx: Optional[Any], variables: Optional[Dict[str, Any]], path: Optional["Path"], ) -> Union["CoercionResult", "UNDEFINED_VALUE", "SKIP_FIELD"]: """ Computes the value of an input field. :param input_field: the input field to compute :param parent_node: the root parent AST node :param value_node: the value node to compute :param ctx: context passed to the query execution :param variables: the variables provided in the GraphQL request :param path: the path traveled until this coercer :type input_field: GraphQLInputField :type parent_node: Union[VariableDefinitionNode, InputValueDefinitionNode] :type value_node: Union[ValueNode, VariableNode, UNDEFINED_VALUE] :type ctx: Optional[Any] :type variables: Optional[Dict[str, Any]] :type path: Optional[Path] :return: the computed value :rtype: Union[CoercionResult, UNDEFINED_VALUE, SKIP_FIELD] """ if is_invalid_value(value_node) or is_missing_variable( value_node.value, variables ): if input_field.default_value is not None: input_field_node = input_field.default_value elif input_field.graphql_type.is_non_null_type: return UNDEFINED_VALUE else: return SKIP_FIELD else: input_field_node = value_node.value return await input_field.literal_coercer( parent_node, input_field_node, ctx, variables=variables, path=path )
async def input_object_coercer( parent_node: Union["VariableDefinitionNode", "InputValueDefinitionNode"], node: Union["ValueNode", "VariableNode"], ctx: Optional[Any], input_object_type: "GraphQLInputObjectType", variables: Optional[Dict[str, Any]] = None, path: Optional["Path"] = None, ) -> "CoercionResult": """ Computes the value of an input object. :param parent_node: the root parent AST node :param node: the AST node to treat :param ctx: context passed to the query execution :param input_object_type: the GraphQLInputObjectType instance of the input object :param variables: the variables provided in the GraphQL request :param path: the path traveled until this coercer :type parent_node: Union[VariableDefinitionNode, InputValueDefinitionNode] :type node: Union[ValueNode, VariableNode] :type ctx: Optional[Any] :type input_object_type: GraphQLInputObjectType :type variables: Optional[Dict[str, Any]] :type path: Optional[Path] :return: the computed value :rtype: CoercionResult """ # pylint: disable=too-many-locals if not isinstance(node, ObjectValueNode): return CoercionResult(value=UNDEFINED_VALUE) field_nodes = { field_node.name.value: field_node for field_node in node.fields } input_fields = input_object_type.input_fields results = await asyncio.gather( *[ input_field_value_coercer( input_field, parent_node, field_nodes.get(input_field_name, UNDEFINED_VALUE), ctx, variables, path=Path(path, input_field_name), ) for input_field_name, input_field in input_fields.items() ] ) errors = [] coerced_values = {} for input_field_name, input_field_result in zip(input_fields, results): if input_field_result is SKIP_FIELD: continue if is_invalid_value(input_field_result): return CoercionResult(value=UNDEFINED_VALUE) input_field_value, input_field_errors = input_field_result if is_invalid_value(input_field_value): return CoercionResult(value=UNDEFINED_VALUE) if input_field_errors: errors.extend(input_field_errors) elif not errors: coerced_values[input_field_name] = input_field_value return CoercionResult(value=coerced_values, errors=errors)
async def coerce_arguments( argument_definitions: Dict[str, "GraphQLArgument"], node: Union["FieldNode", "DirectiveNode"], variable_values: Dict[str, Any], ctx: Optional[Any], ) -> Dict[str, Any]: """ Returns the computed values of the arguments. :param argument_definitions: the argument definitions to treat :param node: the parent AST node of the arguments :param variable_values: the variables provided in the GraphQL request :param ctx: context passed to the query execution :type argument_definitions: Dict[str, GraphQLArgument] :type node: Union[FieldNode, DirectiveNode] :type variable_values: Dict[str, Any] :type ctx: Optional[Any] :return: the computed values of the arguments :rtype: Dict[str, Any] """ # pylint: disable=too-many-locals argument_nodes = node.arguments if not argument_definitions or argument_nodes is None: return {} argument_nodes_map = { argument_node.name.value: argument_node for argument_node in argument_nodes } results = await asyncio.gather( *[ argument_definition.coercer( argument_definition, node, argument_nodes_map.get(argument_definition.name), variable_values, ctx, ) for argument_definition in argument_definitions.values() ], return_exceptions=True, ) coercion_errors: List["TartifletteError"] = [] coerced_values: Dict[str, Any] = {} for argument_name, result in zip(argument_definitions, results): if isinstance(result, Exception): coercion_errors.extend( located_error( result, nodes=argument_nodes_map.get(argument_name)).exceptions) continue if is_invalid_value(result): continue if not isinstance(result, CoercionResult): coerced_values[argument_name] = result continue value, errors = result if errors: coercion_errors.extend(errors) elif not is_invalid_value(result): coerced_values[argument_name] = value if coercion_errors: raise MultipleException(coercion_errors) return coerced_values
async def literal_directives_coercer( parent_node: Union["VariableDefinitionNode", "InputValueDefinitionNode"], node: Union["ValueNode", "VariableNode"], ctx: Optional[Any], coercer: Callable, directives: Optional[Callable], variables: Optional[Dict[str, Any]] = None, path: Optional["Path"] = None, is_input_field: bool = False, is_non_null_type: bool = False, ) -> Any: """ Executes the directives on the coerced value. :param parent_node: the root parent AST node :param node: the AST node to treat :param ctx: context passed to the query execution :param coercer: pre-computed coercer to use on the value :param directives: the directives to execute :param variables: the variables provided in the GraphQL request :param path: the path traveled until this coercer :param is_input_field: determines whether or not the node is an InputField :param is_non_null_type: determines whether or not the value is nullable :type parent_node: Union[VariableDefinitionNode, InputValueDefinitionNode] :type node: Union[ValueNode, VariableNode] :type ctx: Optional[Any] :type coercer: Callable :type directives: Optional[Callable] :type variables: Optional[Dict[str, Any]] :type path: Optional[Path] :type is_input_field: bool :type is_non_null_type: bool :return: the computed value :rtype: Any """ # pylint: disable=too-many-locals,too-many-arguments coercion_result = await coercer( parent_node, node, ctx, variables=variables, path=path, is_non_null_type=is_non_null_type, ) if not directives or (isinstance(node, VariableNode) and not is_input_field): return coercion_result value, errors = coercion_result if is_invalid_value(value) or errors: return coercion_result try: return CoercionResult(value=await directives( parent_node, value, ctx, context_coercer=ctx)) except Exception as raw_exception: # pylint: disable=broad-except return CoercionResult(errors=[ graphql_error_from_nodes( str(raw_exception), node, original_error=(raw_exception if not is_coercible_exception( raw_exception) else None), ) for raw_exception in (raw_exception.exceptions if isinstance( raw_exception, MultipleException) else [raw_exception]) ])
async def list_coercer( parent_node: Union["VariableDefinitionNode", "InputValueDefinitionNode"], node: Union["ValueNode", "VariableNode"], ctx: Optional[Any], is_non_null_item_type: bool, inner_coercer: Callable, variables: Optional[Dict[str, Any]] = None, path: Optional["Path"] = None, ) -> "CoercionResult": """ Computes the value of a list. :param parent_node: the root parent AST node :param node: the AST node to treat :param ctx: context passed to the query execution :param is_non_null_item_type: determines whether or not the inner value is nullable :param inner_coercer: the pre-computed coercer to use on each value in the list :param variables: the variables provided in the GraphQL request :type parent_node: Union[VariableDefinitionNode, InputValueDefinitionNode] :type node: Union[ValueNode, VariableNode] :type ctx: Optional[Any] :type is_non_null_item_type: bool :type inner_coercer: Callable :type variables: Optional[Dict[str, Any]] :return: the computed value :rtype: CoercionResult """ # pylint: disable=too-many-locals if isinstance(node, ListValueNode): results = await asyncio.gather( *[ list_item_coercer( parent_node, item_node, ctx, is_non_null_item_type, inner_coercer, variables, path=Path(path, index), ) for index, item_node in enumerate(node.values) ] ) errors = [] coerced_values = [] for coerced_result in results: if is_invalid_value(coerced_result): return CoercionResult(value=UNDEFINED_VALUE) coerced_value, coerced_errors = coerced_result if is_invalid_value(coerced_value): return CoercionResult(value=UNDEFINED_VALUE) if coerced_errors: errors.extend(coerced_errors) elif not errors: coerced_values.append(coerced_value) return CoercionResult(value=coerced_values, errors=errors) coerced_item_value, coerced_item_errors = await inner_coercer( parent_node, node, ctx, variables=variables, path=path ) if is_invalid_value(coerced_item_value): return CoercionResult(value=UNDEFINED_VALUE) return CoercionResult( value=[coerced_item_value], errors=coerced_item_errors )
async def input_object_coercer( parent_node: Union["VariableDefinitionNode", "InputValueDefinitionNode"], node: "Node", value: Any, ctx: Optional[Any], input_object_type: "GraphQLInputObjectType", path: Optional["Path"] = None, ) -> "CoercionResult": """ Computes the value of an input object. :param parent_node: the root parent AST node :param node: the AST node to treat :param value: the raw value to compute :param ctx: context passed to the query execution :param input_object_type: the GraphQLInputObjectType instance of the input object :param path: the path traveled until this coercer :type parent_node: Union[VariableDefinitionNode, InputValueDefinitionNode] :type node: Node :type value: Any :type ctx: Optional[Any] :type input_object_type: GraphQLInputObjectType :type path: Optional[Path] :return: the coercion result :rtype: CoercionResult """ # pylint: disable=too-many-locals if not isinstance(value, dict): return CoercionResult(errors=[ coercion_error( f"Expected type < {input_object_type.name} > to be an object", node, path, ) ]) input_fields = input_object_type.input_fields results = await asyncio.gather(*[ input_field_value_coercer( parent_node, node, value.get(input_field_name, UNDEFINED_VALUE), ctx, input_field, path=Path(path, input_field_name), ) for input_field_name, input_field in input_fields.items() ]) errors = [] coerced_values = {} for input_field_name, input_field_result in zip(input_fields, results): if is_invalid_value(input_field_result): continue input_field_value, input_field_errors = input_field_result if input_field_errors: errors.extend(input_field_errors) elif not errors: coerced_values[input_field_name] = input_field_value for input_field_name in value: if input_field_name not in input_fields: errors.append( coercion_error( f"Field < {input_field_name} > is not defined by type " f"< {input_object_type.name} >", node, path, did_you_mean( get_close_matches(input_field_name, input_fields.keys(), n=5)), )) return CoercionResult(value=coerced_values, errors=errors)
async def argument_coercer( argument_definition: "GraphQLArgument", node: Union["FieldNode", "DirectiveNode"], argument_node: Optional["ArgumentNode"], variable_values: Dict[str, Any], ctx: Optional[Any], directives: Optional[Callable], ) -> Union["CoercionResult", "UNDEFINED_VALUE"]: """ Computes the value of an argument. :param argument_definition: the argument definition to treat :param node: AST node linked to the argument :param argument_node: AST node representing the argument :param variable_values: the variables provided in the GraphQL request :param ctx: context passed to the query execution :param directives: the directives to execute :type argument_definition: GraphQLArgument :type node: Union[FieldNode, DirectiveNode] :type argument_node: Optional[ArgumentNode] :type variable_values: Dict[str, Any] :type ctx: Optional[Any] :type directives: Optional[Callable] :return: the computed value :rtype: Union["CoercionResult", "UNDEFINED_VALUE"] """ # pylint: disable=too-many-locals,too-many-branches,too-complex name = argument_definition.name arg_type = argument_definition.graphql_type if argument_node and isinstance(argument_node.value, VariableNode): variable_name = argument_node.value.name.value has_value = variable_values and variable_name in variable_values is_null = has_value and variable_values[variable_name] is None else: has_value = argument_node is not None is_null = argument_node and isinstance(argument_node.value, NullValueNode) coercion_result = UNDEFINED_VALUE value_node = None if not has_value and argument_definition.default_value is not None: value_node = argument_definition.default_value elif (not has_value or is_null) and arg_type.is_non_null_type: if is_null: return CoercionResult(errors=[ graphql_error_from_nodes( f"Argument < {name} > of non-null type < {arg_type} > " "must not be null.", nodes=argument_node.value, ) ]) if argument_node and isinstance(argument_node.value, VariableNode): return CoercionResult(errors=[ graphql_error_from_nodes( f"Argument < {name} > of required type < {arg_type} > " f"was provided the variable < ${variable_name} > " "which was not provided a runtime value.", nodes=argument_node.value, ) ]) return CoercionResult(errors=[ graphql_error_from_nodes( f"Argument < {name} > of required type < {arg_type} > was " "not provided.", nodes=node, ) ]) elif has_value: if isinstance(argument_node.value, NullValueNode): coercion_result = CoercionResult(value=None) elif isinstance(argument_node.value, VariableNode): coercion_result = CoercionResult( value=variable_values[argument_node.value.name.value]) else: value_node = argument_node.value if value_node: coercion_result = await argument_definition.literal_coercer( argument_definition.definition, value_node, ctx, variables=variable_values, ) if is_invalid_value(coercion_result): return coercion_result value, errors = coercion_result if is_invalid_value(value): return CoercionResult(errors=[ graphql_error_from_nodes( f"Argument < {name} > has invalid value < {value_node} >.", nodes=argument_node.value, ) ]) if not directives or errors: return coercion_result return await directives(node, argument_node, value, ctx, context_coercer=ctx)