Skip to content

Commit 36d6be8

Browse files
committed
coerce_value: Simplify path printing
Replicates graphql/graphql-js@dae9f87
1 parent cba6b50 commit 36d6be8

File tree

3 files changed

+30
-38
lines changed

3 files changed

+30
-38
lines changed

src/graphql/utilities/coerce_value.py

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ def coerce_value(
108108
coerced_value_list: List[Any] = []
109109
append_item = coerced_value_list.append
110110
for index, item_value in enumerate(value):
111+
item_path = Path(path, index)
111112
coerced_item = coerce_value(
112-
item_value, item_type, blame_node, at_path(path, index)
113+
item_value, item_type, blame_node, item_path
113114
)
114115
if coerced_item.errors:
115116
errors = add(errors, *coerced_item.errors)
@@ -136,6 +137,7 @@ def coerce_value(
136137

137138
# Ensure every defined field is valid.
138139
for field_name, field in fields.items():
140+
field_path = Path(path, field_name)
139141
field_value = value.get(field_name, INVALID)
140142
if field_value is INVALID:
141143
if field.default_value is not INVALID:
@@ -147,14 +149,15 @@ def coerce_value(
147149
errors = add(
148150
errors,
149151
coercion_error(
150-
f"Field {print_path(at_path(path, field_name))}"
151-
f" of required type {field.type} was not provided",
152+
f"Field of required type {inspect(field.type)}"
153+
" was not provided",
152154
blame_node,
155+
field_path,
153156
),
154157
)
155158
else:
156159
coerced_field = coerce_value(
157-
field_value, field.type, blame_node, at_path(path, field_name)
160+
field_value, field.type, blame_node, field_path
158161
)
159162
if coerced_field.errors:
160163
errors = add(errors, *coerced_field.errors)
@@ -201,37 +204,26 @@ def add(
201204
return (errors or []) + list(more_errors)
202205

203206

204-
def at_path(prev: Optional[Path], key: Union[str, int]) -> Path:
205-
return Path(prev, key)
206-
207-
208207
def coercion_error(
209208
message: str,
210209
blame_node: Node = None,
211210
path: Path = None,
212211
sub_message: str = None,
213212
original_error: Exception = None,
214213
) -> GraphQLError:
215-
"""Return a GraphQLError instance"""
216-
path_str = print_path(path)
217-
if path_str:
218-
message += f" at {path_str}"
219-
message += "."
220-
if sub_message:
221-
message += sub_message
222-
# noinspection PyArgumentEqualDefault
223-
return GraphQLError(message, blame_node, None, None, None, original_error)
224-
225-
226-
def print_path(path: Optional[Path]) -> str:
227-
"""Build string describing the path into the value where error was found"""
228-
path_str = ""
229-
current_path: Optional[Path] = path
230-
while current_path:
231-
path_str = (
232-
f".{current_path.key}"
233-
if isinstance(current_path.key, str)
234-
else f"[{current_path.key}]"
235-
) + path_str
236-
current_path = current_path.prev
237-
return f"value{path_str}" if path_str else ""
214+
"""Return a coercion error with the given message describing the given path"""
215+
full_message = message
216+
# Build a string describing the path into the value where the error was found
217+
if path:
218+
segment_strings: List[str] = []
219+
current_path: Optional[Path] = path
220+
while current_path:
221+
key = current_path.key
222+
segment_strings.insert(0, f".{key}" if isinstance(key, str) else f"[{key}]")
223+
current_path = current_path.prev
224+
full_message += " at value" + "".join(segment_strings)
225+
226+
full_message += "." + sub_message if sub_message else "."
227+
228+
# Return a GraphQLError instance
229+
return GraphQLError(full_message, blame_node, None, None, None, original_error)

tests/execution/test_variables.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,8 @@ def errors_on_omission_of_nested_non_null():
395395
[
396396
{
397397
"message": "Variable '$input' got invalid value"
398-
" {'a': 'foo', 'b': 'bar'}; Field value.c"
399-
" of required type String! was not provided.",
398+
" {'a': 'foo', 'b': 'bar'}; Field of required type String!"
399+
" was not provided at value.c.",
400400
"locations": [(2, 24)],
401401
}
402402
],
@@ -415,14 +415,14 @@ def errors_on_deep_nested_errors_and_with_many_errors():
415415
[
416416
{
417417
"message": "Variable '$input' got invalid value"
418-
" {'na': {'a': 'foo'}}; Field value.na.c"
419-
" of required type String! was not provided.",
418+
" {'na': {'a': 'foo'}}; Field of required type String!"
419+
" was not provided at value.na.c.",
420420
"locations": [(2, 28)],
421421
},
422422
{
423423
"message": "Variable '$input' got invalid value"
424-
" {'na': {'a': 'foo'}}; Field value.nb"
425-
" of required type String! was not provided.",
424+
" {'na': {'a': 'foo'}}; Field of required type String!"
425+
" was not provided at value.nb.",
426426
"locations": [(2, 28)],
427427
},
428428
],

tests/utilities/test_coerce_value.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def returns_multiple_errors_for_multiple_invalid_fields():
140140
def returns_error_for_a_missing_required_field():
141141
result = coerce_value({"bar": 123}, TestInputObject)
142142
assert expect_errors(result) == [
143-
"Field value.foo of required type Int! was not provided."
143+
"Field of required type Int! was not provided at value.foo."
144144
]
145145

146146
def returns_error_for_an_unknown_field():

0 commit comments

Comments
 (0)