Skip to content

Commit 01f0539

Browse files
committed
Unit tests for deferred.
1 parent d70ddd1 commit 01f0539

File tree

3 files changed

+279
-28
lines changed

3 files changed

+279
-28
lines changed

graphql/core/defer.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def raise_exception(self):
113113
raise self.type(self.value).with_traceback(self.traceback)
114114

115115
else:
116-
exec("""def raise_exception(self):
116+
exec ("""def raise_exception(self):
117117
raise self.type, self.value, self.traceback""")
118118

119119
def catch(self, *errors):
@@ -258,6 +258,8 @@ def add_callbacks(self, callback, errback=None,
258258
if self.called:
259259
self._next()
260260

261+
return self
262+
261263
def add_errback(self, func, *args, **kwargs):
262264
"""Add a callable (function or method) to the errback chain only.
263265
@@ -288,8 +290,8 @@ def add_errback(self, func, *args, **kwargs):
288290
>>> deferred.result
289291
'ignored'
290292
"""
291-
self.add_callbacks(_passthrough, func, errback_args=args,
292-
errback_kwargs=kwargs)
293+
return self.add_callbacks(_passthrough, func, errback_args=args,
294+
errback_kwargs=kwargs)
293295

294296
def add_callback(self, func, *args, **kwargs):
295297
"""Add a callable (function or method) to the callback chain only.
@@ -312,8 +314,8 @@ def add_callback(self, func, *args, **kwargs):
312314
>>> deferred.result
313315
2
314316
"""
315-
self.add_callbacks(func, _passthrough, callback_args=args,
316-
callback_kwargs=kwargs)
317+
return self.add_callbacks(func, _passthrough, callback_args=args,
318+
callback_kwargs=kwargs)
317319

318320
def errback(self, error=None):
319321
"""Start processing the errorback chain starting with the
@@ -339,6 +341,7 @@ def errback(self, error=None):
339341
elif not isinstance(error, DeferredException):
340342
assert isinstance(error, Exception)
341343
error = DeferredException(error.__class__, error, None)
344+
342345
self.called = True
343346
self.result = error
344347
self._next()
@@ -358,16 +361,28 @@ def callback(self, result=None):
358361
if self.called:
359362
raise AlreadyCalledDeferred()
360363
self.called = True
364+
365+
if isinstance(result, Deferred):
366+
self.paused = True
367+
return result.add_callbacks(self._continue, self._continue)
368+
361369
self.result = result
362370
self._next()
363371

364372
def _continue(self, result):
365373
"""Continue processing the Deferred with the given result."""
374+
# If the result of the deferred is another deferred, we will need to wait for
375+
# it to resolve again.
376+
if isinstance(result, Deferred):
377+
return result.add_callbacks(self._continue, self._continue)
378+
366379
self.result = result
367380
self.paused = False
368381
if self.called:
369382
self._next()
370383

384+
return result
385+
371386
def _next(self):
372387
"""Process the next callback."""
373388
if self._running or self.paused:
@@ -380,18 +395,19 @@ def _next(self):
380395
callback, args, kwargs = next_pair[isinstance(self.result,
381396
DeferredException)]
382397

383-
if callback is _passthrough:
384-
continue
398+
if callback is not _passthrough:
399+
self._running = True
400+
try:
401+
self.result = callback(self.result, *args, **kwargs)
385402

386-
self._running = True
387-
try:
388-
self.result = callback(self.result, *args, **kwargs)
403+
except:
404+
self.result = DeferredException()
389405

390-
except:
391-
self.result = DeferredException()
406+
finally:
407+
self._running = False
392408

393-
finally:
394-
self._running = False
409+
if isinstance(self.result, Exception):
410+
self.result = DeferredException(self.result)
395411

396412
if isinstance(self.result, Deferred):
397413
# If a Deferred was returned add this deferred as callbacks to
@@ -428,12 +444,15 @@ def defer(func, *args, **kwargs):
428444
True
429445
"""
430446
assert isinstance(func, collections.Callable)
447+
431448
try:
432449
result = func(*args, **kwargs)
433450
except:
434451
result = DeferredException()
452+
435453
if isinstance(result, Deferred):
436454
return result
455+
437456
deferred = Deferred()
438457
deferred.callback(result)
439458
return deferred

graphql/core/execution/executor.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,13 @@ def _execute(self, request='', root=None, args=None, operation_name=None, execut
6161
def _execute_graphql_query(self, root, ast, operation_name, args, execute_serially=False):
6262
ctx = ExecutionContext(self.schema, root, ast, operation_name, args)
6363

64-
d = defer(self._execute_operation, ctx, root, ctx.operation, execute_serially)
65-
d.add_errback(
64+
return defer(self._execute_operation, ctx, root, ctx.operation, execute_serially) \
65+
.add_errback(
6666
lambda error: ctx.errors.append(error)
67-
)
68-
d.add_callback(
67+
) \
68+
.add_callback(
6969
lambda data: ExecutionResult(data, list(map(format_error, ctx.errors))),
7070
)
71-
return d
7271

7372
def _execute_operation(self, ctx, root, operation, execute_serially):
7473
type = get_operation_root_type(ctx.schema, operation)
@@ -91,15 +90,13 @@ def collect_result(resolved_result):
9190
return results
9291

9392
if isinstance(result, Deferred):
94-
result.add_callback(collect_result)
95-
return result
93+
return result.add_callback(collect_result)
9694

9795
else:
9896
return collect_result(result)
9997

10098
def execute_field(prev_deferred, response_name):
101-
prev_deferred.add_callback(execute_field_callback, response_name)
102-
return prev_deferred
99+
return prev_deferred.add_callback(execute_field_callback, response_name)
103100

104101
return functools.reduce(execute_field, fields.keys(), succeed({}))
105102

@@ -169,8 +166,7 @@ def handle_error(error):
169166
ctx.errors.append(error)
170167
return None
171168

172-
completed.add_errback(handle_error)
173-
return completed
169+
return completed.add_errback(handle_error)
174170

175171
return completed
176172
except Exception as e:
@@ -196,7 +192,7 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
196192
"""
197193
# If field type is NonNull, complete for inner type, and throw field error if result is null.
198194
if isinstance(result, Deferred):
199-
result.add_callbacks(
195+
return result.add_callbacks(
200196
lambda resolved: self.complete_value(
201197
ctx,
202198
return_type,
@@ -206,7 +202,6 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
206202
),
207203
lambda error: fail(GraphQLError(str(error), field_asts, error))
208204
)
209-
return result
210205

211206
if isinstance(result, Exception):
212207
raise GraphQLError(str(result), field_asts, result)
@@ -263,7 +258,7 @@ def complete_value(self, ctx, return_type, field_asts, info, result):
263258
runtime_type = return_type.resolve_type(result)
264259
if runtime_type and not return_type.is_possible_type(runtime_type):
265260
raise GraphQLError(
266-
'Runtime Object type "{}" is nt a possible type for "{}".'.format(runtime_type, return_type),
261+
'Runtime Object type "{}" is not a possible type for "{}".'.format(runtime_type, return_type),
267262
field_asts
268263
)
269264

0 commit comments

Comments
 (0)