Skip to content

Commit f2a51bb

Browse files
committed
test_ast_from_value: improve coverage
Also fix porting bug revealed in added test. Replicates graphql/graphql-js@34c5580
1 parent d217330 commit f2a51bb

File tree

2 files changed

+57
-25
lines changed

2 files changed

+57
-25
lines changed

src/graphql/utilities/ast_from_value.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import re
2-
from typing import Any, Iterable, List, Mapping, Optional, cast
2+
from typing import Any, Iterable, Mapping, Optional, cast
33

44
from ..language import (
55
BooleanValueNode,
@@ -14,7 +14,7 @@
1414
StringValueNode,
1515
ValueNode,
1616
)
17-
from ..pyutils import inspect, is_nullish, is_invalid
17+
from ..pyutils import FrozenList, inspect, is_nullish, is_invalid
1818
from ..type import (
1919
GraphQLID,
2020
GraphQLInputType,
@@ -71,8 +71,9 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]:
7171
type_ = cast(GraphQLList, type_)
7272
item_type = type_.of_type
7373
if isinstance(value, Iterable) and not isinstance(value, str):
74-
value_nodes = [ast_from_value(item, item_type) for item in value]
75-
return ListValueNode(values=value_nodes)
74+
maybe_value_nodes = (ast_from_value(item, item_type) for item in value)
75+
value_nodes = filter(None, maybe_value_nodes)
76+
return ListValueNode(values=FrozenList(value_nodes))
7677
return ast_from_value(value, item_type)
7778

7879
# Populate the fields of the input object by creating ASTs from each value in the
@@ -81,18 +82,17 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]:
8182
if value is None or not isinstance(value, Mapping):
8283
return None
8384
type_ = cast(GraphQLInputObjectType, type_)
84-
field_nodes: List[ObjectFieldNode] = []
85-
append_node = field_nodes.append
86-
for field_name, field in type_.fields.items():
87-
if field_name in value:
88-
field_value = ast_from_value(value[field_name], field.type)
89-
if field_value:
90-
append_node(
91-
ObjectFieldNode(
92-
name=NameNode(value=field_name), value=field_value
93-
)
94-
)
95-
return ObjectValueNode(fields=field_nodes)
85+
field_items = (
86+
(field_name, ast_from_value(value[field_name], field.type))
87+
for field_name, field in type_.fields.items()
88+
if field_name in value
89+
)
90+
field_nodes = (
91+
ObjectFieldNode(name=NameNode(value=field_name), value=field_value)
92+
for field_name, field_value in field_items
93+
if field_value
94+
)
95+
return ObjectValueNode(fields=FrozenList(field_nodes))
9696

9797
if is_leaf_type(type_):
9898
# Since value is an internally represented value, it must be serialized to an

tests/utilities/test_ast_from_value.py

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
GraphQLInt,
2626
GraphQLList,
2727
GraphQLNonNull,
28+
GraphQLScalarType,
2829
GraphQLString,
2930
)
3031
from graphql.utilities import ast_from_value
@@ -123,6 +124,33 @@ def converts_id_values_to_int_or_string_asts():
123124

124125
assert ast_from_value(INVALID, GraphQLString) is None
125126

127+
def converts_using_serialize_from_a_custom_scalar_type():
128+
pass_through_scalar = GraphQLScalarType(
129+
"PassThroughScalar", serialize=lambda value: value,
130+
)
131+
132+
assert ast_from_value("value", pass_through_scalar) == StringValueNode(
133+
value="value"
134+
)
135+
136+
return_null_scalar = GraphQLScalarType(
137+
"ReturnNullScalar", serialize=lambda value: None,
138+
)
139+
140+
assert ast_from_value("value", return_null_scalar) is None
141+
142+
class SomeClass:
143+
pass
144+
145+
return_custom_class_scalar = GraphQLScalarType(
146+
"ReturnCustomClassScalar", serialize=lambda value: SomeClass(),
147+
)
148+
149+
with raises(TypeError) as exc_info:
150+
ast_from_value("value", return_custom_class_scalar)
151+
msg = str(exc_info.value)
152+
assert msg == "Cannot convert value to AST: <SomeClass instance>"
153+
126154
def does_not_convert_non_null_values_to_null_value():
127155
non_null_boolean = GraphQLNonNull(GraphQLBoolean)
128156
assert ast_from_value(None, non_null_boolean) is None
@@ -162,12 +190,21 @@ def converts_list_singletons():
162190
value="FOO"
163191
)
164192

165-
def converts_input_objects():
166-
input_obj = GraphQLInputObjectType(
167-
"MyInputObj",
168-
{"foo": GraphQLInputField(GraphQLFloat), "bar": GraphQLInputField(my_enum)},
193+
def skips_invalid_list_items():
194+
ast = ast_from_value(
195+
["FOO", None, "BAR"], GraphQLList(GraphQLNonNull(GraphQLString))
196+
)
197+
198+
assert ast == ListValueNode(
199+
values=[StringValueNode(value="FOO"), StringValueNode(value="BAR")]
169200
)
170201

202+
input_obj = GraphQLInputObjectType(
203+
"MyInputObj",
204+
{"foo": GraphQLInputField(GraphQLFloat), "bar": GraphQLInputField(my_enum)},
205+
)
206+
207+
def converts_input_objects():
171208
assert ast_from_value({"foo": 3, "bar": "HELLO"}, input_obj) == ObjectValueNode(
172209
fields=[
173210
ObjectFieldNode(
@@ -180,11 +217,6 @@ def converts_input_objects():
180217
)
181218

182219
def converts_input_objects_with_explicit_nulls():
183-
input_obj = GraphQLInputObjectType(
184-
"MyInputObj",
185-
{"foo": GraphQLInputField(GraphQLFloat), "bar": GraphQLInputField(my_enum)},
186-
)
187-
188220
assert ast_from_value({"foo": None}, input_obj) == ObjectValueNode(
189221
fields=[ObjectFieldNode(name=NameNode(value="foo"), value=NullValueNode())]
190222
)

0 commit comments

Comments
 (0)