Closed voith closed 5 years ago
cc @syrusakbary
tests are failing because yield from
syntax is not supported on python2.7
and pypy
The inspiration for this feature came from here. I will try to explain the problem again over here. Here's an MWE to explain the problem:
import asyncio
from graphql import graphql
from graphql.execution.executors.asyncio import AsyncioExecutor
from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString
async def resolver(context, *_):
await asyncio.sleep(0.001)
return "hey"
async def resolver_2(context, *_):
await asyncio.sleep(0.003)
return "hey2"
def resolver_3(contest, *_):
return "hey3"
Type = GraphQLObjectType(
"Type",
{
"a": GraphQLField(GraphQLString, resolver=resolver),
"b": GraphQLField(GraphQLString, resolver=resolver_2),
"c": GraphQLField(GraphQLString, resolver=resolver_3),
},
)
async def get_result(query):
# AsyncioExecutor will try to execute `loop.run_until_complete`
# But since trinity is already running `run_forever`,
# it will result in a error: `RuntimeError('This event loop is already running',)`
result = graphql(GraphQLSchema(Type), query, executor=AsyncioExecutor())
return result
if __name__ == "__main__":
# think of this loop used by an async framework event loop
loop = asyncio.get_event_loop()
query = "{a, b, c}"
# The async will have its own event_loop running
result = loop.run_until_complete(get_result(query))
print('result', result.data)
print('error', result.errors)
This gives the following output:
result None
error [RuntimeError('Cannot run the event loop while another loop is running',)]
If I try to use a new_loop
for AsyncioExecutor
, It results in the following:
In order to do so, just modify the code and replace get_result
with:
async def get_result(query):
result = graphql(GraphQLSchema(Type), query, executor=AsyncioExecutor(loop=asyncio.new_event_loop()))
return result
The output of this code is:
result None
error [RuntimeError('Cannot run the event loop while another loop is running',)]
So the only fix I could think of was supporting await graphql_async(schema, query, executor=AsyncioExecutor())
. This was done by introducing a new coroutine wait_until_finished_async
on AsyncioExecutor
that waits for tasks to finish asynchronously.
looks like this PR is not needed. I didn't know about return_promise
.
loop = asyncio.get_event_loop()
async def do_exec():
result = await execute(
GraphQLSchema(Type),
ast,
executor=AsyncioExecutor(loop),
return_promise=True,
)
assert not result.errors
assert result.data == {"a": "hey", "b": "hey2", "c": "hey3"}
loop.run_until_complete(do_exec())
What was wrong?
graphql(schema, query, executor=AsyncioExecutor())
is blocking.grapqhl
is executed with anotherasync
framework which already has an event loop running. The following error is raised in such cases:How was it fixed?
await graphql_async(schema, query)
syntaxAsyncioExecutor
. A new coroutinewait_until_finished_async
has been implemented.wait_until_finished_async
raisesNotImplementedError
error for all other executors.GraphQLCoreBackend
. This has been done by implementing a new coroutinedocument_from_string_async
.document_from_string_async
raisesNotImplementedError
for other backends although this support can be added if needed.