Skip to content

Commit 59dacf9

Browse files
authored
Merge pull request #141 from graphql-python/features/async-execution
Features/async execution
2 parents 9aed997 + 1d66271 commit 59dacf9

File tree

4 files changed

+64
-29
lines changed

4 files changed

+64
-29
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ python:
55
- 3.4
66
- 3.5
77
- 3.6
8-
- pypy
8+
- "pypy-5.3.1"
99
before_install:
1010
- |
1111
if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then

graphql/error/format_error.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1+
from .base import GraphQLError
2+
3+
14
def format_error(error):
25
formatted_error = {
3-
'message': error.message,
6+
'message': str(error),
47
}
5-
if error.locations is not None:
6-
formatted_error['locations'] = [
7-
{'line': loc.line, 'column': loc.column}
8-
for loc in error.locations
9-
]
8+
if isinstance(error, GraphQLError):
9+
if error.locations is not None:
10+
formatted_error['locations'] = [
11+
{'line': loc.line, 'column': loc.column}
12+
for loc in error.locations
13+
]
1014

1115
return formatted_error

graphql/execution/executor.py

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,14 @@ def on_resolve(data):
6565
return ExecutionResult(data=data)
6666
return ExecutionResult(data=data, errors=context.errors)
6767

68-
promise = Promise.resolve(None).then(executor).catch(on_rejected).then(on_resolve)
69-
if return_promise:
70-
return promise
71-
context.executor.wait_until_finished()
72-
return promise.get()
68+
promise = Promise.resolve(None).then(
69+
executor).catch(on_rejected).then(on_resolve)
70+
71+
if not return_promise:
72+
context.executor.wait_until_finished()
73+
return promise.get()
74+
75+
return promise
7376

7477

7578
def execute_operation(exe_context, operation, root_value):
@@ -122,7 +125,8 @@ def execute_fields(exe_context, parent_type, source_value, fields):
122125
final_results = OrderedDict()
123126

124127
for response_name, field_asts in fields.items():
125-
result = resolve_field(exe_context, parent_type, source_value, field_asts)
128+
result = resolve_field(exe_context, parent_type,
129+
source_value, field_asts)
126130
if result is Undefined:
127131
continue
128132

@@ -175,7 +179,8 @@ def resolve_field(exe_context, parent_type, source, field_asts):
175179
)
176180

177181
executor = exe_context.executor
178-
result = resolve_or_error(resolve_fn_middleware, source, info, args, executor)
182+
result = resolve_or_error(resolve_fn_middleware,
183+
source, info, args, executor)
179184

