Skip to content

Commit 30cf381

Browse files
committed
Scalars: convert errors from 'TypeError' to 'GraphQLError'
Replicates graphql/graphql-js@3d86489
1 parent 5e43688 commit 30cf381

13 files changed

+448
-709
lines changed

docs/usage/validator.rst

+1-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ As a result, you will get a complete list of all errors that the validators has
2424
In this case, we will get::
2525

2626
[GraphQLError(
27-
"Expected value of type 'String!', found NEWHOPE;"
28-
" String cannot represent a non string value: NEWHOPE",
27+
'String cannot represent a non string value: NEWHOPE',
2928
locations=[SourceLocation(line=3, column=17)]),
3029
GraphQLError(
3130
"Cannot query field 'homeTown' on type 'Human'."

src/graphql/type/scalars.py

+38-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from math import isfinite
22
from typing import Any
33

4+
from ..error import GraphQLError
45
from ..pyutils import inspect, is_finite, is_integer, FrozenDict
56
from ..language.ast import (
67
BooleanValueNode,
@@ -51,19 +52,19 @@ def serialize_int(value: Any) -> int:
5152
if num != float_value:
5253
raise ValueError
5354
except (OverflowError, ValueError, TypeError):
54-
raise TypeError(f"Int cannot represent non-integer value: {inspect(value)}")
55+
raise GraphQLError(f"Int cannot represent non-integer value: {inspect(value)}")
5556
if not MIN_INT <= num <= MAX_INT:
56-
raise TypeError(
57+
raise GraphQLError(
5758
f"Int cannot represent non 32-bit signed integer value: {inspect(value)}"
5859
)
5960
return num
6061

6162

6263
def coerce_int(value: Any) -> int:
6364
if not is_integer(value):
64-
raise TypeError(f"Int cannot represent non-integer value: {inspect(value)}")
65+
raise GraphQLError(f"Int cannot represent non-integer value: {inspect(value)}")
6566
if not MIN_INT <= value <= MAX_INT:
66-
raise TypeError(
67+
raise GraphQLError(
6768
f"Int cannot represent non 32-bit signed integer value: {inspect(value)}"
6869
)
6970
return int(value)
@@ -72,11 +73,14 @@ def coerce_int(value: Any) -> int:
7273
def parse_int_literal(ast, _variables=None):
7374
"""Parse an integer value node in the AST."""
7475
if not isinstance(ast, IntValueNode):
75-
raise TypeError(f"Int cannot represent non-integer value: {print_ast(ast)}")
76+
raise GraphQLError(
77+
f"Int cannot represent non-integer value: {print_ast(ast)}", ast
78+
)
7679
num = int(ast.value)
7780
if not MIN_INT <= num <= MAX_INT:
78-
raise TypeError(
79-
f"Int cannot represent non 32-bit signed integer value: {print_ast(ast)}"
81+
raise GraphQLError(
82+
f"Int cannot represent non 32-bit signed integer value: {print_ast(ast)}",
83+
ast,
8084
)
8185
return num
8286

@@ -103,20 +107,26 @@ def serialize_float(value: Any) -> float:
103107
if not isfinite(num):
104108
raise ValueError
105109
except (ValueError, TypeError):
106-
raise TypeError(f"Float cannot represent non numeric value: {inspect(value)}")
110+
raise GraphQLError(
111+
f"Float cannot represent non numeric value: {inspect(value)}"
112+
)
107113
return num
108114

109115

110116
def coerce_float(value: Any) -> float:
111117
if not is_finite(value):
112-
raise TypeError(f"Float cannot represent non numeric value: {inspect(value)}")
118+
raise GraphQLError(
119+
f"Float cannot represent non numeric value: {inspect(value)}"
120+
)
113121
return float(value)
114122

115123

116124
def parse_float_literal(ast, _variables=None):
117125
"""Parse a float value node in the AST."""
118126
if not isinstance(ast, (FloatValueNode, IntValueNode)):
119-
raise TypeError(f"Float cannot represent non numeric value: {print_ast(ast)}")
127+
raise GraphQLError(
128+
f"Float cannot represent non numeric value: {print_ast(ast)}", ast
129+
)
120130
return float(ast.value)
121131

122132

@@ -142,20 +152,24 @@ def serialize_string(value: Any) -> str:
142152
# do not serialize builtin types as strings, but allow serialization of custom
143153
# types via their `__str__` method
144154
if type(value).__module__ == "builtins":
145-
raise TypeError(f"String cannot represent value: {inspect(value)}")
155+
raise GraphQLError(f"String cannot represent value: {inspect(value)}")
146156
return str(value)
147157

148158

149159
def coerce_string(value: Any) -> str:
150160
if not isinstance(value, str):
151-
raise TypeError(f"String cannot represent a non string value: {inspect(value)}")
161+
raise GraphQLError(
162+
f"String cannot represent a non string value: {inspect(value)}"
163+
)
152164
return value
153165

154166

155167
def parse_string_literal(ast, _variables=None):
156168
"""Parse a string value node in the AST."""
157169
if not isinstance(ast, StringValueNode):
158-
raise TypeError(f"String cannot represent a non string value: {print_ast(ast)}")
170+
raise GraphQLError(
171+
f"String cannot represent a non string value: {print_ast(ast)}", ast
172+
)
159173
return ast.value
160174

161175

@@ -176,12 +190,14 @@ def serialize_boolean(value: Any) -> bool:
176190
return value
177191
if is_finite(value):
178192
return bool(value)
179-
raise TypeError(f"Boolean cannot represent a non boolean value: {inspect(value)}")
193+
raise GraphQLError(
194+
f"Boolean cannot represent a non boolean value: {inspect(value)}"
195+
)
180196

181197

182198
def coerce_boolean(value: Any) -> bool:
183199
if not isinstance(value, bool):
184-
raise TypeError(
200+
raise GraphQLError(
185201
f"Boolean cannot represent a non boolean value: {inspect(value)}"
186202
)
187203
return value
@@ -190,8 +206,8 @@ def coerce_boolean(value: Any) -> bool:
190206
def parse_boolean_literal(ast, _variables=None):
191207
"""Parse a boolean value node in the AST."""
192208
if not isinstance(ast, BooleanValueNode):
193-
raise TypeError(
194-
f"Boolean cannot represent a non boolean value: {print_ast(ast)}"
209+
raise GraphQLError(
210+
f"Boolean cannot represent a non boolean value: {print_ast(ast)}", ast
195211
)
196212
return ast.value
197213

@@ -213,13 +229,13 @@ def serialize_id(value: Any) -> str:
213229
# do not serialize builtin types as IDs, but allow serialization of custom types
214230
# via their `__str__` method
215231
if type(value).__module__ == "builtins":
216-
raise TypeError(f"ID cannot represent value: {inspect(value)}")
232+
raise GraphQLError(f"ID cannot represent value: {inspect(value)}")
217233
return str(value)
218234

219235

220236
def coerce_id(value: Any) -> str:
221237
if not isinstance(value, str) and not is_integer(value):
222-
raise TypeError(f"ID cannot represent value: {inspect(value)}")
238+
raise GraphQLError(f"ID cannot represent value: {inspect(value)}")
223239
if isinstance(value, float):
224240
value = int(value)
225241
return str(value)
@@ -228,8 +244,9 @@ def coerce_id(value: Any) -> str:
228244
def parse_id_literal(ast, _variables=None):
229245
"""Parse an ID value node in the AST."""
230246
if not isinstance(ast, (StringValueNode, IntValueNode)):
231-
raise TypeError(
232-
f"ID cannot represent a non-string and non-integer value: {print_ast(ast)}"
247+
raise GraphQLError(
248+
f"ID cannot represent a non-string and non-integer value: {print_ast(ast)}",
249+
ast,
233250
)
234251
return ast.value
235252

src/graphql/utilities/coerce_input_value.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ def coerce_input_value(
129129
type_ = cast(GraphQLScalarType, type_)
130130
try:
131131
parse_result = type_.parse_value(input_value)
132-
except (TypeError, ValueError) as error:
132+
except GraphQLError as error:
133+
on_error(path.as_list() if path else [], input_value, error)
134+
return INVALID
135+
except Exception as error:
133136
on_error(
134137
path.as_list() if path else [],
135138
input_value,

src/graphql/utilities/value_from_ast.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,13 @@ def value_from_ast(
141141
# Scalars fulfill parsing a literal value via `parse_literal()`. Invalid values
142142
# represent a failure to parse correctly, in which case INVALID is returned.
143143
type_ = cast(GraphQLScalarType, type_)
144+
# noinspection PyBroadException
144145
try:
145146
if variables:
146147
result = type_.parse_literal(value_node, variables)
147148
else:
148149
result = type_.parse_literal(value_node)
149-
except (ArithmeticError, TypeError, ValueError):
150+
except Exception:
150151
return INVALID
151152
if is_invalid(result):
152153
return INVALID

src/graphql/validation/rules/values_of_correct_type.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,15 @@ def is_valid_value_node(self, node: ValueNode) -> None:
153153
node,
154154
)
155155
)
156+
except GraphQLError as error:
157+
self.report_error(error)
156158
except Exception as error:
157-
# Ensure a reference to the original error is maintained.
158159
self.report_error(
159160
GraphQLError(
160161
f"Expected value of type '{location_type}',"
161162
f" found {print_ast(node)}; {error}",
162163
node,
164+
# Ensure a reference to the original error is maintained.
163165
original_error=error,
164166
)
165167
)

tests/execution/test_variables.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -658,15 +658,14 @@ def reports_error_for_array_passed_into_string_input():
658658
[
659659
{
660660
"message": "Variable '$value' got invalid value [1, 2, 3];"
661-
" Expected type 'String'. String cannot represent"
662-
" a non string value: [1, 2, 3]",
661+
" String cannot represent a non string value: [1, 2, 3]",
663662
"locations": [(2, 24)],
664663
"path": None,
665664
}
666665
],
667666
)
668667

669-
assert isinstance(result.errors[0].original_error, TypeError)
668+
assert result.errors[0].original_error is None
670669

671670
def reports_error_for_non_provided_variables_for_non_nullable_inputs():
672671
# Note: this test would typically fail validation before
@@ -974,7 +973,6 @@ def _invalid_value_error(value, index):
974973
return {
975974
"message": "Variable '$input' got invalid value"
976975
f" {value} at 'input[{index}]';"
977-
" Expected type 'String'."
978976
f" String cannot represent a non string value: {value}",
979977
"locations": [(2, 20)],
980978
}

tests/subscription/test_subscribe.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -471,14 +471,14 @@ async def resolves_to_an_error_if_variables_were_wrong_type():
471471
None,
472472
[
473473
{
474-
"message": "Variable '$priority' got invalid value 'meow'; Expected"
475-
" type 'Int'. Int cannot represent non-integer value: 'meow'",
474+
"message": "Variable '$priority' got invalid value 'meow';"
475+
" Int cannot represent non-integer value: 'meow'",
476476
"locations": [(2, 27)],
477477
}
478478
],
479479
)
480480

481-
assert result.errors[0].original_error is not None # type: ignore
481+
assert result.errors[0].original_error is None # type: ignore
482482

483483

484484
# Once a subscription returns a valid AsyncIterator, it can still yield errors.

tests/type/test_enum.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,7 @@ def does_not_accept_enum_literal_in_place_of_int():
216216
None,
217217
[
218218
{
219-
"message": "Expected value of type 'Int', found GREEN;"
220-
" Int cannot represent non-integer value: GREEN",
219+
"message": "Int cannot represent non-integer value: GREEN",
221220
"locations": [(1, 22)],
222221
}
223222
],

0 commit comments

Comments
 (0)