Astroport.ONE/venv/lib/python3.11/site-packages/graphql/execution/values.py

242 lines
8.4 KiB
Python
Raw Normal View History

2024-03-01 16:15:45 +01:00
from typing import Any, Callable, Collection, Dict, List, Optional, Union, cast
from ..error import GraphQLError
from ..language import (
DirectiveNode,
EnumValueDefinitionNode,
ExecutableDefinitionNode,
FieldNode,
FieldDefinitionNode,
InputValueDefinitionNode,
NullValueNode,
SchemaDefinitionNode,
SelectionNode,
TypeDefinitionNode,
TypeExtensionNode,
VariableDefinitionNode,
VariableNode,
print_ast,
)
from ..pyutils import inspect, print_path_list, Undefined
from ..type import (
GraphQLDirective,
GraphQLField,
GraphQLInputType,
GraphQLSchema,
is_input_type,
is_non_null_type,
)
from ..utilities.coerce_input_value import coerce_input_value
from ..utilities.type_from_ast import type_from_ast
from ..utilities.value_from_ast import value_from_ast
__all__ = ["get_argument_values", "get_directive_values", "get_variable_values"]
CoercedVariableValues = Union[List[GraphQLError], Dict[str, Any]]
def get_variable_values(
schema: GraphQLSchema,
var_def_nodes: Collection[VariableDefinitionNode],
inputs: Dict[str, Any],
max_errors: Optional[int] = None,
) -> CoercedVariableValues:
"""Get coerced variable values based on provided definitions.
Prepares a dict of variable values of the correct type based on the provided
variable definitions and arbitrary input. If the input cannot be parsed to match
the variable definitions, a GraphQLError will be raised.
"""
errors: List[GraphQLError] = []
def on_error(error: GraphQLError) -> None:
if max_errors is not None and len(errors) >= max_errors:
raise GraphQLError(
"Too many errors processing variables,"
" error limit reached. Execution aborted."
)
errors.append(error)
try:
coerced = coerce_variable_values(schema, var_def_nodes, inputs, on_error)
if not errors:
return coerced
except GraphQLError as e:
errors.append(e)
return errors
def coerce_variable_values(
schema: GraphQLSchema,
var_def_nodes: Collection[VariableDefinitionNode],
inputs: Dict[str, Any],
on_error: Callable[[GraphQLError], None],
) -> Dict[str, Any]:
coerced_values: Dict[str, Any] = {}
for var_def_node in var_def_nodes:
var_name = var_def_node.variable.name.value
var_type = type_from_ast(schema, var_def_node.type)
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.
var_type_str = print_ast(var_def_node.type)
on_error(
GraphQLError(
f"Variable '${var_name}' expected value of type '{var_type_str}'"
" which cannot be used as an input type.",
var_def_node.type,
)
)
continue
var_type = cast(GraphQLInputType, var_type)
if var_name not in inputs:
if var_def_node.default_value:
coerced_values[var_name] = value_from_ast(
var_def_node.default_value, var_type
)
elif is_non_null_type(var_type): # pragma: no cover else
var_type_str = inspect(var_type)
on_error(
GraphQLError(
f"Variable '${var_name}' of required type '{var_type_str}'"
" was not provided.",
var_def_node,
)
)
continue
value = inputs[var_name]
if value is None and is_non_null_type(var_type):
var_type_str = inspect(var_type)
on_error(
GraphQLError(
f"Variable '${var_name}' of non-null type '{var_type_str}'"
" must not be null.",
var_def_node,
)
)
continue
def on_input_value_error(
path: List[Union[str, int]], invalid_value: Any, error: GraphQLError
) -> None:
invalid_str = inspect(invalid_value)
prefix = f"Variable '${var_name}' got invalid value {invalid_str}"
if path:
prefix += f" at '{var_name}{print_path_list(path)}'"
on_error(
GraphQLError(
prefix + "; " + error.message,
var_def_node,
original_error=error.original_error,
)
)
coerced_values[var_name] = coerce_input_value(
value, var_type, on_input_value_error
)
return coerced_values
def get_argument_values(
type_def: Union[GraphQLField, GraphQLDirective],
node: Union[FieldNode, DirectiveNode],
variable_values: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
"""Get coerced argument values based on provided definitions and nodes.
Prepares a dict of argument values given a list of argument definitions and list
of argument AST nodes.
"""
coerced_values: Dict[str, Any] = {}
arg_node_map = {arg.name.value: arg for arg in node.arguments or []}
for name, arg_def in type_def.args.items():
arg_type = arg_def.type
argument_node = arg_node_map.get(name)
if argument_node is None:
if arg_def.default_value is not Undefined:
coerced_values[arg_def.out_name or name] = arg_def.default_value
elif is_non_null_type(arg_type): # pragma: no cover else
raise GraphQLError(
f"Argument '{name}' of required type '{arg_type}'"
" was not provided.",
node,
)
continue # pragma: no cover
value_node = argument_node.value
is_null = isinstance(argument_node.value, NullValueNode)
if isinstance(value_node, VariableNode):
variable_name = value_node.name.value
if variable_values is None or variable_name not in variable_values:
if arg_def.default_value is not Undefined:
coerced_values[arg_def.out_name or name] = arg_def.default_value
elif is_non_null_type(arg_type): # pragma: no cover else
raise GraphQLError(
f"Argument '{name}' of required type '{arg_type}'"
f" was provided the variable '${variable_name}'"
" which was not provided a runtime value.",
value_node,
)
continue # pragma: no cover
is_null = variable_values[variable_name] is None
if is_null and is_non_null_type(arg_type):
raise GraphQLError(
f"Argument '{name}' of non-null type '{arg_type}' must not be null.",
value_node,
)
coerced_value = value_from_ast(value_node, arg_type, variable_values)
if coerced_value is Undefined:
# Note: `values_of_correct_type` validation should catch this before
# execution. This is a runtime check to ensure execution does not
# continue with an invalid argument value.
raise GraphQLError(
f"Argument '{name}' has invalid value {print_ast(value_node)}.",
value_node,
)
coerced_values[arg_def.out_name or name] = coerced_value
return coerced_values
NodeWithDirective = Union[
EnumValueDefinitionNode,
ExecutableDefinitionNode,
FieldDefinitionNode,
InputValueDefinitionNode,
SelectionNode,
SchemaDefinitionNode,
TypeDefinitionNode,
TypeExtensionNode,
]
def get_directive_values(
directive_def: GraphQLDirective,
node: NodeWithDirective,
variable_values: Optional[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 an AST node
which may contain directives. Optionally also accepts a dict of variable values.
If the directive does not exist on the node, returns None.
"""
directives = node.directives
if directives:
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 None