180185
return complete_value_catching_error(
181186
exe_context,
@@ -206,7 +211,8 @@ def complete_value_catching_error(exe_context, return_type, field_asts, info, re
206211
# Otherwise, error protection is applied, logging the error and
207212
# resolving a null value for this field if one is encountered.
208213
try:
209-
completed = complete_value(exe_context, return_type, field_asts, info, result)
214+
completed = complete_value(
215+
exe_context, return_type, field_asts, info, result)
210216
if is_thenable(completed):
211217
def handle_error(error):
212218
traceback = completed._traceback
@@ -241,7 +247,8 @@ def complete_value(exe_context, return_type, field_asts, info, result):
241247
Otherwise, the field type expects a sub-selection set, and will complete the value by evaluating all
242248
sub-selections.
243249
"""
244-
# If field type is NonNull, complete for inner type, and throw field error if result is null.
250+
# If field type is NonNull, complete for inner type, and throw field error
251+
# if result is null.
245252

246253
if is_thenable(result):
247254
return Promise.resolve(result).then(
@@ -252,7 +259,8 @@ def complete_value(exe_context, return_type, field_asts, info, result):
252259
info,
253260
resolved
254261
),
255-
lambda error: Promise.rejected(GraphQLLocatedError(field_asts, original_error=error))
262+
lambda error: Promise.rejected(
263+
GraphQLLocatedError(field_asts, original_error=error))
256264
)
257265

258266
# print return_type, type(result)
@@ -270,7 +278,8 @@ def complete_value(exe_context, return_type, field_asts, info, result):
270278
if isinstance(return_type, GraphQLList):
271279
return complete_list_value(exe_context, return_type, field_asts, info, result)
272280

273-
# If field type is Scalar or Enum, serialize to a valid value, returning null if coercion is not possible.
281+
# If field type is Scalar or Enum, serialize to a valid value, returning
282+
# null if coercion is not possible.
274283
if isinstance(return_type, (GraphQLScalarType, GraphQLEnumType)):
275284
return complete_leaf_value(return_type, result)
276285

@@ -280,7 +289,8 @@ def complete_value(exe_context, return_type, field_asts, info, result):
280289
if isinstance(return_type, GraphQLObjectType):
281290
return complete_object_value(exe_context, return_type, field_asts, info, result)
282291

283-
assert False, u'Cannot complete value of unexpected type "{}".'.format(return_type)
292+
assert False, u'Cannot complete value of unexpected type "{}".'.format(
293+
return_type)
284294

285295

286296
def complete_list_value(exe_context, return_type, field_asts, info, result):
@@ -295,7 +305,8 @@ def complete_list_value(exe_context, return_type, field_asts, info, result):
295305
completed_results = []
296306
contains_promise = False
297307
for item in result:
298-
completed_item = complete_value_catching_error(exe_context, item_type, field_asts, info, item)
308+
completed_item = complete_value_catching_error(
309+
exe_context, item_type, field_asts, info, item)
299310
if not contains_promise and is_thenable(completed_item):
300311
contains_promise = True
301312

@@ -326,7 +337,8 @@ def complete_abstract_value(exe_context, return_type, field_asts, info, result):
326337
if return_type.resolve_type:
327338
runtime_type = return_type.resolve_type(result, info)
328339
else:
329-
runtime_type = get_default_resolve_type_fn(result, info, return_type)
340+
runtime_type = get_default_resolve_type_fn(
341+
result, info, return_type)
330342

331343
if isinstance(runtime_type, string_types):
332344
runtime_type = info.schema.get_type(runtime_type)
@@ -340,13 +352,14 @@ def complete_abstract_value(exe_context, return_type, field_asts, info, result):
340352
info.field_name,
341353
result,
342354
runtime_type,
343-
),
355+
),
344356
field_asts
345357
)
346358

347359
if not exe_context.schema.is_possible_type(return_type, runtime_type):
348360
raise GraphQLError(
349-
u'Runtime Object type "{}" is not a possible type for "{}".'.format(runtime_type, return_type),
361+
u'Runtime Object type "{}" is not a possible type for "{}".'.format(
362+
runtime_type, return_type),
350363
field_asts
351364
)
352365

@@ -366,7 +379,8 @@ def complete_object_value(exe_context, return_type, field_asts, info, result):
366379
"""
367380
if return_type.is_type_of and not return_type.is_type_of(result, info):
368381
raise GraphQLError(
369-
u'Expected value of type "{}" but got: {}.'.format(return_type, type(result).__name__),
382+
u'Expected value of type "{}" but got: {}.'.format(
383+
return_type, type(result).__name__),
370384
field_asts
371385
)
372386

@@ -384,7 +398,8 @@ def complete_nonnull_value(exe_context, return_type, field_asts, info, result):
384398
)
385399
if completed is None:
386400
raise GraphQLError(
387-
'Cannot return null for non-nullable field {}.{}.'.format(info.parent_type, info.field_name),
401+
'Cannot return null for non-nullable field {}.{}.'.format(
402+
info.parent_type, info.field_name),
388403
field_asts
389404
)
390405

graphql/graphql.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .language.source import Source
55
from .validation import validate
66

7+
from promise import promisify
78

89
# This is the primary entry point function for fulfilling GraphQL operations
910
# by parsing, validating, and executing a GraphQL document along side a
@@ -27,9 +28,19 @@
2728
# The name of the operation to use if requestString contains multiple
2829
# possible operations. Can be omitted if requestString contains only
2930
# one operation.
30-
def graphql(schema, request_string='', root_value=None, context_value=None,
31-
variable_values=None, operation_name=None, executor=None,
32-
return_promise=False, middleware=None):
31+
32+
33+
def graphql(*args, **kwargs):
34+
return_promise = kwargs.get('return_promise', False)
35+
if return_promise:
36+
return execute_graphql_as_promise(*args, **kwargs)
37+
else:
38+
return execute_graphql(*args, **kwargs)
39+
40+
41+
def execute_graphql(schema, request_string='', root_value=None, context_value=None,
42+
variable_values=None, operation_name=None, executor=None,
43+
return_promise=False, middleware=None):
3344
try:
3445
if isinstance(request_string, Document):
3546
ast = request_string
@@ -50,11 +61,16 @@ def graphql(schema, request_string='', root_value=None, context_value=None,
5061
operation_name=operation_name,
5162
variable_values=variable_values or {},
5263
executor=executor,
53-
return_promise=return_promise,
5464
middleware=middleware,
65+
return_promise=return_promise
5566
)
5667
except Exception as e:
5768
return ExecutionResult(
5869
errors=[e],
5970
invalid=True,
6071
)
72+
73+
74+
@promisify
75+
def execute_graphql_as_promise(*args, **kwargs):
76+
return execute_graphql(*args, **kwargs)

0 commit comments

Comments
 (0)