From 5d1e8e73f8d1e3ff885a4059435d0976172dcfdb Mon Sep 17 00:00:00 2001 From: ddmytruk Date: Mon, 25 Apr 2022 19:14:23 +0300 Subject: [PATCH 1/2] exclude unset fields --- src/graphql/execution/values.py | 2 +- src/graphql/type/schema.py | 3 ++ src/graphql/utilities/coerce_input_value.py | 43 ++++++++++++--------- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/graphql/execution/values.py b/src/graphql/execution/values.py index e11733fc..fd4b5bc8 100644 --- a/src/graphql/execution/values.py +++ b/src/graphql/execution/values.py @@ -136,7 +136,7 @@ def on_input_value_error( ) coerced_values[var_name] = coerce_input_value( - value, var_type, on_input_value_error + value, var_type, on_input_value_error, exclude_unset=schema.exclude_unset ) return coerced_values diff --git a/src/graphql/type/schema.py b/src/graphql/type/schema.py index 321659c5..d74f0eb1 100644 --- a/src/graphql/type/schema.py +++ b/src/graphql/type/schema.py @@ -140,6 +140,7 @@ def __init__( ast_node: Optional[ast.SchemaDefinitionNode] = None, extension_ast_nodes: Optional[Collection[ast.SchemaExtensionNode]] = None, assume_valid: bool = False, + exclude_unset: Optional[bool] = False ) -> None: """Initialize GraphQL schema. @@ -202,6 +203,7 @@ def __init__( self.query_type = query self.mutation_type = mutation self.subscription_type = subscription + self.exclude_unset = exclude_unset # Provide specified directives (e.g. @include and @skip) by default self.directives = specified_directives if directives is None else directives @@ -302,6 +304,7 @@ def to_kwargs(self) -> GraphQLSchemaKwargs: ast_node=self.ast_node, extension_ast_nodes=self.extension_ast_nodes, assume_valid=self._validation_errors is not None, + exclude_unset=self.exclude_unset, ) def __copy__(self) -> "GraphQLSchema": # pragma: no cover diff --git a/src/graphql/utilities/coerce_input_value.py b/src/graphql/utilities/coerce_input_value.py index 6901c892..acacf526 100644 --- a/src/graphql/utilities/coerce_input_value.py +++ b/src/graphql/utilities/coerce_input_value.py @@ -44,6 +44,7 @@ def coerce_input_value( type_: GraphQLInputType, on_error: OnErrorCB = default_on_error, path: Optional[Path] = None, + exclude_unset: Optional[bool] = False, ) -> Any: """Coerce a Python value given a GraphQL Input Type.""" if is_non_null_type(type_): @@ -95,25 +96,31 @@ def coerce_input_value( for field_name, field in fields.items(): field_value = input_value.get(field_name, Undefined) - if field_value is Undefined: - if field.default_value is not Undefined: - # Use out name as name if it exists (extension of GraphQL.js). - coerced_dict[field.out_name or field_name] = field.default_value - elif is_non_null_type(field.type): # pragma: no cover else - type_str = inspect(field.type) - on_error( - path.as_list() if path else [], - input_value, - GraphQLError( - f"Field '{field_name}' of required type '{type_str}'" - " was not provided." - ), + if exclude_unset: + if field_name in input_value: + coerced_dict[field.out_name or field_name] = coerce_input_value( + field_value, field.type, on_error, Path(path, field_name, type_.name) ) - continue - - coerced_dict[field.out_name or field_name] = coerce_input_value( - field_value, field.type, on_error, Path(path, field_name, type_.name) - ) + else: + if field_value is Undefined: + if field.default_value is not Undefined: + # Use out name as name if it exists (extension of GraphQL.js). + coerced_dict[field.out_name or field_name] = field.default_value + elif is_non_null_type(field.type): # pragma: no cover else + type_str = inspect(field.type) + on_error( + path.as_list() if path else [], + input_value, + GraphQLError( + f"Field '{field_name}' of required type '{type_str}'" + " was not provided." + ), + ) + continue + + coerced_dict[field.out_name or field_name] = coerce_input_value( + field_value, field.type, on_error, Path(path, field_name, type_.name) + ) # Ensure every provided field is defined. for field_name in input_value: From 2958b1ead0e6c0dee99019c6723181401745e050 Mon Sep 17 00:00:00 2001 From: ddmytruk Date: Mon, 25 Apr 2022 20:08:59 +0300 Subject: [PATCH 2/2] fix deepcopy --- src/graphql/type/schema.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/graphql/type/schema.py b/src/graphql/type/schema.py index d74f0eb1..7cf3ba88 100644 --- a/src/graphql/type/schema.py +++ b/src/graphql/type/schema.py @@ -342,6 +342,7 @@ def __deepcopy__(self, memo_: Dict) -> "GraphQLSchema": ast_node=deepcopy(self.ast_node), extension_ast_nodes=deepcopy(self.extension_ast_nodes), assume_valid=True, + exclude_unset=self.exclude_unset, ) def get_root_type(self, operation: OperationType) -> Optional[GraphQLObjectType]: