Skip to content

Commit 450620d

Browse files
committed
Implement additional tests to ensure that returning exception will properly null a field and log error.
1 parent 4d29d83 commit 450620d

File tree

3 files changed

+90
-7
lines changed

3 files changed

+90
-7
lines changed

graphql/core/error.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class GraphQLError(Error):
1010

1111
def __init__(self, message, nodes=None, stack=None, source=None, positions=None):
1212
super(GraphQLError, self).__init__(message)
13-
self.message = message
13+
self.message = message or 'An unknown error occurred.'
1414
self.nodes = nodes
1515
self.stack = stack or message
1616
self._source = source

graphql/core/execution/executor.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def _resolve_field(self, execution_context, parent_type, source, field_asts):
169169
execution_context
170170
)
171171

172-
result = self.run_resolve_fn(resolve_fn, source, args, info)
172+
result = self.resolve_or_error(resolve_fn, source, args, info)
173173
return self.complete_value_catching_error(
174174
execution_context, return_type, field_asts, info, result
175175
)
@@ -223,7 +223,7 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
223223
info,
224224
resolved
225225
),
226-
lambda error: GraphQLError(str(error.value), field_asts, error)
226+
lambda error: GraphQLError(error.value and str(error.value), field_asts, error)
227227
)
228228

229229
if isinstance(result, Exception):
@@ -307,7 +307,7 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
307307

308308
return self._execute_fields(ctx, runtime_type, result, subfield_asts)
309309

310-
def run_resolve_fn(self, resolve_fn, source, args, info):
310+
def resolve_or_error(self, resolve_fn, source, args, info):
311311
curried_resolve_fn = functools.partial(resolve_fn, source, args, info)
312312

313313
try:

tests/core_execution/test_concurrent_executor.py

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
from graphql.core.execution import Executor
44
from graphql.core.execution.middlewares.sync import SynchronousExecutionMiddleware
55
from graphql.core.pyutils.defer import succeed, Deferred, fail
6-
from graphql.core.language.parser import parse
76
from graphql.core.type import (GraphQLSchema, GraphQLObjectType, GraphQLField,
87
GraphQLArgument, GraphQLList, GraphQLInt, GraphQLString)
98
from graphql.core.type.definition import GraphQLNonNull
10-
119
from .utils import raise_callback_results
1210

1311

@@ -69,7 +67,6 @@ def deeper(self):
6967
}
7068
'''
7169

72-
ast = parse(doc)
7370
expected = {
7471
'a': 'Apple',
7572
'b': 'Banana',
@@ -236,6 +233,92 @@ def promise(self):
236233
assert not result.errors
237234

238235

236+
def test_synchronous_error_nulls_out_error_subtrees():
237+
doc = '''
238+
{
239+
sync
240+
syncError
241+
syncReturnError
242+
syncReturnErrorList
243+
async
244+
asyncReject
245+
asyncEmptyReject
246+
asyncReturnError
247+
}
248+
'''
249+
250+
class Data:
251+
def sync(self):
252+
return 'sync'
253+
254+
def syncError(self):
255+
raise Exception('Error getting syncError')
256+
257+
def syncReturnError(self):
258+
return Exception("Error getting syncReturnError")
259+
260+
def syncReturnErrorList(self):
261+
return [
262+
'sync0',
263+
Exception('Error getting syncReturnErrorList1'),
264+
'sync2',
265+
Exception('Error getting syncReturnErrorList3')
266+
]
267+
268+
def async(self):
269+
return succeed('async')
270+
271+
def asyncReject(self):
272+
return fail(Exception('Error getting asyncReject'))
273+
274+
def asyncEmptyReject(self):
275+
return fail()
276+
277+
def asyncReturnError(self):
278+
return succeed(Exception('Error getting asyncReturnError'))
279+
280+
schema = GraphQLSchema(
281+
query=GraphQLObjectType(
282+
name='Type',
283+
fields={
284+
'sync': GraphQLField(GraphQLString),
285+
'syncError': GraphQLField(GraphQLString),
286+
'syncReturnError': GraphQLField(GraphQLString),
287+
'syncReturnErrorList': GraphQLField(GraphQLList(GraphQLString)),
288+
'async': GraphQLField(GraphQLString),
289+
'asyncReject': GraphQLField(GraphQLString),
290+
'asyncEmptyReject': GraphQLField(GraphQLString),
291+
'asyncReturnError': GraphQLField(GraphQLString),
292+
}
293+
)
294+
)
295+
296+
executor = Executor(map_type=OrderedDict)
297+
298+
def handle_results(result):
299+
assert result.data == {
300+
'async': 'async',
301+
'asyncEmptyReject': None,
302+
'asyncReject': None,
303+
'asyncReturnError': None,
304+
'sync': 'sync',
305+
'syncError': None,
306+
'syncReturnError': None,
307+
'syncReturnErrorList': ['sync0', None, 'sync2', None]
308+
}
309+
assert list(map(format_error, result.errors)) == [
310+
{'locations': [{'line': 4, 'column': 9}], 'message': 'Error getting syncError'},
311+
{'locations': [{'line': 5, 'column': 9}], 'message': 'Error getting syncReturnError'},
312+
{'locations': [{'line': 6, 'column': 9}], 'message': 'Error getting syncReturnErrorList1'},
313+
{'locations': [{'line': 6, 'column': 9}], 'message': 'Error getting syncReturnErrorList3'},
314+
{'locations': [{'line': 8, 'column': 9}], 'message': 'Error getting asyncReject'},
315+
{'locations': [{'line': 9, 'column': 9}], 'message': 'An unknown error occurred.'},
316+
{'locations': [{'line': 10, 'column': 9}], 'message': 'Error getting asyncReturnError'}
317+
]
318+
319+
raise_callback_results(executor.execute(schema, doc, Data()), handle_results)
320+
321+
239322
def test_executor_can_enforce_strict_ordering():
240323
Type = GraphQLObjectType('Type', lambda: {
241324
'a': GraphQLField(GraphQLString,

0 commit comments

Comments
 (0)