Skip to content

Commit a68d134

Browse files
committed
Move is_valid_value to utilities to match graphql-js reference implementation.
* Correct syntax in `get_variable_value`'s error messages. * When using `coerce_value` on a `GraphQLInputObjectType`, it should not populate nullable values into the return value. #5
1 parent c4d3804 commit a68d134

File tree

2 files changed

+82
-46
lines changed

2 files changed

+82
-46
lines changed

graphql/core/execution/values.py

Lines changed: 25 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import collections
2+
import json
23
from six import string_types
34
from ..error import GraphQLError
45
from ..language.printer import print_ast
@@ -11,6 +12,7 @@
1112
is_input_type
1213
)
1314
from ..utils.is_nullish import is_nullish
15+
from ..utils.is_valid_value import is_valid_value
1416
from ..utils.type_from_ast import type_from_ast
1517
from ..utils.value_from_ast import value_from_ast
1618

@@ -22,11 +24,13 @@ def get_variable_values(schema, definition_asts, inputs):
2224
If the input cannot be parsed to match the variable definitions, a GraphQLError will be thrown."""
2325
if inputs is None:
2426
inputs = {}
27+
2528
values = {}
2629
for def_ast in definition_asts:
2730
var_name = def_ast.variable.name.value
2831
value = get_variable_value(schema, def_ast, inputs.get(var_name))
2932
values[var_name] = value
33+
3034
return values
3135

3236

@@ -65,10 +69,12 @@ def get_variable_value(schema, definition_ast, input):
6569
"""Given a variable definition, and any value of input, return a value which adheres to the variable definition,
6670
or throw an error."""
6771
type = type_from_ast(schema, definition_ast.type)
72+
variable = definition_ast.variable
73+
6874
if not type or not is_input_type(type):
6975
raise GraphQLError(
70-
'Variable ${} expected value of type {} which cannot be used as an input type.'.format(
71-
definition_ast.variable.name.value,
76+
'Variable "${}" expected value of type "{}" which cannot be used as an input type.'.format(
77+
variable.name.value,
7278
print_ast(definition_ast.type),
7379
),
7480
[definition_ast]
@@ -81,55 +87,25 @@ def get_variable_value(schema, definition_ast, input):
8187
return value_from_ast(type, default_value, None)
8288
return coerce_value(type, input)
8389

90+
if is_nullish(input):
91+
raise GraphQLError(
92+
'Variable "${}" of required type "{}" was not provided.'.format(
93+
variable.name.value,
94+
print_ast(definition_ast.type)
95+
),
96+
[definition_ast]
97+
)
98+
8499
raise GraphQLError(
85-
'Variable ${} expected value of type {} but got: {}'.format(
86-
definition_ast.variable.name.value,
100+
'Variable "${}" expected value of type "{}" but got: {}'.format(
101+
variable.name.value,
87102
print_ast(definition_ast.type),
88-
repr(input)
103+
json.dumps(input)
89104
),
90105
[definition_ast]
91106
)
92107

93108

94-
def is_valid_value(type, value):
95-
"""Given a type and any value, return True if that value is valid."""
96-
if isinstance(type, GraphQLNonNull):
97-
if is_nullish(value):
98-
return False
99-
return is_valid_value(type.of_type, value)
100-
101-
if is_nullish(value):
102-
return True
103-
104-
if isinstance(type, GraphQLList):
105-
item_type = type.of_type
106-
if not isinstance(value, string_types) and \
107-
isinstance(value, collections.Iterable):
108-
return all(is_valid_value(item_type, item) for item in value)
109-
else:
110-
return is_valid_value(item_type, value)
111-
112-
if isinstance(type, GraphQLInputObjectType):
113-
if not isinstance(value, collections.Mapping):
114-
return False
115-
fields = type.get_fields()
116-
117-
# Ensure every provided field is defined.
118-
if any(field_name not in fields for field_name in value.keys()):
119-
return False
120-
121-
# Ensure every defined field is valid.
122-
return all(
123-
is_valid_value(fields[field_name].type, value.get(field_name))
124-
for field_name in fields
125-
)
126-
127-
assert isinstance(type, (GraphQLScalarType, GraphQLEnumType)), \
128-
'Must be input type'
129-
130-
return not is_nullish(type.parse_value(value))
131-
132-
133109
def coerce_value(type, value):
134110
"""Given a type and any value, return a runtime value coerced to match the type."""
135111
if isinstance(type, GraphQLNonNull):
@@ -153,9 +129,12 @@ def coerce_value(type, value):
153129
obj = {}
154130
for field_name, field in fields.items():
155131
field_value = coerce_value(field.type, value[field_name])
156-
if field_value is None:
132+
if is_nullish(field_value):
157133
field_value = field.default_value
158-
obj[field_name] = field_value
134+
135+
if not is_nullish(field_value):
136+
obj[field_name] = field_value
137+
159138
return obj
160139

161140
assert isinstance(type, (GraphQLScalarType, GraphQLEnumType)), \

graphql/core/utils/is_valid_value.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""
2+
Implementation of isValidJSValue from graphql-js
3+
"""
4+
5+
import collections
6+
from six import string_types
7+
from ..type import (
8+
GraphQLEnumType,
9+
GraphQLInputObjectType,
10+
GraphQLList,
11+
GraphQLNonNull,
12+
GraphQLScalarType,
13+
)
14+
from .is_nullish import is_nullish
15+
16+
17+
def is_valid_value(type, value):
18+
"""Given a type and any value, return True if that value is valid."""
19+
if isinstance(type, GraphQLNonNull):
20+
if is_nullish(value):
21+
return False
22+
23+
return is_valid_value(type.of_type, value)
24+
25+
if is_nullish(value):
26+
return True
27+
28+
if isinstance(type, GraphQLList):
29+
item_type = type.of_type
30+
if not isinstance(value, string_types) and \
31+
isinstance(value, collections.Iterable):
32+
return all(is_valid_value(item_type, item) for item in value)
33+
else:
34+
return is_valid_value(item_type, value)
35+
36+
if isinstance(type, GraphQLInputObjectType):
37+
if not isinstance(value, collections.Mapping):
38+
return False
39+
40+
fields = type.get_fields()
41+
42+
# Ensure every provided field is defined.
43+
if any(field_name not in fields for field_name in value.keys()):
44+
return False
45+
46+
# Ensure every defined field is valid.
47+
return all(
48+
is_valid_value(field.type, value.get(field_name))
49+
for field_name, field in fields.items()
50+
)
51+
52+
assert isinstance(type, (GraphQLScalarType, GraphQLEnumType)), \
53+
'Must be input type'
54+
55+
# Scalar/Enum input checks to ensure the type can parse the value to
56+
# a non-null value.
57+
return not is_nullish(type.parse_value(value))

0 commit comments

Comments
 (0)