Skip to content

Commit

Permalink
Await in parallel
Browse files Browse the repository at this point in the history
  • Loading branch information
mawa committed Sep 21, 2018
1 parent 438aedc commit e3c32a9
Show file tree
Hide file tree
Showing 4 changed files with 280 additions and 245 deletions.
16 changes: 11 additions & 5 deletions graphql/execution/execute.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from asyncio import gather
from inspect import isawaitable
from typing import (
Any,
Expand Down Expand Up @@ -437,12 +438,17 @@ def execute_fields(
# Otherwise, results is a map from field name to the result of
# resolving that field, which is possibly a coroutine object.
# Return a coroutine object that will yield this same map, but with
# any coroutines awaited and replaced with the values they yielded.
# any coroutines awaited in parallel and replaced with the values they
# yielded.
async def get_results():
return {
key: await value if isawaitable(value) else value
for key, value in results.items()
}
async def await_kv(key, value):
return key, await value if isawaitable(value) else value

pairs = await gather(
*(await_kv(key, value) for key, value in results.items())
)

return dict(pairs)

return get_results()

Expand Down
134 changes: 67 additions & 67 deletions tests/execution/test_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
GraphQLResolveInfo,
ResponsePath,
)
from .util import compare_query_results_unordered


def describe_execute_handles_basic_execution_tasks():
Expand Down Expand Up @@ -417,67 +418,70 @@ async def asyncReturnErrorWithExtensions(self, _info):
)
)

assert await execute(schema, ast, Data()) == (
{
"syncOk": "sync ok",
"syncError": None,
"syncRawError": None,
"syncReturnError": None,
"syncReturnErrorList": ["sync0", None, "sync2", None],
"asyncOk": "async ok",
"asyncError": None,
"asyncRawError": None,
"asyncReturnError": None,
"asyncReturnErrorWithExtensions": None,
},
[
{
"message": "Error getting syncError",
"locations": [(3, 15)],
"path": ["syncError"],
},
{
"message": "Error getting syncRawError",
"locations": [(4, 15)],
"path": ["syncRawError"],
},
{
"message": "Error getting syncReturnError",
"locations": [(5, 15)],
"path": ["syncReturnError"],
},
{
"message": "Error getting syncReturnErrorList1",
"locations": [(6, 15)],
"path": ["syncReturnErrorList", 1],
},
{
"message": "Error getting syncReturnErrorList3",
"locations": [(6, 15)],
"path": ["syncReturnErrorList", 3],
},
{
"message": "Error getting asyncError",
"locations": [(8, 15)],
"path": ["asyncError"],
},
{
"message": "Error getting asyncRawError",
"locations": [(9, 15)],
"path": ["asyncRawError"],
},
{
"message": "Error getting asyncReturnError",
"locations": [(10, 15)],
"path": ["asyncReturnError"],
},
compare_query_results_unordered(
await execute(schema, ast, Data()),
(
{
"message": "Error getting asyncReturnErrorWithExtensions",
"locations": [(11, 15)],
"path": ["asyncReturnErrorWithExtensions"],
"extensions": {"foo": "bar"},
"syncOk": "sync ok",
"syncError": None,
"syncRawError": None,
"syncReturnError": None,
"syncReturnErrorList": ["sync0", None, "sync2", None],
"asyncOk": "async ok",
"asyncError": None,
"asyncRawError": None,
"asyncReturnError": None,
"asyncReturnErrorWithExtensions": None,
},
],
[
{
"message": "Error getting syncError",
"locations": [(3, 15)],
"path": ["syncError"],
},
{
"message": "Error getting syncRawError",
"locations": [(4, 15)],
"path": ["syncRawError"],
},
{
"message": "Error getting syncReturnError",
"locations": [(5, 15)],
"path": ["syncReturnError"],
},
{
"message": "Error getting syncReturnErrorList1",
"locations": [(6, 15)],
"path": ["syncReturnErrorList", 1],
},
{
"message": "Error getting syncReturnErrorList3",
"locations": [(6, 15)],
"path": ["syncReturnErrorList", 3],
},
{
"message": "Error getting asyncError",
"locations": [(8, 15)],
"path": ["asyncError"],
},
{
"message": "Error getting asyncRawError",
"locations": [(9, 15)],
"path": ["asyncRawError"],
},
{
"message": "Error getting asyncReturnError",
"locations": [(10, 15)],
"path": ["asyncReturnError"],
},
{
"message": "Error getting asyncReturnErrorWithExtensions",
"locations": [(11, 15)],
"path": ["asyncReturnErrorWithExtensions"],
"extensions": {"foo": "bar"},
},
],
),
)

def full_response_path_is_included_for_non_nullable_fields():
Expand Down Expand Up @@ -893,19 +897,15 @@ async def f(*args):
{
"foo": GraphQLField(GraphQLBoolean, resolve=f),
"bar": GraphQLField(GraphQLBoolean, resolve=f),
}
},
)
)

query = '{foo, bar}'
query = "{foo, bar}"
ast = parse(query)

res = await asyncio.wait_for(
execute(schema, ast),
1.0, # don't wait forever for the test to fail
execute(schema, ast), 1.0 # don't wait forever for the test to fail
)

assert res == (
{"foo": True, "bar": True},
None,
)
assert res == ({"foo": True, "bar": True}, None)
Loading

0 comments on commit e3c32a9

Please sign in to comment.